[
  {
    "path": ".dockerignore",
    "content": "target\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n- package-ecosystem: github-actions\n  directory: \"/\"\n  labels: []\n  rebase-strategy: disabled  # Redundant with mergify\n  schedule:\n    interval: daily\n- package-ecosystem: cargo\n  directory: \"/kernel-standalone-builder\"\n  labels: []\n  rebase-strategy: disabled  # Redundant with mergify\n  schedule:\n    interval: daily\n- package-ecosystem: cargo\n  directory: \"/programs\"\n  labels: []\n  rebase-strategy: disabled  # Redundant with mergify\n  schedule:\n    interval: daily\n- package-ecosystem: cargo\n  directory: \"/\"\n  labels: []\n  rebase-strategy: disabled  # Redundant with mergify\n  schedule:\n    interval: daily\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: Continuous integration\n\non:\n  pull_request:\n\njobs:\n  build-programs:\n    name: Build WASM programs\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v4\n    - name: Install Rust\n      uses: actions-rs/toolchain@v1\n      with:\n        toolchain: nightly-2025-03-14\n        target: wasm32-wasip1\n        override: true\n    - name: Install dependencies\n      run: |\n        sudo apt-get update\n        sudo apt-get install -y cmake\n    - uses: actions/cache@v4.2.3\n      with:\n        path: |\n          ~/.cargo/registry\n          ~/.cargo/git\n          programs/target\n        key: programs-cargo-${{ hashFiles('./programs/Cargo.lock') }}\n    - name: Build programs\n      run: cargo build --manifest-path ./programs/Cargo.toml --workspace --exclude stub --locked --verbose --release --target=wasm32-wasip1\n    - name: Upload WASM programs\n      uses: actions/upload-artifact@v4\n      with:\n        name: wasm-programs\n        path: programs/target\n\n  test-core:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v4\n    - uses: actions/cache@v4.2.3\n      with:\n        path: |\n          ~/.cargo/registry\n          ~/.cargo/git\n          target\n        key: core-cargo-${{ hashFiles('**/Cargo.lock') }}\n    - name: Install nightly Rust\n      uses: actions-rs/toolchain@v1\n      with:\n        toolchain: nightly-2025-03-14\n        target: wasm32-wasip1\n        override: true\n    - name: Test redshirt-core\n      run: cargo test --package redshirt-core\n\n  build-test-standalone:\n    name: Build and test standalone kernel\n    needs: build-programs\n    runs-on: ubuntu-20.04  # TODO: for the more recent QEmu version compared to ubuntu-18\n    strategy:\n      matrix:\n        #target: [x86_64-multiboot2, arm-rpi2]  # TODO: not implemented\n        target: [x86_64-multiboot2]\n    steps:\n    - uses: actions/checkout@v4\n    - name: Download WASM programs\n      uses: actions/download-artifact@v4\n      with:\n        name: wasm-programs\n    - name: Install required packages\n      run: |\n        sudo apt-get update\n        sudo apt-get install -y clang lld libisoburn1 xorriso grub-pc-bin mtools\n    - run: |\n        sudo apt-get install qemu-utils qemu-system-x86\n      if: ${{ matrix.target == 'x86_64-multiboot2'}}\n    - uses: actions/cache@v4.2.3\n      with:\n        path: |\n          ~/.cargo/registry\n          ~/.cargo/git\n          kernel-standalone-builder/target\n          target\n        key: standalone-kernel-cargo-${{ hashFiles('**/Cargo.lock') }}\n    - name: Install nightly Rust\n      uses: actions-rs/toolchain@v1\n      with:\n        toolchain: nightly-2025-03-14\n        target: wasm32-wasip1\n        override: true\n    - name: Install rust-src\n      run: rustup component add rust-src\n    - name: Build kernel\n      run: cargo run --manifest-path=./kernel-standalone-builder/Cargo.toml -- build-image --target ${{ matrix.target }} --device-type cdrom --out image\n    - name: Test kernel\n      run: cargo run --manifest-path=./kernel-standalone-builder/Cargo.toml -- emulator-test --target ${{ matrix.target }} --emulator qemu\n    - name: Upload generated kernel\n      uses: actions/upload-artifact@v4\n      with:\n        name: kernel-${{ matrix.target }}\n        path: image\n\n  fmt:\n    name: Rustfmt\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout sources\n        uses: actions/checkout@v4\n      - name: Install stable toolchain\n        uses: actions-rs/toolchain@v1\n        with:\n          toolchain: stable\n          override: true\n      - name: Install rustfmt\n        run: rustup component add rustfmt\n      - name: Run cargo fmt on root workspace\n        uses: actions-rs/cargo@v1\n        with:\n          command: fmt\n          args: --all -- --check\n      - name: Run cargo fmt on programs workspace\n        uses: actions-rs/cargo@v1\n        with:\n          command: fmt\n          args: --all --manifest-path=programs/Cargo.toml -- --check\n      - name: Run cargo fmt on standalone tester workspace\n        uses: actions-rs/cargo@v1\n        with:\n          command: fmt\n          args: --all --manifest-path=kernel-standalone-builder/Cargo.toml -- --check\n\n  intra-doc-links:\n    name: Check intra-doc links\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout sources\n        uses: actions/checkout@v4\n      - name: Install Rust toolchain\n        uses: actions-rs/toolchain@v1\n        with:\n          toolchain: nightly-2025-03-14\n          target: wasm32-wasip1\n          override: true\n      - name: Install dependencies\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y clang\n      - uses: actions/cache@v4.2.3\n        with:\n          path: |\n            ~/.cargo/registry\n            ~/.cargo/git\n            programs/target\n            kernel-standalone-builder/target\n            target\n          key: intra-doc-links-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}\n      - name: Check core intra-doc links\n        run: RUSTDOCFLAGS=\"--deny broken_intra_doc_links\" cargo doc --verbose --workspace --no-deps --document-private-items\n      - name: Check programs intra-doc links\n        run: RUSTDOCFLAGS=\"--deny broken_intra_doc_links\" cargo doc --verbose --manifest-path programs/Cargo.toml --workspace --no-deps --document-private-items\n\n  all-ci:\n    # This dummy job depends on all the mandatory checks. It succeeds if and only if CI is\n    # considered successful.\n    needs: [build-test-standalone, fmt, intra-doc-links]\n    runs-on: ubuntu-latest\n    steps:\n     - run: echo Success\n"
  },
  {
    "path": ".gitignore",
    "content": "target\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nmembers = [\n    \"kernel/core\",\n    \"kernel/core-proc-macros\",\n    \"kernel/standalone\",\n    \"interface-wrappers/disk\",\n    \"interface-wrappers/ethernet\",\n    \"interface-wrappers/framebuffer\",\n    \"interface-wrappers/hardware\",\n    \"interface-wrappers/interface\",\n    \"interface-wrappers/kernel-debug\",\n    \"interface-wrappers/kernel-log\",\n    \"interface-wrappers/loader\",\n    \"interface-wrappers/log\",\n    \"interface-wrappers/pci\",\n    \"interface-wrappers/random\",\n    \"interface-wrappers/syscalls\",\n    \"interface-wrappers/system-time\",\n    \"interface-wrappers/tcp\",\n    \"interface-wrappers/time\",\n    \"interface-wrappers/video-output\",\n]\n\n[profile.dev]\nopt-level = 1\n\n[profile.dev.package.\"*\"]\nopt-level = 3\n\n[profile.test.package.\"*\"]\nopt-level = 3\n\n[profile.release]\nopt-level = 3\nlto = true\ncodegen-units = 1\npanic = 'abort'\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    Copyright (C) 2019-2020  Pierre Krieger\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    Copyright (C) 2019-2021  Pierre Krieger\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\n"
  },
  {
    "path": "README.md",
    "content": "The **redshirt** operating system is an experiment to build some kind of operating-system-like\nenvironment where executables are all in Wasm and are loaded from an IPFS-like decentralized\nnetwork.\n\nSee the `docs/introduction.md` file for an introduction.\n\n# How to test\n\n**Important**: At the moment, most of the compilation requires a nightly version of Rust. See also https://github.com/tomaka/redshirt/issues/300.\nYour C compiler must be recent enough to be capable of compiling to WebAssembly. This is for example the case for clang 9. See also https://github.com/tomaka/redshirt/issues/257.\n\nYou also need to install the `wasm32-wasip1` target, as the Wasm programs are compiled for Wasi, and the `rust-src` component in order to build the standalone kernel.\n\n```\nrustup toolchain install --target=wasm32-wasip1 nightly\nrustup component add --toolchain=nightly rust-src\n```\n\nBuilding the freestanding kernel is then done through the utility called `standalone-builder`:\n\n```\ncd kernel-standalone-builder\ncargo +nightly run -- emulator-run --emulator qemu --target x86_64-multiboot2\n```\n\n# Repository structure\n\nShort overview of the structure of the repository:\n\n- `docs` contains a description of what redshirt is and how it works. Start with `docs/introduction.md`.\n- `interface-wrappers` contains crates that provide definitions and helpers for Wasm programs to use\n  (examples: `tcp` for TCP/IP, `window` for windowing).\n- `kernel` contains the code required to run the kernel.\n- `kernel-standalone-kernel` contains a utility allowing to run and test the standalone kernel.\n- `programs` contains Wasm programs.\n\n# Contributing\n\nPlease note that so far this is mostly a personal project. I reserve the right to change anything\nat any time, including the license.\n"
  },
  {
    "path": "docs/authorizations.md",
    "content": "It is generally desirable to limit as much as possible the rights that a program has.\n\nIn redshirt, there is no system-wide rights management. Instead, each interface holds a list of which program can have access to the capabilities that they provide.\n\nFor example, it is the network manager program that holds a list of the programs that are allowed to open TCP connections.\n\nBy default, all programs should be banned from using anything, and must instead be whitelisted. For example, when you create a new process, it is by default prevented from using the TCP connection. One must then send a message to the TCP interface to inform the network manager that the newly-created process is allowed to open TCP connections.\n"
  },
  {
    "path": "docs/interfaces.md",
    "content": "This document contains information about interfaces, plus a list of interfaces that exist.\n\n# Interfaces designing\n\n## Does this warrant an interface?\n\nInterfaces are fundamentally related to code re-use and synchronizing components.\n\nIt is for example theoretically possible for an HTTP server to communicate directly with the networking card of the machine and to directly issue read commands to hard-disk drives. This can be done by statically linking the server to device drivers.\n\nIn practice, however, doing so has two big drawbacks:\n\n- Even if we suppose that the HTTP server supports all hardware that has ever existed, new incompatible hardware gets constantly released. As such, the HTTP server would stop working on newer machines unless it gets updated.\n- Multiple programs trying to access the same hardware will conflict with each other.\n\nBecause of these two drawbacks, the hardware should be abstracted behind an interface. The first drawback is solved because the interface user and the interface handler can both be updated separately, and the second drawback is solved by having multiple interface users communicate with the same interface handler.\n\nIf, however, we take the example of font rendering (turning font files into bitmaps), none of these two drawbacks apply. Consequently, there shouldn't be an interface dedicated to font rendering.\n\n## Updating an interface\n\nIt sometimes happens that interfaces need a modification. Interfaces are considered immutable, and modifying an interface can in practice be done only by creating a different interface (that closely resembles the old one) with a different hash.\n\nSimply switching everything to the new interface, however, would break all the existing softwares that use the former interface.\n\nIn order to remedy to this, there are two solutions:\n\n- Interface handlers can register both the old and the new hash.\n- There can be a program can acts as a conversion layer between the old and the new hash, accepting messages from the old interface, translating them, and re-emitting them.\n\n## Avoiding cross-interface concerns\n\nThe list of interfaces will never be set in marble, and each version of an interface is in principle unrelated to the previous versions of that interface. As such, an interface must **never** depend on another interface.\n\nFor example, in the Linux world, creating an OpenGL context requires passing an X11 display. This means that a hypothetical equivalent redshirt OpenGL interface would depend on the equivalent redshirt X11 interface. This is forbidden.\n\nIf an equivalent of OpenGL+X11 had to be designed, one could create an interface that combines all of OpenGL and X11 together.\n\nKeep in mind that there is no one-to-one relation between interfaces and messages. For example an interface can combine into one the messaages of multiple other interfaces. \"Elegance\", \"minimalism\" or \"code reuse\" are not valid reasons to split an interface in multiple parts.\n\n# Kernel-handled interfaces\n\nSome interfaces, such as the `interface` interface, must be handled by the kernel. There is no other way that would lead to a correct implementation.\n\n# Determining an interface hash\n\nUndesigned at the moment.\n\n# List of existing or planned interfaces\n\nAnd now for a list. This list is most likely not up-to-date.\n\nThis list contains human-friendly names, but remember that interfaces are defined by their hash.\n\n- `audio-playback`: Playing sounds.\n- `device-tree`: Accessing hardware devices described by a DeviceTree (if any).\n- `disks`: Registering disks potentially containing files.\n- `ethernet`: Registering Ethernet interfaces.\n- `files`: Opening/reading/writing files on a specific disk.\n- `framebuffer`: Drawing a RGB buffer to an unspecified location.\n- `hardware`: Accessing physical memory. Note: will most likely disappear to be superceded by `pci` and `device-tree`.\n- `hid`: Accessing human-interface devices (keyboard, mouse, joysticks, etc.).\n- `interface`: Registering interfaces.\n- `kernel-debug`: Gathering information and statistics about the kernel. Supposed to be shown to users.\n- `kernel-log`: Indicating to the kernel how to write its logs.\n- `loader`: Loading content-addressed resources.\n- `log`: Sending out logs destined to the user.\n- `pci`: Accessing PCI devices (if any): reading/writing their memory-mapped memory/registers and waiting for interrupts.\n- `random`: Generating random values.\n- `system-time`: Managing the real time clock.\n- `tcp`: TCP/IP sockets.\n- `time`: Getting the value of the monotonic clock and waiting.\n- `udp`: UDP packets.\n- `usb`: Accessing USB devices (if any).\n- `video-output`: Registering video outputs that will be presented to the user. Typically a video card connected to a monitor.\n- `webgpu`: Issuing WebGPU draw calls to an unspecified location.\n"
  },
  {
    "path": "docs/introduction.md",
    "content": "# Introduction\n\nRedshirt is similar to an operating system. It allows executing programs that communicate with each other via messages.\n\n# Programs\n\nThe concept of a **program** is the same as in an operating system. It is a list of instructions that are executed and that have access to some memory.\n\nContrary to most operating systems, the instruction set of programs in redshirt is [WebAssembly](https://webassembly.org/) (also referred to as \"Wasm\").\n\nUsing WebAssembly as the instructions set has two consequences:\n\n- All programs are cross-platform.\n- Programs are not executed directly by the CPU, but by an interpreter or must first be translated into native code.\n\nThanks to the second point, we can eliminate the need for mechanisms such as paging/virtual memory and privilege levels. In other words, we don't make use of any of the sandboxing measures normally provided by the CPU.\n\n## How are programs actually executed?\n\nAt the time of the writing of this documentation, we use [the `wasmi` crate](https://docs.rs/wasmi) to execute programs.\n\nIt has been measured that compiling a program and executing it with `wasmi` is approximately ten times slower than compiling the same program for the native architecture and executing it.\nThis measurement has been performed within Linux and this doesn't account, however, for the overhead introduced by the CPU's sandboxing measures.\n\nCrates such as [`wasmtime`](https://docs.rs/wasmtime) should make it possible to considerably boost the performance of programs. Comparing a well-optimized HTTP server compiled for the native architecture to a badly-optimized HTTP server executed by `wasmtime` showed that the latter was capable of serving half of the requests per second of the former.\n\n## Limitations of sandboxing\n\nOne design issue that hasn't been solved at the time of this writing is  [preemption](https://en.wikipedia.org/wiki/Preemption_(computing)). In other words: how to run multiple CPU-intensive programs on the same CPU? In a typical operating system, the CPU receives periodic interrupts during which the operating system swaps the current thread for another.\n\nIdeally, we would like to avoid relying on the CPU receiving interrupts and instead rely on [cooperating multitasking](https://en.wikipedia.org/wiki/Cooperative_multitasking). It is possible to make the WebAssembly interpreter or JIT insert periodic checks that interrupt the execution if a certain time has passed, but these checks are generally thought to be prohibitively expensive.\n\nAdditionally, at the time of this writing, redshirt doesn't enforce any limit on the memory that Wasm programs can use. This is however only a matter of implementation.\n\n## About threads\n\nWebAssembly at the moment doesn't specify any threading model or any memory model.\n\nWhile redshirt has experimental support for creating multiple threads within a single process, WebAssembly-targeting compilers work under the assumption that only a single thread exists at any given point in time. As an example, LLVM stores the current stack pointer in a global variable.\n\nConsequently, while experimental support exists, it isn't possible at the moment for programs to create secondary threads.\n\n# Messages and interfaces\n\nPrograms are totally sandboxed, except for their capability to send messages to other processes and receive messages sent by other processes.\n\nIt is not possible, however, to send a message to a specific process (through a PID for instance). Instead, when you send a message, what you target is an **interface**.\n\nHere is how it works:\n\n- Program A registers itself towards the operating system to be the handler of a specific interface I.\n- Program B sends a message whose destination is I.\n- Program A receives the message that B has sent.\n- Optionally, A can send a single answer to B's message.\n\nIn this example, B doesn't know about the existence of A. However, A knows about the existence of B so that it can properly track resources allocation.\n\nInterfaces are referred to by a hash.\n\n## What is the hash of an interface?\n\nIn the initial design, interfaces are defined by a list of messages and answers. The hash of an interface corresponds to the hash of the definition of these messages.\n\nThis is however quite difficult to implement in practice, and at the moment the hash is randomly generated manually (by visiting https://random.org) when a new interface is defined.\n\n## Answers\n\nEach message emitted accepts either zero or one answer. The sender indicates to the operating system whether it expects an answer.\n\nIf the emitter indicates that it expects an answer, a unique **message ID** gets assigned. This identifier is later passed to the interface handler for it to indicate which message it is answering.\n\n## Message bodies and answer bodies\n\nThe actual message's body and the answer's body consist of an opaque buffer of data.\n\nThe way this body must be interpreted depends on the interface the message is targetting.\n"
  },
  {
    "path": "docs/messages.md",
    "content": "Contains details about the messages passing system.\n\n# Syscalls\n\nThere exists five syscalls at the moment:\n\n- `next_notification`\n- `emit_message`\n- `emit_answer`\n- `emit_message_error`\n- `cancel_message`\n\nDescribing their exact API/ABI here would be redundant. Please read the source code of the `syscalls` crate.\n\nIn WebAssembly, imported functions always belong to a namespace. The namespace of these five functions is `redshirt`.\n\n# Emitting a message\n\nThe `emit_message` syscall requires passing:\n\n- A target interface.\n- A message body.\n- A flag indicating whether or not an answer is expected.\n- A flag indicating whether or not the function is allowed to wait in case there is no interface handler or the interface handler is overwhelmed.\n\nIf an answer is expected, a `MessageId` gets assigned and is returned to the caller.\n\nIf no interface handler exists for the target interface, or if the interface handler isn't capable of accepting a message at the moment, the function will either wait or immediately return with an error, depending on the function parameters.\n\n## System initialization\n\nAt system initialization, the kernel is tasked to start all the programs that the user has requested to start.\n\nThe kernel doesn't know in advance which program is going to use or register which interface, so it simply starts everything at the same time.\n\nConsequently, it is possible (in particular shortly after the system's initialization) for a program to try emit a message on an interface that hasn't been registered yet but is going to be in the near future.\n\nIt is, consequently, recommended to leave the `allow_block` flag on.\n\n## Limits\n\n(Note: this is not yet implemented at the time of this writing)\n\nThere exists a limit to the number of simultaneous `MessageId`s held by a specific process. Messages continue to count towards the limit as long as they haven't been answered, even if they have been cancelled (see below).\n\nThis mechanism can be compared to the `ulimits` in the Linux world.\n\nNote that this limit is not supposed to be normally reached under normal circumstances, and serves mostly as a protection against accidental infinite loops.\n\n# Waiting for notifications\n\nEach process is characterized by a queue of notifications that can be retrieved using this function. A notification only consists, at the moment, of an answer to a previously-emitted message.\n\nThe `next_notification` syscall allows querying the operating system for notifications. It is similar to `epoll` in the Linux world.\n\nThe parameters of this syscall are:\n\n- A list of `MessageId`s whose answer to query.\n- A flag indicating whether to wait or not.\n\nIf a notification in the queue matches one of the elements in the list, then this notification is retrieved. Otherwise, the function will block if the flag is set or return immediately if it is not.\n\nNotifications contain the `MessageId`, whether the message has been successful or not, and the body of the answer.\n\n## Limit to the queue size\n\n(note: this isn't implemented at the time of writing)\n\nIf the number of notifications in a queue is higher than a certain limit, then emitting a message on the registered interfaces will block the emitter.\n\n# Answering messages\n\nMessages can be answer either by a \"success\" answer, containing a body, or by an \"error\" answer, via respectively the `emit_answer` and `emit_message_error` syscalls.\n\nIf an interface handler crashes, then all of the messages that it was supposed to answer are automatically answered with an error.\n\nAfter a message has been answered, the corresponding `MessageId` is no longer valid.\n\n# Cancelling messages\n\nThe `cancel_message` syscall allows one to notify the kernel that it is no longer interested in the answer to a previously-emitted message.\n\nThe message continues to be processed normally, and the interface handler isn't made aware of the cancellation.\n\nThe difference is that answers to cancelled messages are not pushed in the queue of notifications of the sending process.\n\nCancelling a message makes it possible to avoid the awkward situation where one needs to somehow call `next_notification` with that message only to discard the answer immediately after. Having to call `next_notification` even when we've free'd all the other resources associated with the message can be very annoying to deal with by itself.\n\n# Backpressure\n\nUnder the design described above, an interface handler has no way to pro-actively notify an interface user of something happening.\n\nFor example the network manager has no way to tell the program that has opened a TCP socket that a message has arrived on that socket.\n\nInstead, the interface user must emit a message asking the interface handler for the next event that happens. When the handler wants to notify the user of something, it can do so by answering that message.\n\nThis scheme permits proper backpressure to apply. A message sender is guaranteed to not receive more answers that it has emitted messages. It prevents a possible deadlock where a handler is waiting for more room in a process's queue, while the process is waiting for more room in the handler's queue.\n\nThere is, however, a possible deadlock if A tries to send to B, B sends to C, and C sends to A, while all three queues are full. This need to be solved.\n"
  },
  {
    "path": "interface-wrappers/disk/Cargo.toml",
    "content": "[package]\nname = \"redshirt-disk-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nfutures = \"0.3.13\"\nredshirt-syscalls = { path = \"../syscalls\" }\nparity-scale-codec = { version = \"1.3.6\", features = [\"derive\"] }\nrand = \"0.8.3\"\n"
  },
  {
    "path": "interface-wrappers/disk/src/disk.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Registering disks.\n//!\n//! This module allows you to register your disk. Reading and writing commands can then be issued\n//! towards this disk.\n//!\n//! Use this if you're writing for example an ATA/ATAPI or USB driver.\n//!\n//! # Usage\n//!\n//! - Call [`register_disk`] in order to notify of the existence of a disk.\n//! - You obtain a [`DiskRegistration`] that you can use to obtain the commands that need to be\n//!   executed by the disk.\n//! - Dropping the [`DiskRegistration`] unregisters the disk.\n//!\n\nuse crate::ffi;\nuse core::fmt;\nuse futures::{lock::Mutex, prelude::*};\nuse redshirt_syscalls::{Decode as _, Encode as _, EncodedMessage};\n\n/// Configuration of an interface to register.\n#[derive(Debug)]\npub struct DiskConfig {\n    /// `True` if the disk accepts write commands. `False` is the disk can only be read, for\n    /// example for CD-ROMs.\n    pub allow_write: bool,\n\n    /// Size, in bytes, of a sector.\n    pub sector_size: u32,\n\n    /// Number of sectors on the disk.\n    pub num_sectors: u32,\n}\n\n/// Registers a new disk.\npub async fn register_disk(config: DiskConfig) -> DiskRegistration {\n    unsafe {\n        let id = rand::random();\n\n        redshirt_syscalls::emit_message_without_response(&ffi::INTERFACE, &{\n            ffi::DiskMessage::RegisterDisk {\n                id,\n                allow_write: config.allow_write,\n                sector_size: config.sector_size,\n                num_sectors: config.num_sectors,\n            }\n        })\n        .unwrap();\n\n        DiskRegistration {\n            id,\n            commands: Mutex::new((0..10).map(|_| build_commands_future(id)).collect()),\n        }\n    }\n}\n\n/// Registered disk.\n///\n/// Destroying this object will unregister the interface.\npub struct DiskRegistration {\n    /// Identifier of the interface in the disks manager.\n    id: u64,\n\n    /// Futures that will resolve once we receive a command that the disk must execute.\n    commands: Mutex<stream::FuturesOrdered<redshirt_syscalls::MessageResponseFuture<Vec<u8>>>>,\n}\n\n/// Build a `Future` resolving to the next command to execute by the disk.\nfn build_commands_future(disk_id: u64) -> redshirt_syscalls::MessageResponseFuture<Vec<u8>> {\n    unsafe {\n        let message = ffi::DiskMessage::DiskNextCommand(disk_id).encode();\n        let msg_id = redshirt_syscalls::MessageBuilder::new()\n            .add_data(&message)\n            .emit_with_response_raw(&ffi::INTERFACE)\n            .unwrap();\n        redshirt_syscalls::message_response(msg_id)\n    }\n}\n\nimpl DiskRegistration {\n    /// Returns the next command that the disk must execute.\n    ///\n    /// > **Note**: It is possible to call this method multiple times on the same\n    /// >           [`DiskRegistration`]. If that is done, no guarantee exists as to which\n    /// >           `Future` finishes first.\n    pub async fn next_command(&self) -> Command {\n        let mut commands = self.commands.lock().await;\n        let data = commands.next().await.unwrap();\n        commands.push(build_commands_future(self.id));\n        // TODO: extra copy when decoding :-/\n        let decoded = ffi::DiskCommand::decode(EncodedMessage(data)).unwrap();\n        match decoded {\n            ffi::DiskCommand::StartRead {\n                id,\n                sector_lba,\n                num_sectors,\n            } => Command::Read(ReadCommand {\n                id,\n                sector_lba,\n                num_sectors,\n            }),\n            ffi::DiskCommand::StartWrite {\n                id,\n                sector_lba,\n                data,\n            } => Command::Write(WriteCommand {\n                id,\n                sector_lba,\n                data,\n            }),\n        }\n    }\n}\n\nimpl fmt::Debug for DiskRegistration {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"DiskRegistration\").field(&self.id).finish()\n    }\n}\n\nimpl Drop for DiskRegistration {\n    fn drop(&mut self) {\n        unsafe {\n            let message = ffi::DiskMessage::UnregisterDisk(self.id);\n            redshirt_syscalls::emit_message_without_response(&ffi::INTERFACE, &message).unwrap();\n        }\n    }\n}\n\n/// Command received from the disks manager.\npub enum Command {\n    /// See [`ReadCommand`].\n    Read(ReadCommand),\n    /// See [`WriteCommand`].\n    Write(WriteCommand),\n}\n\n/// Read command received from the disks manager. The registerer must read data from the disk.\npub struct ReadCommand {\n    id: ffi::ReadId,\n    sector_lba: u64,\n    num_sectors: u32,\n}\n\nimpl ReadCommand {\n    /// Returns the first sector to read from.\n    pub fn sector_lba(&self) -> u64 {\n        self.sector_lba\n    }\n\n    /// Returns the number of sectors to read.\n    pub fn num_sectors(&self) -> u32 {\n        self.num_sectors\n    }\n\n    /// Report that the read has finished. Contains the data read from the disk.\n    pub fn report_finished(self, data: Vec<u8>) {\n        unsafe {\n            let message = ffi::DiskMessage::ReadFinished(self.id, data);\n            redshirt_syscalls::emit_message_without_response(&ffi::INTERFACE, &message).unwrap();\n        }\n    }\n}\n\n/// Write command received from the disks manager. The registerer must write data to the disk.\npub struct WriteCommand {\n    id: ffi::WriteId,\n    sector_lba: u64,\n    data: Vec<u8>,\n}\n\nimpl WriteCommand {\n    /// Data to write to the disk.\n    pub fn data(&self) -> &[u8] {\n        &self.data\n    }\n\n    /// Returns the first sector to write to.\n    pub fn sector_lba(&self) -> u64 {\n        self.sector_lba\n    }\n\n    /// Report that the write has finished.\n    pub fn report_finished(self) {\n        unsafe {\n            let message = ffi::DiskMessage::WriteFinished(self.id);\n            redshirt_syscalls::emit_message_without_response(&ffi::INTERFACE, &message).unwrap();\n        }\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/disk/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse parity_scale_codec::{Decode, Encode};\nuse redshirt_syscalls::InterfaceHash;\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0x99, 0x94, 0xca, 0x60, 0xcf, 0x73, 0x7b, 0x59, 0xf7, 0xdc, 0x0c, 0xc4, 0xf0, 0x57, 0x42, 0x2e,\n    0x79, 0xa7, 0xb6, 0x81, 0xbb, 0xf8, 0x4e, 0x24, 0x8e, 0xbf, 0x1a, 0x8f, 0x2c, 0xf6, 0xea, 0xc8,\n]);\n\n#[derive(Debug, Encode, Decode)]\npub enum DiskMessage {\n    /// Notify of the existence of a new disk.\n    // TODO: what if this id was already registered?\n    RegisterDisk {\n        /// Unique per-process identifier.\n        id: u64,\n        /// True if writing to this disk is allowed.\n        allow_write: bool,\n        /// Size, in bytes, of a sector of the disk.\n        sector_size: u32,\n        /// Number of sectors on the disk.\n        num_sectors: u32,\n    },\n\n    /// Removes a previously-registered disk.\n    UnregisterDisk(u64),\n\n    /// Asks for the next command the disk must execute.\n    ///\n    /// Must answer with a [`DiskCommand`].\n    DiskNextCommand(u64),\n\n    /// Report that a [`DiskCommand::StartRead`] has finished.\n    ///\n    /// Has no response.\n    ReadFinished(ReadId, Vec<u8>),\n\n    /// Report that a [`DiskCommand::StartWrite`] has finished.\n    ///\n    /// Has no response.\n    WriteFinished(WriteId),\n}\n\n#[derive(Debug, Encode, Decode)]\npub enum DiskCommand {\n    StartRead {\n        id: ReadId,\n        sector_lba: u64,\n        num_sectors: u32,\n    },\n    StartWrite {\n        id: WriteId,\n        sector_lba: u64,\n        data: Vec<u8>,\n    },\n}\n\n#[derive(Debug, Encode, Decode, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub struct ReadId(pub u64);\n\n#[derive(Debug, Encode, Decode, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub struct WriteId(pub u64);\n"
  },
  {
    "path": "interface-wrappers/disk/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Disk registration and commands issuance.\n//!\n//! # Overview\n//!\n//! This interface allows indicating the presence of a disk on the machine by registering it. The\n//! registered disk can then receive commands (such as reading and writing data) that it must\n//! execute.\n//!\n//! The word \"disk\" should be understood as in a hard disk drive (HDD), solid-state drive (SSD),\n//! CD-ROM drive, floppy disk drive, and anything similar.\n//!\n//! It is recommended to **not** register disks that aren't actual physical objects connected to\n//! the machine (such as disks accessed over the network, or equivalents to UNIX's `losetup`).\n//! Redshirt tries to be as explicit as possible and to keep its abstractions as close as possible\n//! to the objects being abstracted.\n//!\n//! Users of this interface are expected to be ATA/ATAPI drivers, USB drivers, and similar. The\n//! handler of this interface is expected to be a filesystem manager that determines the list of\n//! partitions and handles the file systems.\n//!\n//! # About disks\n//!\n//! In the abstraction exposed by this interface, a disk is composed of a certain number of\n//! sectors, each having a certain size. The size of all sectors is identical. These sectors are\n//! indexed from `0` to `num_sectors - 1`.\n//!\n//! The sector index is typically referred to by the term \"LBA sector\". *LBA* designates the fact\n//! that each sector is addressed through a index ranging linearly from `0` to `num_sectors - 1`,\n//! as opposed to the older *CHS* addressing where sectors were referred to a by a head number,\n//! cylinder number, and sectors offset. CHS addressing isn't used in this interface.\n//!\n//! It is not possible to partially read or write a sector. The sector has to be read entirely,\n//! or written entirely.\n//!\n//! # Flushing\n//!\n//! The interface requires each disk write to be confirmed by sending a message on the interface\n//! after it has been performed. This is important in order for the upper layer to be capable of\n//! handling problematic situations such as a power outage.\n//!\n//! Consequently, while the disk driver is allowed to maintain a write cache, it must not report\n//! a write success after the data has been put in cache, but after it has been written to disk.\n//!\n//! In the interval of time between the moment the writing is issued and the moment it is\n//! confirmed, the upper layers should consider that the sector is physically in an undefined\n//! state.\n\npub mod disk;\npub mod ffi;\n"
  },
  {
    "path": "interface-wrappers/ethernet/Cargo.toml",
    "content": "[package]\nname = \"redshirt-ethernet-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nfutures = \"0.3.13\"\nredshirt-syscalls = { path = \"../syscalls\" }\nparity-scale-codec = { version = \"1.3.6\", features = [\"derive\"] }\nrand = \"0.8.3\"\n"
  },
  {
    "path": "interface-wrappers/ethernet/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse parity_scale_codec::{Decode, Encode};\nuse redshirt_syscalls::InterfaceHash;\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0x56, 0xf0, 0xad, 0x54, 0x6c, 0x6d, 0x91, 0xce, 0xc2, 0x10, 0x88, 0xf6, 0x32, 0x2b, 0x66, 0x45,\n    0xd4, 0xcf, 0xbe, 0xa3, 0xf7, 0x03, 0x13, 0xcd, 0x04, 0x65, 0xfd, 0x7f, 0x06, 0xd4, 0x24, 0xa1,\n]);\n\n#[derive(Debug, Encode, Decode)]\npub enum NetworkMessage {\n    /// Notify of the existence of a new Ethernet interface.\n    // TODO: what if this id was already registered?\n    RegisterInterface {\n        /// Unique per-process identifier.\n        id: u64,\n        /// MAC address of the interface.\n        mac_address: [u8; 6],\n    },\n\n    /// Removes a previously-registered interface.\n    UnregisterInterface(u64),\n\n    /// Notify when an interface has received data (e.g. from the outside world). Must answer with\n    /// a `()` when the send is finished and we're ready to accept a new packet.\n    ///\n    /// The packet must be an Ethernet frame without the CRC.\n    InterfaceOnData(u64, Vec<u8>),\n\n    /// Asks for the next packet of data to send out through this interface (e.g. going towards\n    /// the outside world). Must answer with a `Vec<u8>`.\n    ///\n    /// The packet must be an Ethernet frame without the CRC.\n    InterfaceWaitData(u64),\n}\n"
  },
  {
    "path": "interface-wrappers/ethernet/src/interface.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Registering Ethernet interfaces.\n//!\n//! This module allows you to register your Ethernet interface. TCP and UDP sockets will then use\n//! it to communicate with the outside.\n//!\n//! Use this if you're writing for example a networking driver or a VPN.\n//!\n//! # Usage\n//!\n//! - Call [`register_interface`] in order to notify of the existence of an interface.\n//! - You obtain a [`NetInterfaceRegistration`] that you can use to report packets that came from\n//! the wire, and from which you can obtain packets to send to the wire.\n//! - Dropping the [`NetInterfaceRegistration`] unregisters the interface.\n//!\n\nuse crate::ffi;\nuse core::fmt;\nuse futures::{\n    lock::{Mutex, MutexGuard},\n    prelude::*,\n};\nuse redshirt_syscalls::Encode as _;\n\n/// Configuration of an interface to register.\n#[derive(Debug)]\npub struct InterfaceConfig {\n    /// MAC address of the interface.\n    ///\n    /// If this is a virtual device, feel free to randomly generate a MAC address.\n    pub mac_address: [u8; 6],\n}\n\n/// Registers a new network interface.\npub async fn register_interface(config: InterfaceConfig) -> NetInterfaceRegistration {\n    unsafe {\n        let id = rand::random();\n\n        redshirt_syscalls::emit_message_without_response(&ffi::INTERFACE, &{\n            ffi::NetworkMessage::RegisterInterface {\n                id,\n                mac_address: config.mac_address,\n            }\n        })\n        .unwrap();\n\n        NetInterfaceRegistration {\n            id,\n            packet_from_net: Mutex::new(None),\n            packet_to_net: Mutex::new((0..10).map(|_| build_packet_to_net(id)).collect()),\n        }\n    }\n}\n\n/// Registered network interface.\n///\n/// Destroying this object will unregister the interface.\npub struct NetInterfaceRegistration {\n    /// Identifier of the interface in the network manager.\n    id: u64,\n\n    /// Futures that will resolve once we receive a packet from the network manager to send to the\n    /// network.\n    packet_to_net: Mutex<stream::FuturesOrdered<redshirt_syscalls::MessageResponseFuture<Vec<u8>>>>,\n\n    /// Future that will resolve once we have successfully delivered a packet from the network,\n    /// and are ready to deliver a next one.\n    // TODO: should probably change to send multiple packets in parallel\n    packet_from_net: Mutex<Option<redshirt_syscalls::MessageResponseFuture<()>>>,\n}\n\n/// Build a `Future` resolving to the next packet to send to the network.\n///\n/// Only one such `Future` must be alive at any given point in time.\nfn build_packet_to_net(interface_id: u64) -> redshirt_syscalls::MessageResponseFuture<Vec<u8>> {\n    unsafe {\n        let message = ffi::NetworkMessage::InterfaceWaitData(interface_id).encode();\n        let msg_id = redshirt_syscalls::MessageBuilder::new()\n            .add_data(&message)\n            .emit_with_response_raw(&ffi::INTERFACE)\n            .unwrap();\n        redshirt_syscalls::message_response(msg_id)\n    }\n}\n\nimpl NetInterfaceRegistration {\n    /// Wait until the network manager is ready to accept a packet coming from the network.\n    ///\n    /// Returns a [`PacketFromNetwork`] object that allows you to transmit the packet.\n    ///\n    /// > **Note**: It is possible to call this method multiple times on the same\n    /// >           [`NetInterfaceRegistration`]. If that is done, no guarantee exists as to which\n    /// >           `Future` finishes first.\n    pub async fn packet_from_network<'a>(&'a self) -> PacketFromNetwork<'a> {\n        // Wait for the previous send to be finished.\n        let mut packet_from_net = self.packet_from_net.lock().await;\n        if let Some(fut) = packet_from_net.as_mut() {\n            fut.await;\n        }\n        *packet_from_net = None;\n\n        PacketFromNetwork {\n            parent: self,\n            send_future: packet_from_net,\n        }\n    }\n\n    /// Returns the next packet to send to the network.\n    ///\n    /// > **Note**: It is possible to call this method multiple times on the same\n    /// >           [`NetInterfaceRegistration`]. If that is done, no guarantee exists as to which\n    /// >           `Future` finishes first.\n    pub async fn packet_to_send(&self) -> Vec<u8> {\n        let mut packet_to_net = self.packet_to_net.lock().await;\n        let data = packet_to_net.next().await.unwrap();\n        packet_to_net.push(build_packet_to_net(self.id));\n        data\n    }\n}\n\nimpl fmt::Debug for NetInterfaceRegistration {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"NetInterfaceRegistration\")\n            .field(&self.id)\n            .finish()\n    }\n}\n\nimpl Drop for NetInterfaceRegistration {\n    fn drop(&mut self) {\n        unsafe {\n            let message = ffi::NetworkMessage::UnregisterInterface(self.id);\n            redshirt_syscalls::emit_message_without_response(&ffi::INTERFACE, &message).unwrap();\n        }\n    }\n}\n\n/// Allows you to transmit a packet received from the network to the manager.\n#[must_use]\npub struct PacketFromNetwork<'a> {\n    parent: &'a NetInterfaceRegistration,\n    send_future: MutexGuard<'a, Option<redshirt_syscalls::MessageResponseFuture<()>>>,\n}\n\nimpl<'a> PacketFromNetwork<'a> {\n    /// Send the packet to the manager.\n    pub fn send(mut self, data: impl Into<Vec<u8>>) {\n        unsafe {\n            debug_assert!(self.send_future.is_none());\n            let message =\n                ffi::NetworkMessage::InterfaceOnData(self.parent.id, data.into()).encode();\n            let msg_id = redshirt_syscalls::MessageBuilder::new()\n                .add_data(&message)\n                .emit_with_response_raw(&ffi::INTERFACE)\n                .unwrap();\n            let fut = redshirt_syscalls::message_response(msg_id);\n            *self.send_future = Some(fut);\n        }\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/ethernet/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Ethernet interfaces.\n//!\n//! This interface allows registering Ethernet interfaces that conform to the requirements\n//! described in [RFC1122](https://tools.ietf.org/html/rfc1122).\n//!\n//! Users of this interface can notify of the presence of an Ethernet interface, after which it\n//! can notify of Ethernet frames having been received on this interface, and request Ethernet\n//! frames to be sent on the interface.\n//!\n//! The Ethernet frames that are communicated contain:\n//!\n//! - The destination MAC.\n//! - The source MAC.\n//! - An optional 802.1Q tag.\n//! - The Ethertype field.\n//! - The payload.\n//!\n//! Most notably, they **don't** include any preamble, delimiter, interpacket gap, and checksum.\n//!\n//! # Networking overview\n//!\n//! This section provides some overview of networking in general.\n//!\n//! ## Link layer routing\n//!\n//! Each Ethernet interface registered with this interface possesses a MAC address, and is assumed\n//! to be directly connected to zero, one, or more other machines.\n//!\n//! Thanks to the ARP or NDP protocols, it is possible to broadcast a request on the Ethernet\n//! interface asking who we are connected to. The nodes that receive the request respond with their\n//! IP and MAC address. If later we want to send a direct message to one of these nodes, we simply\n//! emit an Ethernet frame with the MAC address of the destination.\n//!\n//! Note that being \"directly connected\" to a node doesn't necessarily mean that there exists a\n//! physical cable between us and this node. Hubs, switches, or Wifi routers, can act as an\n//! intermediary.\n//!\n//! ## IP layer routing\n//!\n//! All of the registered Ethernet interfaces are considered as being part of one single network\n//! (typically the Internet).\n//!\n//! > **Note**: This doesn't mean that we are free to send out packets on any interface that we\n//! >           want and expect the routing to make the packet find its way. In particular, this\n//! >           single network can be disjoint.\n//!\n//! Nodes on this network (i.e. something with an IP address) can be split into two categories:\n//!\n//! - Nodes we are directly connected to, as described in the previous section. It is possible to\n//! send a direct message to these nodes by writing bytes on the right interface.\n//! - Nodes we are *not* directly connected to.\n//!\n//! The implementer of this interface maintains what we call a *routing table*. A routing table is\n//! a collection of entries, each entry consisting of:\n//!\n//! - A \"pattern\", kind of similar to a regex for example. This pattern consists of an IP address\n//! and mask. An IP address matches that pattern if\n//! `(ip_addr & pattern.mask) == (pattern.ip & pattern.mask)`.\n//! - A gateway. This is the IP address of a node that we are physically connected to and that is\n//! in charge of relaying packets to nodes that match the given pattern.\n//! - The network interface the gateway is connected to.\n//!\n//! When we want to reach the node with a specific IP address, we look through the table until\n//! we find an entry whose pattern matches the target IP address. If multiple entries are matching,\n//! we pick the one with the most specific mask.\n//!\n//! The gateway is then expected to properly direct the packet towards its rightful destination.\n//!\n\npub mod ffi;\npub mod interface;\n"
  },
  {
    "path": "interface-wrappers/framebuffer/Cargo.toml",
    "content": "[package]\nname = \"redshirt-framebuffer-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nfutures = \"0.3\"\nparity-scale-codec = { version = \"1.3.6\", features = [\"derive\"] }\nredshirt-random-interface = { path = \"../random\", default-features = false }\nredshirt-syscalls = { path = \"../syscalls\", default-features = false }\n"
  },
  {
    "path": "interface-wrappers/framebuffer/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//!\n//!\n//! Message format:\n//!\n//! The type of message depends on the first byte:\n//!\n//! - 0: Creates a framebuffer. Next 4 bytes are a \"framebuffer ID\" as decided by the message\n//! emitter. Next 4 bytes are the width in little endian. Next 4 bytes are the height in little\n//! endian.\n//! - 1: Destroys a framebuffer. Next 4 bytes are the framebuffer ID.\n//! - 2: Set framebuffer content. Next 4 bytes are the framebuffer ID. The rest is 3 * width *\n//! height values. The rest is RGB triplets.\n//! - 3: Send back the next input event. Next 4 bytes are the framebuffer ID. The answer consists\n//! in an input event whose format is a SCALE-encoding of the [`Event`] struct below.\n//!\n//! There actually exists two interfaces that use the same messages format: with events, or without\n//! events. Messages whose first byte is `3` are invalid in the \"without events\" interface.\n\nuse redshirt_syscalls::InterfaceHash;\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE_WITH_EVENTS: InterfaceHash = InterfaceHash::from_raw_hash([\n    0xfc, 0x60, 0x2e, 0x6e, 0xf2, 0x43, 0x9c, 0xa0, 0x40, 0x88, 0x81, 0x7d, 0xe5, 0xaf, 0xb6, 0x90,\n    0x9e, 0x57, 0xc6, 0xc2, 0x5e, 0xbf, 0x02, 0x5b, 0x87, 0x7f, 0xaa, 0xae, 0xbe, 0xd5, 0x19, 0x9c,\n]);\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE_WITHOUT_EVENTS: InterfaceHash = InterfaceHash::from_raw_hash([\n    0xdf, 0x67, 0x74, 0x34, 0xd8, 0x0d, 0xc5, 0x9e, 0xf0, 0x6e, 0xb9, 0x44, 0xce, 0xaa, 0xc4, 0xde,\n    0x8d, 0x2f, 0xdf, 0x39, 0x0a, 0xe6, 0xa8, 0x29, 0x3c, 0x8f, 0x88, 0x76, 0x5b, 0xe9, 0x1c, 0x70,\n]);\n\n/// Event that can be reported by a framebuffer.\n///\n/// > **Note**: These events are designed to take into account the possibility that some events are\n/// >           lost. This can happen if the recipient queues messages too slowly.\n#[derive(Debug, Clone, parity_scale_codec::Encode, parity_scale_codec::Decode)]\npub enum Event {\n    /// A keyboard key has been pressed or released.\n    KeyboardChange {\n        /// Scancode as defined in the USB HID Usage tables.\n        ///\n        /// See table 12 on page 53:\n        /// https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf\n        scancode: u16,\n\n        /// New state of the given key.\n        new_state: ElementState,\n    },\n\n    /// The cursor has moved over the framebuffer.\n    CursorMoved {\n        /// New position of the cursor in millipixels relative to the top-left hand corner of the\n        /// framebuffer. `None` if the cursor is not on the framebuffer.\n        ///\n        /// Please note that these are millipixels. As such, you have to divide them by 1000 to\n        /// obtain a value in pixels.\n        new_position: Option<(u64, u64)>,\n    },\n\n    /// A mouse button has been pressed or released.\n    MouseButtonChange {\n        /// Which mouse button is concerned.\n        button: MouseButton,\n\n        /// New state of the given button.\n        new_state: ElementState,\n    },\n}\n\n#[derive(Debug, Clone, parity_scale_codec::Encode, parity_scale_codec::Decode)]\npub enum MouseButton {\n    /// Typically but not necessarily the left mouse button.\n    Main,\n    /// Typically but not necessarily the right mouse button.\n    Secondary,\n}\n\n#[derive(Debug, Clone, parity_scale_codec::Encode, parity_scale_codec::Decode)]\npub enum ElementState {\n    Pressed,\n    Released,\n}\n"
  },
  {
    "path": "interface-wrappers/framebuffer/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Framebuffer interface.\n//!\n//! Allows drawing an image.\n//!\n//! > **Note**: The fate of this interface is kind of vague. It is also unclear whether\n//! >           keyboard/mouse input should be handled here as well. Use at your own risks.\n\n#![no_std]\n\nextern crate alloc;\n\nuse alloc::collections::VecDeque;\nuse core::convert::TryFrom as _;\nuse redshirt_syscalls::{InterfaceHash, MessageId};\n\npub mod ffi;\n\n/// Framebuffer containing pixel data.\npub struct Framebuffer {\n    /// Identifier of the framebuffer. Used for all communications.\n    id: u32,\n\n    /// Interface used for this framebuffer.\n    interface: &'static InterfaceHash,\n\n    /// Width of the framebuffer in pixels.\n    width: u32,\n    /// Height of the framebuffer in pixels.\n    height: u32,\n\n    /// List of active messages that will be responded with incoming events.\n    ///\n    /// The capacity of this container also corresponds to the number of elements that we want to\n    /// have in it at any given moment. In other words, there is no field in this struct indicating\n    /// the number of events because that'd be redundant with `event_messages.capacity()`.\n    event_messages: VecDeque<MessageId>,\n}\n\nimpl Framebuffer {\n    /// Initializes a new framebuffer of the given width and height.\n    pub async fn new(with_events: bool, width: u32, height: u32) -> Self {\n        let id = unsafe {\n            let mut out = [0; 4];\n            redshirt_random_interface::generate_in(&mut out).await;\n            u32::from_le_bytes(out)\n        };\n\n        let interface = if with_events {\n            &ffi::INTERFACE_WITH_EVENTS\n        } else {\n            &ffi::INTERFACE_WITHOUT_EVENTS\n        };\n\n        unsafe {\n            let id_le_bytes = id.to_le_bytes();\n            let width_le_bytes = width.to_le_bytes();\n            let height_le_bytes = height.to_le_bytes();\n            redshirt_syscalls::MessageBuilder::new()\n                .add_data_raw(&[0])\n                .add_data_raw(&id_le_bytes[..])\n                .add_data_raw(&width_le_bytes[..])\n                .add_data_raw(&height_le_bytes[..])\n                .emit_without_response(interface)\n                .unwrap();\n        }\n\n        let num_events_queue = if with_events { 10 } else { 0 };\n\n        let mut fb = Framebuffer {\n            id,\n            interface,\n            width,\n            height,\n            event_messages: VecDeque::with_capacity(num_events_queue),\n        };\n        fb.fill_event_messages();\n        fb\n    }\n\n    /// Sets the data in the framebuffer.\n    ///\n    /// The size of `data` must be `width * height * 3`.\n    pub fn set_data(&self, data: &[u8]) {\n        unsafe {\n            assert_eq!(\n                data.len(),\n                usize::try_from(\n                    self.width\n                        .checked_mul(self.height)\n                        .unwrap()\n                        .checked_mul(3)\n                        .unwrap()\n                )\n                .unwrap()\n            );\n\n            let id_le_bytes = self.id.to_le_bytes();\n            redshirt_syscalls::MessageBuilder::new()\n                .add_data_raw(&[2])\n                .add_data_raw(&id_le_bytes[..])\n                .add_data_raw(data)\n                .emit_without_response(self.interface)\n                .unwrap();\n        }\n    }\n\n    /// Returns the next event that the framebuffer receives.\n    // TODO: proper return type\n    pub async fn next_event(&mut self) -> u32 {\n        if let Some(first_event) = self.event_messages.front() {\n            let event: u32 = redshirt_syscalls::message_response(*first_event).await; // TODO: proper event type\n            self.event_messages.pop_front();\n            self.fill_event_messages();\n            event\n        } else {\n            futures::future::pending().await\n        }\n    }\n\n    /// Pushes back events to `event_messages` until we reach the maximum.\n    fn fill_event_messages(&mut self) {\n        while self.event_messages.len() < self.event_messages.capacity() {\n            let new_event = unsafe {\n                redshirt_syscalls::MessageBuilder::new()\n                    .add_data_raw(&[3])\n                    .add_data_raw(&self.id.to_le_bytes()[..])\n                    .emit_with_response_raw(self.interface)\n                    .unwrap()\n            };\n\n            self.event_messages.push_back(new_event);\n        }\n    }\n}\n\nimpl Drop for Framebuffer {\n    fn drop(&mut self) {\n        unsafe {\n            let id_le_bytes = self.id.to_le_bytes();\n            redshirt_syscalls::MessageBuilder::new()\n                .add_data_raw(&[1])\n                .add_data_raw(&id_le_bytes[..])\n                .emit_without_response(self.interface)\n                .unwrap();\n        }\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/hardware/Cargo.toml",
    "content": "[package]\nname = \"redshirt-hardware-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nfutures = { version = \"0.3.13\", default-features = false }\nredshirt-syscalls = { path = \"../syscalls\", default-features = false }\nparity-scale-codec = { version = \"1.3.6\", default-features = false, features = [\"derive\"] }\n\n[features]\ndefault = [\"std\"]\nstd = []\n"
  },
  {
    "path": "interface-wrappers/hardware/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse alloc::vec::Vec;\nuse parity_scale_codec::{Decode, Encode};\nuse redshirt_syscalls::InterfaceHash;\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0x24, 0x5d, 0x25, 0x5e, 0x37, 0xf1, 0x8a, 0xce, 0x23, 0xd6, 0x68, 0xe9, 0xe2, 0xd8, 0xd1, 0xbc,\n    0x37, 0xf3, 0xd3, 0x3c, 0xad, 0x55, 0xf8, 0xd9, 0x22, 0x3a, 0x57, 0xd1, 0x54, 0x46, 0x7b, 0x78,\n]);\n\n/// Message in destination to the hardware interface handler.\n#[derive(Debug, Encode, Decode)]\npub enum HardwareMessage {\n    /// Allocate RAM. Must answer with a `u64`. The value `0` is returned if the allocation is\n    /// too large.\n    ///\n    /// This is useful in situations where you want to pass a pointer to a device.\n    Malloc {\n        /// Size to allocate.\n        size: u64,\n        /// Alignment of the pointer to return.\n        ///\n        /// The returned value modulo `alignment` must be equal to 0.\n        alignment: u64,\n    },\n    /// Opposite of malloc.\n    Free {\n        /// Value previously returned after a malloc message.\n        ptr: u64,\n    },\n    /// Request to perform some access on the physical memory or ports.\n    ///\n    /// All operations must be performed in order.\n    ///\n    /// If there is at least one memory or port read, the response must be a\n    /// `Vec<HardwareAccessResponse>` where each element corresponds to a read. No response is\n    /// expected if there are only writes.\n    // TODO: should we enforce some limits in the amount of data that can be returned in a response?\n    HardwareAccess(Vec<Operation>),\n\n    /// Ask the handler to send back a response when the interrupt with the given number is\n    /// triggered.\n    ///\n    /// > **Note**: If called with a non-hardware interrupt, no response will ever come back.\n    // TODO: how to not miss any interrupt? we instead need some registration system or something\n    InterruptWait(u32),\n}\n\n/// Request to perform accesses to physical memory or to ports.\n#[derive(Debug, Encode, Decode)]\npub enum Operation {\n    PhysicalMemoryMemset {\n        address: u64,\n        len: u64,\n        value: u8,\n    },\n    PhysicalMemoryWriteU8 {\n        address: u64,\n        data: Vec<u8>,\n    },\n    /// Uses the platform's native endianess.\n    PhysicalMemoryWriteU16 {\n        address: u64,\n        data: Vec<u16>,\n    },\n    /// Uses the platform's native endianess.\n    PhysicalMemoryWriteU32 {\n        address: u64,\n        data: Vec<u32>,\n    },\n    PhysicalMemoryReadU8 {\n        address: u64,\n        len: u32,\n    },\n    PhysicalMemoryReadU16 {\n        address: u64,\n        /// Number of `u16`s to read.\n        len: u32,\n    },\n    PhysicalMemoryReadU32 {\n        address: u64,\n        /// Number of `u32`s to read.\n        len: u32,\n    },\n    /// Write data to a port.\n    ///\n    /// If the hardware doesn't support this operation, then nothing happens.\n    PortWriteU8 {\n        port: u32,\n        data: u8,\n    },\n    /// Write data to a port.\n    ///\n    /// If the hardware doesn't support this operation, then nothing happens.\n    PortWriteU16 {\n        port: u32,\n        data: u16,\n    },\n    /// Write data to a port.\n    ///\n    /// If the hardware doesn't support this operation, then nothing happens.\n    PortWriteU32 {\n        port: u32,\n        data: u32,\n    },\n    /// Reads data from a port.\n    ///\n    /// If the hardware doesn't support this operation, then `0` is produced.\n    PortReadU8 {\n        port: u32,\n    },\n    /// Reads data from a port.\n    ///\n    /// If the hardware doesn't support this operation, then `0` is produced.\n    PortReadU16 {\n        port: u32,\n    },\n    /// Reads data from a port.\n    ///\n    /// If the hardware doesn't support this operation, then `0` is produced.\n    PortReadU32 {\n        port: u32,\n    },\n}\n\n/// Response to a [`HardwareMessage::HardwareAccess`].\n#[derive(Debug, Encode, Decode)]\npub enum HardwareAccessResponse {\n    /// Sent back in response to a [`Operation::PhysicalMemoryReadU8`].\n    PhysicalMemoryReadU8(Vec<u8>),\n    /// Sent back in response to a [`Operation::PhysicalMemoryReadU16`].\n    PhysicalMemoryReadU16(Vec<u16>),\n    /// Sent back in response to a [`Operation::PhysicalMemoryReadU32`].\n    PhysicalMemoryReadU32(Vec<u32>),\n    /// Sent back in response to a [`Operation::PortReadU8`].\n    PortReadU8(u8),\n    /// Sent back in response to a [`Operation::PortReadU16`].\n    PortReadU16(u16),\n    /// Sent back in response to a [`Operation::PortReadU32`].\n    PortReadU32(u32),\n}\n"
  },
  {
    "path": "interface-wrappers/hardware/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Access to physical hardware.\n//!\n//! Use this interface if you're writing a device driver.\n\n#![cfg_attr(not(feature = \"std\"), no_std)]\n\nextern crate alloc;\n\nuse alloc::{vec, vec::Vec};\nuse core::convert::TryFrom as _;\nuse futures::prelude::*;\n\npub mod ffi;\npub mod malloc;\n\n/// Builder for write-only hardware operations.\npub struct HardwareWriteOperationsBuilder {\n    operations: Vec<ffi::Operation>,\n}\n\nimpl HardwareWriteOperationsBuilder {\n    pub fn new() -> Self {\n        HardwareWriteOperationsBuilder {\n            operations: Vec::new(),\n        }\n    }\n\n    pub fn with_capacity(capacity: usize) -> Self {\n        HardwareWriteOperationsBuilder {\n            operations: Vec::with_capacity(capacity),\n        }\n    }\n\n    pub unsafe fn memset(&mut self, address: u64, len: u64, value: u8) {\n        self.operations.push(ffi::Operation::PhysicalMemoryMemset {\n            address,\n            len,\n            value,\n        });\n    }\n\n    pub unsafe fn write(&mut self, address: u64, data: impl Into<Vec<u8>>) {\n        self.operations.push(ffi::Operation::PhysicalMemoryWriteU8 {\n            address,\n            data: data.into(),\n        });\n    }\n\n    pub unsafe fn write_one_u32(&mut self, address: u64, data: u32) {\n        self.operations\n            .push(ffi::Operation::PhysicalMemoryWriteU32 {\n                address,\n                data: vec![data],\n            });\n    }\n\n    pub unsafe fn port_write_u8(&mut self, port: u32, data: u8) {\n        self.operations\n            .push(ffi::Operation::PortWriteU8 { port, data });\n    }\n\n    pub unsafe fn port_write_u16(&mut self, port: u32, data: u16) {\n        self.operations\n            .push(ffi::Operation::PortWriteU16 { port, data });\n    }\n\n    pub unsafe fn port_write_u32(&mut self, port: u32, data: u32) {\n        self.operations\n            .push(ffi::Operation::PortWriteU32 { port, data });\n    }\n\n    pub fn send(self) {\n        unsafe {\n            if self.operations.is_empty() {\n                return;\n            }\n\n            let msg = ffi::HardwareMessage::HardwareAccess(self.operations);\n            redshirt_syscalls::emit_message_without_response(&ffi::INTERFACE, &msg).unwrap();\n        }\n    }\n}\n\n/// Writes the given data to the given physical memory address location.\npub unsafe fn write(address: u64, data: impl Into<Vec<u8>>) {\n    let mut builder = HardwareWriteOperationsBuilder::with_capacity(1);\n    builder.write(address, data);\n    builder.send();\n}\n\n/// Reads memory to a buffer.\npub async unsafe fn read_to(address: u64, mut out: &mut [u8]) {\n    let mut ops = HardwareOperationsBuilder::new();\n    ops.read(address, &mut out);\n    ops.send().await;\n}\n\n/// Reads memory.\npub async unsafe fn read(address: u64, len: u32) -> Vec<u8> {\n    let len_usize = usize::try_from(len).unwrap();\n    let mut out = Vec::with_capacity(len_usize);\n    out.set_len(len_usize);\n    let mut ops = HardwareOperationsBuilder::new();\n    ops.read(address, &mut out);\n    ops.send().await;\n    out\n}\n\n/// Reads a single `u32` from the given memory address.\n#[cfg(feature = \"std\")]\npub async unsafe fn read_one_u32(address: u64) -> u32 {\n    let mut ops = HardwareOperationsBuilder::new();\n    let mut out = [0];\n    ops.read_u32(address, &mut out);\n    ops.send().await;\n    out[0]\n}\n\npub unsafe fn write_one_u32(address: u64, data: u32) {\n    let mut builder = HardwareWriteOperationsBuilder::with_capacity(1);\n    builder.write_one_u32(address, data);\n    builder.send();\n}\n\npub unsafe fn port_write_u8(port: u32, data: u8) {\n    let mut builder = HardwareWriteOperationsBuilder::with_capacity(1);\n    builder.port_write_u8(port, data);\n    builder.send();\n}\n\npub unsafe fn port_write_u16(port: u32, data: u16) {\n    let mut builder = HardwareWriteOperationsBuilder::with_capacity(1);\n    builder.port_write_u16(port, data);\n    builder.send();\n}\n\npub unsafe fn port_write_u32(port: u32, data: u32) {\n    let mut builder = HardwareWriteOperationsBuilder::with_capacity(1);\n    builder.port_write_u32(port, data);\n    builder.send();\n}\n\n/// Reads the given port.\npub async unsafe fn port_read_u8(port: u32) -> u8 {\n    let mut builder = HardwareOperationsBuilder::with_capacity(1);\n    let mut out = 0;\n    builder.port_read_u8(port, &mut out);\n    builder.send().await;\n    out\n}\n\npub async unsafe fn port_read_u16(port: u32) -> u16 {\n    let mut builder = HardwareOperationsBuilder::with_capacity(1);\n    let mut out = 0;\n    builder.port_read_u16(port, &mut out);\n    builder.send().await;\n    out\n}\n\npub async unsafe fn port_read_u32(port: u32) -> u32 {\n    let mut builder = HardwareOperationsBuilder::with_capacity(1);\n    let mut out = 0;\n    builder.port_read_u32(port, &mut out);\n    builder.send().await;\n    out\n}\n\n/// Builder for read and write hardware operations.\npub struct HardwareOperationsBuilder<'a> {\n    operations: Vec<ffi::Operation>,\n    out: Vec<Out<'a>>,\n}\n\nenum Out<'a> {\n    MemReadU8(&'a mut [u8]),\n    MemReadU16(&'a mut [u16]),\n    MemReadU32(&'a mut [u32]),\n    PortU8(&'a mut u8),\n    PortU16(&'a mut u16),\n    PortU32(&'a mut u32),\n    Discard,\n}\n\nimpl<'a> HardwareOperationsBuilder<'a> {\n    pub fn new() -> Self {\n        HardwareOperationsBuilder {\n            operations: Vec::new(),\n            out: Vec::new(),\n        }\n    }\n\n    pub fn with_capacity(capacity: usize) -> Self {\n        HardwareOperationsBuilder {\n            operations: Vec::with_capacity(capacity),\n            out: Vec::with_capacity(capacity),\n        }\n    }\n\n    pub unsafe fn read(&mut self, address: u64, out: &'a mut (impl ?Sized + AsMut<[u8]>)) {\n        let out = out.as_mut();\n        self.operations.push(ffi::Operation::PhysicalMemoryReadU8 {\n            address,\n            len: out.len() as u32, // TODO: don't use `as`\n        });\n        self.out.push(Out::MemReadU8(out));\n    }\n\n    pub unsafe fn read_u16(&mut self, address: u64, out: &'a mut (impl ?Sized + AsMut<[u16]>)) {\n        let out = out.as_mut();\n        self.operations.push(ffi::Operation::PhysicalMemoryReadU16 {\n            address,\n            len: out.len() as u32, // TODO: don't use `as`\n        });\n        self.out.push(Out::MemReadU16(out));\n    }\n\n    pub unsafe fn read_u32(&mut self, address: u64, out: &'a mut (impl ?Sized + AsMut<[u32]>)) {\n        let out = out.as_mut();\n        self.operations.push(ffi::Operation::PhysicalMemoryReadU32 {\n            address,\n            len: out.len() as u32, // TODO: don't use `as`\n        });\n        self.out.push(Out::MemReadU32(out));\n    }\n\n    pub unsafe fn memset(&mut self, address: u64, len: u64, value: u8) {\n        self.operations.push(ffi::Operation::PhysicalMemoryMemset {\n            address,\n            len,\n            value,\n        });\n    }\n\n    pub unsafe fn write(&mut self, address: u64, data: impl Into<Vec<u8>>) {\n        self.operations.push(ffi::Operation::PhysicalMemoryWriteU8 {\n            address,\n            data: data.into(),\n        });\n    }\n\n    pub unsafe fn write_one_u32(&mut self, address: u64, data: u32) {\n        self.operations\n            .push(ffi::Operation::PhysicalMemoryWriteU32 {\n                address,\n                data: vec![data],\n            });\n    }\n\n    pub unsafe fn port_write_u8(&mut self, port: u32, data: u8) {\n        self.operations\n            .push(ffi::Operation::PortWriteU8 { port, data });\n    }\n\n    pub unsafe fn port_write_u16(&mut self, port: u32, data: u16) {\n        self.operations\n            .push(ffi::Operation::PortWriteU16 { port, data });\n    }\n\n    pub unsafe fn port_write_u32(&mut self, port: u32, data: u32) {\n        self.operations\n            .push(ffi::Operation::PortWriteU32 { port, data });\n    }\n\n    pub unsafe fn port_read_u8(&mut self, port: u32, out: &'a mut u8) {\n        self.operations.push(ffi::Operation::PortReadU8 { port });\n        self.out.push(Out::PortU8(out));\n    }\n\n    pub unsafe fn port_read_u16(&mut self, port: u32, out: &'a mut u16) {\n        self.operations.push(ffi::Operation::PortReadU16 { port });\n        self.out.push(Out::PortU16(out));\n    }\n\n    pub unsafe fn port_read_u32(&mut self, port: u32, out: &'a mut u32) {\n        self.operations.push(ffi::Operation::PortReadU32 { port });\n        self.out.push(Out::PortU32(out));\n    }\n\n    pub unsafe fn port_read_u8_discard(&mut self, port: u32) {\n        self.operations.push(ffi::Operation::PortReadU8 { port });\n        self.out.push(Out::Discard);\n    }\n\n    pub unsafe fn port_read_u16_discard(&mut self, port: u32) {\n        self.operations.push(ffi::Operation::PortReadU16 { port });\n        self.out.push(Out::Discard);\n    }\n\n    pub unsafe fn port_read_u32_discard(&mut self, port: u32) {\n        self.operations.push(ffi::Operation::PortReadU32 { port });\n        self.out.push(Out::Discard);\n    }\n\n    pub fn send(self) -> impl Future<Output = ()> + 'a {\n        unsafe {\n            let msg = ffi::HardwareMessage::HardwareAccess(self.operations);\n            let out = self.out;\n            redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg)\n                .unwrap()\n                .then(move |response: Vec<ffi::HardwareAccessResponse>| {\n                    for (response_elem, out) in response.into_iter().zip(out) {\n                        match (response_elem, out) {\n                            (_, Out::Discard) => {}\n                            (ffi::HardwareAccessResponse::PortReadU8(val), Out::PortU8(out)) => {\n                                *out = val\n                            }\n                            (ffi::HardwareAccessResponse::PortReadU16(val), Out::PortU16(out)) => {\n                                *out = val\n                            }\n                            (ffi::HardwareAccessResponse::PortReadU32(val), Out::PortU32(out)) => {\n                                *out = val\n                            }\n                            (\n                                ffi::HardwareAccessResponse::PhysicalMemoryReadU8(val),\n                                Out::MemReadU8(out),\n                            ) => out.copy_from_slice(&val),\n                            (\n                                ffi::HardwareAccessResponse::PhysicalMemoryReadU16(val),\n                                Out::MemReadU16(out),\n                            ) => out.copy_from_slice(&val),\n                            (\n                                ffi::HardwareAccessResponse::PhysicalMemoryReadU32(val),\n                                Out::MemReadU32(out),\n                            ) => out.copy_from_slice(&val),\n                            _ => unreachable!(),\n                        }\n                    }\n\n                    future::ready(())\n                })\n        }\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/hardware/src/malloc.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Allocation of physical memory.\n//!\n//! There are situations where it is necessary to pass to a device a pointer to a region of\n//! memory. This is where this module comes into play.\n\nuse crate::{ffi, HardwareOperationsBuilder, HardwareWriteOperationsBuilder};\n\nuse alloc::{boxed::Box, vec, vec::Vec};\nuse core::{convert::TryFrom, marker::PhantomData, mem, ptr, slice};\nuse futures::prelude::*;\n\n/// Buffer located in physical memory.\npub struct PhysicalBuffer<T: ?Sized> {\n    /// Location of the buffer in physical memory.\n    ptr: u64,\n    /// Size in bytes of the buffer.\n    size: u64,\n    /// Marker to pin the `T` generic.\n    marker: PhantomData<Box<T>>,\n}\n\nimpl<T> PhysicalBuffer<T> {\n    /// Creates a new buffer and moves `data` into it.\n    ///\n    /// > **Note**: `data` will **not** be free'd if you drop the buffer. In other words, it is as\n    /// >           if you called `std::mem::forget(data)`. You should preferably not pass anything\n    /// >           else than plain data, or call [`PhysicalBuffer::take`].\n    ///\n    pub fn new(data: T) -> impl Future<Output = Self> {\n        let size = u64::try_from(mem::size_of_val(&data)).unwrap();\n        let align = u64::try_from(mem::align_of_val(&data)).unwrap();\n\n        malloc(size, align).map(move |ptr| {\n            let buf = PhysicalBuffer {\n                ptr,\n                size,\n                marker: PhantomData,\n            };\n            buf.write(data);\n            buf\n        })\n    }\n\n    /// Overwrites the content of the buffer with a new value.\n    ///\n    /// This moves `data` into the buffer. The previous value is **not** dropped, but simply\n    /// leaked out.\n    pub fn write(&self, data: T) {\n        unsafe {\n            let mut data_buf = Vec::<u8>::with_capacity(mem::size_of_val(&data));\n            ptr::write_unaligned(data_buf.as_mut_ptr() as *mut T, data);\n            data_buf.set_len(data_buf.capacity());\n\n            let mut builder = HardwareWriteOperationsBuilder::with_capacity(1);\n            builder.write(self.ptr, data_buf);\n            builder.send();\n        }\n    }\n\n    /// Reads back the content of the buffer and destroys the buffer.\n    pub fn take(self) -> impl Future<Output = T> {\n        unsafe { self.read_inner() }\n    }\n\n    /// Returns a copy of the content of the buffer.\n    pub fn read(&self) -> impl Future<Output = T>\n    where\n        T: Copy,\n    {\n        unsafe { self.read_inner() }\n    }\n\n    /// Reads the content of the buffer and returns a copy.\n    ///\n    /// # Safety\n    ///\n    /// This function performs a copy of the content of the buffer. This is only safe if `T`\n    /// implements `Copy`, or if you guarantee that no multiple copies of the same object are\n    /// being read. In other words, this function is meant to be called from within\n    /// [`PhysicalBuffer::take`] or [`PhysicalBuffer::read`].\n    unsafe fn read_inner(&self) -> impl Future<Output = T> {\n        // Note: we can't use `HardwareOperationsBuilder`, as this would require an `async`\n        // function or block, which aren't available in `no_std` environments at the time of\n        // writing.\n\n        let msg =\n            ffi::HardwareMessage::HardwareAccess(vec![ffi::Operation::PhysicalMemoryReadU8 {\n                address: self.ptr,\n                len: u32::try_from(mem::size_of::<T>()).unwrap(),\n            }]);\n\n        redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg)\n            .unwrap()\n            .map(move |mut response: Vec<ffi::HardwareAccessResponse>| {\n                debug_assert_eq!(response.len(), 1);\n                let buf = match response.remove(0) {\n                    ffi::HardwareAccessResponse::PhysicalMemoryReadU8(val) => val,\n                    _ => unreachable!(),\n                };\n                ptr::read_unaligned(buf.as_ptr() as *const T)\n            })\n    }\n}\n\nimpl<T> PhysicalBuffer<[T]> {\n    /// Allocates a new buffer with uninitialized contents.\n    pub async fn new_uninit_slice(len: usize) -> PhysicalBuffer<[mem::MaybeUninit<T>]> {\n        Self::new_uninit_slice_with_align(len, mem::align_of::<T>()).await\n    }\n\n    /// Allocates a new buffer with uninitialized contents.\n    pub async fn new_uninit_slice_with_align(\n        len: usize,\n        align: usize,\n    ) -> PhysicalBuffer<[mem::MaybeUninit<T>]> {\n        let size = u64::try_from(mem::size_of::<T>())\n            .unwrap()\n            .checked_mul(u64::try_from(len).unwrap())\n            .unwrap();\n        let align = u64::try_from(align).unwrap();\n\n        PhysicalBuffer {\n            ptr: malloc(size, align).await,\n            size,\n            marker: PhantomData,\n        }\n    }\n\n    /// Returns the number of elements in the buffer.\n    pub fn len(&self) -> usize {\n        usize::try_from(self.size / u64::try_from(mem::size_of::<T>()).unwrap()).unwrap()\n    }\n\n    pub fn write_one(&self, idx: usize, value: T) {\n        unsafe {\n            if idx >= self.len() {\n                panic!()\n            }\n\n            let mut ops = HardwareWriteOperationsBuilder::with_capacity(1);\n            ops.write(\n                self.ptr + u64::try_from(idx * mem::size_of::<T>()).unwrap(),\n                slice::from_raw_parts(&value as *const T as *const u8, mem::size_of::<T>())\n                    .to_vec(),\n            );\n            ops.send();\n\n            mem::forget(value);\n        }\n    }\n}\n\nimpl<T: Copy> PhysicalBuffer<[T]> {\n    pub async fn read_one(&self, idx: usize) -> Option<T> {\n        unsafe {\n            if idx >= self.len() {\n                return None;\n            }\n\n            let mut out = mem::MaybeUninit::<T>::uninit();\n\n            let mut ops = HardwareOperationsBuilder::with_capacity(1);\n            ops.read(\n                self.ptr + u64::try_from(idx * mem::size_of::<T>()).unwrap(),\n                slice::from_raw_parts_mut(out.as_mut_ptr() as *mut u8, mem::size_of::<T>()),\n            );\n            ops.send().await;\n\n            Some(out.assume_init())\n        }\n    }\n\n    pub async fn read_slice(&self, idx: usize, out: &mut [T]) {\n        unsafe {\n            assert!(idx + out.len() <= self.len());\n\n            let mut ops = HardwareOperationsBuilder::with_capacity(1);\n            ops.read(\n                self.ptr + u64::try_from(idx * mem::size_of::<T>()).unwrap(),\n                slice::from_raw_parts_mut(\n                    out.as_mut_ptr() as *mut u8,\n                    out.len() * mem::size_of::<T>(),\n                ),\n            );\n            ops.send().await;\n        }\n    }\n\n    pub fn write_slice(&self, idx: usize, data: &[T]) {\n        unsafe {\n            assert!(idx + data.len() <= self.len());\n\n            let mut ops = HardwareWriteOperationsBuilder::with_capacity(1);\n            ops.write(\n                self.ptr + u64::try_from(idx * mem::size_of::<T>()).unwrap(),\n                slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::<T>())\n                    .to_vec(),\n            );\n            ops.send();\n        }\n    }\n}\n\nimpl<T> PhysicalBuffer<[mem::MaybeUninit<T>]> {\n    /// Converts to an actual buffer.\n    pub unsafe fn assume_init(self) -> PhysicalBuffer<[T]> {\n        let size = self.size;\n        let ptr = self.ptr;\n        mem::forget(self);\n\n        PhysicalBuffer {\n            ptr,\n            size,\n            marker: PhantomData,\n        }\n    }\n}\n\nimpl<T: ?Sized> PhysicalBuffer<T> {\n    /// Returns the location in physical memory of the buffer.\n    pub fn pointer(&self) -> u64 {\n        self.ptr\n    }\n}\n\nimpl<T: ?Sized> Drop for PhysicalBuffer<T> {\n    fn drop(&mut self) {\n        free(self.ptr)\n    }\n}\n\n/// Allocates physical memory.\n///\n/// # Panic\n///\n/// Panics if the allocation fails, for example if `size` is too large to be acceptable.\n///\npub fn malloc(size: u64, alignment: u64) -> impl Future<Output = u64> {\n    unsafe {\n        let msg = ffi::HardwareMessage::Malloc { size, alignment };\n        redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg)\n            .unwrap()\n            .map(move |ptr: u64| {\n                assert_ne!(ptr, 0);\n                debug_assert_eq!(ptr % alignment, 0);\n                ptr\n            })\n    }\n}\n\n/// Frees physical memory previously allocated with [`malloc`].\npub fn free(ptr: u64) {\n    unsafe {\n        let msg = ffi::HardwareMessage::Free { ptr };\n        redshirt_syscalls::emit_message_without_response(&ffi::INTERFACE, &msg).unwrap();\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/interface/Cargo.toml",
    "content": "[package]\nname = \"redshirt-interface-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nfutures = { version = \"0.3.13\", default-features = false, features = [\"alloc\"] }\nparity-scale-codec = { version = \"1.3.6\", default-features = false, features = [\"derive\"] }\nredshirt-syscalls = { path = \"../syscalls\", default-features = false }\n"
  },
  {
    "path": "interface-wrappers/interface/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse alloc::vec::Vec;\nuse core::{convert::TryFrom as _, num::NonZeroU64};\nuse redshirt_syscalls::{EncodedMessage, InterfaceHash, MessageId, Pid};\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0x49, 0x6e, 0x56, 0x14, 0x8c, 0xd4, 0x2b, 0xc3, 0x9b, 0x4e, 0xbf, 0x5e, 0xb6, 0x2c, 0x60, 0x4d,\n    0x7d, 0xd5, 0x70, 0x92, 0x4d, 0x4f, 0x70, 0xdf, 0xb3, 0xda, 0xf6, 0xfe, 0xdc, 0x65, 0x93, 0x8a,\n]);\n\n#[derive(Debug, parity_scale_codec::Encode, parity_scale_codec::Decode)]\npub enum InterfaceMessage {\n    Register(InterfaceHash),\n    NextMessage(NonZeroU64),\n    Answer(MessageId, Result<Vec<u8>, ()>),\n}\n\n#[derive(Debug, parity_scale_codec::Encode, parity_scale_codec::Decode)]\npub struct InterfaceRegisterResponse {\n    pub result: Result<NonZeroU64, InterfaceRegisterError>,\n}\n\n#[derive(Debug, Clone, parity_scale_codec::Encode, parity_scale_codec::Decode)]\npub enum InterfaceRegisterError {\n    /// There already exists a process registered for this interface.\n    AlreadyRegistered,\n}\n\n/// Either a decoded interface notification or a decoded process destroyed notification.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum DecodedInterfaceOrDestroyed {\n    /// Interface notification.\n    Interface(DecodedInterfaceNotification),\n    /// Process destroyed notification.\n    ProcessDestroyed(DecodedProcessDestroyedNotification),\n}\n\n/// Attempt to decode a notification.\npub fn decode_notification(buffer: &[u8]) -> Result<DecodedInterfaceOrDestroyed, ()> {\n    if buffer.is_empty() {\n        return Err(());\n    }\n\n    match buffer[0] {\n        0 => decode_interface_notification(buffer).map(DecodedInterfaceOrDestroyed::Interface),\n        2 => decode_process_destroyed_notification(buffer)\n            .map(DecodedInterfaceOrDestroyed::ProcessDestroyed),\n        _ => Err(()),\n    }\n}\n\n/// Builds a interface notification from its raw components.\npub fn build_interface_notification(\n    interface: &InterfaceHash,\n    message_id: Option<MessageId>,\n    emitter_pid: Pid,\n    actual_data: &EncodedMessage,\n) -> InterfaceNotificationBuilder {\n    let mut buffer = Vec::with_capacity(1 + 32 + 8 + 8 + actual_data.0.len());\n    buffer.push(0);\n    buffer.extend_from_slice(interface.as_ref());\n    buffer.extend_from_slice(&message_id.map(u64::from).unwrap_or(0).to_le_bytes());\n    buffer.extend_from_slice(&u64::from(emitter_pid).to_le_bytes());\n    buffer.extend_from_slice(&actual_data.0);\n\n    debug_assert_eq!(buffer.capacity(), buffer.len());\n    InterfaceNotificationBuilder { data: buffer }\n}\n\n#[derive(Debug, Clone)]\npub struct InterfaceNotificationBuilder {\n    data: Vec<u8>,\n}\n\nimpl InterfaceNotificationBuilder {\n    /// Returns the [`MessageId`] that was put in the builder.\n    pub fn message_id(&self) -> Option<MessageId> {\n        let id = u64::from_le_bytes([\n            self.data[33],\n            self.data[34],\n            self.data[35],\n            self.data[36],\n            self.data[37],\n            self.data[38],\n            self.data[39],\n            self.data[40],\n        ]);\n\n        MessageId::try_from(id).ok()\n    }\n\n    pub fn len(&self) -> usize {\n        self.data.len()\n    }\n\n    pub fn into_bytes(self) -> Vec<u8> {\n        // TODO: return EncodedMessage\n        self.data\n    }\n}\n\npub fn decode_interface_notification(buffer: &[u8]) -> Result<DecodedInterfaceNotification, ()> {\n    if buffer.len() < 1 + 32 + 8 + 8 {\n        return Err(());\n    }\n\n    if buffer[0] != 0x0 {\n        return Err(());\n    }\n\n    Ok(DecodedInterfaceNotification {\n        interface: InterfaceHash::from({\n            let mut hash = [0; 32];\n            hash.copy_from_slice(&buffer[1..33]);\n            hash\n        }),\n        message_id: {\n            let id = u64::from_le_bytes([\n                buffer[33], buffer[34], buffer[35], buffer[36], buffer[37], buffer[38], buffer[39],\n                buffer[40],\n            ]);\n\n            MessageId::try_from(id).ok()\n        },\n        emitter_pid: From::from(u64::from_le_bytes([\n            buffer[41], buffer[42], buffer[43], buffer[44], buffer[45], buffer[46], buffer[47],\n            buffer[48],\n        ])),\n        actual_data: EncodedMessage(buffer[49..].to_vec()),\n    })\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct DecodedInterfaceNotification {\n    /// Interface the message concerns.\n    // TODO: remove\n    pub interface: InterfaceHash,\n    /// Id of the message. Can be used for answering. `None` if no answer is expected.\n    pub message_id: Option<MessageId>,\n    /// Id of the process that emitted the message.\n    ///\n    /// This should be used for security purposes, so that a process can't modify another process'\n    /// resources.\n    pub emitter_pid: Pid,\n    pub actual_data: EncodedMessage,\n}\n\npub fn build_process_destroyed_notification(pid: Pid) -> ProcessDestroyedNotificationBuilder {\n    let mut buffer = Vec::with_capacity(1 + 8);\n    buffer.push(2);\n    buffer.extend_from_slice(&u64::from(pid).to_le_bytes());\n\n    debug_assert_eq!(buffer.capacity(), buffer.len());\n    ProcessDestroyedNotificationBuilder { data: buffer }\n}\n\n#[derive(Debug, Clone)]\npub struct ProcessDestroyedNotificationBuilder {\n    data: Vec<u8>,\n}\n\nimpl ProcessDestroyedNotificationBuilder {\n    pub fn len(&self) -> usize {\n        self.data.len()\n    }\n\n    pub fn into_bytes(self) -> Vec<u8> {\n        self.data\n    }\n}\n\npub fn decode_process_destroyed_notification(\n    buffer: &[u8],\n) -> Result<DecodedProcessDestroyedNotification, ()> {\n    if buffer.len() != 1 + 8 {\n        return Err(());\n    }\n\n    if buffer[0] != 0x2 {\n        return Err(());\n    }\n\n    Ok(DecodedProcessDestroyedNotification {\n        pid: From::from(u64::from_le_bytes([\n            buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8],\n        ])),\n    })\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct DecodedProcessDestroyedNotification {\n    /// Identifier of the process that got destroyed.\n    pub pid: Pid,\n}\n"
  },
  {
    "path": "interface-wrappers/interface/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Interfaces registration.\n\n#![no_std]\n\nextern crate alloc;\n\nuse core::{mem, num::NonZeroU64};\nuse futures::prelude::*;\nuse redshirt_syscalls::{Encode, EncodedMessage, InterfaceHash, MessageId};\n\npub use ffi::{DecodedInterfaceOrDestroyed, InterfaceRegisterError};\n\npub mod ffi;\n\n/// Registers the current program as the provider for the given interface hash.\n///\n/// > **Note**: Interface hashes can be found in the various `ffi` modules of the crates in the\n/// >           `interface-wrappers` directory, although that is subject to change.\n///\n/// Returns an error if there was already a program registered for that interface.\npub async fn register_interface(\n    hash: InterfaceHash,\n) -> Result<Registration, InterfaceRegisterError> {\n    let msg = ffi::InterfaceMessage::Register(hash);\n    // Unwrapping is ok because there's always something that handles interface registration.\n    let id = {\n        let msg: ffi::InterfaceRegisterResponse =\n            unsafe { redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg) }\n                .unwrap()\n                .await;\n        msg.result?\n    };\n\n    let mut registration = Registration {\n        id,\n        messages: stream::FuturesOrdered::new(),\n    };\n\n    for _ in 0..32 {\n        registration.add_message();\n    }\n\n    Ok(registration)\n}\n\n/// Registered interface.\npub struct Registration {\n    /// Identifier of the interface registration.\n    id: NonZeroU64,\n    /// Futures that will resolve when a message is received on the interface.\n    messages: stream::FuturesOrdered<redshirt_syscalls::MessageResponseFuture<EncodedMessage>>,\n}\n\nimpl Registration {\n    /// Returns the next message received on this interface.\n    pub async fn next_message_raw(&mut self) -> DecodedInterfaceOrDestroyed {\n        let message = self.messages.next().await.unwrap();\n        self.add_message();\n        ffi::decode_notification(&message.0).unwrap()\n    }\n\n    fn add_message(&mut self) {\n        self.messages.push(unsafe {\n            let message = ffi::InterfaceMessage::NextMessage(self.id).encode();\n            let msg_id = redshirt_syscalls::MessageBuilder::new()\n                .add_data(&EncodedMessage(message.0))\n                .emit_with_response_raw(&ffi::INTERFACE)\n                .unwrap();\n            redshirt_syscalls::message_response(msg_id)\n        });\n    }\n}\n\nimpl Drop for Registration {\n    fn drop(&mut self) {\n        // Before dropping the registration, cancel all existing messages.\n        let _ = mem::take(&mut self.messages);\n\n        // TODO: unregister; unregistrations aren't supported at the moment\n    }\n}\n\n/// Answers the given message.\npub fn emit_answer(message_id: MessageId, msg: impl Encode) {\n    #[cfg(target_arch = \"wasm32\")] // TODO: we should have a proper operating system name instead\n    fn imp(message_id: MessageId, msg: impl Encode) {\n        unsafe {\n            // TODO: more optimized version ; right now there's extra copies below\n            redshirt_syscalls::emit_message_without_response(\n                &ffi::INTERFACE,\n                ffi::InterfaceMessage::Answer(message_id, Ok(msg.encode().0)),\n            )\n            .unwrap()\n        }\n    }\n    #[cfg(not(target_arch = \"wasm32\"))]\n    fn imp(_: MessageId, _: impl Encode) {\n        unreachable!()\n    }\n    imp(message_id, msg)\n}\n\n/// Answers the given message by notifying of an error in the message.\npub fn emit_message_error(message_id: MessageId) {\n    #[cfg(target_arch = \"wasm32\")] // TODO: we should have a proper operating system name instead\n    fn imp(message_id: MessageId) {\n        unsafe {\n            // TODO: more optimized version ; right now there's extra copies below\n            redshirt_syscalls::emit_message_without_response(\n                &ffi::INTERFACE,\n                ffi::InterfaceMessage::Answer(message_id, Err(())),\n            )\n            .unwrap()\n        }\n    }\n    #[cfg(not(target_arch = \"wasm32\"))]\n    fn imp(_: MessageId) {\n        unreachable!()\n    }\n    imp(message_id)\n}\n"
  },
  {
    "path": "interface-wrappers/kernel-debug/Cargo.toml",
    "content": "[package]\nname = \"redshirt-kernel-debug-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nredshirt-syscalls = { path = \"../syscalls\", default-features = false }\n"
  },
  {
    "path": "interface-wrappers/kernel-debug/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Gathering kernel metrics.\n//!\n//! This interface provides a way to gather information from the kernel. In particular, the kernel\n//! returns [Prometheus](https://prometheus.io) metrics.\n//!\n//! # Message format\n//!\n//! - Sender sends a message with an empty body.\n//! - Handler sends back a Prometheus-compatible UTF-8 message.\n//!\n//! See [this page](https://prometheus.io/docs/instrumenting/exposition_formats/#text-format-details)\n//! for more information about the format.\n//!\n\n#![no_std]\n\nextern crate alloc;\n\nuse alloc::{string::String, vec::Vec};\nuse redshirt_syscalls::InterfaceHash;\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0x8c, 0xb4, 0xc6, 0xee, 0xc9, 0x29, 0xc5, 0xce, 0xaf, 0x46, 0x28, 0x74, 0x9e, 0x96, 0x72, 0x58,\n    0xea, 0xd2, 0xa2, 0xa2, 0xd6, 0xeb, 0x7d, 0xc8, 0xe3, 0x95, 0x0c, 0x0e, 0x53, 0xde, 0x8c, 0xba,\n]);\n\n/// Loads metrics from the kernel, as a Prometheus-compatible UTF-8 string.\npub async fn get_prometheus_metrics() -> String {\n    unsafe {\n        let response: redshirt_syscalls::EncodedMessage =\n            redshirt_syscalls::emit_message_with_response(\n                &INTERFACE,\n                redshirt_syscalls::EncodedMessage(Vec::new()),\n            )\n            .unwrap()\n            .await;\n\n        String::from_utf8(response.0).unwrap()\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/kernel-log/Cargo.toml",
    "content": "[package]\nname = \"redshirt-kernel-log-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nparity-scale-codec = { version = \"1.3.6\", default-features = false, features = [\"derive\"] }\nredshirt-syscalls = { path = \"../syscalls\", default-features = false }\n"
  },
  {
    "path": "interface-wrappers/kernel-log/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n/// Communication between a process and the interface handler.\n///\n/// A message consists of either:\n///\n/// - A `0` byte followed with a UTF-8 log message.\n/// - A `1` byte followed with a SCALE-codec-encoded [`KernelLogMethod`].\n///\nuse parity_scale_codec::{Decode, Encode};\nuse redshirt_syscalls::InterfaceHash;\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0xcd, 0xba, 0x59, 0xb1, 0xb6, 0x5e, 0xd4, 0x9a, 0xfe, 0x25, 0xd0, 0x7c, 0x04, 0x1f, 0xae, 0x82,\n    0x5b, 0xf3, 0xc9, 0xca, 0x89, 0x48, 0x81, 0xe0, 0x3b, 0x3a, 0xd2, 0x76, 0x29, 0x04, 0x21, 0x1b,\n]);\n\n/// How the kernel should log messages.\n#[derive(Debug, Clone, Encode, Decode)]\npub struct KernelLogMethod {\n    /// If `true`, log messages should be shown. If `false`, they should be buffered up (to a\n    /// certain limit) and will be shown as soon as `enabled` is true.\n    pub enabled: bool,\n\n    /// If `Some`, the logs will be printed on a video framebuffer.\n    pub framebuffer: Option<FramebufferInfo>,\n\n    /// If `Some`, logs will be emitted on an UART.\n    pub uart: Option<UartInfo>,\n}\n\n/// Information about how the kernel should print on an UART.\n///\n/// In order to write, the kernel should repeatidly read a value from `wait_address` until\n/// its value, when AND-ed with `wait_mask`, is equal to `wait_compare_equal_if_ready`. Then it\n/// should write a value to `write_address`.\n#[derive(Debug, Clone, Encode, Decode)]\npub struct UartInfo {\n    /// Where to read the value to compare.\n    pub wait_address: UartAccess,\n    /// Mask to apply (by AND'ing) to the value read from `wait_address`.\n    pub wait_mask: u32,\n    /// Compares the value (after the mask is applied) with this reference value. If equal, the\n    /// UART is ready.\n    pub wait_compare_equal_if_ready: u32,\n    /// Where to write the output when ready.\n    pub write_address: UartAccess,\n}\n\n/// How to access either the value to compare or where to write the output.\n#[derive(Debug, Clone, Encode, Decode)]\npub enum UartAccess {\n    /// 32bits at a specific memory location.\n    MemoryMappedU32(u64),\n    /// Single byte (8bits) on I/O port. Typically on x86/amd64 systems.\n    IoPortU8(u16),\n}\n\n/// Information about how the kernel should print on the framebuffer.\n#[derive(Debug, Clone, Encode, Decode)]\npub struct FramebufferInfo {\n    /// Location in physical memory where the framebuffer starts.\n    pub address: u64,\n    /// Width of the screen, either in pixels or characters.\n    pub width: u32,\n    /// Height of the screen, either in pixels or characters.\n    pub height: u32,\n    /// In order to reach the second line of pixels or characters, one has to advance this number of bytes.\n    pub pitch: u64,\n    /// Number of bytes a pixel or a character occupies in memory.\n    pub bytes_per_character: u8,\n    /// Format of the framebuffer's data.\n    pub format: FramebufferFormat,\n}\n\n/// Format of the framebuffer's data.\n#[derive(Debug, Clone, Encode, Decode)]\npub enum FramebufferFormat {\n    /// One ASCII character followed with one byte of characteristics.\n    Text,\n    Rgb {\n        red_size: u8,\n        red_position: u8,\n        green_size: u8,\n        green_position: u8,\n        blue_size: u8,\n        blue_position: u8,\n    },\n}\n"
  },
  {
    "path": "interface-wrappers/kernel-log/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Kernel logging.\n//!\n//! This interface permits two things:\n//!\n//! - Send logs for the kernel to print.\n//! - Configure how the kernel prints logs.\n//!\n//! It is important for programs such as video drivers to keep the kernel up-to-date with how\n//! logs should be displayed. In the case of a kernel panic, the kernel will use the information\n//! contained in the latest received message in order to show diagnostics to the user.\n\n#![no_std]\n\nextern crate alloc;\n\nuse parity_scale_codec::Encode as _;\n\npub mod ffi;\npub use ffi::KernelLogMethod;\n\n/// Appends a single ASCII string to the kernel logs.\n///\n/// This function always adds a single entry to the logs. An entry can made up of multiple lines\n/// (separated with `\\n`), but the lines are notably *not* split into multiple entries.\n///\n/// > **Note**: The message is expected to be in ASCII. It will otherwise be considered invalid\n/// >           and get discarded.\n///\n/// # About `\\r` vs `\\n`\n///\n/// In order to follow the Unix world, the character `\\n` (LF, 0xA) means \"new line\". The\n/// character `\\r` (CR, 0xD) is ignored.\n///\npub fn log(msg: &[u8]) {\n    unsafe {\n        redshirt_syscalls::MessageBuilder::new()\n            .add_data_raw(&[0][..])\n            .add_data_raw(msg)\n            .emit_without_response(&ffi::INTERFACE)\n            .unwrap();\n    }\n}\n\n/// Sets how the kernel should log messages.\npub async fn configure_kernel(method: KernelLogMethod) {\n    unsafe {\n        let encoded = method.encode();\n        redshirt_syscalls::MessageBuilder::new()\n            .add_data_raw(&[1][..])\n            .add_data_raw(&encoded)\n            .emit_with_response::<()>(&ffi::INTERFACE)\n            .unwrap()\n            .await;\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/loader/Cargo.toml",
    "content": "[package]\nname = \"redshirt-loader-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nfutures = { version = \"0.3.13\", default-features = false }\nredshirt-syscalls = { path = \"../syscalls\", default-features = false }\nparity-scale-codec = { version = \"1.3.6\", default-features = false, features = [\"derive\"] }\n"
  },
  {
    "path": "interface-wrappers/loader/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse alloc::vec::Vec;\nuse parity_scale_codec::{Decode, Encode};\nuse redshirt_syscalls::InterfaceHash;\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0x1c, 0x72, 0xb5, 0x18, 0x7f, 0x73, 0x52, 0xfd, 0xf7, 0xa7, 0x81, 0xe2, 0xa8, 0x46, 0x51, 0xd7,\n    0xb3, 0xc6, 0x2d, 0x24, 0x31, 0x88, 0x96, 0x95, 0x6e, 0xfc, 0x7d, 0x4d, 0x86, 0x3f, 0xff, 0xa6,\n]);\n\n#[derive(Debug, Encode, Decode)]\npub enum LoaderMessage {\n    /// Load the data corresponding to the blake3 hash passed as parameter.\n    Load([u8; 32]),\n}\n\n#[derive(Debug, Encode, Decode)]\npub struct LoadResponse {\n    pub result: Result<Vec<u8>, ()>,\n}\n"
  },
  {
    "path": "interface-wrappers/loader/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Loading WASM programs.\n//!\n//! This interface is a bit special, as it is used by the kernel in order to load WASM programs.\n\n#![no_std]\n\nextern crate alloc;\n\nuse alloc::vec::Vec;\nuse futures::prelude::*;\n\npub mod ffi;\n\n/// Tries to load a WASM module based on its hash.\n///\n/// Returns either the binary content of the module, or an error if no module with that hash\n/// could be found.\n// TODO: better error type\npub fn load(hash: [u8; 32]) -> impl Future<Output = Result<Vec<u8>, ()>> {\n    unsafe {\n        let msg = ffi::LoaderMessage::Load(hash);\n        match redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg) {\n            Ok(fut) => fut.map(|rep: ffi::LoadResponse| rep.result).left_future(),\n            Err(_) => future::ready(Err(())).right_future(),\n        }\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/log/Cargo.toml",
    "content": "[package]\nname = \"redshirt-log-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nlog = \"0.4.14\"\nredshirt-syscalls = { path = \"../syscalls\", default-features = false }\n"
  },
  {
    "path": "interface-wrappers/log/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Communication between a process and the interface handler.\n//!\n//! A log message consists of one byte indicating the log level, followed with the log message\n//! itself encoded in UTF-8.\n//!\n//! Log levels:\n//!\n//! - Error: 4\n//! - Warn: 3\n//! - Info: 2\n//! - Debug: 1\n//! - Trace: 0\n//!\n\nuse core::{convert::TryFrom, fmt, str};\nuse redshirt_syscalls::{Decode, EncodedMessage, InterfaceHash};\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0xa6, 0xbc, 0x8d, 0xc3, 0x43, 0xbd, 0xdd, 0x3b, 0x44, 0x2f, 0x06, 0x40, 0xa8, 0x40, 0xad, 0x4f,\n    0x25, 0x57, 0x23, 0x91, 0x79, 0xc8, 0x16, 0x07, 0x6f, 0xab, 0xa9, 0xd6, 0x38, 0xca, 0x01, 0x8b,\n]);\n\n/// Log level of a message.\n#[derive(Debug, Copy, Clone, PartialEq, Eq)]\npub enum Level {\n    Error,\n    Warn,\n    Info,\n    Debug,\n    Trace,\n}\n\nimpl From<Level> for u8 {\n    fn from(level: Level) -> u8 {\n        match level {\n            Level::Error => 4,\n            Level::Warn => 3,\n            Level::Info => 2,\n            Level::Debug => 1,\n            Level::Trace => 0,\n        }\n    }\n}\n\nimpl TryFrom<u8> for Level {\n    type Error = InvalidLevelError;\n\n    fn try_from(value: u8) -> Result<Self, InvalidLevelError> {\n        Ok(match value {\n            4 => Level::Error,\n            3 => Level::Warn,\n            2 => Level::Info,\n            1 => Level::Debug,\n            0 => Level::Trace,\n            n => return Err(InvalidLevelError(n)),\n        })\n    }\n}\n\n/// Error that can happen when decoding a [`Level`].\n#[derive(Debug)]\npub struct InvalidLevelError(u8);\n\nimpl InvalidLevelError {\n    /// Returns the value that failed to decode.\n    pub fn value(&self) -> u8 {\n        self.0\n    }\n}\n\nimpl fmt::Display for InvalidLevelError {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"Invalid log level\")\n    }\n}\n\n/// Decoded version of a message on the log interface.\npub struct DecodedLogMessage {\n    level: Level,\n    buffer: EncodedMessage,\n}\n\nimpl DecodedLogMessage {\n    /// Returns the log level of the message.\n    pub fn level(&self) -> Level {\n        self.level\n    }\n\n    /// Returns the message itself.\n    pub fn message(&self) -> &str {\n        // We checked the validity when decoding.\n        str::from_utf8(&self.buffer.0[1..]).unwrap()\n    }\n}\n\nimpl Decode for DecodedLogMessage {\n    type Error = DecodeError;\n\n    fn decode(buffer: EncodedMessage) -> Result<Self, DecodeError> {\n        if buffer.0.is_empty() {\n            return Err(DecodeError::LevelMissing);\n        }\n        let level = Level::try_from(buffer.0[0]).map_err(DecodeError::LevelDecodeError)?;\n        let _ = str::from_utf8(&buffer.0[1..]).map_err(DecodeError::NotUtf8)?;\n        Ok(DecodedLogMessage { level, buffer })\n    }\n}\n\n/// Error that can happen when decoding a log message.\n#[derive(Debug)]\npub enum DecodeError {\n    LevelMissing,\n    LevelDecodeError(InvalidLevelError),\n    NotUtf8(str::Utf8Error),\n}\n\nimpl fmt::Display for DecodeError {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            DecodeError::LevelMissing => write!(f, \"Missing log level\"),\n            DecodeError::LevelDecodeError(_) => write!(f, \"Invalid log level\"),\n            DecodeError::NotUtf8(_) => write!(f, \"Not UTF-8 error\"),\n        }\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/log/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Logging.\n//!\n//! This interface allows a program to send out messages for the purpose of being logged.\n//!\n//! How these logs are handled is at the discretion of the rest of the system, but the intent is\n//! for them to be shown to a human being if desired.\n//!\n//! # The `log` crate\n//!\n//! This interface provides a backend for the `log` crate.\n//!\n//! Example usage:\n//!\n//! ```no_run\n//! redshirt_log_interface::init();\n//! log::debug!(\"debug log message here\");\n//! ```\n\n#![no_std]\n\nextern crate alloc;\n\nuse alloc::format;\n\npub mod ffi;\n\npub use ffi::Level;\npub use log;\n\n/// Appends a single string to the logs of the program.\n///\n/// This function always adds a single entry to the logs. An entry can made up of multiple lines\n/// (separated with `\\n`), but the lines are notably *not* split into multiple entries.\n///\n/// # About `\\r` vs `\\n`\n///\n/// In order to follow the Unix world, the character `\\n` (LF, 0xA) means \"new line\". The\n/// character `\\r` (CR, 0xD) is ignored.\n///\npub fn emit_log(level: Level, msg: &str) {\n    unsafe {\n        let level: [u8; 1] = [u8::from(level)];\n        redshirt_syscalls::MessageBuilder::new()\n            .add_data_raw(&level[..])\n            .add_data_raw(msg.as_bytes())\n            .emit_without_response(&ffi::INTERFACE)\n            .unwrap();\n    }\n}\n\n/// Attempts to initializes the global logger.\n///\n/// # Panic\n///\n/// This function will panic if it is called more than once, or if another library has already\n/// initialized a global logger.\npub fn try_init() -> Result<(), log::SetLoggerError> {\n    static LOGGER: GlobalLogger = GlobalLogger;\n    let res = log::set_logger(&LOGGER);\n    if res.is_ok() {\n        log::set_max_level(log::LevelFilter::Trace);\n    }\n    res\n}\n\n/// Initializes the global logger.\n///\n/// # Panic\n///\n/// This function will panic if it is called more than once, or if another library has already\n/// initialized a global logger.\npub fn init() {\n    try_init().unwrap();\n}\n\n/// The logger.\n///\n/// Implements the [`Log`](log::Log) trait.\npub struct GlobalLogger;\n\nimpl log::Log for GlobalLogger {\n    fn enabled(&self, _: &log::Metadata) -> bool {\n        true\n    }\n\n    fn log(&self, record: &log::Record) {\n        let level = match record.level() {\n            log::Level::Error => Level::Error,\n            log::Level::Warn => Level::Warn,\n            log::Level::Info => Level::Info,\n            log::Level::Debug => Level::Debug,\n            log::Level::Trace => Level::Trace,\n        };\n\n        let message = format!(\"{} -- {}\", record.target(), record.args());\n        emit_log(level, &message)\n    }\n\n    fn flush(&self) {}\n}\n"
  },
  {
    "path": "interface-wrappers/pci/Cargo.toml",
    "content": "[package]\nname = \"redshirt-pci-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nfutures = { version = \"0.3.13\", default-features = false }\nredshirt-syscalls = { path = \"../syscalls\", default-features = false }\nparity-scale-codec = { version = \"1.3.6\", default-features = false, features = [\"derive\"] }\n"
  },
  {
    "path": "interface-wrappers/pci/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse alloc::vec::Vec;\nuse parity_scale_codec::{Decode, Encode};\nuse redshirt_syscalls::InterfaceHash;\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0x2d, 0x93, 0xd0, 0x48, 0xab, 0x88, 0x1c, 0x95, 0x87, 0xf5, 0x5c, 0x3b, 0xe6, 0x4d, 0x8f, 0x65,\n    0x3f, 0x37, 0x4c, 0x4e, 0xad, 0xea, 0x15, 0xcc, 0xf0, 0x17, 0x44, 0x0f, 0x6d, 0x6e, 0x5d, 0xc8,\n]);\n\n/// Message in destination to the PCI interface handler.\n#[derive(Debug, Encode, Decode)]\npub enum PciMessage {\n    /// Request list of PCI devices. Answered with a [`GetDevicesListResponse`].\n    GetDevicesList,\n\n    /// Makes the current process as the \"owner\" of the given PCI device.\n    ///\n    /// Returns a SCALE-encoded `Ok(())` if the locking worked, and a SCALE-encoded `Err(())` if\n    /// the device has already been locked.\n    // TODO: no, proper answer\n    LockDevice(PciDeviceBdf),\n\n    /// Unlocks a previously-locked device.\n    ///\n    /// Has no effect if the device wasn't locked by the current process.\n    ///\n    /// Doesn't return any answer.\n    ///\n    /// Answers all the pending [`PciMessage::NextInterrupt`] messages for this device.\n    UnlockDevice(PciDeviceBdf),\n\n    /// Sets the `COMMAND` register.\n    ///\n    /// Has no effect if the device wasn't locked by the current process.\n    ///\n    /// Doesn't return any answer.\n    SetCommand {\n        location: PciDeviceBdf,\n        bus_master: bool,\n        memory_space: bool,\n        io_space: bool,\n    },\n\n    /// Produces a [`NextInterruptResponse`] answer when the next interrupt from the PCI device\n    /// happens. The PCI must have been locked.\n    ///\n    /// Note that multiple PCI devices might share the same interrupt line, and spurious answers\n    /// might therefore happen. The `status` register of the PCI device is not necessarily checked.\n    ///\n    /// For clean-up reasons, answers are also triggered if you unlock the device.\n    NextInterrupt(PciDeviceBdf),\n\n    /// Read or write the configuration space of a device.\n    // TODO: forbid writing some parts such as the BARs\n    ConfigurationSpaceOperations {\n        /// Device to access. Must have been previously locked.\n        device: PciDeviceBdf,\n        operations: Vec<MemoryOperation>,\n    },\n\n    /// Read or write the mapped memory of a PCI device.\n    ///\n    /// Answers with a SCALE-encoded `Vec<MemoryAccessResponse>` containins one element per\n    /// successful read.\n    BarMemoryOperations {\n        /// Device to access. Must have been previously locked.\n        device: PciDeviceBdf,\n        /// Which BAR (Base Address Register) is concerned. Must in the range `0..6`.\n        bar_offset: u8,\n        /// List of operations to perform.\n        operations: Vec<MemoryOperation>,\n    },\n\n    /// Read or write the I/O ports accessing a PCI device.\n    ///\n    /// Answers with a SCALE-encoded `Vec<IoAccessResponse>` containins one element per\n    /// successful read.\n    BarIoOperations {\n        /// Device to access. Must have been previously locked.\n        device: PciDeviceBdf,\n        /// Which BAR (Base Address Register) is concerned. Must in the range `0..6`.\n        bar_offset: u8,\n        /// List of operations to perform.\n        operations: Vec<IoOperation>,\n    },\n}\n\n/// Response to [`PciMessage::GetDevicesList`].\n#[derive(Debug, Encode, Decode)]\npub struct GetDevicesListResponse {\n    /// List of PCI devices available on the system.\n    pub devices: Vec<PciDeviceInfo>,\n}\n\n/// Response to [`PciMessage::NextInterrupt`].\n#[derive(Debug, Encode, Decode)]\npub enum NextInterruptResponse {\n    /// Success. We got an interrupt.\n    Interrupt,\n\n    /// Returned if the specified device isn't locked.\n    BadDevice,\n\n    /// Returned if the specified device was locked but got unlocked before an interrupt happened.\n    Unlocked,\n}\n\n/// Location of a PCI device according to the controller.\n///\n/// > **Note**: The acronym BDF stands for \"Bus, Device, Function\".\n#[derive(Debug, Clone, PartialEq, Eq, Hash, Encode, Decode)]\npub struct PciDeviceBdf {\n    pub bus: u8,\n    pub device: u8,\n    pub function: u8,\n}\n\n/// Description of a single PCI device.\n#[derive(Debug, Clone, Encode, Decode)]\npub struct PciDeviceInfo {\n    /// Location of the device on the machine. Uniquely identifies each device.\n    pub location: PciDeviceBdf,\n\n    pub vendor_id: u16,\n    pub device_id: u16,\n\n    pub class_code: u8,\n    pub subclass: u8,\n    pub prog_if: u8,\n    pub revision_id: u8,\n\n    pub base_address_registers: Vec<PciBaseAddressRegister>,\n    // TODO: add more fields\n}\n\n/// Description of a single PCI device.\n// TODO: actually figure out PCI and adjust this\n#[derive(Debug, Clone, Encode, Decode)]\npub enum PciBaseAddressRegister {\n    Memory { base_address: u64 },\n    Io { base_address: u32 },\n}\n\n/// Request to perform accesses to memory-mapped memory.\n#[derive(Debug, Encode, Decode)]\npub enum MemoryOperation {\n    Memset {\n        offset: u64,\n        len: u64,\n        value: u8,\n    },\n    WriteU8 {\n        offset: u64,\n        data: Vec<u8>,\n    },\n    /// Uses the platform's native endianess.\n    WriteU16 {\n        offset: u64,\n        data: Vec<u16>,\n    },\n    /// Uses the platform's native endianess.\n    WriteU32 {\n        offset: u64,\n        data: Vec<u32>,\n    },\n    ReadU8 {\n        offset: u64,\n        len: u32,\n    },\n    ReadU16 {\n        offset: u64,\n        /// Number of `u16`s to read.\n        len: u32,\n    },\n    ReadU32 {\n        offset: u64,\n        /// Number of `u32`s to read.\n        len: u32,\n    },\n}\n\n/// Request to perform accesses to I/O ports.\n#[derive(Debug, Encode, Decode)]\npub enum IoOperation {\n    /// Write data to a port.\n    WriteU8 {\n        /// Offset of the port from the value in the BAR.\n        port_offset: u32,\n        /// Data to write.\n        data: u8,\n    },\n    /// Write data to a port.\n    WriteU16 {\n        /// Offset of the port from the value in the BAR.\n        port_offset: u32,\n        /// Data to write.\n        data: u16,\n    },\n    /// Write data to a port.\n    WriteU32 {\n        /// Offset of the port from the value in the BAR.\n        port_offset: u32,\n        /// Data to write.\n        data: u32,\n    },\n    /// Reads data from a port.\n    ReadU8 {\n        /// Offset of the port from the value in the BAR.\n        port_offset: u32,\n    },\n    /// Reads data from a port.\n    ReadU16 {\n        /// Offset of the port from the value in the BAR.\n        port_offset: u32,\n    },\n    /// Reads data from a port.\n    ReadU32 {\n        /// Offset of the port from the value in the BAR.\n        port_offset: u32,\n    },\n}\n\n/// Response to a [`PciMessage::BarMemoryOperations`].\n#[derive(Debug, Encode, Decode)]\npub enum MemoryAccessResponse {\n    /// Sent back in response to a [`MemoryOperation::ReadU8`].\n    ReadU8(Vec<u8>),\n    /// Sent back in response to a [`MemoryOperation::ReadU16`].\n    ReadU16(Vec<u16>),\n    /// Sent back in response to a [`MemoryOperation::ReadU32`].\n    ReadU32(Vec<u32>),\n}\n\n/// Response to a [`PciMessage::BarIoOperations`].\n#[derive(Debug, Encode, Decode)]\npub enum IoAccessResponse {\n    /// Sent back in response to a [`IoOperation::ReadU8`].\n    ReadU8(u8),\n    /// Sent back in response to a [`IoOperation::ReadU16`].\n    ReadU16(u16),\n    /// Sent back in response to a [`IoOperation::ReadU32`].\n    ReadU32(u32),\n}\n"
  },
  {
    "path": "interface-wrappers/pci/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Access to PCI devices.\n//!\n//! Use this interface if you're writing a device driver.\n\n#![no_std]\n\nextern crate alloc;\n\npub use self::ffi::{PciBaseAddressRegister, PciDeviceBdf, PciDeviceInfo};\n\nuse alloc::vec::Vec;\nuse futures::prelude::*;\n\npub mod ffi;\n\n/// Returns the list of PCI devices available on the system.\npub fn get_pci_devices() -> impl Future<Output = Vec<PciDeviceInfo>> {\n    unsafe {\n        let msg = ffi::PciMessage::GetDevicesList;\n        // TODO: don't unwrap?\n        redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg)\n            .unwrap()\n            .map(|response: ffi::GetDevicesListResponse| response.devices)\n    }\n}\n\n// TODO: provide a good API for all this\n\n/// Active lock of a PCI device.\n///\n/// While this struct is alive, no other program can lock that same PCI device.\npub struct PciDeviceLock {\n    device: ffi::PciDeviceBdf,\n}\n\nimpl PciDeviceLock {\n    // TODO: shouldn't be public?\n    pub async fn lock(bdf: ffi::PciDeviceBdf) -> Result<Self, ()> {\n        let result: Result<(), ()> = unsafe {\n            let msg = ffi::PciMessage::LockDevice(bdf.clone());\n            redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg)\n                .unwrap()\n                .await\n        };\n\n        result?;\n\n        Ok(PciDeviceLock { device: bdf })\n    }\n\n    pub fn set_command(&self, bus_master: bool, memory_space: bool, io_space: bool) {\n        unsafe {\n            redshirt_syscalls::emit_message_without_response(&ffi::INTERFACE, &{\n                ffi::PciMessage::SetCommand {\n                    location: self.device.clone(),\n                    bus_master,\n                    memory_space,\n                    io_space,\n                }\n            })\n            .unwrap();\n        }\n    }\n\n    /// Waits until the device produces an interrupt.\n    ///\n    /// The returned future is disconnected from the [`PciDeviceLock`]. However, polling the\n    /// future after its corresponding [`PciDeviceLock`] has been destroyed will panic.\n    ///\n    /// > **Note**: Be aware that this `Future` only returns the *next* interrupt that happens.\n    /// >           PCI devices typically provide a way for the driver to know the reason why an\n    /// >           interrupt happened. In order to not miss any follow-up interrupt, call this\n    /// >           function *before* reading the reason, but only await on the returned Future\n    /// >           *after* reading the reason.\n    pub fn next_interrupt(&self) -> impl Future<Output = ()> + Send + 'static {\n        let bdf = self.device.clone();\n\n        // We send the message outside of the `async` block in order to be sure that the message\n        // gets sent before the user starts polling the `Future`.\n        let response = {\n            let msg = ffi::PciMessage::NextInterrupt(bdf);\n            unsafe { redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg) }.unwrap()\n        };\n\n        async move {\n            response\n                .map(|response: ffi::NextInterruptResponse| match response {\n                    ffi::NextInterruptResponse::Interrupt => {}\n                    ffi::NextInterruptResponse::BadDevice => panic!(),\n                    ffi::NextInterruptResponse::Unlocked => unreachable!(),\n                })\n                .await\n        }\n    }\n}\n\nimpl Drop for PciDeviceLock {\n    fn drop(&mut self) {\n        unsafe {\n            let msg = ffi::PciMessage::UnlockDevice(self.device.clone());\n            redshirt_syscalls::emit_message_without_response(&ffi::INTERFACE, msg).unwrap();\n        }\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/random/Cargo.toml",
    "content": "[package]\nname = \"redshirt-random-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nredshirt-syscalls = { path = \"../syscalls\", default-features = false }\nparity-scale-codec = { version = \"1.3.6\", default-features = false, features = [\"derive\"] }\n\n[features]\ndefault = [\"std\"]\nstd = []\n"
  },
  {
    "path": "interface-wrappers/random/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse alloc::vec::Vec;\nuse parity_scale_codec::{Decode, Encode};\nuse redshirt_syscalls::InterfaceHash;\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0xfb, 0x83, 0xa5, 0x46, 0xfd, 0xf1, 0x50, 0x7a, 0xef, 0x8c, 0xb6, 0x8f, 0xa5, 0x44, 0x49, 0x21,\n    0x53, 0xe5, 0x83, 0xda, 0xf0, 0x66, 0xbc, 0x1a, 0xd2, 0x18, 0xfd, 0x00, 0x54, 0x7f, 0xdb, 0x25,\n]);\n\n#[derive(Debug, Encode, Decode)]\npub enum RandomMessage {\n    /// Ask to generate cryptographically-secure list of random numbers of the given length.\n    ///\n    /// The length is a `u16`, so the maximum size is 64kiB and there's no need to handle potential\n    /// errors about the length being too long to fit in memory. Call multiple times to obtain\n    /// more.\n    Generate { len: u16 },\n}\n\n#[derive(Debug, Encode, Decode)]\npub struct GenerateResponse {\n    /// Random bytes. Must be of the requested length.\n    pub result: Vec<u8>,\n}\n"
  },
  {
    "path": "interface-wrappers/random/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Generating cryptographically-secure random data.\n\n#![cfg_attr(not(feature = \"std\"), no_std)]\n\nextern crate alloc;\n\nuse alloc::vec::Vec;\nuse core::convert::TryFrom as _;\n\npub mod ffi;\n\n/// Generate `len` bytes of random data and returns them.\npub async fn generate(len: usize) -> Vec<u8> {\n    unsafe {\n        let mut out = Vec::with_capacity(len);\n        out.set_len(len);\n        generate_in(&mut out).await;\n        out\n    }\n}\n\n/// Fills `out` with randomly-generated data.\npub async fn generate_in(out: &mut [u8]) {\n    for chunk in out.chunks_mut(usize::from(u16::max_value())) {\n        let msg = ffi::RandomMessage::Generate {\n            len: u16::try_from(chunk.len()).unwrap(),\n        };\n        let rep: ffi::GenerateResponse = unsafe {\n            redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg)\n                .unwrap()\n                .await\n        };\n        chunk.copy_from_slice(&rep.result);\n    }\n}\n\n/// Generates a random `u8`.\npub async fn generate_u8() -> u8 {\n    let mut buf = [0; 1];\n    generate_in(&mut buf).await;\n    buf[0]\n}\n\n/// Generates a random `u16`.\npub async fn generate_u16() -> u16 {\n    let mut buf = [0; 2];\n    generate_in(&mut buf).await;\n    u16::from_ne_bytes(buf)\n}\n\n/// Generates a random `u32`.\npub async fn generate_u32() -> u32 {\n    let mut buf = [0; 4];\n    generate_in(&mut buf).await;\n    u32::from_ne_bytes(buf)\n}\n\n/// Generates a random `u64`.\npub async fn generate_u64() -> u64 {\n    let mut buf = [0; 8];\n    generate_in(&mut buf).await;\n    u64::from_ne_bytes(buf)\n}\n\n/// Generates a random `u128`.\npub async fn generate_u128() -> u128 {\n    let mut buf = [0; 16];\n    generate_in(&mut buf).await;\n    u128::from_ne_bytes(buf)\n}\n"
  },
  {
    "path": "interface-wrappers/syscalls/Cargo.toml",
    "content": "[package]\nname = \"redshirt-syscalls\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nfutures = { version = \"0.3.13\", default-features = false, features = [\"alloc\"] }\ngeneric-array = { version = \"0.14.4\", default-features = false }\nhashbrown = { version = \"0.9.1\", default-features = false }\nlazy_static = { version = \"1.4.0\", features = [\"spin_no_std\"] }\nnohash-hasher = { version = \"0.2.0\", default-features = false }\nparity-scale-codec = { version = \"1.3.6\", default-features = false, features = [\"derive\"] }\npin-project = \"1.0.5\"\nslab = { version = \"0.4.9\", default-features = false }\nspinning_top = \"0.2.2\"\n"
  },
  {
    "path": "interface-wrappers/syscalls/src/block_on.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! As explained in the crate root, the futures of this crate can only work with [`block_on`], and\n//! vice-versa.\n//!\n//! The way it works is the following:\n//!\n//! - We hold a global buffer of interface messages waiting to be processed, and a global buffer\n//!   of responses that have been received and that are waiting to be processed.\n//!\n//! - We also hold a global buffer of message IDs that we want a response for, and an associated\n//!   `core::task::Waker`.\n//!\n//! - When one of the `Future`s gets polled, it first look whether an interface message or a\n//!   response is available in one of the buffers. If not, it registers a waker using the\n//!   [`register_message_waker`] function.\n//!\n//! - The [`block_on`] function polls the `Future` passed to it, which optionally calls\n//!   [`register_message_waker`], then asks the kernel for responses to the message IDs that have\n//!   been registered. Once one or more messages have come back, we poll the `Future` again.\n//!   Repeat until the `Future` has ended.\n//!\n\nuse crate::{ffi, MessageId};\nuse alloc::{sync::Arc, vec::Vec};\nuse core::{\n    sync::atomic::{AtomicBool, Ordering},\n    task::{Context, Poll, Waker},\n};\nuse futures::{prelude::*, task};\nuse hashbrown::HashMap;\nuse nohash_hasher::BuildNoHashHasher;\nuse slab::Slab;\nuse spinning_top::Spinlock;\n\n/// Registers a message ID and an associated waker. The `block_on` function will then ask the\n/// kernel for a message corresponding to this ID. If one is received, the `Waker` is called.\n///\n/// Registering multiple wakers for the same message is a logic error.\npub(crate) fn register_message_waker(message_id: MessageId, waker: Waker) -> WakerRegistration {\n    let mut state = (&*STATE).lock();\n\n    let index = state.wakers.insert(Some(waker));\n\n    if state.message_ids.len() <= index {\n        state.message_ids.resize(index + 1, 0);\n    }\n\n    debug_assert_eq!(state.message_ids[index], 0);\n    state.message_ids[index] = From::from(message_id);\n\n    WakerRegistration { index }\n}\n\n/// If a response to this message ID has previously been obtained, extracts it for processing.\npub(crate) fn peek_response(msg_id: MessageId) -> Option<Vec<u8>> {\n    let mut state = (&*STATE).lock();\n    state.pending_messages.remove(&msg_id)\n}\n\npub(crate) struct WakerRegistration {\n    /// Index within `STATE::message_ids` and `STATE::wakers`.\n    index: usize,\n}\n\nimpl WakerRegistration {\n    /// Modifies the registered waker.\n    pub fn update(&self, waker: &Waker) {\n        let mut state = (&*STATE).lock();\n        match &mut state.wakers[self.index] {\n            Some(w) if w.will_wake(waker) => {}\n            w @ _ => *w = Some(waker.clone()),\n        }\n    }\n}\n\nimpl Drop for WakerRegistration {\n    fn drop(&mut self) {\n        let mut state = (&*STATE).lock();\n        state.message_ids[self.index] = 0;\n        state.wakers.remove(self.index);\n\n        // Reclaim memory if possible.\n        if state.wakers.is_empty() {\n            state.wakers.shrink_to_fit();\n            state.message_ids = Vec::new();\n        }\n    }\n}\n\n/// Blocks the current thread until the [`Future`](core::future::Future) passed as parameter\n/// finishes.\npub fn block_on<T>(future: impl Future<Output = T>) -> T {\n    futures::pin_mut!(future);\n\n    // This `Arc<AtomicBool>` will be set to true if we are waken up during the polling.\n    let woken_up = Arc::new(AtomicBool::new(false));\n    let waker = {\n        struct Notify(Arc<AtomicBool>);\n        impl task::ArcWake for Notify {\n            fn wake_by_ref(arc_self: &Arc<Self>) {\n                arc_self.0.store(true, Ordering::SeqCst);\n            }\n        }\n        task::waker(Arc::new(Notify(woken_up.clone())))\n    };\n\n    let mut context = Context::from_waker(&waker);\n\n    loop {\n        // We poll the future continuously until it is either Ready, or the waker stops being\n        // invoked during the polling.\n        loop {\n            if let Poll::Ready(val) = Future::poll(future.as_mut(), &mut context) {\n                return val;\n            }\n\n            // If the waker has been used during the polling of this future, then we have to pol\n            // again.\n            if woken_up.swap(false, Ordering::SeqCst) {\n                continue;\n            } else {\n                break;\n            }\n        }\n\n        let mut state = (&*STATE).lock();\n\n        // `block` indicates whether we should block the thread or just peek. Always `true` during\n        // the first iteration, and `false` in further iterations.\n        let mut block = true;\n\n        // We process in a loop all pending messages.\n        while let Some(raw) = next_notification(&mut state.message_ids, block) {\n            block = false;\n\n            let msg = ffi::decode_notification(&raw).unwrap();\n\n            // Value is zero-ed by the kernel.\n            debug_assert_eq!(state.message_ids[msg.index_in_list as usize], 0);\n            if let Some(waker) = state.wakers[msg.index_in_list as usize].take() {\n                waker.wake();\n            }\n\n            let _was_in = state.pending_messages.insert(msg.message_id, raw);\n            debug_assert!(_was_in.is_none());\n        }\n\n        debug_assert!(!block);\n    }\n}\n\nlazy_static::lazy_static! {\n    // TODO: we're using a Mutex, which is ok for as long as WASM doesn't have threads\n    // if WASM ever gets threads and no pre-emptive multitasking, then we might spin forever\n    static ref STATE: Spinlock<BlockOnState> = {\n        Spinlock::new(BlockOnState {\n            message_ids: Vec::new(),\n            wakers: Slab::new(),\n            pending_messages: HashMap::with_capacity_and_hasher(6, Default::default()),\n        })\n    };\n}\n\n/// State of the global `block_on` mechanism.\n///\n/// This is instantiated only once.\nstruct BlockOnState {\n    /// List of messages for which we are waiting for a response. A pointer to this list is passed\n    /// to the kernel.\n    message_ids: Vec<u64>,\n\n    /// List whose length is identical to [`BlockOnState::message_ids`]. For each element in\n    /// [`BlockOnState::message_ids`], contains a corresponding `Waker` that must be waken up\n    /// when a response comes.\n    wakers: Slab<Option<Waker>>,\n\n    /// Queue of response messages waiting to be delivered.\n    ///\n    /// > **Note**: We have to maintain this queue as a global variable rather than a per-future\n    /// >           channel, otherwise dropping a `Future` would silently drop messages that have\n    /// >           already been received.\n    pending_messages: HashMap<MessageId, Vec<u8>, BuildNoHashHasher<u64>>,\n}\n\n/// Checks whether a new message arrives, optionally blocking the thread.\n///\n/// If `block` is true, then the return value is always `Some`.\n///\n/// See the `next_notification` FFI function for the semantics of `to_poll`.\npub(crate) fn next_notification(to_poll: &mut [u64], block: bool) -> Option<Vec<u8>> {\n    next_notification_impl(to_poll, block)\n}\n\n#[cfg(target_arch = \"wasm32\")] // TODO: we should have a proper operating system name instead\nfn next_notification_impl(to_poll: &mut [u64], block: bool) -> Option<Vec<u8>> {\n    unsafe {\n        let flags = if block { 1 } else { 0 };\n\n        let mut out = Vec::<u64>::with_capacity(4);\n        loop {\n            let ret = crate::ffi::next_notification(\n                to_poll.as_mut_ptr(),\n                to_poll.len() as u32,\n                out.as_mut_ptr() as *mut u8,\n                out.capacity() as u32 * 8,\n                flags,\n            ) as usize;\n            if ret == 0 {\n                debug_assert!(!block);\n                return None;\n            }\n            if ret > out.capacity() * 8 {\n                out.reserve(8 * (1 + (ret - 1) / 8));\n                continue;\n            }\n            let out_slice = core::slice::from_raw_parts(out.as_ptr() as *const u8, ret);\n            // TODO: don't use to_vec(), ideally\n            return Some(out_slice.to_vec());\n        }\n    }\n}\n\n#[cfg(not(target_arch = \"wasm32\"))]\nfn next_notification_impl(_: &mut [u64], _: bool) -> Option<Vec<u8>> {\n    unimplemented!()\n}\n"
  },
  {
    "path": "interface-wrappers/syscalls/src/emit.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::{Decode, Encode, EncodedMessage, InterfaceHash, MessageId};\nuse core::{\n    convert::TryFrom as _,\n    fmt,\n    marker::PhantomData,\n    mem::MaybeUninit,\n    pin::Pin,\n    task::{Context, Poll},\n};\nuse futures::prelude::*;\nuse generic_array::{\n    sequence::Concat as _,\n    typenum::consts::{U0, U2},\n    ArrayLength, GenericArray,\n};\n\n/// Prototype for a message in construction.\n///\n/// Use this struct if you want to send out a message split between multiple slices.\npub struct MessageBuilder<'a, TLen: ArrayLength<u32>> {\n    /// Parameter for the FFI function.\n    allow_delay: bool,\n    /// Array of slices, passed to the FFI function.\n    array: GenericArray<u32, TLen>,\n    /// Pin the lifetime. The lifetime corresponds to the lifetime of buffers pointer to\n    /// within `array`.\n    marker: PhantomData<&'a ()>,\n}\n\nimpl<'a> MessageBuilder<'a, U0> {\n    /// Start building an empty message.\n    pub fn new() -> Self {\n        MessageBuilder {\n            allow_delay: true,\n            array: Default::default(),\n            marker: PhantomData,\n        }\n    }\n}\n\nimpl<'a, TLen> MessageBuilder<'a, TLen>\nwhere\n    TLen: ArrayLength<u32>,\n{\n    /// If called, emitting the message will fail if no interface handler is available. Otherwise,\n    /// emitting the message will block the thread until a handler is available.\n    pub fn with_no_delay(mut self) -> Self {\n        self.allow_delay = false;\n        self\n    }\n\n    /// Append a slice of message data to the builder.\n    ///\n    /// > **Note**: This operation is cheap and doesn't perform any copy of the message data\n    /// >           itself.\n    pub fn add_data<TOutLen>(self, buffer: &'a EncodedMessage) -> MessageBuilder<'a, TOutLen>\n    where\n        TLen: core::ops::Add<U2, Output = TOutLen>,\n        TOutLen: ArrayLength<u32>,\n    {\n        self.add_data_raw(&buffer.0)\n    }\n\n    /// Append a slice of message data to the builder.\n    ///\n    /// > **Note**: This operation is cheap and doesn't perform any copy of the message data\n    /// >           itself.\n    pub fn add_data_raw<TOutLen>(self, buffer: &'a [u8]) -> MessageBuilder<'a, TOutLen>\n    where\n        TLen: core::ops::Add<U2, Output = TOutLen>,\n        TOutLen: ArrayLength<u32>,\n    {\n        let mut new_pair = GenericArray::<u32, U2>::default();\n        new_pair[0] = u32::try_from(buffer.as_ptr() as usize).unwrap();\n        new_pair[1] = u32::try_from(buffer.len()).unwrap();\n\n        MessageBuilder {\n            allow_delay: self.allow_delay,\n            array: self.array.concat(new_pair),\n            marker: self.marker,\n        }\n    }\n\n    /// Emit the message and returns a `Future` that will yield the response.\n    // TODO: could we remove the error type?\n    pub unsafe fn emit_with_response<T>(\n        self,\n        interface: &InterfaceHash,\n    ) -> Result<impl Future<Output = T>, EmitErr>\n    where\n        T: Decode,\n    {\n        let msg_id = self.emit_with_response_raw(interface)?;\n        let response_fut = crate::message_response(msg_id);\n        Ok(EmitMessageWithResponse {\n            inner: Some(response_fut),\n            msg_id,\n        })\n    }\n\n    /// Emit the message and returns the emitted [`MessageId`].\n    // TODO: could we remove the error type?\n    pub unsafe fn emit_with_response_raw(\n        self,\n        interface: &InterfaceHash,\n    ) -> Result<MessageId, EmitErr> {\n        Ok(self.emit_raw(interface, true)?.unwrap())\n    }\n\n    /// Emit the message. The message doesn't expect any response. If the handler tries to\n    /// respond, the response will be ignored.\n    // TODO: could we remove the error type?\n    pub unsafe fn emit_without_response(self, interface: &InterfaceHash) -> Result<(), EmitErr> {\n        let out = self.emit_raw(interface, false)?;\n        debug_assert!(out.is_none());\n        Ok(())\n    }\n\n    /// Emit the message. You can decide at runtime whether or not the message expects a response.\n    ///\n    /// If `needs_answer` is `true`, then on success a `Some` will always be returned.\n    /// If `needs_answer` is `false`, then on success a `None` will always be returned.\n    // TODO: could we remove the error type?\n    pub unsafe fn emit_raw(\n        self,\n        interface: &InterfaceHash,\n        needs_answer: bool,\n    ) -> Result<Option<MessageId>, EmitErr> {\n        self.emit_raw_impl(interface, needs_answer)\n    }\n\n    #[cfg(target_arch = \"wasm32\")] // TODO: we should have a proper operating system name instead\n    unsafe fn emit_raw_impl(\n        self,\n        interface: &InterfaceHash,\n        needs_answer: bool,\n    ) -> Result<Option<MessageId>, EmitErr> {\n        let flags = {\n            let mut flags = 0;\n            if needs_answer {\n                flags |= 1 << 0;\n            }\n            if self.allow_delay {\n                flags |= 1 << 1;\n            }\n            flags\n        };\n\n        let mut message_id_out = MaybeUninit::uninit();\n\n        let ret = crate::ffi::emit_message(\n            interface as *const InterfaceHash as *const _,\n            self.array.as_ptr(),\n            u32::try_from(self.array.len() / 2).unwrap(),\n            flags,\n            message_id_out.as_mut_ptr(),\n        );\n\n        if ret != 0 {\n            return Err(EmitErr::BadInterface);\n        }\n\n        if needs_answer {\n            Ok(Some(MessageId::from_u64_unchecked(\n                message_id_out.assume_init(),\n            )))\n        } else {\n            Ok(None)\n        }\n    }\n\n    #[cfg(not(target_arch = \"wasm32\"))]\n    unsafe fn emit_raw_impl(\n        self,\n        _: &InterfaceHash,\n        _: bool,\n    ) -> Result<Option<MessageId>, EmitErr> {\n        unimplemented!()\n    }\n}\n\nimpl<'a> Default for MessageBuilder<'a, U0> {\n    fn default() -> Self {\n        MessageBuilder::new()\n    }\n}\n\nimpl<'a, TLen> fmt::Debug for MessageBuilder<'a, TLen>\nwhere\n    TLen: ArrayLength<u32>,\n{\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"MessageBuilder\").finish()\n    }\n}\n\n/// Emits a message destined to the handler of the given interface.\n///\n/// Returns `Ok` if the message has been successfully dispatched. Returns an error if no handler\n/// is available for that interface.\n/// Whether this function succeeds only depends on whether an interface handler is available. This\n/// function doesn't perform any validity check on the message itself.\n///\n/// # Safety\n///\n/// While the action of sending a message is totally safe, the message itself might instruct the\n/// environment to perform actions that would lead to unsafety.\n///\npub unsafe fn emit_message_without_response<'a>(\n    interface: &InterfaceHash,\n    msg: impl Encode,\n) -> Result<(), EmitErr> {\n    let msg = msg.encode();\n    MessageBuilder::new()\n        .add_data(&msg)\n        .emit_without_response(interface)\n}\n\n/// Emis a message, then waits for a response to come back.\n///\n/// Returns `Ok` if the message has been successfully dispatched. Returns an error if no handler\n/// is available for that interface.\n/// Whether this function succeeds only depends on whether an interface handler is available. This\n/// function doesn't perform any validity check on the message itself.\n///\n/// The returned future will cancel the message if it is dropped early.\n///\n/// # Safety\n///\n/// While the action of sending a message is totally safe, the message itself might instruct the\n/// environment to perform actions that would lead to unsafety.\n///\npub unsafe fn emit_message_with_response<'a, T: Decode>(\n    interface: &InterfaceHash,\n    msg: impl Encode,\n) -> Result<impl Future<Output = T>, EmitErr> {\n    let msg = msg.encode();\n    MessageBuilder::new()\n        .add_data(&msg)\n        .emit_with_response(interface)\n}\n\n/// Cancel the given message. No answer will be received.\n///\n/// Has no effect if the message is invalid.\npub fn cancel_message(message_id: MessageId) {\n    #[cfg(target_arch = \"wasm32\")] // TODO: we should have a proper operating system name instead\n    fn imp(message_id: MessageId) {\n        unsafe { crate::ffi::cancel_message(&u64::from(message_id)) }\n    }\n    #[cfg(not(target_arch = \"wasm32\"))]\n    fn imp(_: MessageId) {\n        unreachable!()\n    }\n    imp(message_id)\n}\n\n/// Error that can be retuend by functions that emit a message.\n#[derive(Debug)]\npub enum EmitErr {\n    /// The given interface has no handler.\n    BadInterface,\n}\n\nimpl fmt::Display for EmitErr {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            EmitErr::BadInterface => write!(f, \"The given interface has no handler\"),\n        }\n    }\n}\n\n/// Future that drives [`emit_message_with_response`] to completion.\n#[must_use]\n#[pin_project::pin_project(PinnedDrop)]\npub struct EmitMessageWithResponse<T> {\n    #[pin]\n    inner: Option<crate::MessageResponseFuture<T>>,\n    // TODO: redundant with `inner`\n    msg_id: MessageId,\n}\n\nimpl<T: Decode> Future for EmitMessageWithResponse<T> {\n    type Output = T;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {\n        unsafe {\n            let mut this = self.project();\n            let val = match this\n                .inner\n                .as_mut()\n                .map_unchecked_mut(|opt| opt.as_mut().unwrap())\n                .poll(cx)\n            {\n                Poll::Ready(val) => val,\n                Poll::Pending => return Poll::Pending,\n            };\n            *this.inner = None;\n            Poll::Ready(val)\n        }\n    }\n}\n\n#[pin_project::pinned_drop]\nimpl<T> PinnedDrop for EmitMessageWithResponse<T> {\n    fn drop(self: Pin<&mut Self>) {\n        if self.inner.is_some() {\n            let _ = cancel_message(self.msg_id);\n        }\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/syscalls/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::{EncodedMessageRef, MessageId};\n\nuse alloc::vec::Vec;\nuse core::convert::TryFrom as _;\n\n#[cfg(target_arch = \"wasm32\")] // TODO: we should have a proper operating system name instead\n#[link(wasm_import_module = \"redshirt\")]\nextern \"C\" {\n    /// Asks for the next notification.\n    ///\n    /// The `to_poll` parameter must be a list (whose length is `to_poll_len`) of messages whose\n    /// answer to poll. Entries in this list equal to `0` are ignored. If a notification is\n    /// successfully pulled, the corresponding entry in `to_poll` is set to `0`.\n    ///\n    /// Flags is a bitfield, defined as:\n    ///\n    /// - Bit 0: the `block` flag. If set, then this function puts the thread to sleep until a\n    /// notification is available. Otherwise, this function returns as soon as possible.\n    ///\n    /// If the function returns 0, then there is no notification available and nothing has been\n    /// written.\n    /// This function never returns 0 if the `block` flag is set.\n    /// If the function returns a value larger than `out_len`, then a notification is available\n    /// whose  length is the value that has been returned, but nothing has been written in `out`.\n    /// If the function returns value inferior or equal to `out_len` (and different from 0), then\n    /// a notification has been written in `out`. `out` must be 8-bytes-aligned.\n    ///\n    /// Messages, amongst the set that matches `to_poll`, are always returned in the order they\n    /// have been received. In particular, this function does **not** search the queue of\n    /// notifications for a notification that fits in `out_len`. It will however skip the\n    /// notifications in the queue that do not match any entry in `to_poll`.\n    ///\n    /// Messages written in `out` can be decoded using [`decode_notification`].\n    ///\n    /// When this function is being called, a \"lock\" is being held on the memory pointed by\n    /// `to_poll` and `out`. In particular, it is invalid to modify these buffers while the\n    /// function is running.\n    pub(crate) fn next_notification(\n        to_poll: *mut u64,\n        to_poll_len: u32,\n        out: *mut u8,\n        out_len: u32,\n        flags: u64,\n    ) -> u32;\n\n    /// Sends a message to the process that has registered the given interface.\n    ///\n    /// The memory area pointed to by `msg_bufs_ptrs` must contain a list of `msg_bufs_num` pairs\n    /// of two 32-bits values encoded in little endian. In other words, the list must contain\n    /// `msg_bufs_num * 2` values. Each pair is composed of a memory address and a length\n    /// referring to a buffer containing a slice of the message body.\n    /// The message body consists of the concatenation of all these buffers.\n    ///\n    /// > **Note**: This API is similar to the one of the `writev` POSIX function. The\n    /// >           `msg_bufs_ptrs` parameter is similar to the `iov` parameter of `writev`, and\n    /// >           the `msg_bufs_num` parameter is similar to the `iovcnt` parameter of `writev`.\n    ///\n    /// The message body is what will go into the\n    /// [`actual_data`](DecodedInterfaceNotification::actual_data) field of the\n    /// [`DecodedInterfaceNotification`] that the target will receive.\n    ///\n    /// Flags is a bitfield, defined as:\n    ///\n    /// - Bit 0: the `needs_answer` flag. If set, then this message expects an answer.\n    /// - Bit 1: the `allow_delay` flag. If set, the kernel is allowed to block the thread in\n    /// order to lazily-load a handler for that interface if necessary. If this flag is not set,\n    /// and no interface handler is available, then the function fails immediately.\n    ///\n    /// Returns `0` on success, and `1` in case of error.\n    ///\n    /// On success, if `needs_answer` is true, will write the ID of new event into the memory\n    /// pointed by `message_id_out`.\n    ///\n    /// When this function is being called, a \"lock\" is being held on the memory pointed by\n    /// `interface_hash`, `msg_bufs_ptrs`, `message_id_out`, and all the sub-buffers referred to\n    /// within `msg_bufs_ptrs`. In particular, it is invalid to modify these buffers while the\n    /// function is running.\n    // TODO: document error that can happen\n    pub(crate) fn emit_message(\n        interface_hash: *const u8,\n        msg_bufs_ptrs: *const u32,\n        msg_bufs_num: u32,\n        flags: u64,\n        message_id_out: *mut u64,\n    ) -> u32;\n\n    /// Cancel an expected answer.\n    ///\n    /// After a message that needs an answer has been emitted using `emit_message`,\n    /// the `cancel_message` function can be used to signal that we're not interested in the\n    /// answer.\n    ///\n    /// After this function has been called, the passed `message_id` is no longer valid.\n    /// Has no effect if the message id is zero or refers to an invalid message. This can\n    /// legitimately happen if the process that emitted the message has crashed or stopped.\n    ///\n    /// When this function is being called, a \"lock\" is being held on the memory pointed by\n    /// `message_id`. In particular, it is invalid to modify this buffer while the function is\n    /// running.\n    pub(crate) fn cancel_message(message_id: *const u64);\n}\n\n// TODO: all the decoding performs unaligned reads, which isn't great\n\npub fn build_notification(\n    message_id: MessageId,\n    index_in_list: u32,\n    actual_data: Result<EncodedMessageRef, ()>,\n) -> NotificationBuilder {\n    let mut buffer = Vec::with_capacity(\n        1 + 8 + 4 + 1 + actual_data.as_ref().map(|m| m.as_ref().len()).unwrap_or(0),\n    );\n    buffer.push(1);\n    buffer.extend_from_slice(&u64::from(message_id).to_le_bytes());\n    buffer.extend_from_slice(&index_in_list.to_le_bytes());\n    if let Ok(actual_data) = actual_data {\n        buffer.push(0);\n        buffer.extend_from_slice(actual_data.as_ref());\n    } else {\n        buffer.push(1);\n    }\n\n    debug_assert_eq!(buffer.capacity(), buffer.len());\n    NotificationBuilder { data: buffer }\n}\n\n#[derive(Debug, Clone)]\npub struct NotificationBuilder {\n    data: Vec<u8>,\n}\n\nimpl NotificationBuilder {\n    /// Updates the `index_in_list` field of the message.\n    pub fn set_index_in_list(&mut self, value: u32) {\n        self.data[9..13].copy_from_slice(&value.to_le_bytes());\n    }\n\n    pub fn message_id(&self) -> MessageId {\n        MessageId::try_from(u64::from_le_bytes([\n            self.data[1],\n            self.data[2],\n            self.data[3],\n            self.data[4],\n            self.data[5],\n            self.data[6],\n            self.data[7],\n            self.data[8],\n        ]))\n        .unwrap()\n    }\n\n    pub fn len(&self) -> usize {\n        self.data.len()\n    }\n\n    pub fn into_bytes(self) -> Vec<u8> {\n        self.data\n    }\n}\n\npub fn decode_notification(buffer: &[u8]) -> Result<DecodedNotificationRef, ()> {\n    if buffer.len() < 1 + 8 + 4 + 1 {\n        return Err(());\n    }\n\n    if buffer[0] != 0x1 {\n        return Err(());\n    }\n\n    let success = buffer[13] == 0;\n    if !success && buffer.len() != 1 + 8 + 4 + 1 {\n        return Err(());\n    }\n\n    Ok(DecodedNotificationRef {\n        message_id: MessageId::try_from({\n            u64::from_le_bytes([\n                buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7],\n                buffer[8],\n            ])\n        })\n        .map_err(|_| ())?,\n        index_in_list: u32::from_le_bytes([buffer[9], buffer[10], buffer[11], buffer[12]]),\n        actual_data: if success {\n            Ok(EncodedMessageRef::from(&buffer[14..]))\n        } else {\n            Err(())\n        },\n    })\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct DecodedNotificationRef<'a> {\n    /// Identifier of the message whose answer we are receiving.\n    pub message_id: MessageId,\n\n    /// Index within the list to poll where this message was.\n    pub index_in_list: u32,\n\n    /// The response, or `Err` if:\n    ///\n    /// - The interface handler has crashed.\n    /// - The interface handler marked our message as invalid.\n    ///\n    pub actual_data: Result<EncodedMessageRef<'a>, ()>,\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use core::convert::TryFrom;\n\n    #[test]\n    fn response_message_encode_decode() {\n        let message_id = TryFrom::try_from(0x0123456789abcdef).unwrap();\n        let index_in_list = 0xdeadbeef;\n        let message = EncodedMessageRef::from(&[8, 7, 9][..]);\n\n        let mut resp_notif = build_notification(message_id, 0xf00baa, Ok(message));\n        resp_notif.set_index_in_list(index_in_list);\n        assert_eq!(resp_notif.message_id(), message_id);\n\n        let encoded = resp_notif.into_bytes();\n        let decoded = decode_notification(&encoded).unwrap();\n        assert_eq!(decoded.message_id, message_id);\n        assert_eq!(decoded.index_in_list, index_in_list);\n        assert_eq!(decoded.actual_data, Ok(message));\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/syscalls/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Bindings for interfacing with the environment of the \"kernel\".\n//!\n//! # Messages and responses\n//!\n//! The environment available to `redshirt` programs consists in a collection of **interfaces**.\n//! An interface is referred to by a 32-bytes hash.\n//!\n//! Programs can emit messages by passing a target interface (a 32 bytes array), and a buffer\n//! containing the body of the message. The way the body of the message must be interpreted is\n//! entirely dependant on the interface it is sent on. Emitting a message always succeeds if the\n//! interface is available to the program, even if the body is malformed.\n//!\n//! When emitting a message, the sender must indicate whether or not it expects a response. If the\n//! interface handler sends back a response when none is expected, the response is discarded. If\n//! the interface handler doesn't send back a response when one is expected, then you effectively\n//! have a memory leak.\n//!\n//! A response can also be cancelled by the sender, in which case it is as if it had decided to not\n//! expect any response.\n//!\n//! The two primary and recommended ways to emit a message are the\n//! [`emit_message_without_response`] and [`emit_message_with_response`] functions.\n//!\n//! # Interface handling\n//!\n//! A program can register itself as an interface handler. This can be done by sending a message\n//! on a special-cased interface, called the \"interface\" interface. This is out of scoope of this\n//! crate. See the `redshirt_interface_interface` crate instead.\n//!\n//! # About threads\n//!\n//! Multithreading in WASM isn't specified yet, and Rust doesn't allow multithreaded WASM code.\n//! In particular, multithreaded WASM code in LLVM is undefined behaviour.\n//!\n//! With that in mind, this makes writing an implementation of `Future` challenging. When the\n//! `Future` returns `Poll::Pending`, the `Waker` has to be stored somewhere and invoked. Since\n//! there is no possibility of having multiple threads, the only moment when the `Waker` can be\n//! invoked is when we explicitly call a function whose role is to do that. The only reasonable\n//! choice for such function is the [`block_on()`] function, or similar functions.\n//!\n//! For the same reason, it is also challenging to write an implementation of [`block_on()`].\n//! Putting the current thread to sleep is not enough, because the lack of background threads\n//! makes it impossible for the `Waker` to be invoked. An implementation of [`block_on()`] **must**\n//! somehow perform actions that will drive to completion the `Future` it is blocking upon,\n//! otherwise nothing will ever happen.\n//!\n//! Consequently, it has been decided that the implementations of `Future` that this module\n//! provide interact, through a global variable, with the behaviour of [`block_on()`]. More\n//! precisely, before a `Future` returns `Poll::Pending`, it stores its `Waker` in a global\n//! variable alongside with the ID of the message whose response we are waiting for, and the\n//! [`block_on()`] function reads and processes that global variable.\n//!\n//! It is not possible to build a `Future` that is not built on top of one of the `Future`\n//! provided by this crate, and every single use-cases of `Future`s that we could think of\n//! can and must be built on top of them. Similarly, it is not possible to build an implementation\n//! of [`block_on()`] without having access to the internals of these `Future`s. Tying these\n//! `Future`s to the implementation of [`block_on()`] is therefore the logical thing to do.\n//!\n\n#![no_std]\n\nextern crate alloc;\n\npub use block_on::block_on;\npub use emit::{\n    cancel_message, emit_message_with_response, emit_message_without_response, MessageBuilder,\n};\npub use ffi::DecodedNotificationRef;\npub use response::{message_response, message_response_sync_raw, MessageResponseFuture};\npub use traits::{Decode, Encode, EncodedMessage, EncodedMessageRef};\n\nuse core::{cmp::PartialEq, convert::TryFrom, fmt, num::NonZeroU64};\n\nmod block_on;\nmod emit;\nmod response;\nmod traits;\n\npub mod ffi;\n\n/// Identifier of a running process within a core.\n// TODO: move to a Pid module?\n// TODO: should be NonZeroU64?\n#[derive(\n    Copy, Clone, PartialEq, Eq, Hash, parity_scale_codec::Encode, parity_scale_codec::Decode,\n)]\npub struct Pid(u64);\n\nimpl From<NonZeroU64> for Pid {\n    fn from(id: NonZeroU64) -> Pid {\n        Pid(id.get())\n    }\n}\n\nimpl From<u64> for Pid {\n    fn from(id: u64) -> Pid {\n        Pid(id)\n    }\n}\n\nimpl From<Pid> for u64 {\n    fn from(pid: Pid) -> u64 {\n        pid.0\n    }\n}\n\nimpl fmt::Debug for Pid {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"#{:020}\", self.0)\n    }\n}\n\n/// Identifier of a running thread within a core.\n// TODO: move to a separate module?\n// TODO: should be NonZeroU64?\n#[derive(\n    Copy, Clone, PartialEq, Eq, Hash, parity_scale_codec::Encode, parity_scale_codec::Decode,\n)]\npub struct ThreadId(u64);\n\nimpl From<NonZeroU64> for ThreadId {\n    fn from(id: NonZeroU64) -> ThreadId {\n        ThreadId(id.get())\n    }\n}\n\nimpl From<u64> for ThreadId {\n    fn from(id: u64) -> ThreadId {\n        ThreadId(id)\n    }\n}\n\nimpl From<ThreadId> for u64 {\n    fn from(tid: ThreadId) -> u64 {\n        tid.0\n    }\n}\n\nimpl fmt::Debug for ThreadId {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"#{:020}\", self.0)\n    }\n}\n\n/// Identifier of a message to answer.\n// TODO: move to a MessageId module?\n#[derive(\n    Copy, Clone, PartialEq, Eq, Hash, parity_scale_codec::Encode, parity_scale_codec::Decode,\n)]\npub struct MessageId(NonZeroU64);\n\nimpl MessageId {\n    /// Turns a raw integer into a [`MessageId`] without checking its validity.\n    ///\n    /// # Safety\n    ///\n    /// `id` must not be equal to 0.\n    pub unsafe fn from_u64_unchecked(id: u64) -> Self {\n        MessageId(NonZeroU64::new_unchecked(id))\n    }\n}\n\nimpl TryFrom<u64> for MessageId {\n    type Error = InvalidMessageIdErr;\n\n    fn try_from(id: u64) -> Result<Self, Self::Error> {\n        match id {\n            0 => Err(InvalidMessageIdErr),\n            n => Ok(MessageId(NonZeroU64::new(n).unwrap())),\n        }\n    }\n}\n\nimpl TryFrom<NonZeroU64> for MessageId {\n    type Error = InvalidMessageIdErr;\n\n    fn try_from(id: NonZeroU64) -> Result<Self, Self::Error> {\n        Ok(MessageId(id))\n    }\n}\n\nimpl From<MessageId> for NonZeroU64 {\n    fn from(mid: MessageId) -> NonZeroU64 {\n        mid.0\n    }\n}\n\nimpl From<MessageId> for u64 {\n    fn from(mid: MessageId) -> u64 {\n        mid.0.get()\n    }\n}\n\nimpl fmt::Debug for MessageId {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"#{:020}\", self.0)\n    }\n}\n\n/// Error when trying to build a [`MessageId`] from a raw id.\n#[derive(Debug)]\npub struct InvalidMessageIdErr;\n\nimpl fmt::Display for InvalidMessageIdErr {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"Invalid message ID\")\n    }\n}\n\n/// Hash of a module.\n#[derive(Clone, parity_scale_codec::Encode, parity_scale_codec::Decode, PartialEq, Eq, Hash)]\npub struct InterfaceHash([u8; 32]);\n\nimpl InterfaceHash {\n    /// Builds the [`InterfaceHash`] given the raw bytes.\n    pub const fn from_raw_hash(hash: [u8; 32]) -> Self {\n        InterfaceHash(hash)\n    }\n}\n\nimpl AsRef<[u8]> for InterfaceHash {\n    fn as_ref(&self) -> &[u8] {\n        &self.0\n    }\n}\n\nimpl From<InterfaceHash> for [u8; 32] {\n    fn from(interface: InterfaceHash) -> [u8; 32] {\n        interface.0\n    }\n}\n\nimpl From<[u8; 32]> for InterfaceHash {\n    fn from(hash: [u8; 32]) -> InterfaceHash {\n        InterfaceHash(hash)\n    }\n}\n\nimpl PartialEq<[u8; 32]> for InterfaceHash {\n    fn eq(&self, other: &[u8; 32]) -> bool {\n        self.0 == *other\n    }\n}\n\nimpl PartialEq<InterfaceHash> for [u8; 32] {\n    fn eq(&self, other: &InterfaceHash) -> bool {\n        *self == other.0\n    }\n}\n\nimpl fmt::Debug for InterfaceHash {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"InterfaceHash(0x\")?;\n        for byte in &self.0 {\n            write!(f, \"{:02x}\", *byte)?\n        }\n        write!(f, \")\")?;\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/syscalls/src/response.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::{ffi, Decode, EncodedMessage, MessageId};\n\nuse core::{\n    marker::PhantomData,\n    pin::Pin,\n    task::{Context, Poll},\n};\nuse futures::prelude::*;\n\n/// Waits until a response to the given message comes back.\n///\n/// Returns the undecoded response.\n// TODO: two futures for the same message will compete with each other; document that?\npub fn message_response_sync_raw(msg_id: MessageId) -> EncodedMessage {\n    let notification = crate::block_on::next_notification(&mut [msg_id.into()], true).unwrap();\n    ffi::decode_notification(&notification)\n        .unwrap()\n        .actual_data\n        .unwrap()\n        .into()\n}\n\n/// Returns a future that is ready when a response to the given message comes back.\n///\n/// The return value is the type the message decodes to.\npub fn message_response<T: Decode>(msg_id: MessageId) -> MessageResponseFuture<T> {\n    MessageResponseFuture {\n        finished: false,\n        msg_id,\n        registration: None,\n        marker: PhantomData,\n    }\n}\n\n// TODO: add a variant of message_response but for multiple messages\n\n/// Future that drives [`message_response`] to completion.\n///\n/// This future is \"atomic\", in the sense that destroying this future will not consume the message\n/// unless `Poll::Ready` has been returned. In other words, even if the response would have been\n/// ready to be delivered, destroying this future before the response has actually been delivered\n/// with `Poll::Ready` does not consume the response.\n#[must_use]\npub struct MessageResponseFuture<T> {\n    msg_id: MessageId,\n    finished: bool,\n    registration: Option<crate::block_on::WakerRegistration>,\n    marker: PhantomData<T>,\n}\n\nimpl<T> Future for MessageResponseFuture<T>\nwhere\n    T: Decode,\n{\n    type Output = T;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {\n        assert!(!self.finished);\n\n        if let Some(response) = crate::block_on::peek_response(self.msg_id) {\n            self.finished = true;\n            let decoded = ffi::decode_notification(&response).unwrap();\n            return Poll::Ready(Decode::decode(decoded.actual_data.unwrap().into()).unwrap());\n            // TODO: don't unwrap here?\n        }\n\n        if let Some(r) = &mut self.registration {\n            r.update(cx.waker());\n            return Poll::Pending;\n        }\n\n        // The first time `poll` is called, we normally register the message towards the `block_on`\n        // module. But before doing that, we do a peeking syscall to see if a response has already\n        // arrived. This makes it possible for code such as `future.now_or_never()` to work.\n        if let Some(notif) = crate::block_on::next_notification(&mut [self.msg_id.into()], false) {\n            let decoded = ffi::decode_notification(&notif).unwrap();\n            debug_assert_eq!(decoded.index_in_list, 0);\n            debug_assert_eq!(decoded.message_id, self.msg_id);\n\n            self.finished = true;\n            return Poll::Ready(Decode::decode(decoded.actual_data.unwrap().into()).unwrap());\n            // TODO: don't unwrap here?\n        }\n\n        self.registration = Some(crate::block_on::register_message_waker(\n            self.msg_id,\n            cx.waker().clone(),\n        ));\n        Poll::Pending\n    }\n}\n\nimpl<T> Unpin for MessageResponseFuture<T> {}\n"
  },
  {
    "path": "interface-wrappers/syscalls/src/traits.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse alloc::vec::Vec;\nuse core::fmt;\n\n/// Message already encoded.\n///\n/// The [`Encode`] and [`Decode`] trait implementations are no-op.\n// TODO: make field private\n#[derive(Clone, PartialEq, Eq)]\npub struct EncodedMessage(pub Vec<u8>);\n\n/// Objects that represent messages that can be serialized in order to be sent on an interface.\npub trait Encode {\n    /// Turn the object into bytes ready to be transmitted.\n    fn encode(self) -> EncodedMessage;\n}\n\n/// Objects that represent messages that can be unserialized.\npub trait Decode {\n    type Error: fmt::Debug;\n\n    /// Decode the raw data passed as parameter.\n    // TODO: consider EncodedMessageRef?\n    fn decode(buffer: EncodedMessage) -> Result<Self, Self::Error>\n    where\n        Self: Sized;\n}\n\nimpl EncodedMessage {\n    pub fn decode<T: Decode>(self) -> Result<T, T::Error> {\n        T::decode(self)\n    }\n}\n\nimpl Encode for EncodedMessage {\n    fn encode(self) -> EncodedMessage {\n        self\n    }\n}\n\nimpl<T> Encode for T\nwhere\n    T: parity_scale_codec::Encode,\n{\n    fn encode(self) -> EncodedMessage {\n        EncodedMessage(parity_scale_codec::Encode::encode(&self))\n    }\n}\n\nimpl Decode for EncodedMessage {\n    type Error = core::convert::Infallible; // TODO: `!`\n\n    fn decode(buffer: EncodedMessage) -> Result<Self, Self::Error> {\n        Ok(buffer)\n    }\n}\n\nimpl<T> Decode for T\nwhere\n    T: parity_scale_codec::DecodeAll,\n{\n    type Error = ();\n\n    fn decode(buffer: EncodedMessage) -> Result<Self, Self::Error> {\n        parity_scale_codec::DecodeAll::decode_all(&buffer.0).map_err(|_| ())\n    }\n}\n\nimpl<'a> From<EncodedMessageRef<'a>> for EncodedMessage {\n    fn from(msg: EncodedMessageRef<'a>) -> Self {\n        EncodedMessage(msg.0.into())\n    }\n}\n\nimpl AsRef<[u8]> for EncodedMessage {\n    fn as_ref(&self) -> &[u8] {\n        &self.0\n    }\n}\n\nimpl fmt::Debug for EncodedMessage {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        fmt::Debug::fmt(&self.0, f)\n    }\n}\n\n/// Reference to an [`EncodedMessage`].\n#[derive(Copy, Clone, PartialEq, Eq)]\npub struct EncodedMessageRef<'a>(&'a [u8]);\n\nimpl<'a> From<&'a [u8]> for EncodedMessageRef<'a> {\n    fn from(buf: &'a [u8]) -> EncodedMessageRef<'a> {\n        EncodedMessageRef(buf)\n    }\n}\n\nimpl<'a> AsRef<[u8]> for EncodedMessageRef<'a> {\n    fn as_ref(&self) -> &[u8] {\n        self.0\n    }\n}\n\nimpl<'a> From<&'a EncodedMessage> for EncodedMessageRef<'a> {\n    fn from(msg: &'a EncodedMessage) -> Self {\n        EncodedMessageRef(&msg.0)\n    }\n}\n\nimpl<'a> fmt::Debug for EncodedMessageRef<'a> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        fmt::Debug::fmt(&self.0, f)\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/system-time/Cargo.toml",
    "content": "[package]\nname = \"redshirt-system-time-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nfutures = { version = \"0.3.13\", default-features = false, features = [\"alloc\"] }\nredshirt-syscalls = { path = \"../syscalls\", default-features = false }\nparity-scale-codec = { version = \"1.3.6\", default-features = false, features = [\"derive\"] }\npin-project = \"1.0.5\"\n"
  },
  {
    "path": "interface-wrappers/system-time/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse parity_scale_codec::{Decode, Encode};\nuse redshirt_syscalls::InterfaceHash;\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0xc2, 0xf9, 0xf8, 0xc5, 0xd5, 0xcb, 0x84, 0xb5, 0xc5, 0xfe, 0x34, 0x1d, 0x21, 0xb2, 0xc3, 0x6f,\n    0xed, 0xfb, 0x86, 0xd1, 0xdb, 0xd6, 0x76, 0x41, 0x07, 0x02, 0x49, 0xeb, 0xfe, 0x1b, 0xa7, 0xc4,\n]);\n\n#[derive(Debug, Encode, Decode)]\npub enum TimeMessage {\n    /// Must respond with a `u128`.\n    GetSystem,\n}\n"
  },
  {
    "path": "interface-wrappers/system-time/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Time.\n\n#![no_std]\n\nextern crate alloc;\n\nuse futures::prelude::*;\n\npub mod ffi;\n\n/// Returns the number of nanoseconds since the Epoch (January 1st, 1970 at midnight UTC).\npub fn system_clock() -> impl Future<Output = u128> {\n    unsafe {\n        let msg = ffi::TimeMessage::GetSystem;\n        redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg).unwrap()\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/tcp/Cargo.toml",
    "content": "[package]\nname = \"redshirt-tcp-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nderive_more = \"0.99.11\"\nfutures = \"0.3.13\"\nredshirt-syscalls = { path = \"../syscalls\" }\nparity-scale-codec = { version = \"1.3.6\", features = [\"derive\"] }\ntokio = { version = \"1.2.0\", default-features = false }\n"
  },
  {
    "path": "interface-wrappers/tcp/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse parity_scale_codec::{Decode, Encode};\nuse redshirt_syscalls::InterfaceHash;\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0x10, 0x19, 0x16, 0x2a, 0x2b, 0x0c, 0x41, 0x36, 0x4a, 0x20, 0x01, 0x51, 0x47, 0x38, 0x27, 0x08,\n    0x4a, 0x3c, 0x1e, 0x07, 0x18, 0x1c, 0x27, 0x11, 0x55, 0x15, 0x1d, 0x5f, 0x22, 0x5b, 0x16, 0x20,\n]);\n\n#[derive(Debug, Encode, Decode)]\npub enum TcpMessage {\n    Open(TcpOpen),\n    /// Ask to close the socket. Replied with a [`TcpCloseResponse`].\n    Close(TcpClose),\n    /// Ask to read data from a socket. The response is a [`TcpReadResponse`].\n    Read(TcpRead),\n    /// Ask to write data to a socket. A response is sent back once written. For each socket, only\n    /// one write can exist at any given point in time.\n    Write(TcpWrite),\n    /// Destroy the given socket. Doesn't expect any response. The given socket ID will no longer\n    /// be valid, and any existing message be replied to with `InvalidSocket`.\n    Destroy(u32),\n}\n\n#[derive(Debug, Encode, Decode)]\npub struct TcpOpen {\n    /// If true, then `ip` and `port` designate a local IP and port that the socket must listen\n    /// on. A response will arrive when a remote connects to this IP and port.\n    ///\n    /// If false, then `ip` and `port` designate a remote IP and port that the socket will try to\n    /// connect to. A response will arrive when we successfully connect or fail to connect.\n    pub listen: bool,\n    /// IPv6 address.\n    pub ip: [u16; 8],\n    /// TCP port.\n    pub port: u16,\n}\n\n#[derive(Debug, Encode, Decode)]\npub struct TcpOpenResponse {\n    // TODO: proper error type\n    pub result: Result<TcpSocketOpen, ()>,\n}\n\n#[derive(Debug, Encode, Decode)]\npub struct TcpSocketOpen {\n    pub socket_id: u32,\n    pub local_ip: [u16; 8],\n    pub local_port: u16,\n    pub remote_ip: [u16; 8],\n    pub remote_port: u16,\n}\n\n#[derive(Debug, Encode, Decode)]\npub struct TcpClose {\n    pub socket_id: u32,\n}\n\n#[derive(Debug, Encode, Decode)]\npub struct TcpCloseResponse {\n    pub result: Result<(), TcpCloseError>,\n}\n\n#[derive(Debug, Encode, Decode, derive_more::Display)]\npub enum TcpCloseError {\n    /// We have already sent a FIN to the remote. It is invalid to send another one.\n    /// This happens if the connection is in the \"Fin wait\", \"Fin wait 2\", or \"Last ACK\" states.\n    FinAlreaySent,\n    /// Connection is in the \"Finished\" state.\n    ConnectionFinished,\n    /// The socket ID is invalid.\n    InvalidSocket,\n}\n\n#[derive(Debug, Encode, Decode)]\npub struct TcpRead {\n    pub socket_id: u32,\n}\n\n#[derive(Debug, Encode, Decode)]\npub struct TcpReadResponse {\n    /// If the connection is in the \"Closed\" wait or \"Last ACK\" state, it is known that no more\n    /// data will be received and an empty `Vec` is returned. If the connection is in the\n    /// \"Finished\" state, then [`TcpReadError::ConnectionFinished`] is returned.\n    pub result: Result<Vec<u8>, TcpReadError>,\n}\n\n#[derive(Debug, Encode, Decode, derive_more::Display)]\npub enum TcpReadError {\n    /// Connection is in the \"Finished\" state.\n    ConnectionFinished,\n    /// The socket ID is invalid.\n    InvalidSocket,\n}\n\n#[derive(Debug, Encode, Decode)]\npub struct TcpWrite {\n    pub socket_id: u32,\n    pub data: Vec<u8>,\n}\n\n#[derive(Debug, Encode, Decode)]\npub struct TcpWriteResponse {\n    pub result: Result<(), TcpWriteError>,\n}\n\n#[derive(Debug, Encode, Decode, derive_more::Display)]\npub enum TcpWriteError {\n    /// We have sent a FIN to the remote, and thus are not allowed to send any more data.\n    /// This happens if the connection is in the \"Fin wait\", \"Fin wait 2\", or \"Last ACK\" states.\n    FinAlreaySent,\n    /// Connection is in the \"Finished\" state.\n    ConnectionFinished,\n    /// The socket ID is invalid.\n    InvalidSocket,\n}\n"
  },
  {
    "path": "interface-wrappers/tcp/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! TCP/IP sockets.\n//!\n//! Allows opening asynchronous TCP sockets and listeners, similar to what the `tokio` or\n//! `async-std` libraries do.\n//!\n//! See [the Wikipedia page](https://en.wikipedia.org/wiki/TCP/IP) for an introduction to TCP/IP.\n//!\n//! # Socket state\n//!\n//! At any given time, a TCP socket is in one of the following states:\n//!\n//! - Connecting/Listening. The socket is performing the three-way handshake or, for listening\n//! sockets, is waiting for an incoming connection. From that state, a connection can transition\n//! to the Established state.\n//! - Established. The socket is connected and performing normal reads and writes.\n//! - Closed wait. The socket has received a FIN from the remote. In this state, it is guaranteed\n//! that reading from the socket will not produce any more data. Writing is still possible.\n//! Depending on the logic of the application, the local machine might be encouraged to close\n//! their side as soon as possible, or can continue writing data on the socket for a long period\n//! of time.\n//! - Fin wait. Our side has sent a FIN to the remote. This only happens if the application layer\n//! has requested so. Writing is no longer allowed. Reading is still allowed and might yield more\n//! data.\n//! - Fin wait 2. The remote has ACK'ed the FIN that we have sent to it. Only happens after\n//! the Fin wait state.\n//! - Last ACK. The socket has received a FIN from the remote, and we have sent a FIN to the remote\n//! as well, but the remote still has to ACK it.\n//! - Finished. Both sides have sent a FIN to each other. Writing is forbidden, and reading is\n//! guaranteed to no longer produce any data. The only sensible thing that can be done with the\n//! socket is to destroy it.\n//!\n//! +---------------+       +---------------+      +---------------+\n//! |  Connecting   |+----->|  Established  |+---->|  Closed wait  |\n//! +---------------+       +---------------+      +---------------+\n//!                                 | Close                | Close\n//!                                 v                      v\n//!                         +---------------+      +---------------+\n//!                         |   Fin wait    |+---->|   Last ACK    |\n//!                         +---------------+      +---------------+\n//!                                 |                      |\n//!                                 v                      v\n//!                         +---------------+      +---------------+\n//!                         |  Fin wait 2   |+---->|   Finished    |\n//!                         +---------------+      +---------------+\n//!\n//! Additionally, the connection can jump at any point to the \"Finished\" state without any prior\n//! warning, for example if a RST packet is received or if a protocol error is detected.\n//!\n//! > **Note**: The official denomination of the \"Finished\" state is \"CLOSED\", but we chose the\n//! >           word \"Finished\" to clear any confusion regarding the relationship with the action\n//! >           of sending a FIN packet.\n//!\n//! From the point of view of the user of this interface, all the state transitions happen\n//! automatically except for the transitions from \"Established\" to \"Fin wait\" and from \"Closed\n//! wait\" to \"Last ACK\", which happen when they request to close the socket.\n//!\n//! ## About listening sockets\n//!\n//! Contrary to Berkley sockets, there is no such thing as a listening socket that *accepts*\n//! incoming connections and produces other sockets.\n//!\n//! Instead, you are expected to create multiple listening sockets that all listen on the same\n//! port. When a remote tries to connect, one of these sockets transitions to the `Established`\n//! state and is now considered connected to that the remote.\n//!\n\nuse futures::{lock::Mutex, prelude::*, ready};\nuse redshirt_syscalls::{Encode as _, MessageResponseFuture};\nuse std::{\n    cmp, io, mem,\n    net::{IpAddr, Ipv6Addr, SocketAddr},\n    pin::Pin,\n    task::{Context, Poll},\n};\n\npub mod ffi;\n\n/// Active TCP connection to a remote.\n///\n/// This type is similar to [`std::net::TcpStream`].\npub struct TcpStream {\n    handle: u32,\n    /// Buffer of data that has been read from the socket but not transmitted to the user yet.\n    /// Contains `None` after the remote has sent us a FIN, meaning that we will not get any more\n    /// data.\n    read_buffer: Option<Vec<u8>>,\n    /// If Some, we have sent out a \"read\" message and are waiting for a response.\n    pending_read: Option<MessageResponseFuture<ffi::TcpReadResponse>>,\n    /// If Some, we have sent out a \"write\" message and are waiting for a response.\n    pending_write: Option<MessageResponseFuture<ffi::TcpWriteResponse>>,\n    /// If Some, we have sent out a \"close\" message and are waiting for a response.\n    pending_close: Option<MessageResponseFuture<ffi::TcpCloseResponse>>,\n}\n\n/// Active TCP listening socket.\n///\n/// This type is similar to [`std::net::TcpListener`].\npub struct TcpListener {\n    local_addr: SocketAddr,\n    next_incoming: Mutex<\n        stream::FuturesUnordered<\n            Pin<Box<dyn Future<Output = Result<(TcpStream, SocketAddr), ()>> + Send>>,\n        >,\n    >,\n}\n\nimpl TcpStream {\n    /// Start connecting to the given address. Returns a `TcpStream` if the connection is\n    /// successful. The returned `TcpStream` is in the \"Established\" state (but might quickly\n    /// transition to another state).\n    pub fn connect(socket_addr: &SocketAddr) -> impl Future<Output = Result<TcpStream, ()>> {\n        let fut = TcpStream::new(socket_addr, false);\n        async move { Ok(fut.await?.0) }\n    }\n\n    /// Dialing and listening use the same underlying messages. The only different being a boolean\n    /// indicating whether the address is a binding point or a destination.\n    fn new(\n        socket_addr: &SocketAddr,\n        listen: bool,\n    ) -> impl Future<Output = Result<(TcpStream, SocketAddr), ()>> {\n        let tcp_open = ffi::TcpMessage::Open(match socket_addr {\n            SocketAddr::V4(addr) => ffi::TcpOpen {\n                ip: addr.ip().to_ipv6_mapped().segments(),\n                port: addr.port(),\n                listen,\n            },\n            SocketAddr::V6(addr) => ffi::TcpOpen {\n                ip: addr.ip().segments(),\n                port: addr.port(),\n                listen,\n            },\n        });\n\n        // Send the opening message here, so that the socket starts connecting or listening to\n        // connections before we start polling the returned `Future`.\n        let open_future = unsafe {\n            let msg = tcp_open.encode();\n            redshirt_syscalls::MessageBuilder::new()\n                .add_data(&msg)\n                .emit_with_response(&ffi::INTERFACE)\n                .unwrap()\n        };\n\n        async move {\n            let message: ffi::TcpOpenResponse = open_future.await;\n\n            let socket_open_info = message.result?;\n            let remote_addr = {\n                let ip = Ipv6Addr::from(socket_open_info.remote_ip);\n                SocketAddr::new(IpAddr::from(ip), socket_open_info.remote_port)\n            };\n\n            let stream = TcpStream {\n                handle: socket_open_info.socket_id,\n                read_buffer: Some(Vec::new()),\n                pending_read: None,\n                pending_write: None,\n                pending_close: None,\n            };\n\n            Ok((stream, remote_addr))\n        }\n    }\n}\n\nimpl AsyncRead for TcpStream {\n    fn poll_read(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context,\n        buf: &mut [u8],\n    ) -> Poll<Result<usize, io::Error>> {\n        loop {\n            if let Some(pending_read) = self.pending_read.as_mut() {\n                self.read_buffer = match ready!(Future::poll(Pin::new(pending_read), cx)).result {\n                    Ok(d) if d.is_empty() => None,\n                    Ok(d) => Some(d),\n                    Err(ffi::TcpReadError::ConnectionFinished) => {\n                        return Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()))\n                    }\n                    Err(ffi::TcpReadError::InvalidSocket) => unreachable!(),\n                };\n                self.pending_read = None;\n            }\n\n            debug_assert!(self.pending_read.is_none());\n\n            let read_buffer = match self.read_buffer.as_mut() {\n                Some(b) => b,\n                // We have received a FIN. Returning EOF.\n                None => return Poll::Ready(Ok(0)),\n            };\n\n            if !read_buffer.is_empty() {\n                let to_copy = cmp::min(read_buffer.len(), buf.len());\n                let mut tmp = mem::replace(read_buffer, Vec::new());\n                *read_buffer = tmp.split_off(to_copy);\n                buf[..to_copy].copy_from_slice(&tmp);\n                return Poll::Ready(Ok(to_copy));\n            }\n\n            self.pending_read = {\n                let tcp_read = ffi::TcpMessage::Read(ffi::TcpRead {\n                    socket_id: self.handle,\n                });\n\n                let msg_id = unsafe {\n                    let msg = tcp_read.encode();\n                    redshirt_syscalls::MessageBuilder::new()\n                        .add_data(&msg)\n                        .emit_with_response_raw(&ffi::INTERFACE)\n                        .unwrap()\n                };\n\n                Some(redshirt_syscalls::message_response(msg_id))\n            };\n        }\n    }\n\n    // TODO: implement poll_read_vectored\n    // TODO: unsafe fn initializer(&self) -> Initializer { ... }\n}\n\nimpl AsyncWrite for TcpStream {\n    fn poll_write(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context,\n        buf: &[u8],\n    ) -> Poll<Result<usize, io::Error>> {\n        ready!(AsyncWrite::poll_flush(self.as_mut(), cx))?;\n        debug_assert!(self.pending_write.is_none());\n\n        // Perform the write, and store into `self.pending_write` a future to when we can start\n        // the next write.\n        self.pending_write = {\n            let tcp_write = ffi::TcpMessage::Write(ffi::TcpWrite {\n                socket_id: self.handle,\n                data: buf.to_vec(), // TODO: meh for cloning\n            });\n\n            let msg_id = unsafe {\n                let msg = tcp_write.encode(); // TODO: meh because we clone data a second time here\n                redshirt_syscalls::MessageBuilder::new()\n                    .add_data(&msg)\n                    .emit_with_response_raw(&ffi::INTERFACE)\n                    .unwrap()\n            };\n\n            Some(redshirt_syscalls::message_response(msg_id))\n        };\n\n        Poll::Ready(Ok(buf.len()))\n    }\n\n    // TODO: implement poll_write_vectored\n\n    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), io::Error>> {\n        // Try to finish the previous write, if any is in progress.\n        if let Some(pending_write) = self.pending_write.as_mut() {\n            let result = ready!(Future::poll(Pin::new(pending_write), cx)).result;\n            self.pending_write = None;\n            match result {\n                Ok(()) => Poll::Ready(Ok(())),\n                Err(ffi::TcpWriteError::FinAlreaySent) => {\n                    Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()))\n                }\n                Err(ffi::TcpWriteError::ConnectionFinished) => {\n                    Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()))\n                }\n                Err(ffi::TcpWriteError::InvalidSocket) => unreachable!(),\n            }\n        } else {\n            Poll::Ready(Ok(()))\n        }\n    }\n\n    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), io::Error>> {\n        // Try to finish the previous write, if any is in progress.\n        if let Some(pending_write) = self.pending_write.as_mut() {\n            let result = ready!(Future::poll(Pin::new(pending_write), cx)).result;\n            self.pending_write = None;\n            match result {\n                Ok(()) => {}\n                Err(ffi::TcpWriteError::FinAlreaySent) => return Poll::Ready(Ok(())),\n                Err(ffi::TcpWriteError::ConnectionFinished) => {\n                    return Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()))\n                }\n                Err(ffi::TcpWriteError::InvalidSocket) => unreachable!(),\n            }\n        }\n\n        debug_assert!(self.pending_write.is_none());\n\n        loop {\n            // Try to finish the previous close, if any is in progress.\n            if let Some(pending_close) = self.pending_close.as_mut() {\n                let result = ready!(Future::poll(Pin::new(pending_close), cx)).result;\n                self.pending_close = None;\n                match result {\n                    Ok(()) | Err(ffi::TcpCloseError::FinAlreaySent) => return Poll::Ready(Ok(())),\n                    Err(ffi::TcpCloseError::ConnectionFinished) => {\n                        return Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()))\n                    }\n                    Err(ffi::TcpCloseError::InvalidSocket) => unreachable!(),\n                }\n            }\n\n            debug_assert!(self.pending_close.is_none());\n\n            self.pending_close = {\n                let tcp_close = ffi::TcpMessage::Close(ffi::TcpClose {\n                    socket_id: self.handle,\n                });\n\n                let msg_id = unsafe {\n                    redshirt_syscalls::MessageBuilder::new()\n                        .add_data(&tcp_close.encode())\n                        .emit_with_response_raw(&ffi::INTERFACE)\n                        .unwrap()\n                };\n\n                Some(redshirt_syscalls::message_response(msg_id))\n            };\n        }\n    }\n}\n\nimpl tokio::io::AsyncRead for TcpStream {\n    fn poll_read(\n        self: Pin<&mut Self>,\n        cx: &mut Context,\n        buf: &mut tokio::io::ReadBuf<'_>,\n    ) -> Poll<Result<(), io::Error>> {\n        let result = AsyncRead::poll_read(self, cx, buf.initialize_unfilled());\n        if let Poll::Ready(Ok(n)) = result {\n            buf.advance(n);\n        }\n        result.map_ok(|_| ())\n    }\n}\n\nimpl tokio::io::AsyncWrite for TcpStream {\n    fn poll_write(\n        self: Pin<&mut Self>,\n        cx: &mut Context,\n        buf: &[u8],\n    ) -> Poll<Result<usize, io::Error>> {\n        AsyncWrite::poll_write(self, cx, buf)\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), io::Error>> {\n        AsyncWrite::poll_flush(self, cx)\n    }\n\n    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), io::Error>> {\n        AsyncWrite::poll_close(self, cx)\n    }\n}\n\nimpl Drop for TcpStream {\n    fn drop(&mut self) {\n        unsafe {\n            let destroy = ffi::TcpMessage::Destroy(self.handle);\n            let _ = redshirt_syscalls::emit_message_without_response(&ffi::INTERFACE, &destroy);\n        }\n    }\n}\n\nimpl TcpListener {\n    /// Create a new [`TcpListener`] listening on the given address and port.\n    pub fn bind(socket_addr: &SocketAddr) -> impl Future<Output = Result<TcpListener, ()>> {\n        let next_incoming = Mutex::new(\n            (0..10)\n                .map(|_| Box::pin(TcpStream::new(socket_addr, true)) as Pin<Box<_>>)\n                .collect(),\n        );\n\n        let socket_addr = socket_addr.clone();\n        async move {\n            Ok(TcpListener {\n                local_addr: socket_addr,\n                next_incoming,\n            })\n        }\n    }\n\n    /// Returns the local address of the listener. Useful to determine the port.\n    pub fn local_addr(&self) -> SocketAddr {\n        self.local_addr\n    }\n\n    /// Waits for a new incoming connection and returns it.\n    pub async fn accept(&self) -> (TcpStream, SocketAddr) {\n        let mut next_incoming = self.next_incoming.lock().await;\n\n        let (tcp_stream, remote_addr) = loop {\n            match next_incoming.next().await {\n                Some(Ok(v)) => break v,\n                Some(Err(_)) => continue,\n                None => unreachable!(),\n            }\n        };\n\n        next_incoming.push(Box::pin(TcpStream::new(&self.local_addr, true)));\n        (tcp_stream, remote_addr)\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/time/Cargo.toml",
    "content": "[package]\nname = \"redshirt-time-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nfutures = { version = \"0.3.13\", default-features = false, features = [\"alloc\"] }\nredshirt-syscalls = { path = \"../syscalls\", default-features = false }\nparity-scale-codec = { version = \"1.3.6\", default-features = false, features = [\"derive\"] }\npin-project = \"1.0.5\"\n"
  },
  {
    "path": "interface-wrappers/time/src/delay.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::{monotonic_wait_until, Instant};\nuse alloc::boxed::Box;\nuse core::{fmt, future::Future, pin::Pin, task::Context, task::Poll, time::Duration};\n\n/// Mimics the API of `futures_timer::Delay`.\npub struct Delay {\n    when: Instant,\n    inner: Pin<Box<dyn Future<Output = ()> + Send>>,\n}\n\nimpl Delay {\n    pub fn new(dur: Duration) -> Delay {\n        Delay::new_at(Instant::now() + dur)\n    }\n\n    pub fn new_at(at: Instant) -> Delay {\n        Delay {\n            when: at,\n            inner: Box::pin(monotonic_wait_until(at.inner)),\n        }\n    }\n\n    pub fn when(&self) -> Instant {\n        self.when\n    }\n\n    pub fn reset(&mut self, at: Instant) {\n        *self = Delay::new_at(at);\n    }\n}\n\nimpl fmt::Debug for Delay {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_struct(\"Delay\").field(\"when\", &self.when).finish()\n    }\n}\n\nimpl Future for Delay {\n    type Output = ();\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {\n        Future::poll(self.inner.as_mut(), cx)\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/time/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse parity_scale_codec::{Decode, Encode};\nuse redshirt_syscalls::InterfaceHash;\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0x19, 0x97, 0x70, 0x2f, 0x6f, 0xd9, 0x52, 0xcd, 0xb2, 0xc3, 0x75, 0x1c, 0x11, 0xb4, 0x95, 0x41,\n    0x81, 0xa6, 0x4f, 0x91, 0x67, 0x63, 0xb5, 0xb1, 0x8d, 0x31, 0xdf, 0xb1, 0x47, 0x03, 0xa6, 0xbf,\n]);\n\n#[derive(Debug, Encode, Decode)]\npub enum TimeMessage {\n    /// Must respond with a `u128`.\n    GetMonotonic,\n    /// Send response when the monotonic clock reaches this value. Responds with nothing (`()`).\n    WaitMonotonic(u128),\n}\n"
  },
  {
    "path": "interface-wrappers/time/src/instant.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::monotonic_clock;\nuse core::{convert::TryFrom, ops::Add, ops::Sub, time::Duration};\n\n/// Mimics the API of `std::time::Instant`, except that it works.\n///\n/// > **Note**: This struct should be removed in the future, as `std::time::Instant` should work\n/// >           when compiling to WASI.\n#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]\npub struct Instant {\n    pub(crate) inner: u128,\n}\n\nimpl Instant {\n    pub fn now() -> Instant {\n        let val = redshirt_syscalls::block_on(monotonic_clock());\n        Instant { inner: val }\n    }\n\n    pub fn duration_since(&self, earlier: Instant) -> Duration {\n        *self - earlier\n    }\n\n    pub fn elapsed(&self) -> Duration {\n        Instant::now() - *self\n    }\n}\n\nimpl Add<Duration> for Instant {\n    type Output = Instant;\n\n    fn add(self, other: Duration) -> Instant {\n        let new_val = self.inner + other.as_nanos();\n        Instant { inner: new_val }\n    }\n}\n\nimpl Sub<Duration> for Instant {\n    type Output = Instant;\n\n    fn sub(self, other: Duration) -> Instant {\n        let new_val = self.inner - other.as_nanos();\n        Instant { inner: new_val }\n    }\n}\n\nimpl Sub<Instant> for Instant {\n    type Output = Duration;\n\n    fn sub(self, other: Instant) -> Duration {\n        let ns = self.inner - other.inner;\n        // TODO: not great to unwrap, but we don't care\n        Duration::from_nanos(u64::try_from(ns).unwrap())\n    }\n}\n"
  },
  {
    "path": "interface-wrappers/time/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Time.\n\n#![no_std]\n\nextern crate alloc;\n\nuse core::time::Duration;\nuse futures::prelude::*;\n\npub use self::delay::Delay;\npub use self::instant::Instant;\n\nmod delay;\nmod instant;\n\npub mod ffi;\n\n/// Returns the number of nanoseconds since an arbitrary point in time in the past.\npub fn monotonic_clock() -> impl Future<Output = u128> {\n    unsafe {\n        let msg = ffi::TimeMessage::GetMonotonic;\n        redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg).unwrap()\n    }\n}\n\n/// Returns a `Future` that yields when the monotonic clock reaches this value.\npub fn monotonic_wait_until(until: u128) -> impl Future<Output = ()> {\n    unsafe {\n        let msg = ffi::TimeMessage::WaitMonotonic(until);\n        redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg).unwrap()\n    }\n}\n\n/// Returns a `Future` that outputs after `duration` has elapsed.\npub fn monotonic_wait(duration: Duration) -> impl Future<Output = ()> {\n    let dur_nanos = u128::from(duration.as_secs())\n        .saturating_mul(1_000_000_000)\n        .saturating_add(u128::from(duration.subsec_nanos()));\n\n    // TODO: meh for two syscalls\n    monotonic_clock().then(move |now| monotonic_wait_until(now.saturating_add(dur_nanos)))\n}\n"
  },
  {
    "path": "interface-wrappers/video-output/Cargo.toml",
    "content": "[package]\nname = \"redshirt-video-output-interface\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\nfutures = \"0.3.13\"\nredshirt-random-interface = { path = \"../random\" }\nredshirt-syscalls = { path = \"../syscalls\" }\nparity-scale-codec = { version = \"1.3.6\", features = [\"derive\"] }\n"
  },
  {
    "path": "interface-wrappers/video-output/src/ffi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse parity_scale_codec::{Decode, Encode};\nuse redshirt_syscalls::InterfaceHash;\n\n// TODO: this has been randomly generated; instead should be a hash or something\npub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([\n    0x87, 0x9d, 0xe0, 0xda, 0x61, 0x13, 0x26, 0x1d, 0x1f, 0x3e, 0xfa, 0x79, 0x4c, 0x9e, 0xa4, 0x67,\n    0xf2, 0x81, 0xe8, 0x00, 0x39, 0x5e, 0xbe, 0x94, 0x1e, 0x49, 0xb8, 0xf8, 0xd4, 0x3b, 0x07, 0xce,\n]);\n\n#[derive(Debug, Encode, Decode)]\npub enum VideoOutputMessage {\n    /// Notify of the existence of a new video output.\n    // TODO: what if this id was already registered?\n    Register {\n        /// Unique per-process identifier.\n        id: u64,\n        /// Width in pixels of the output.\n        width: u32,\n        /// Height in pixels of the output.\n        height: u32,\n        /// Expected format of the output.\n        format: Format,\n    },\n\n    /// Removes a previously-registered video output.\n    Unregister(u64),\n\n    /// Asks for the next image to present on this output. Must answer with a `NextImage`.\n    NextImage(u64),\n}\n\n#[derive(Debug, Encode, Decode, Clone)]\npub struct NextImage {\n    pub changes: Vec<NextImageChange>,\n}\n\n#[derive(Debug, Encode, Decode, Clone)]\npub struct NextImageChange {\n    pub screen_x_start: u32,\n    // TODO: not necessary?\n    pub screen_x_len: u32,\n    pub screen_y_start: u32,\n    /// Rows of pixels.\n    pub pixels: Vec<Vec<u8>>,\n}\n\n#[derive(Debug, Encode, Decode, Clone)]\npub enum Format {\n    R8G8B8X8,\n}\n"
  },
  {
    "path": "interface-wrappers/video-output/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Video output interface.\n//!\n//! This interface serves to register devices capable of presenting an image to the user. Usually\n//! a monitor.\n//!\n//! This interface is extremely naive at the moment. In the future, it should include:\n//!\n//! - Giving the list of supported video modes, and allowing changing the video mode of the output.\n//! - Generic graphics rendering. One would register graphics accelerators, connected to 0 or more\n//!   monitors.\n//! - Still registering devices in \"linear framebuffer mode\", for compatibility with VGA/VBE on PC,\n//!   or more primitive hardware on embedded devices.\n//!\n//! The main inspiration for designing \"graphics commands\" should be Vulkan and WebGPU.\n//!\n\npub mod ffi;\npub mod video_output;\n"
  },
  {
    "path": "interface-wrappers/video-output/src/video_output.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Registering video outputs.\n//!\n//! Use this if you're writing for example a video card driver.\n\nuse crate::ffi;\nuse core::fmt;\nuse futures::{lock::Mutex, prelude::*};\nuse redshirt_syscalls::Encode as _;\n\n/// Configuration of a video output to register.\n#[derive(Debug)]\npub struct VideoOutputConfig {\n    /// Width in pixels of the output.\n    pub width: u32,\n    /// Height in pixels of the output.\n    pub height: u32,\n    /// Format of the output.\n    pub format: ffi::Format,\n}\n\n/// Registers a new video output.\npub async fn register(config: VideoOutputConfig) -> VideoOutputRegistration {\n    unsafe {\n        let id = redshirt_random_interface::generate_u64().await;\n\n        redshirt_syscalls::emit_message_without_response(&ffi::INTERFACE, &{\n            ffi::VideoOutputMessage::Register {\n                id,\n                width: config.width,\n                height: config.height,\n                format: config.format,\n            }\n        })\n        .unwrap();\n\n        VideoOutputRegistration {\n            id,\n            frames: Mutex::new((0..10).map(|_| build_frame_future(id)).collect()),\n        }\n    }\n}\n\n/// Registered network interface.\n///\n/// Destroying this object will unregister the interface.\npub struct VideoOutputRegistration {\n    /// Identifier of the interface in the network manager.\n    id: u64,\n    /// Futures that resolve when we receive the next frame to draw.\n    frames: Mutex<stream::FuturesOrdered<redshirt_syscalls::MessageResponseFuture<ffi::NextImage>>>,\n}\n\n/// Build a `Future` resolving to the next frame to display.\nfn build_frame_future(id: u64) -> redshirt_syscalls::MessageResponseFuture<ffi::NextImage> {\n    unsafe {\n        let message = ffi::VideoOutputMessage::NextImage(id).encode();\n        let msg_id = redshirt_syscalls::MessageBuilder::new()\n            .add_data(&message)\n            .emit_with_response_raw(&ffi::INTERFACE)\n            .unwrap();\n        redshirt_syscalls::message_response(msg_id)\n    }\n}\n\nimpl VideoOutputRegistration {\n    /// Returns the next packet to send to the network.\n    ///\n    /// This function will pull and merge all the pending frames into one. Even if the code calling\n    /// this method lags behind, only one frame will be returned.\n    ///\n    /// > **Note**: It is possible to call this method multiple times on the same\n    /// >           [`VideoOutputRegistration`]. If that is done, no guarantee exists as to which\n    /// >           `Future` finishes first.\n    pub async fn next_frame(&self) -> ffi::NextImage {\n        let mut frames = self.frames.lock().await;\n\n        let mut out = frames.next().await.unwrap();\n        while let Some(next_frame) = frames.select_next_some().now_or_never() {\n            out.changes.extend(next_frame.changes);\n        }\n\n        while frames.len() < 10 {\n            frames.push(build_frame_future(self.id));\n        }\n\n        out\n    }\n}\n\nimpl fmt::Debug for VideoOutputRegistration {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"VideoOutputRegistration\")\n            .field(&self.id)\n            .finish()\n    }\n}\n\nimpl Drop for VideoOutputRegistration {\n    fn drop(&mut self) {\n        unsafe {\n            let message = ffi::VideoOutputMessage::Unregister(self.id);\n            redshirt_syscalls::emit_message_without_response(&ffi::INTERFACE, &message).unwrap();\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/core/Cargo.toml",
    "content": "[package]\nname = \"redshirt-core\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[features]\ndefault = []\nnightly = [\"redshirt-core-proc-macros/nightly\"]\n\n[dependencies]\natomic = \"0.5.0\"\nblake3 = { version = \"1.6.1\", default-features = false }\nbs58 = { version = \"0.4.0\", default-features = false, features = [\"alloc\"] }\ncrossbeam-queue = { version = \"0.3.1\", default-features = false, features = [\n    \"alloc\",\n] }\neither = { version = \"1.6.1\", default-features = false }\nfnv = { version = \"1.0.7\", default-features = false }\nfutures = { version = \"0.3.13\", default-features = false }\nhashbrown = { version = \"0.9.1\", default-features = false }\nitertools = { version = \"0.14.0\", default-features = false }\nnohash-hasher = { version = \"0.2.0\", default-features = false }\nredshirt-core-proc-macros = { path = \"../core-proc-macros\" }\nredshirt-interface-interface = { path = \"../../interface-wrappers/interface\", default-features = false }\nredshirt-kernel-debug-interface = { path = \"../../interface-wrappers/kernel-debug\", default-features = false }\nredshirt-loader-interface = { path = \"../../interface-wrappers/loader\", default-features = false }\nredshirt-log-interface = { path = \"../../interface-wrappers/log\", default-features = false }\nredshirt-random-interface = { path = \"../../interface-wrappers/random\", default-features = false }\nredshirt-syscalls = { path = \"../../interface-wrappers/syscalls\", default-features = false }\nredshirt-system-time-interface = { path = \"../../interface-wrappers/system-time\", default-features = false }\nredshirt-time-interface = { path = \"../../interface-wrappers/time\", default-features = false }\nrand = { version = \"0.8.3\", default-features = false }\nrand_chacha = { version = \"0.3.0\", default-features = false }\nrand_core = { version = \"0.6.0\", default-features = false }\nslab = { version = \"0.4.9\", default-features = false }\nsmallvec = { version = \"1.6.1\", default-features = false }\nspinning_top = \"0.3.0\"\nwasi = { git = \"https://github.com/bytecodealliance/wasi\", rev = \"45536ac956a6211e3cff047f36cf19d6da82fd95\", default-features = false } # TODO: dependabot cannot parse the versioning scheme (`0.10.0+wasi-snapshot-preview1`) of this crate on crates.io\nwasmi = { version = \"0.42.1\", default-features = false }\n\n[dev-dependencies]\ncriterion = \"0.3\"\nfutures = { version = \"0.3.13\", default-features = false, features = [\n    \"executor\",\n] }\ntiny-keccak = { version = \"2.0.2\", features = [\"keccak\"] }\n\n[[bench]]\nname = \"keccak\"\nharness = false\n"
  },
  {
    "path": "kernel/core/benches/keccak.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse criterion::{criterion_group, criterion_main, Criterion};\nuse redshirt_core::{extrinsics::wasi::WasiExtrinsics, Module, SystemBuilder, SystemRunOutcome};\n\nfn bench(c: &mut Criterion) {\n    /* Original code:\n    #![feature(alloc_error_handler)]\n    #![no_std]\n    #![no_main]\n\n    #[global_allocator]\n    static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;\n\n    #[cfg(not(any(test, doc, doctest)))]\n    #[panic_handler]\n    fn panic(_: &core::panic::PanicInfo) -> ! {\n        unsafe { core::hint::unreachable_unchecked() }\n    }\n\n    #[cfg(not(any(test, doc, doctest)))]\n    #[alloc_error_handler]\n    fn alloc_error_handler(_: core::alloc::Layout) -> ! {\n        panic!()\n    }\n\n    extern crate alloc;\n    use alloc::vec;\n    use futures::prelude::*;\n    use tiny_keccak::*;\n\n    #[no_mangle]\n    fn _start() {\n        let data = [254u8; 4096];\n\n        let mut res: [u8; 32] = [0; 32];\n        let mut keccak = tiny_keccak::Keccak::v256();\n        keccak.update(&data);\n        keccak.finalize(&mut res);\n\n        assert_ne!(res[0] as isize, 0);\n    }\n    */\n    let module = Module::from_bytes(&include_bytes!(\"keccak.wasm\")[..]).unwrap();\n\n    c.bench_function(\"keccak-wasm-4096-bytes\", |b| {\n        let system = SystemBuilder::<WasiExtrinsics>::new([0; 64])\n            .build()\n            .unwrap();\n        b.iter(|| {\n            system.execute(&module).unwrap();\n            futures::executor::block_on(async {\n                loop {\n                    match system.run().await {\n                        SystemRunOutcome::ProgramFinished { outcome, .. } => break outcome,\n                        _ => panic!(),\n                    }\n                }\n            })\n            .unwrap();\n        })\n    });\n\n    c.bench_function(\"keccak-native-4096-bytes\", |b| {\n        b.iter(|| {\n            use tiny_keccak::*;\n\n            let data = [254u8; 4096];\n\n            let mut res: [u8; 32] = [0; 32];\n            let mut keccak = tiny_keccak::Keccak::v256();\n            keccak.update(&data);\n            keccak.finalize(&mut res);\n\n            assert_ne!(res[0] as isize, 0);\n        })\n    });\n}\n\ncriterion_group!(benches, bench);\ncriterion_main!(benches);\n"
  },
  {
    "path": "kernel/core/src/extrinsics/log_calls.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Implementation of the [`Extrinsics`] trait that wraps around another implementation and sends\n//! all the calls to the `log` interface for debugging.\n\nuse crate::extrinsics::{Extrinsics, ExtrinsicsAction, ExtrinsicsMemoryAccess, SupportedExtrinsic};\nuse crate::{EncodedMessage, EncodedMessageRef, ThreadId, WasmValue};\n\nuse alloc::{borrow::Cow, format, string::String, vec, vec::Vec};\nuse core::mem;\n\n/// Implementation of the [`Extrinsics`] trait that logs all calls to the underlying handler.\n///\n/// Every time a call has finished, a message is sent to the `log` interface containing the\n/// parameters and return value.\n///\n/// This struct only has access to the low-level signatures of the functions it wraps around, and\n/// therefore cannot, for example, print the content of memory that the inner function reads from\n/// or writes to.\n#[derive(Debug)]\npub struct LogExtrinsics<TInner> {\n    /// Actual implementation.\n    inner: TInner,\n    /// Log level for the messages.\n    log_level: redshirt_log_interface::Level,\n}\n\nimpl<TInner> LogExtrinsics<TInner> {\n    /// Builds a new [`LogExtrinsics`].\n    pub fn new(inner: TInner) -> Self {\n        LogExtrinsics {\n            inner,\n            log_level: redshirt_log_interface::Level::Trace,\n        }\n    }\n}\n\nimpl<TInner> Default for LogExtrinsics<TInner>\nwhere\n    TInner: Default,\n{\n    fn default() -> Self {\n        Self::new(Default::default())\n    }\n}\n\n/// Identifier of an extrinsic.\n#[derive(Debug, Clone)]\npub struct ExtrinsicId<TInner> {\n    /// The function name prefixed with its module name.\n    f_name: String,\n    /// Actual identifier.\n    inner: TInner,\n}\n\n/// Context for a logging call.\npub struct Context<TInner> {\n    /// The inner context.\n    inner: TInner,\n\n    /// Start of the encoded log message. Only the return value is missing.\n    message_start: Vec<u8>,\n\n    /// If `Some`, the inner context has finished and we have sent a log message. When the\n    /// confirmation comes back, we send back the content in this `Option`.\n    waiting_for_log_message: Option<ExtrinsicsAction>,\n}\n\n/// Wraps around the inner iterator for supported extrinsics.\n#[derive(Debug, Copy, Clone)]\npub struct LogIterator<TInner>(TInner);\n\nimpl<TInner> Extrinsics for LogExtrinsics<TInner>\nwhere\n    TInner: Extrinsics,\n{\n    type ExtrinsicId = ExtrinsicId<TInner::ExtrinsicId>;\n    type Context = Context<TInner::Context>;\n    type Iterator = LogIterator<TInner::Iterator>;\n\n    fn supported_extrinsics() -> Self::Iterator {\n        LogIterator(TInner::supported_extrinsics())\n    }\n\n    fn new_context(\n        &self,\n        thread_id: ThreadId,\n        id: &Self::ExtrinsicId,\n        params: impl ExactSizeIterator<Item = WasmValue>,\n        mem_access: &mut impl ExtrinsicsMemoryAccess,\n    ) -> (Self::Context, ExtrinsicsAction) {\n        let params = params.collect::<Vec<_>>();\n\n        let message_start = {\n            let mut msg = vec![u8::from(self.log_level)];\n            msg.extend(id.f_name.as_bytes());\n            msg.extend(b\"(\");\n            for (n, param) in params.iter().enumerate() {\n                if n != 0 {\n                    msg.extend(b\", \");\n                }\n                msg.extend(format!(\"{:?}\", param).as_bytes());\n            }\n            msg.extend(b\") -> \");\n            msg\n        };\n\n        let (inner_ctxt, action) =\n            self.inner\n                .new_context(thread_id, &id.inner, params.into_iter(), mem_access);\n        let mut ctxt = Context {\n            inner: inner_ctxt,\n            message_start,\n            waiting_for_log_message: None,\n        };\n\n        let ret_value_str = match action {\n            ExtrinsicsAction::Resume(val) => {\n                ctxt.waiting_for_log_message = Some(ExtrinsicsAction::Resume(val));\n                Cow::Owned(format!(\"{:?}\", val).into_bytes())\n            }\n            a @ ExtrinsicsAction::ProgramCrash => {\n                ctxt.waiting_for_log_message = Some(a);\n                Cow::Borrowed(&b\"<crash>\"[..])\n            }\n            a @ ExtrinsicsAction::EmitMessage { .. } => return (ctxt, a),\n        };\n\n        let mut message = mem::replace(&mut ctxt.message_start, Vec::new());\n        message.extend(&ret_value_str[..]);\n\n        debug_assert!(ctxt.waiting_for_log_message.is_some());\n        let action = ExtrinsicsAction::EmitMessage {\n            interface: redshirt_log_interface::ffi::INTERFACE,\n            message: EncodedMessage(message),\n            response_expected: false,\n        };\n\n        (ctxt, action)\n    }\n\n    fn inject_message_response(\n        &self,\n        ctxt: &mut Self::Context,\n        response: Option<EncodedMessageRef>,\n        mem_access: &mut impl ExtrinsicsMemoryAccess,\n    ) -> ExtrinsicsAction {\n        if let Some(waiting_for_log_message) = ctxt.waiting_for_log_message.take() {\n            debug_assert!(response.is_none());\n            debug_assert!(ctxt.message_start.is_empty());\n            return waiting_for_log_message;\n        }\n\n        let ret_value_str =\n            match self\n                .inner\n                .inject_message_response(&mut ctxt.inner, response, mem_access)\n            {\n                ExtrinsicsAction::Resume(val) => {\n                    ctxt.waiting_for_log_message = Some(ExtrinsicsAction::Resume(val));\n                    Cow::Owned(format!(\"{:?}\", val).into_bytes())\n                }\n                a @ ExtrinsicsAction::ProgramCrash => {\n                    ctxt.waiting_for_log_message = Some(a);\n                    Cow::Borrowed(&b\"<crash>\"[..])\n                }\n                a @ ExtrinsicsAction::EmitMessage { .. } => return a,\n            };\n\n        let mut message = mem::replace(&mut ctxt.message_start, Vec::new());\n        message.extend(&ret_value_str[..]);\n\n        debug_assert!(ctxt.waiting_for_log_message.is_some());\n        ExtrinsicsAction::EmitMessage {\n            interface: redshirt_log_interface::ffi::INTERFACE,\n            message: EncodedMessage(message),\n            response_expected: false,\n        }\n    }\n}\n\nimpl<TInner, TExtId> Iterator for LogIterator<TInner>\nwhere\n    TInner: Iterator<Item = SupportedExtrinsic<TExtId>>,\n{\n    type Item = SupportedExtrinsic<ExtrinsicId<TExtId>>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        let item = self.0.next()?;\n\n        let id = ExtrinsicId {\n            f_name: format!(\"{}::{}\", item.wasm_interface, item.function_name),\n            inner: item.id,\n        };\n\n        Some(SupportedExtrinsic {\n            id,\n            wasm_interface: item.wasm_interface,\n            function_name: item.function_name,\n            signature: item.signature,\n        })\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.0.size_hint()\n    }\n}\n\nimpl<TInner, TExtId> ExactSizeIterator for LogIterator<TInner> where\n    TInner: ExactSizeIterator<Item = SupportedExtrinsic<TExtId>>\n{\n}\n"
  },
  {
    "path": "kernel/core/src/extrinsics/wasi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Implementation of the [`Extrinsics`] trait that supports WASI.\n\n// Reference for function signatures:\n// https://github.com/WebAssembly/wasi-libc/blob/e1149ab0677317c6c981bcbb5e4c159e4d2b9669/libc-bottom-half/headers/public/wasi/api.h\n\nuse crate::extrinsics::{Extrinsics, ExtrinsicsAction, ExtrinsicsMemoryAccess, SupportedExtrinsic};\nuse crate::{sig, Encode as _, EncodedMessage, EncodedMessageRef, ThreadId, WasmValue};\n\nuse alloc::{\n    borrow::Cow,\n    string::String,\n    sync::Arc,\n    vec,\n    vec::{IntoIter, Vec},\n};\nuse core::{cmp, convert::TryFrom as _, fmt};\nuse hashbrown::HashMap;\nuse spinning_top::Spinlock;\n\n/// Implementation of the [`Extrinsics`] trait for WASI.\n#[derive(Debug)]\npub struct WasiExtrinsics {\n    /// Arguments passed to the program.\n    args: Vec<Vec<u8>>,\n\n    /// Environment variables passed to the program.\n    env_vars: Vec<Vec<u8>>,\n\n    /// List of open file descriptors.\n    /// The integer representing the file descriptor is the index within that table. Since file\n    /// descriptors must not change value over time, we instead replace them with `None` when\n    /// closing.\n    file_descriptors: Spinlock<Vec<Option<FileDescriptor>>>,\n\n    /// Virtual file system accessible to the program.\n    file_system: Arc<Inode>,\n}\n\n#[derive(Debug)]\nenum FileDescriptor {\n    /// Valid file descriptor but that points to nothing.\n    Empty,\n    LogOut {\n        /// We buffer data and emit a log message only on line splits.\n        buffer: Vec<u8>,\n        level: redshirt_log_interface::Level,\n    },\n    FilesystemEntry {\n        inode: Arc<Inode>,\n        /// Position of the cursor within the file. Always 0 for directories.\n        file_cursor_pos: u64,\n    },\n}\n\n#[derive(Debug)]\nenum Inode {\n    Directory {\n        entries: Spinlock<HashMap<String, Arc<Inode>, fnv::FnvBuildHasher>>,\n    },\n    File {\n        content: Vec<u8>,\n    },\n}\n\nimpl Default for WasiExtrinsics {\n    fn default() -> WasiExtrinsics {\n        let fs_root = Arc::new(Inode::Directory {\n            entries: Spinlock::new({\n                let mut hashmap = HashMap::default();\n                /*// TODO: hack to toy with DOOM\n                hashmap.insert(\n                    \"doom1.wad\".to_string(),\n                    Arc::new(Inode::File {\n                        content: include_bytes!(\"../../../../DOOM/doom1.wad\").to_vec(),\n                    }),\n                );*/\n                hashmap\n            }),\n        });\n\n        WasiExtrinsics {\n            args: vec![b\"foo\".to_vec()], // TODO: \"foo\" is a dummy program name\n            env_vars: vec![b\"HOME=/home\".to_vec()], // TODO: dummy\n            file_descriptors: Spinlock::new(vec![\n                // stdin\n                Some(FileDescriptor::Empty),\n                // stdout\n                Some(FileDescriptor::LogOut {\n                    level: redshirt_log_interface::Level::Info,\n                    buffer: Vec::new(),\n                }),\n                // stderr\n                Some(FileDescriptor::LogOut {\n                    level: redshirt_log_interface::Level::Error,\n                    buffer: Vec::new(),\n                }),\n                // pre-opened access to filesystem\n                Some(FileDescriptor::FilesystemEntry {\n                    inode: fs_root.clone(),\n                    file_cursor_pos: 0,\n                }),\n            ]),\n            file_system: fs_root,\n        }\n    }\n}\n\n/// Identifier of a WASI extrinsic.\n#[derive(Debug, Clone)]\npub struct ExtrinsicId(ExtrinsicIdInner);\n\n#[derive(Debug, Clone)]\nenum ExtrinsicIdInner {\n    ArgsGet,\n    ArgsSizesGet,\n    ClockTimeGet,\n    EnvironGet,\n    EnvironSizesGet,\n    FdClose,\n    FdFdstatGet,\n    FdFdstatSetFlags,\n    FdFilestatGet,\n    FdPrestatDirName,\n    FdPrestatGet,\n    FdRead,\n    FdSeek,\n    FdTell,\n    FdWrite,\n    PathCreateDirectory,\n    PathFilestatGet,\n    PathOpen,\n    PollOneOff,\n    ProcExit,\n    RandomGet,\n    SchedYield,\n}\n\n/// Context for a call to a WASI external function.\npub struct Context(ContextInner);\n\nenum ContextInner {\n    WaitClockVal { out_ptr: u32 },\n    WaitRandom { out_ptr: u32, remaining_len: u32 },\n    TryFlushLogOut(usize),\n    Resume(Option<WasmValue>),\n    Finished,\n}\n\nimpl Extrinsics for WasiExtrinsics {\n    type ExtrinsicId = ExtrinsicId;\n    type Context = Context;\n    type Iterator = IntoIter<SupportedExtrinsic<Self::ExtrinsicId>>;\n\n    fn supported_extrinsics() -> Self::Iterator {\n        vec![\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::ArgsGet),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"args_get\"),\n                signature: sig!((I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::ArgsSizesGet),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"args_sizes_get\"),\n                signature: sig!((I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::ClockTimeGet),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"clock_time_get\"),\n                signature: sig!((I32, I64, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::EnvironGet),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"environ_get\"),\n                signature: sig!((I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::EnvironSizesGet),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"environ_sizes_get\"),\n                signature: sig!((I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::FdClose),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"fd_close\"),\n                signature: sig!((I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::FdFdstatGet),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"fd_fdstat_get\"),\n                signature: sig!((I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::FdFdstatSetFlags),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"fd_fdstat_set_flags\"),\n                signature: sig!((I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::FdFilestatGet),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"fd_filestat_get\"),\n                signature: sig!((I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::FdPrestatDirName),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"fd_prestat_dir_name\"),\n                signature: sig!((I32, I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::FdPrestatGet),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"fd_prestat_get\"),\n                signature: sig!((I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::FdRead),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"fd_read\"),\n                signature: sig!((I32, I32, I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::FdSeek),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"fd_seek\"),\n                signature: sig!((I32, I64, I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::FdTell),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"fd_tell\"),\n                signature: sig!((I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::FdWrite),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"fd_write\"),\n                signature: sig!((I32, I32, I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::PathCreateDirectory),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"path_create_directory\"),\n                signature: sig!((I32, I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::PathFilestatGet),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"path_filestat_get\"),\n                signature: sig!((I32, I32, I32, I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::PathOpen),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"path_open\"),\n                signature: sig!((I32, I32, I32, I32, I32, I64, I64, I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::PollOneOff),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"poll_oneoff\"),\n                signature: sig!((I32, I32, I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::ProcExit),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"proc_exit\"),\n                signature: sig!((I32)),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::RandomGet),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"random_get\"),\n                signature: sig!((I32, I32) -> I32),\n            },\n            SupportedExtrinsic {\n                id: ExtrinsicId(ExtrinsicIdInner::SchedYield),\n                wasm_interface: Cow::Borrowed(\"wasi_snapshot_preview1\"),\n                function_name: Cow::Borrowed(\"sched_yield\"),\n                signature: sig!(() -> I32),\n            },\n        ]\n        .into_iter()\n    }\n\n    fn new_context(\n        &self,\n        _: ThreadId,\n        id: &Self::ExtrinsicId,\n        params: impl ExactSizeIterator<Item = WasmValue>,\n        mem_access: &mut impl ExtrinsicsMemoryAccess,\n    ) -> (Self::Context, ExtrinsicsAction) {\n        // All these function calls have the same return type. They return an error if there is\n        // something fundamentally wrong in the system call (for example: a pointer to\n        // out-of-bounds memory) and we have to make the program crash.\n        let result = match id.0 {\n            ExtrinsicIdInner::ArgsGet => args_get(self, params, mem_access),\n            ExtrinsicIdInner::ArgsSizesGet => args_sizes_get(self, params, mem_access),\n            ExtrinsicIdInner::ClockTimeGet => clock_time_get(self, params, mem_access),\n            ExtrinsicIdInner::EnvironGet => environ_get(self, params, mem_access),\n            ExtrinsicIdInner::EnvironSizesGet => environ_sizes_get(self, params, mem_access),\n            ExtrinsicIdInner::FdClose => fd_close(self, params, mem_access),\n            ExtrinsicIdInner::FdFdstatGet => fd_fdstat_get(self, params, mem_access),\n            ExtrinsicIdInner::FdFdstatSetFlags => unimplemented!(),\n            ExtrinsicIdInner::FdFilestatGet => fd_filestat_get(self, params, mem_access),\n            ExtrinsicIdInner::FdPrestatDirName => fd_prestat_dir_name(self, params, mem_access),\n            ExtrinsicIdInner::FdPrestatGet => fd_prestat_get(self, params, mem_access),\n            ExtrinsicIdInner::FdRead => fd_read(self, params, mem_access),\n            ExtrinsicIdInner::FdSeek => fd_seek(self, params, mem_access),\n            ExtrinsicIdInner::FdTell => unimplemented!(),\n            ExtrinsicIdInner::FdWrite => fd_write(self, params, mem_access),\n            ExtrinsicIdInner::PathCreateDirectory => unimplemented!(),\n            ExtrinsicIdInner::PathFilestatGet => path_filestat_get(self, params, mem_access),\n            ExtrinsicIdInner::PathOpen => path_open(self, params, mem_access),\n            ExtrinsicIdInner::PollOneOff => poll_oneoff(self, params, mem_access),\n            ExtrinsicIdInner::ProcExit => proc_exit(self, params, mem_access),\n            ExtrinsicIdInner::RandomGet => random_get(self, params, mem_access),\n            ExtrinsicIdInner::SchedYield => sched_yield(self, params, mem_access),\n        };\n\n        match result {\n            Ok((context, action)) => (Context(context), action),\n            Err(WasiCallErr) => (\n                Context(ContextInner::Finished),\n                ExtrinsicsAction::ProgramCrash,\n            ),\n        }\n    }\n\n    fn inject_message_response(\n        &self,\n        ctxt: &mut Self::Context,\n        response: Option<EncodedMessageRef>,\n        mem_access: &mut impl ExtrinsicsMemoryAccess,\n    ) -> ExtrinsicsAction {\n        match ctxt.0 {\n            ContextInner::WaitClockVal { out_ptr } => {\n                let response = response.unwrap();\n                // TODO: extra copy\n                let value: u128 = match EncodedMessage::from(response).decode() {\n                    Ok(v) => v,\n                    Err(_) => return ExtrinsicsAction::ProgramCrash,\n                };\n\n                let converted_value: wasi::Timestamp =\n                    wasi::Timestamp::try_from(value % u128::from(wasi::Timestamp::max_value()))\n                        .unwrap();\n                mem_access\n                    .write_memory(out_ptr, &converted_value.to_le_bytes())\n                    .unwrap(); // TODO: don't unwrap\n\n                ctxt.0 = ContextInner::Finished;\n                ExtrinsicsAction::Resume(Some(WasmValue::I32(0)))\n            }\n            ContextInner::WaitRandom {\n                mut out_ptr,\n                mut remaining_len,\n            } => {\n                let response = response.unwrap();\n                // TODO: extra copy\n                let value: redshirt_random_interface::ffi::GenerateResponse =\n                    match EncodedMessage::from(response).decode() {\n                        Ok(v) => v,\n                        Err(_) => return ExtrinsicsAction::ProgramCrash,\n                    };\n\n                assert!(\n                    u32::try_from(value.result.len()).unwrap_or(u32::max_value()) <= remaining_len\n                );\n                mem_access.write_memory(out_ptr, &value.result).unwrap(); // TODO: don't unwrap\n\n                assert_ne!(value.result.len(), 0); // TODO: don't unwrap\n                out_ptr += u32::try_from(value.result.len()).unwrap();\n                remaining_len -= u32::try_from(value.result.len()).unwrap();\n\n                if remaining_len == 0 {\n                    ctxt.0 = ContextInner::Finished;\n                    ExtrinsicsAction::Resume(Some(WasmValue::I32(0)))\n                } else {\n                    let len_to_request = u16::try_from(remaining_len).unwrap_or(u16::max_value());\n                    debug_assert!(u32::from(len_to_request) <= remaining_len);\n\n                    ctxt.0 = ContextInner::WaitRandom {\n                        out_ptr,\n                        remaining_len,\n                    };\n\n                    ExtrinsicsAction::EmitMessage {\n                        interface: redshirt_random_interface::ffi::INTERFACE,\n                        message: redshirt_random_interface::ffi::RandomMessage::Generate {\n                            len: len_to_request,\n                        }\n                        .encode(),\n                        response_expected: true,\n                    }\n                }\n            }\n            ContextInner::TryFlushLogOut(fd) => {\n                let mut file_descriptors_lock = self.file_descriptors.lock();\n                let file_descriptor = {\n                    match file_descriptors_lock.get_mut(fd).and_then(|v| v.as_mut()) {\n                        Some(fd) => fd,\n                        None => {\n                            ctxt.0 = ContextInner::Finished;\n                            return ExtrinsicsAction::Resume(Some(WasmValue::I32(0)));\n                        }\n                    }\n                };\n\n                if let FileDescriptor::LogOut { level, buffer } = file_descriptor {\n                    if let Some(split_pos) = buffer.iter().position(|c| *c == b'\\n') {\n                        let mut encoded_message = Vec::new();\n                        encoded_message.push(u8::from(*level));\n                        encoded_message.extend(buffer.drain(..split_pos));\n                        buffer.remove(0);\n\n                        let action = ExtrinsicsAction::EmitMessage {\n                            interface: redshirt_log_interface::ffi::INTERFACE,\n                            message: EncodedMessage(encoded_message),\n                            response_expected: false,\n                        };\n\n                        ctxt.0 = ContextInner::TryFlushLogOut(fd);\n                        action\n                    } else {\n                        ctxt.0 = ContextInner::Finished;\n                        ExtrinsicsAction::Resume(Some(WasmValue::I32(0)))\n                    }\n                } else {\n                    ctxt.0 = ContextInner::Finished;\n                    ExtrinsicsAction::Resume(Some(WasmValue::I32(0)))\n                }\n            }\n            ContextInner::Resume(value) => {\n                ctxt.0 = ContextInner::Finished;\n                ExtrinsicsAction::Resume(value)\n            }\n            ContextInner::Finished => unreachable!(),\n        }\n    }\n}\n\n// Implementations of WASI function calls below.\n//\n// # About unwrapping and panics\n//\n// It is allowed and encouraged to panic in case of an anomaly in the number or the types of\n// arguments. This is because function signatures have normally been verified before the call is\n// made.\n//\n// Any other error condition, including for example converting `i32` parameters to `u32`, should\n// be handled by not panicking.\n\n/// Dummy error type that \"absorbs\" all possible error types.\nstruct WasiCallErr;\nimpl<T: fmt::Debug> From<T> for WasiCallErr {\n    fn from(_: T) -> Self {\n        WasiCallErr\n    }\n}\n\nfn args_get(\n    state: &WasiExtrinsics,\n    params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    args_or_env_get(&state.args, params, mem_access)\n}\n\nfn args_sizes_get(\n    state: &WasiExtrinsics,\n    params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    args_or_env_sizes_get(&state.args, params, mem_access)\n}\n\nfn clock_time_get(\n    _: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    _: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let clock_id = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    let _precision = params.next().unwrap().into_i64().unwrap();\n\n    let time_out = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    assert!(params.next().is_none());\n\n    match clock_id {\n        wasi::CLOCKID_REALTIME => {\n            let action = ExtrinsicsAction::EmitMessage {\n                interface: redshirt_system_time_interface::ffi::INTERFACE,\n                message: redshirt_system_time_interface::ffi::TimeMessage::GetSystem.encode(),\n                response_expected: true,\n            };\n\n            let context = ContextInner::WaitClockVal { out_ptr: time_out };\n            Ok((context, action))\n        }\n        wasi::CLOCKID_MONOTONIC => {\n            let action = ExtrinsicsAction::EmitMessage {\n                interface: redshirt_time_interface::ffi::INTERFACE,\n                message: redshirt_time_interface::ffi::TimeMessage::GetMonotonic.encode(),\n                response_expected: true,\n            };\n\n            let context = ContextInner::WaitClockVal { out_ptr: time_out };\n            Ok((context, action))\n        }\n        wasi::CLOCKID_PROCESS_CPUTIME_ID => unimplemented!(), // TODO:\n        wasi::CLOCKID_THREAD_CPUTIME_ID => unimplemented!(),  // TODO:\n        _ => Err(WasiCallErr),\n    }\n}\n\nfn environ_get(\n    state: &WasiExtrinsics,\n    params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    args_or_env_get(&state.env_vars, params, mem_access)\n}\n\nfn environ_sizes_get(\n    state: &WasiExtrinsics,\n    params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    args_or_env_sizes_get(&state.env_vars, params, mem_access)\n}\n\nfn fd_close(\n    state: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    _: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let mut file_descriptors_lock = state.file_descriptors.lock();\n\n    let fd = usize::try_from(params.next().unwrap().into_i32().unwrap())?;\n    assert!(params.next().is_none());\n\n    // Check validity of the file descriptor.\n    if file_descriptors_lock\n        .get(fd)\n        .map(|f| f.is_none())\n        .unwrap_or(true)\n    {\n        let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n        let action = ExtrinsicsAction::Resume(ret);\n        return Ok((ContextInner::Finished, action));\n    }\n\n    file_descriptors_lock[fd] = None;\n\n    // Clean up the tail of `file_descriptors_lock`.\n    while file_descriptors_lock\n        .last()\n        .map(|f| f.is_none())\n        .unwrap_or(false)\n    {\n        file_descriptors_lock.pop();\n    }\n    file_descriptors_lock.shrink_to_fit();\n\n    let action = ExtrinsicsAction::Resume(Some(WasmValue::I32(0)));\n    Ok((ContextInner::Finished, action))\n}\n\nfn fd_fdstat_get(\n    state: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let file_descriptors_lock = state.file_descriptors.lock();\n\n    // Find out which file descriptor the user wants to write to.\n    let file_descriptor = {\n        let fd = usize::try_from(params.next().unwrap().into_i32().unwrap())?;\n        match file_descriptors_lock.get(fd).and_then(|v| v.as_ref()) {\n            Some(fd) => fd,\n            None => {\n                let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n                let action = ExtrinsicsAction::Resume(ret);\n                return Ok((ContextInner::Finished, action));\n            }\n        }\n    };\n\n    // TODO: we mimic what wasmtime does, but documentation about these rights is pretty sparse\n    let dirs_rights = wasi::RIGHTS_FD_FDSTAT_SET_FLAGS\n        | wasi::RIGHTS_FD_SYNC\n        | wasi::RIGHTS_FD_ADVISE\n        | wasi::RIGHTS_PATH_CREATE_DIRECTORY\n        | wasi::RIGHTS_PATH_CREATE_FILE\n        | wasi::RIGHTS_PATH_LINK_SOURCE\n        | wasi::RIGHTS_PATH_LINK_TARGET\n        | wasi::RIGHTS_PATH_OPEN\n        | wasi::RIGHTS_FD_READDIR\n        | wasi::RIGHTS_PATH_READLINK\n        | wasi::RIGHTS_PATH_RENAME_SOURCE\n        | wasi::RIGHTS_PATH_RENAME_TARGET\n        | wasi::RIGHTS_PATH_FILESTAT_GET\n        | wasi::RIGHTS_PATH_FILESTAT_SET_SIZE\n        | wasi::RIGHTS_PATH_FILESTAT_SET_TIMES\n        | wasi::RIGHTS_FD_FILESTAT_GET\n        | wasi::RIGHTS_FD_FILESTAT_SET_SIZE\n        | wasi::RIGHTS_FD_FILESTAT_SET_TIMES\n        | wasi::RIGHTS_PATH_SYMLINK\n        | wasi::RIGHTS_PATH_REMOVE_DIRECTORY\n        | wasi::RIGHTS_PATH_UNLINK_FILE\n        | wasi::RIGHTS_POLL_FD_READWRITE;\n    let files_rights = wasi::RIGHTS_FD_DATASYNC\n        | wasi::RIGHTS_FD_READ\n        | wasi::RIGHTS_FD_SEEK\n        | wasi::RIGHTS_FD_FDSTAT_SET_FLAGS\n        | wasi::RIGHTS_FD_SYNC\n        | wasi::RIGHTS_FD_TELL\n        | wasi::RIGHTS_FD_WRITE\n        | wasi::RIGHTS_FD_ADVISE\n        | wasi::RIGHTS_FD_ALLOCATE\n        | wasi::RIGHTS_FD_FILESTAT_GET\n        | wasi::RIGHTS_FD_FILESTAT_SET_SIZE\n        | wasi::RIGHTS_FD_FILESTAT_SET_TIMES\n        | wasi::RIGHTS_POLL_FD_READWRITE;\n\n    let stat = match file_descriptor {\n        FileDescriptor::Empty => wasi::Fdstat {\n            fs_filetype: wasi::FILETYPE_CHARACTER_DEVICE,\n            fs_flags: 0,\n            fs_rights_base: 0,\n            fs_rights_inheriting: 0,\n        },\n        FileDescriptor::LogOut { .. } => wasi::Fdstat {\n            fs_filetype: wasi::FILETYPE_CHARACTER_DEVICE,\n            fs_flags: wasi::FDFLAGS_APPEND,\n            fs_rights_base: 0x0820_004a, // TODO: that's what wasmtime returns, don't know what it means\n            fs_rights_inheriting: 0x0820_004a, // TODO: that's what wasmtime returns, don't know what it means\n        },\n        FileDescriptor::FilesystemEntry { inode, .. } => match **inode {\n            Inode::Directory { .. } => wasi::Fdstat {\n                fs_filetype: wasi::FILETYPE_DIRECTORY,\n                fs_flags: 0,\n                fs_rights_base: dirs_rights,\n                fs_rights_inheriting: files_rights | dirs_rights,\n            },\n            Inode::File { .. } => wasi::Fdstat {\n                fs_filetype: wasi::FILETYPE_REGULAR_FILE,\n                fs_flags: 0,\n                fs_rights_base: files_rights,\n                fs_rights_inheriting: files_rights,\n            },\n        },\n    };\n\n    let stat_out_buf = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    assert!(params.next().is_none());\n\n    // Note: this is a bit of dark magic, but it is the only solution at the moment.\n    // Can be tested with the following snippet:\n    // ```c\n    // #include <stdio.h>\n    // #include <wasi/api.h>\n    // int main() {\n    //     __wasi_fdstat_t* ptr = (__wasi_fdstat_t*)0x1000;\n    //     printf(\"%p %p %p %p %p %d\\n\", ptr, &ptr->fs_filetype, &ptr->fs_flags, &ptr->fs_rights_base, &ptr->fs_rights_inheriting, sizeof(__wasi_fdstat_t));\n    //     return 0;\n    // }\n    // ```\n    // Which prints `0x1000 0x1000 0x1002 0x1008 0x1010 24`\n    mem_access.write_memory(stat_out_buf, &[0; 24])?;\n    mem_access.write_memory(stat_out_buf, &[stat.fs_filetype])?;\n    mem_access.write_memory(\n        stat_out_buf.checked_add(2).ok_or(WasiCallErr)?,\n        &stat.fs_flags.to_le_bytes(),\n    )?;\n    mem_access.write_memory(\n        stat_out_buf.checked_add(8).ok_or(WasiCallErr)?,\n        &stat.fs_rights_base.to_le_bytes(),\n    )?;\n    mem_access.write_memory(\n        stat_out_buf.checked_add(16).ok_or(WasiCallErr)?,\n        &stat.fs_rights_inheriting.to_le_bytes(),\n    )?;\n\n    let action = ExtrinsicsAction::Resume(Some(WasmValue::I32(0)));\n    Ok((ContextInner::Finished, action))\n}\n\nfn fd_filestat_get(\n    state: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    _mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let file_descriptors_lock = state.file_descriptors.lock();\n\n    // Find out which file descriptor the user wants to write to.\n    let file_descriptor = {\n        let fd = usize::try_from(params.next().unwrap().into_i32().unwrap())?;\n        match file_descriptors_lock.get(fd).and_then(|v| v.as_ref()) {\n            Some(fd) => fd,\n            None => {\n                let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n                let action = ExtrinsicsAction::Resume(ret);\n                return Ok((ContextInner::Finished, action));\n            }\n        }\n    };\n\n    let _stat_out_buf = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    assert!(params.next().is_none());\n\n    unimplemented!();\n}\n\nfn fd_prestat_dir_name(\n    state: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let file_descriptors_lock = state.file_descriptors.lock();\n\n    // Find out which file descriptor the user wants to write to.\n    let file_descriptor = {\n        let fd = usize::try_from(params.next().unwrap().into_i32().unwrap())?;\n        match file_descriptors_lock.get(fd).and_then(|v| v.as_ref()) {\n            Some(fd) => fd,\n            None => {\n                let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n                let action = ExtrinsicsAction::Resume(ret);\n                return Ok((ContextInner::Finished, action));\n            }\n        }\n    };\n\n    let name = match file_descriptor {\n        FileDescriptor::Empty | FileDescriptor::LogOut { .. } => {\n            // TODO: is that the correct return type?\n            let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n            let action = ExtrinsicsAction::Resume(ret);\n            return Ok((ContextInner::Finished, action));\n        }\n        // TODO: correct name; note that no null terminator is needed\n        // note that apparently any value other than an empty string will fail to match relative paths? it's weird\n        // cc https://github.com/CraneStation/wasi-libc/blob/9efc2f428358564fe64c374d762d0bfce1d92507/libc-bottom-half/libpreopen/libpreopen.c#L470\n        FileDescriptor::FilesystemEntry { .. } => b\"\",\n    };\n\n    let path_out = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    let path_out_len =\n        usize::try_from(params.next().unwrap().into_i32().unwrap()).unwrap_or(usize::max_value());\n    assert!(params.next().is_none());\n\n    // TODO: is it correct to truncate if the buffer is too small?\n    let to_write = cmp::min(path_out_len, name.len());\n    mem_access.write_memory(path_out, &name[..to_write])?;\n\n    let action = ExtrinsicsAction::Resume(Some(WasmValue::I32(0)));\n    Ok((ContextInner::Finished, action))\n}\n\nfn fd_prestat_get(\n    state: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let file_descriptors_lock = state.file_descriptors.lock();\n\n    // Find out which file descriptor the user wants to write to.\n    let file_descriptor = {\n        let fd = usize::try_from(params.next().unwrap().into_i32().unwrap())?;\n        match file_descriptors_lock.get(fd).and_then(|v| v.as_ref()) {\n            Some(fd) => fd,\n            None => {\n                let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n                let action = ExtrinsicsAction::Resume(ret);\n                return Ok((ContextInner::Finished, action));\n            }\n        }\n    };\n\n    let pr_name_len: u32 = match file_descriptor {\n        FileDescriptor::Empty | FileDescriptor::LogOut { .. } => {\n            let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_NOTSUP)));\n            let action = ExtrinsicsAction::Resume(ret);\n            return Ok((ContextInner::Finished, action));\n        }\n        FileDescriptor::FilesystemEntry { inode, .. } => match **inode {\n            // TODO: we don't know for sure that it's been pre-open\n            Inode::Directory { .. } => 0, // TODO: must match the length of the return value of `fd_prestat_dir_name`\n            Inode::File { .. } => {\n                // TODO: is that the correct return type?\n                let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_NOTSUP)));\n                let action = ExtrinsicsAction::Resume(ret);\n                return Ok((ContextInner::Finished, action));\n            }\n        },\n    };\n\n    let prestat_out_buf = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    assert!(params.next().is_none());\n\n    // Note: this is a bit of dark magic, but it is the only solution at the moment.\n    // Can be tested with the following snippet:\n    // ```c\n    // #include <stdio.h>\n    // #include <wasi/api.h>\n    // int main() {\n    //     __wasi_prestat_t* ptr = (__wasi_prestat_t*)0x1000;\n    //     printf(\"%p %p %p %d\\n\", ptr, &ptr->tag, &ptr->u.dir, sizeof(__wasi_prestat_t));\n    //     return 0;\n    // }\n    // ```\n    // Which prints `0x1000 0x1000 0x1004 8`\n    mem_access.write_memory(prestat_out_buf, &[0; 8])?;\n    mem_access.write_memory(prestat_out_buf, &[wasi::PREOPENTYPE_DIR])?;\n    mem_access.write_memory(\n        prestat_out_buf.checked_add(4).ok_or(WasiCallErr)?,\n        &pr_name_len.to_le_bytes(),\n    )?;\n\n    let action = ExtrinsicsAction::Resume(Some(WasmValue::I32(0)));\n    Ok((ContextInner::Finished, action))\n}\n\nfn fd_read(\n    state: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let mut file_descriptors_lock = state.file_descriptors.lock();\n\n    // Find out which file descriptor the user wants to read from.\n    let mut file_descriptor = {\n        let fd = usize::try_from(params.next().unwrap().into_i32().unwrap())?;\n        match file_descriptors_lock.get_mut(fd).and_then(|v| v.as_mut()) {\n            Some(fd) => fd,\n            None => {\n                let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n                let action = ExtrinsicsAction::Resume(ret);\n                return Ok((ContextInner::Finished, action));\n            }\n        }\n    };\n\n    // Get a list of pointers and lengths to read to.\n    // Elements 0, 2, 4, 6, ... in that list are pointers, and elements 1, 3, 5, 7, ... are\n    // lengths.\n    let out_buffers_list = {\n        let addr = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n        let num = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n        let list_buf = mem_access.read_memory(addr..addr + 4 * num * 2)?;\n        // TODO: don't panic if allocation size is too large\n        let mut list_out = Vec::with_capacity(usize::try_from(num)?);\n        for elem in list_buf.chunks(4) {\n            list_out.push(u32::from_le_bytes(<[u8; 4]>::try_from(elem).unwrap()));\n        }\n        list_out\n    };\n\n    let total_read: u32 = match &mut file_descriptor {\n        FileDescriptor::Empty | FileDescriptor::LogOut { .. } => 0,\n        FileDescriptor::FilesystemEntry {\n            inode,\n            file_cursor_pos,\n        } => {\n            match &**inode {\n                Inode::Directory { .. } => {\n                    // TODO: is that the correct error?\n                    let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n                    let action = ExtrinsicsAction::Resume(ret);\n                    return Ok((ContextInner::Finished, action));\n                }\n                Inode::File { content, .. } => {\n                    let mut total_read = 0;\n                    for buffer in out_buffers_list.chunks(2) {\n                        let buffer_ptr = buffer[0];\n                        let buffer_len = usize::try_from(buffer[1])?;\n                        // The cursor position cannot go past `content.len()`, and thus always\n                        // fits in a `usize`.\n                        let file_cursor_pos_usize = usize::try_from(*file_cursor_pos).unwrap();\n                        debug_assert!(file_cursor_pos_usize <= content.len());\n                        let to_copy = cmp::min(content.len() - file_cursor_pos_usize, buffer_len);\n                        if to_copy == 0 {\n                            break;\n                        }\n                        mem_access.write_memory(\n                            buffer_ptr,\n                            &content[file_cursor_pos_usize..file_cursor_pos_usize + to_copy],\n                        )?;\n                        *file_cursor_pos = file_cursor_pos\n                            .checked_add(u64::try_from(to_copy)?)\n                            .ok_or(WasiCallErr)?;\n                        debug_assert!(\n                            *file_cursor_pos\n                                <= u64::try_from(content.len()).unwrap_or(u64::max_value())\n                        );\n                        total_read += to_copy;\n                    }\n                    u32::try_from(total_read)?\n                }\n            }\n        }\n    };\n\n    // Write to the last parameter the number of bytes that have been read in total.\n    let out_ptr = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    assert!(params.next().is_none());\n    mem_access.write_memory(out_ptr, &total_read.to_le_bytes())?;\n\n    let action = ExtrinsicsAction::Resume(Some(WasmValue::I32(0)));\n    Ok((ContextInner::Finished, action))\n}\n\nfn fd_seek(\n    state: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let mut file_descriptors_lock = state.file_descriptors.lock();\n\n    // Find out which file descriptor the user wants to seek.\n    let mut file_descriptor = {\n        let fd = usize::try_from(params.next().unwrap().into_i32().unwrap())?;\n        match file_descriptors_lock.get_mut(fd).and_then(|v| v.as_mut()) {\n            Some(fd) => fd,\n            None => {\n                let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n                let action = ExtrinsicsAction::Resume(ret);\n                return Ok((ContextInner::Finished, action));\n            }\n        }\n    };\n\n    let offset: i64 = params.next().unwrap().into_i64().unwrap();\n    let whence = u8::try_from(params.next().unwrap().into_i32().unwrap())?;\n\n    let new_offset: u64 = match &mut file_descriptor {\n        FileDescriptor::Empty | FileDescriptor::LogOut { .. } => {\n            // TODO: is that the correct error?\n            let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n            let action = ExtrinsicsAction::Resume(ret);\n            return Ok((ContextInner::Finished, action));\n        }\n        FileDescriptor::FilesystemEntry {\n            inode,\n            file_cursor_pos,\n        } => {\n            match &**inode {\n                Inode::Directory { .. } => {\n                    // TODO: is that the correct error?\n                    let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n                    let action = ExtrinsicsAction::Resume(ret);\n                    return Ok((ContextInner::Finished, action));\n                }\n                Inode::File { content, .. } => {\n                    let max_offset = u64::try_from(content.len())?;\n                    // TODO: do that properly\n                    let new_offset = match whence {\n                        wasi::WHENCE_SET => {\n                            cmp::min(u64::try_from(cmp::max(offset, 0))?, max_offset)\n                        }\n                        wasi::WHENCE_CUR => {\n                            cmp::min(file_cursor_pos.saturating_add(offset as u64), max_offset)\n                        }\n                        wasi::WHENCE_END => cmp::min(\n                            u64::try_from(cmp::max(0, max_offset as i64 + offset))?,\n                            max_offset,\n                        ),\n                        _ => panic!(), // TODO: no\n                    };\n                    *file_cursor_pos = new_offset;\n                    new_offset\n                }\n            }\n        }\n    };\n\n    // Write to the last parameter the new offset.\n    let out_ptr = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    assert!(params.next().is_none());\n    mem_access.write_memory(out_ptr, &new_offset.to_le_bytes())?;\n\n    let action = ExtrinsicsAction::Resume(Some(WasmValue::I32(0)));\n    Ok((ContextInner::Finished, action))\n}\n\nfn fd_write(\n    state: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let mut file_descriptors_lock = state.file_descriptors.lock();\n\n    // Find out which file descriptor the user wants to write to.\n    let fd = usize::try_from(params.next().unwrap().into_i32().unwrap())?;\n    let file_descriptor = {\n        match file_descriptors_lock.get_mut(fd).and_then(|v| v.as_mut()) {\n            Some(fd) => fd,\n            None => {\n                let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n                let action = ExtrinsicsAction::Resume(ret);\n                return Ok((ContextInner::Finished, action));\n            }\n        }\n    };\n\n    // Get a list of pointers and lengths to write.\n    // Elements 0, 2, 4, 6, ... in that list are pointers, and elements 1, 3, 5, 7, ... are\n    // lengths.\n    let list_to_write = {\n        let addr = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n        let num = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n        let list_buf = mem_access.read_memory(addr..addr + 4 * num * 2)?;\n        // TODO: don't panic if allocation size is too large\n        let mut list_out = Vec::with_capacity(usize::try_from(num)?);\n        for elem in list_buf.chunks(4) {\n            list_out.push(u32::from_le_bytes(<[u8; 4]>::try_from(elem).unwrap()));\n        }\n        list_out\n    };\n\n    match file_descriptor {\n        FileDescriptor::Empty => {\n            // TODO: is that the right error code?\n            let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_NOSYS)));\n            let action = ExtrinsicsAction::Resume(ret);\n            Ok((ContextInner::Finished, action))\n        }\n        FileDescriptor::LogOut { level, buffer } => {\n            let mut total_written = 0usize;\n            for ptr_and_len in list_to_write.chunks(2) {\n                let ptr = ptr_and_len[0];\n                let len = ptr_and_len[1];\n\n                buffer.extend(mem_access.read_memory(ptr..ptr + len)?);\n                total_written = total_written\n                    .checked_add(usize::try_from(len)?)\n                    .ok_or(WasiCallErr)?;\n            }\n\n            // Write to the fourth parameter the number of bytes written to the file descriptor.\n            {\n                let out_ptr = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n                let total_written = u32::try_from(total_written)?;\n                mem_access.write_memory(out_ptr, &total_written.to_le_bytes())?;\n            }\n\n            assert!(params.next().is_none());\n\n            // Flush `buffer` into a log message if possible.\n            if let Some(split_pos) = buffer.iter().position(|c| *c == b'\\n') {\n                let mut encoded_message = Vec::new();\n                encoded_message.push(u8::from(*level));\n                encoded_message.extend(buffer.drain(..split_pos));\n                buffer.remove(0);\n\n                let action = ExtrinsicsAction::EmitMessage {\n                    interface: redshirt_log_interface::ffi::INTERFACE,\n                    message: EncodedMessage(encoded_message),\n                    response_expected: false,\n                };\n\n                let context = ContextInner::TryFlushLogOut(fd);\n                Ok((context, action))\n            } else {\n                let action = ExtrinsicsAction::Resume(Some(WasmValue::I32(0)));\n                Ok((ContextInner::Finished, action))\n            }\n        }\n        FileDescriptor::FilesystemEntry { .. } => unimplemented!(), // TODO:\n    }\n}\n\nfn path_filestat_get(\n    state: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let file_descriptors_lock = state.file_descriptors.lock();\n\n    let file_descriptor = {\n        let fd = usize::try_from(params.next().unwrap().into_i32().unwrap())?;\n        match file_descriptors_lock.get(fd).and_then(|v| v.as_ref()) {\n            Some(fd) => fd,\n            None => {\n                let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n                let action = ExtrinsicsAction::Resume(ret);\n                return Ok((ContextInner::Finished, action));\n            }\n        }\n    };\n\n    let fd_inode = match file_descriptor {\n        FileDescriptor::Empty | FileDescriptor::LogOut { .. } => {\n            // TODO: is that the correct return type?\n            let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n            let action = ExtrinsicsAction::Resume(ret);\n            return Ok((ContextInner::Finished, action));\n        }\n        FileDescriptor::FilesystemEntry { inode, .. } => inode.clone(),\n    };\n\n    let _lookup_flags = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n\n    let path = {\n        let path_buf = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n        let path_buf_len = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n        let path_utf8 = mem_access.read_memory(path_buf..path_buf + path_buf_len)?;\n        String::from_utf8(path_utf8)? // TODO: return error code?\n    };\n\n    let resolved_path = match resolve_path(&fd_inode, &path) {\n        Some(p) => p,\n        None => {\n            let action =\n                ExtrinsicsAction::Resume(Some(WasmValue::I32(From::from(wasi::ERRNO_NOENT))));\n            return Ok((ContextInner::Finished, action));\n        }\n    };\n\n    let filestat = filestat_from_inode(&resolved_path);\n\n    let filestat_out_buf = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    assert!(params.next().is_none());\n\n    // Note: this is a bit of dark magic, but it is the only solution at the moment.\n    // Can be tested with the following snippet:\n    // ```c\n    // #include <stdio.h>\n    // #include <wasi/api.h>\n    // int main() {\n    //     __wasi_filestat_t* ptr = (__wasi_filestat_t*)0x1000;\n    //     printf(\"%p %p %p %p %p %p %p %p %p %d\\n\", ptr, &ptr->dev, &ptr->ino, &ptr->filetype, &ptr->nlink, &ptr->size, &ptr->atim, &ptr->mtim, &ptr->ctim, sizeof(__wasi_filestat_t));\n    //     return 0;\n    // }\n    // ```\n    // Which prints `0x1000 0x1000 0x1008 0x1010 0x1018 0x1020 0x1028 0x1030 0x1038 64`\n    mem_access.write_memory(filestat_out_buf, &[0; 64])?;\n    mem_access.write_memory(filestat_out_buf, &filestat.dev.to_le_bytes())?;\n    mem_access.write_memory(\n        filestat_out_buf.checked_add(8).ok_or(WasiCallErr)?,\n        &filestat.ino.to_le_bytes(),\n    )?;\n    mem_access.write_memory(\n        filestat_out_buf.checked_add(16).ok_or(WasiCallErr)?,\n        &filestat.filetype.to_le_bytes(),\n    )?;\n    mem_access.write_memory(\n        filestat_out_buf.checked_add(24).ok_or(WasiCallErr)?,\n        &filestat.nlink.to_le_bytes(),\n    )?;\n    mem_access.write_memory(\n        filestat_out_buf.checked_add(32).ok_or(WasiCallErr)?,\n        &filestat.size.to_le_bytes(),\n    )?;\n    mem_access.write_memory(\n        filestat_out_buf.checked_add(40).ok_or(WasiCallErr)?,\n        &filestat.atim.to_le_bytes(),\n    )?;\n    mem_access.write_memory(\n        filestat_out_buf.checked_add(48).ok_or(WasiCallErr)?,\n        &filestat.mtim.to_le_bytes(),\n    )?;\n    mem_access.write_memory(\n        filestat_out_buf.checked_add(56).ok_or(WasiCallErr)?,\n        &filestat.ctim.to_le_bytes(),\n    )?;\n\n    let action = ExtrinsicsAction::Resume(Some(WasmValue::I32(0)));\n    Ok((ContextInner::Finished, action))\n}\n\nfn path_open(\n    state: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let mut file_descriptors_lock = state.file_descriptors.lock();\n\n    let file_descriptor = {\n        let fd = usize::try_from(params.next().unwrap().into_i32().unwrap())?;\n        match file_descriptors_lock.get(fd).and_then(|v| v.as_ref()) {\n            Some(fd) => fd,\n            None => {\n                let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n                let action = ExtrinsicsAction::Resume(ret);\n                return Ok((ContextInner::Finished, action));\n            }\n        }\n    };\n\n    let fd_inode = match file_descriptor {\n        FileDescriptor::Empty | FileDescriptor::LogOut { .. } => {\n            // TODO: is that the correct return type?\n            let ret = Some(WasmValue::I32(From::from(wasi::ERRNO_BADF)));\n            let action = ExtrinsicsAction::Resume(ret);\n            return Ok((ContextInner::Finished, action));\n        }\n        FileDescriptor::FilesystemEntry { inode, .. } => inode.clone(),\n    };\n\n    let _lookup_flags = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n\n    let path = {\n        let path_buf = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n        let path_buf_len = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n        let path_utf8 = mem_access.read_memory(path_buf..path_buf + path_buf_len)?;\n        String::from_utf8(path_utf8)? // TODO: return error code?\n    };\n\n    let resolved_path = match resolve_path(&fd_inode, &path) {\n        Some(p) => p,\n        None => {\n            let action =\n                ExtrinsicsAction::Resume(Some(WasmValue::I32(From::from(wasi::ERRNO_NOENT))));\n            return Ok((ContextInner::Finished, action));\n        }\n    };\n\n    let _open_flags = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    let _fs_rights_base = u64::try_from(params.next().unwrap().into_i64().unwrap())?;\n    let _fs_rights_inherting = u64::try_from(params.next().unwrap().into_i64().unwrap())?;\n    let _fd_flags = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n\n    let new_fd = if let Some(fd_val) = file_descriptors_lock.iter().position(|fd| fd.is_none()) {\n        file_descriptors_lock[fd_val] = Some(FileDescriptor::FilesystemEntry {\n            inode: resolved_path,\n            file_cursor_pos: 0,\n        });\n        // TODO: return error code with \"too many fds\"\n        u32::try_from(fd_val).unwrap()\n    } else {\n        let fd_val = file_descriptors_lock.len();\n        file_descriptors_lock.push(Some(FileDescriptor::FilesystemEntry {\n            inode: resolved_path,\n            file_cursor_pos: 0,\n        }));\n        // TODO: return error code with \"too many fds\"\n        u32::try_from(fd_val).unwrap()\n    };\n\n    let opened_fd_ptr = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    assert!(params.next().is_none());\n\n    mem_access.write_memory(opened_fd_ptr, &new_fd.to_le_bytes())?;\n\n    let action = ExtrinsicsAction::Resume(Some(WasmValue::I32(0)));\n    Ok((ContextInner::Finished, action))\n}\n\nfn poll_oneoff(\n    _: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    _: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let _subscriptions_buf = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    let _events_out_buf = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    let _buf_size = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    let _num_events_out = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    assert!(params.next().is_none());\n\n    unimplemented!()\n}\n\nfn proc_exit(\n    _: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    _: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let _ret_val = params.next().unwrap().into_i32().unwrap();\n    assert!(params.next().is_none());\n\n    // TODO: returning `ProgramCrash` leads to `unimplemented!()`, so we panic\n    // beforehand for a more explicit message\n    // If the exit code is weird, it's probably one of these values:\n    // https://github.com/WebAssembly/wasi-libc/blob/320054e84f8f2440def3b1c8700cedb8fd697bf8/libc-top-half/musl/include/sysexits.h\n    panic!(\"proc_exit called with {:?}\", _ret_val);\n\n    // TODO: implement in a better way than crashing?\n    Ok((ContextInner::Finished, ExtrinsicsAction::ProgramCrash))\n}\n\nfn random_get(\n    _: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    _: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let buf = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    let len = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    assert!(params.next().is_none());\n\n    let len_to_request = u16::try_from(len).unwrap_or(u16::max_value());\n    debug_assert!(u32::from(len_to_request) <= len);\n    let action = ExtrinsicsAction::EmitMessage {\n        interface: redshirt_random_interface::ffi::INTERFACE,\n        message: redshirt_random_interface::ffi::RandomMessage::Generate {\n            len: len_to_request,\n        }\n        .encode(),\n        response_expected: true,\n    };\n\n    let context = ContextInner::WaitRandom {\n        out_ptr: buf,\n        remaining_len: len,\n    };\n\n    Ok((context, action))\n}\n\nfn sched_yield(\n    _: &WasiExtrinsics,\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    _: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    // TODO: implement in a better way?\n    assert!(params.next().is_none());\n    let action = ExtrinsicsAction::Resume(Some(WasmValue::I32(0)));\n    Ok((ContextInner::Finished, action))\n}\n\n// Utility functions below.\n\nfn args_or_env_get(\n    list: &[Vec<u8>],\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let argv = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    let argv_buf = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    assert!(params.next().is_none());\n\n    let mut argv_pos = 0;\n    let mut argv_buf_pos = 0;\n\n    for arg in list.iter() {\n        mem_access.write_memory(\n            argv.checked_add(argv_pos).ok_or(WasiCallErr)?,\n            &(argv_buf.checked_add(argv_buf_pos).ok_or(WasiCallErr)?).to_le_bytes(),\n        )?;\n        argv_pos = argv_pos.checked_add(4).ok_or(WasiCallErr)?;\n        mem_access.write_memory(argv_buf.checked_add(argv_buf_pos).ok_or(WasiCallErr)?, &arg)?;\n        argv_buf_pos = argv_buf_pos\n            .checked_add(u32::try_from(arg.len())?)\n            .ok_or(WasiCallErr)?;\n        mem_access.write_memory(argv_buf.checked_add(argv_buf_pos).ok_or(WasiCallErr)?, &[0])?;\n        argv_buf_pos = argv_buf_pos.checked_add(1).ok_or(WasiCallErr)?;\n    }\n\n    let action = ExtrinsicsAction::Resume(Some(WasmValue::I32(0)));\n    Ok((ContextInner::Finished, action))\n}\n\nfn args_or_env_sizes_get(\n    list: &[Vec<u8>],\n    mut params: impl ExactSizeIterator<Item = WasmValue>,\n    mem_access: &mut impl ExtrinsicsMemoryAccess,\n) -> Result<(ContextInner, ExtrinsicsAction), WasiCallErr> {\n    let argc_out = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    let argv_buf_size_out = u32::try_from(params.next().unwrap().into_i32().unwrap())?;\n    assert!(params.next().is_none());\n\n    mem_access.write_memory(argc_out, &u32::try_from(list.len())?.to_le_bytes())?;\n    let argv_buf_size = list\n        .iter()\n        .fold(0usize, |s, a| s.saturating_add(a.len()).saturating_add(1));\n    mem_access.write_memory(\n        argv_buf_size_out,\n        &u32::try_from(argv_buf_size)?.to_le_bytes(),\n    )?;\n\n    let action = ExtrinsicsAction::Resume(Some(WasmValue::I32(0)));\n    Ok((ContextInner::Finished, action))\n}\n\nfn filestat_from_inode(inode: &Arc<Inode>) -> wasi::Filestat {\n    wasi::Filestat {\n        dev: 1,                                        // TODO:\n        ino: &**inode as *const Inode as usize as u64, // TODO:\n        filetype: match **inode {\n            Inode::Directory { .. } => wasi::FILETYPE_DIRECTORY,\n            Inode::File { .. } => wasi::FILETYPE_REGULAR_FILE,\n        },\n        nlink: 1, // TODO:\n        size: match &**inode {\n            Inode::Directory { .. } => 0,\n            Inode::File { content } => {\n                wasi::Filesize::try_from(content.len()).unwrap_or(wasi::Filesize::max_value())\n            }\n        },\n        atim: 0, // TODO:\n        mtim: 0, // TODO:\n        ctim: 0, // TODO:\n    }\n}\n\nfn resolve_path(root: &Arc<Inode>, path: &str) -> Option<Arc<Inode>> {\n    let mut current = root.clone();\n\n    for component in path.split('/') {\n        if component == \".\" {\n            continue;\n        }\n\n        if component == \"..\" {\n            unimplemented!()\n        }\n\n        let next = match &*current {\n            Inode::File { .. } => return None,\n            Inode::Directory { entries } => {\n                let entries = entries.lock();\n                entries.get(component)?.clone()\n            }\n        };\n\n        current = next;\n    }\n\n    Some(current)\n}\n"
  },
  {
    "path": "kernel/core/src/extrinsics.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Provides a way to implement custom extrinsics.\n//!\n//! The [`Extrinsics`] trait can be implemented on types that represent a collection of functions\n//! that can be called by a WASM module.\n//!\n//! A function that is available to a WASM module is called an **extrinsic**.\n//!\n//! TODO: write doc on how to implement this trait\n\nuse crate::primitives::{Signature, WasmValue};\nuse crate::{EncodedMessage, EncodedMessageRef, InterfaceHash, ThreadId};\n\nuse alloc::{borrow::Cow, vec::Vec};\nuse core::{fmt, iter, ops::Range};\n\npub mod log_calls;\npub mod wasi;\n\n/// Trait implemented on types that can handle extrinsics.\n///\n/// The `Default` trait is used to instantiate structs that implement this trait. One instance is\n/// created for each WASM process.\n// TODO: in this API one can only emit one message at the time; this is fine in terms of logic, but\n// is sub-optimal\npub trait Extrinsics: Default {\n    /// Identifier for an extrinsic function.\n    ///\n    /// Instead of passing around function names, we pass around identifiers.\n    ///\n    /// This is typically an `enum` or an integer.\n    type ExtrinsicId: Send;\n\n    /// Created when an extrinsic is called by a WASM module.\n    type Context: Send;\n\n    /// Iterator returned by [`Extrinsics::supported_extrinsics`].\n    type Iterator: Iterator<Item = SupportedExtrinsic<Self::ExtrinsicId>>;\n\n    /// Returns an iterator to the list of extrinsics that this struct supports.\n    fn supported_extrinsics() -> Self::Iterator;\n\n    /// Called when a WASM module calls an extrinsic.\n    ///\n    /// Returns what to do next on this context.\n    ///\n    /// Returning [`ExtrinsicsAction::Resume`] or [`ExtrinsicsAction::ProgramCrash`] finishes the\n    /// extrinsic call and destroys the context.\n    fn new_context(\n        &self,\n        tid: ThreadId,\n        id: &Self::ExtrinsicId,\n        params: impl ExactSizeIterator<Item = WasmValue>,\n        proc_access: &mut impl ExtrinsicsMemoryAccess,\n    ) -> (Self::Context, ExtrinsicsAction);\n\n    /// If [`ExtrinsicsAction::EmitMessage`] has been emitted, this function is later called in\n    /// order to notify of the response.\n    ///\n    /// The response is `None` if no response is expected.\n    ///\n    /// Returns what to do next on this context.\n    ///\n    /// Returning [`ExtrinsicsAction::Resume`] or [`ExtrinsicsAction::ProgramCrash`] finishes the\n    /// extrinsic call and destroys the context.\n    fn inject_message_response(\n        &self,\n        ctxt: &mut Self::Context,\n        response: Option<EncodedMessageRef>,\n        proc_access: &mut impl ExtrinsicsMemoryAccess,\n    ) -> ExtrinsicsAction;\n}\n\n/// Access to a process's memory.\npub trait ExtrinsicsMemoryAccess {\n    /// Reads the process' memory in the given range and returns a copy of it.\n    ///\n    /// # Panic\n    ///\n    /// A panic can occur if the start of the range is superior to its end. Note, however, that\n    /// zero-sized ranges are allowed.\n    // TODO: zero-cost API\n    fn read_memory(&self, range: Range<u32>) -> Result<Vec<u8>, ExtrinsicsMemoryAccessErr>;\n\n    /// Writes the given data in the process's memory at the given offset.\n    fn write_memory(&mut self, offset: u32, data: &[u8]) -> Result<(), ExtrinsicsMemoryAccessErr>;\n}\n\n/// Error that can happen when reading or writing the memory of a process.\n#[derive(Debug)]\npub enum ExtrinsicsMemoryAccessErr {\n    /// The range is outside of the memory allocated to this process.\n    OutOfRange,\n}\n\nimpl fmt::Display for ExtrinsicsMemoryAccessErr {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            ExtrinsicsMemoryAccessErr::OutOfRange => write!(\n                f,\n                \"The range is outside of the memory allocated to this process.\"\n            ),\n        }\n    }\n}\n\n/// Description of an extrinsic supported by the implementation of [`Extrinsics`].\n#[derive(Debug)]\npub struct SupportedExtrinsic<TExtId> {\n    /// Identifier of the extrinsic. Passed to [`Extrinsics::new_context`] when the extrinsic is\n    /// called.\n    pub id: TExtId,\n\n    /// Name of the interface the function belongs to.\n    ///\n    /// In WASM, each function belongs to what is called an interface. An interface can be summed\n    /// up as the namespace of the function. This is unrelated to the concept of \"interface\"\n    /// proper to redshirt.\n    pub wasm_interface: Cow<'static, str>,\n\n    /// Name of the function.\n    pub function_name: Cow<'static, str>,\n\n    /// Signature of the function. The parameters passed to [`Extrinsics::new_context`] are\n    /// guaranteed to match this signature.\n    pub signature: Signature,\n}\n\n/// Action to perform in the context of an extrinsic being called.\n#[derive(Debug, Clone)]\npub enum ExtrinsicsAction {\n    /// Crash the program that called the extrinsic.\n    ProgramCrash,\n\n    /// Successfully finish the call and return with the given value.\n    Resume(Option<WasmValue>),\n\n    /// Emit a message.\n    ///\n    /// This makes it as if the process had emitted a message on the given interface, except that\n    /// the response is later injected back using [`Extrinsics::inject_message_response`].\n    EmitMessage {\n        interface: InterfaceHash,\n        message: EncodedMessage,\n        response_expected: bool,\n    },\n}\n\n/// Dummy implementation of the [`Extrinsics`] trait.\n#[derive(Debug, Default)]\npub struct NoExtrinsics;\n\nimpl Extrinsics for NoExtrinsics {\n    type ExtrinsicId = core::convert::Infallible; // TODO: `!` instead\n    type Context = core::convert::Infallible; // TODO: `!` instead\n    type Iterator = iter::Empty<SupportedExtrinsic<Self::ExtrinsicId>>;\n\n    fn supported_extrinsics() -> Self::Iterator {\n        iter::empty()\n    }\n\n    fn new_context(\n        &self,\n        _: ThreadId,\n        id: &Self::ExtrinsicId,\n        _: impl ExactSizeIterator<Item = WasmValue>,\n        _: &mut impl ExtrinsicsMemoryAccess,\n    ) -> (Self::Context, ExtrinsicsAction) {\n        match *id {} // unreachable\n    }\n\n    fn inject_message_response(\n        &self,\n        ctxt: &mut Self::Context,\n        _: Option<EncodedMessageRef>,\n        _: &mut impl ExtrinsicsMemoryAccess,\n    ) -> ExtrinsicsAction {\n        match *ctxt {} // unreachable\n    }\n}\n"
  },
  {
    "path": "kernel/core/src/id_pool.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse core::{convert::TryFrom, fmt};\nuse crossbeam_queue::SegQueue;\nuse rand::distributions::{Distribution as _, Uniform};\nuse rand_chacha::ChaCha20Rng;\nuse rand_core::SeedableRng as _;\nuse spinning_top::Spinlock;\n\n// Maths note: after 3 billion iterations, there's a 2% chance of a collision\n//\n// Chance of collision is approximately: 1 - exp(-n^2 / 2^(b+1))\n// where `n` is the number of generated IDs, `b` number of bits in the ID (64 here)\n\n/// Lock-free pool of identifiers. Can assign new identifiers from it.\npub struct IdPool {\n    /// Sources of randomness.\n    /// Every time we need a random number, we pop a state from this list, then push it back when\n    /// we're done.\n    rngs: SegQueue<ChaCha20Rng>,\n    /// Distribution of IDs.\n    distribution: Uniform<u64>,\n    /// PRNG used to seed the other thread-specific PRNGs stored in `rngs`.\n    master_rng: Spinlock<ChaCha20Rng>,\n}\n\nimpl IdPool {\n    /// Initializes a new pool.\n    pub fn with_seed(seed: [u8; 32]) -> Self {\n        IdPool {\n            rngs: SegQueue::new(),\n            distribution: Uniform::from(0..=u64::max_value()),\n            master_rng: Spinlock::new(ChaCha20Rng::from_seed(seed)),\n        }\n    }\n\n    /// Assigns a new PID from this pool.\n    ///\n    /// The returned value must implement the `TryFrom<u64>` trait. `u64`s are rolled as long as\n    /// as calling `TryFrom` returns an error.\n    pub fn assign<T: TryFrom<u64>>(&self) -> T {\n        if let Some(mut rng) = self.rngs.pop() {\n            return loop {\n                let raw_id = self.distribution.sample(&mut rng);\n                if let Ok(id) = TryFrom::try_from(raw_id) {\n                    self.rngs.push(rng);\n                    break id;\n                }\n            };\n        }\n\n        let mut master_rng = self.master_rng.lock();\n        let mut new_rng = match ChaCha20Rng::from_rng(&mut *master_rng) {\n            Ok(r) => r,\n            Err(_) => unreachable!(),\n        };\n\n        loop {\n            let raw_id = self.distribution.sample(&mut new_rng);\n            if let Ok(id) = TryFrom::try_from(raw_id) {\n                self.rngs.push(new_rng);\n                break id;\n            }\n        }\n    }\n}\n\nimpl fmt::Debug for IdPool {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"IdPool\").finish()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use nohash_hasher::BuildNoHashHasher;\n\n    #[test]\n    fn ids_different() {\n        let mut ids = hashbrown::HashSet::<u64, BuildNoHashHasher<u64>>::default();\n        let pool = super::IdPool::with_seed([0; 32]);\n        for _ in 0..5000 {\n            assert!(ids.insert(pool.assign()));\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/core/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Core components of a redshirt kernel.\n//!\n//! The main structure of this crate is [`System`]. A [`System`] represents a running operating\n//! system, and is a collection of *programs* exchanging messages between each others.\n//!\n//! > **Note**: A [`System`] doesn't run automatically in the background. You must call the\n//! >           [`System::run`] function repeatedly in order for the programs within the\n//! >           [`System`] to advance.\n//!\n//! Programs within a [`System`] are written in [the Wasm language](https://webassembly.org/),\n//! or, more likely, written in a programming language then compiled to Wasm. In order to start\n//! a Wasm program, pass the binary either to [`SystemBuilder::with_startup_process`] if you're\n//! building a [`System`], or to [`System::execute`] if the [`System`] is already constructed.\n//!\n//! Each program within a [`System`] gets attributed a single [`Pid`] that identifies it.\n//!\n//! # Messages\n//!\n//! As part of their execution, programs (both Wasm and native) can emit *messages*. A message can\n//! accept either zero or one response. Each emitted message gets attribute a single unique\n//! [`MessageId`] that identifies it.\n//!\n//! In order to emit a message, you must pass three main information:\n//!\n//! - The hash of a target *interface* (more on that below).\n//! - The body of the message, opaque to the `redshirt_core` crate. The way it must be interpreted\n//! depends on the target *interface*.\n//! - Whether or not a response is expected.\n//!\n//! Contrary to many other operating systems, messages don't target a specific program, but rather\n//! an *interface* that can be referred to with an [`InterfaceHash`].\n//!\n//! There exists a few *interfaces* hardcoded within the [`System`]. When a program emits a\n//! message targetting one of these interfaces, the message will be treated (and answer, if\n//! necessary) by the [`System`] itself. Here is a list:\n//!\n//! - `interface`. The interface named `interface` allows programs to register themselves as\n//! provider of an interface. If a program then emits a message targetting the interface, then\n//! the registered program will be in charge of treating the message.\n//! - `threads`. The interface named `threads` provides a few utilities related to multithreading\n//! (TODO: this isn't really done yet)\n//!\n//! > **Note**: A very common workflow for a program is, immediately after it starts, to emit a\n//! >           message on the `interface` interface in order to register itself as the handler of\n//! >           a specific interface. It will then be in charge of processing the messages coming\n//! >           on that registered interface.\n//!\n//! > **Note**: Only one program at a time can be registered as an interface handler. This is done\n//! >           in a first-come-first-serve manner. If a second program tries to register itself\n//! >           for the same interface, the second registration will fail.\n//!\n//! # Wasm programs isolation\n//!\n//! Wasm programs are isolated entirely within their virtual machine, and have no access to the\n//! outside except for passing messages around.\n//! Any action requiring intervention from the hardware can only be done directly by a\n//! *native program*.\n//!\n//! Because of their non-isolated nature, the list of *native programs* should be composed only\n//! of the strict minimum, and can't be changed once the [`System`] has been constructed.\n//!\n//! # Lazy interfaces registration\n//!\n//! Since programs all start simultaneously at the system initialization, and because we don't\n//! know in advance which interface(s) (if any) a program will register and when, it is possible\n//! for a program to emit a message on an interface that has no registered handler but that will\n//! have one soon in the future.\n//!\n//! > **Example**: Program A is an HTTP server and wants to open a TCP socket to start listening\n//! >              for incoming connections. To do so, program A emits a message of the interface\n//! >              named `tcp`. Program B is the network manager and registers itself as the\n//! >              provider of the `tcp` interface. Since A and B start at the same time, it is\n//! >              possible for A to emit its message before B has registered itself.\n//!\n//! In order to solve this problem, emitting a message will block the execution of the current\n//! thread until a handler is available for the target interface. It is possible, when emitting\n//! a message, to disable this behaviour and fail immediately if no handler is registered.\n//!\n//! Additionally, no timeout mechanism exists. In other words, if no program registers itself as\n//! the handler of an interface for which a message has been emitted, then the sending thread\n//! will block forever.\n//!\n//! > **Note**: As a general rule in IT, the only two timeout values that make sense are *0*\n//! >           and *infinite*.\n//!\n//! While this hasn't been implemented yet, the best way to deal with this kind of situation is\n//! to somehow report to the user the list of programs being stuck waiting for an interface\n//! handler.\n//!\n\n#![warn(missing_docs)]\n//#![deny(unsafe_code)] // TODO: 🤷\n#![allow(dead_code)] // TODO: temporary during development\n\n// The crate uses the stdlib for testing purposes.\n#![cfg_attr(not(test), no_std)]\n\nextern crate alloc;\n\npub use self::system::{ExecuteOut, System, SystemBuilder, SystemRunOutcome};\npub use primitives::{ValueType, WasmValue};\npub use redshirt_syscalls::{\n    Decode, Encode, EncodedMessage, EncodedMessageRef, InterfaceHash, InvalidMessageIdErr,\n    MessageId, Pid, ThreadId,\n};\n\n/// Compiles a WASM module and includes it similar to `include_bytes!`.\n///\n/// Must be passed the path to a directory containing a `Cargo.toml`.\n/// Can be passed an optional second argument containing the binary name to compile. Mandatory if\n/// the package contains multiple binaries.\n#[cfg(feature = \"nightly\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"nightly\")))]\n// TODO: enable unconditonally after https://github.com/rust-lang/rust/issues/43781\npub use redshirt_core_proc_macros::build_wasm_module;\n\n#[doc(hidden)]\npub use redshirt_core_proc_macros::wat_to_bin;\n\n/// Builds a WASM binary from a WASM text representation.\n///\n/// The WASM text representation is parsed and transformed at compile time.\n#[macro_export]\nmacro_rules! from_wat {\n    // TODO: also build the hash at compile-time? https://github.com/tomaka/redshirt/issues/218\n    // TODO: we need this hack with a special `local` tag because of macro paths resolution issues\n    (local, $wat:expr) => {{\n        redshirt_core_proc_macros::wat_to_bin!($wat)\n    }};\n    ($wat:expr) => {{\n        $crate::wat_to_bin!($wat)\n    }};\n}\n\nmod id_pool;\n\npub mod extrinsics;\npub mod module;\npub mod primitives;\npub mod scheduler;\npub mod system;\n"
  },
  {
    "path": "kernel/core/src/module.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse core::fmt;\n\n/// Hash of a module.\n#[derive(Clone, PartialEq, Eq, Hash)]\npub struct ModuleHash([u8; 32]);\n\n/// Error that can happen when calling [`ModuleHash::from_base58`].\n#[derive(Debug)]\npub struct FromBase58Error {}\n\nimpl From<[u8; 32]> for ModuleHash {\n    fn from(hash: [u8; 32]) -> ModuleHash {\n        ModuleHash(hash)\n    }\n}\n\nimpl From<ModuleHash> for [u8; 32] {\n    fn from(hash: ModuleHash) -> [u8; 32] {\n        hash.0\n    }\n}\n\nimpl ModuleHash {\n    /// Returns the hash of the given bytes.\n    pub fn from_bytes(buffer: impl AsRef<[u8]>) -> Self {\n        ModuleHash(blake3::hash(buffer.as_ref()).into())\n    }\n\n    /// Decodes the given base58-encoded string into a hash.\n    ///\n    /// See also https://en.wikipedia.org/wiki/Base58.\n    // TODO: check that we return an error if the string is too long\n    pub fn from_base58(encoding: &str) -> Result<Self, FromBase58Error> {\n        let mut out = [0; 32];\n        let written = bs58::decode(encoding)\n            .into(&mut out)\n            .map_err(|_| FromBase58Error {})?;\n        let mut out2 = [0; 32];\n        out2[32 - written..].copy_from_slice(&out[..written]);\n        Ok(ModuleHash(out2))\n    }\n}\n\nimpl fmt::Debug for ModuleHash {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"ModuleHash({})\", bs58::encode(&self.0).into_string())\n    }\n}\n\nimpl fmt::Display for FromBase58Error {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"FromBase58Error\")\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    #[test]\n    fn empty_wat_works() {\n        let _ = from_wat!(local, \"(module)\");\n    }\n\n    #[test]\n    fn simple_wat_works() {\n        let _ = from_wat!(\n            local,\n            r#\"\n            (module\n                (func $add (param i32 i32) (result i32)\n                    local.get 0\n                    local.get 1\n                    i32.add)\n                (export \"add\" (func $add)))\n            \"#\n        );\n    }\n}\n"
  },
  {
    "path": "kernel/core/src/primitives.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Primitive types used when interacting with Wasm code.\n\nuse alloc::vec::Vec;\nuse smallvec::SmallVec;\n\n/// Low-level Wasm function signature.\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub struct Signature {\n    params: SmallVec<[ValueType; 2]>,\n    ret_ty: Option<ValueType>,\n}\n\n/// Easy way to generate a [`Signature`](crate::primitives::Signature).\n///\n/// # Example\n///\n/// ```\n/// let _sig: redshirt_core::primitives::Signature = redshirt_core::sig!((I32, I64) -> I32);\n/// ```\n#[macro_export]\nmacro_rules! sig {\n    (($($p:ident),*)) => {{\n        let params = core::iter::empty();\n        $(let params = params.chain(core::iter::once($crate::ValueType::$p));)*\n        $crate::primitives::Signature::new(params, None)\n    }};\n    (($($p:ident),*) -> $ret:ident) => {{\n        let params = core::iter::empty();\n        $(let params = params.chain(core::iter::once($crate::ValueType::$p));)*\n        $crate::primitives::Signature::new(params, Some($crate::ValueType::$ret))\n    }};\n}\n\nimpl Signature {\n    /// Creates a [`Signature`] from the given parameter types and return type.\n    pub fn new(\n        params: impl Iterator<Item = ValueType>,\n        ret_ty: impl Into<Option<ValueType>>,\n    ) -> Signature {\n        Signature {\n            params: params.collect(),\n            ret_ty: ret_ty.into(),\n        }\n    }\n\n    /// Returns a list of all the types of the parameters.\n    pub fn parameters(&self) -> impl ExactSizeIterator<Item = &ValueType> {\n        self.params.iter()\n    }\n\n    /// Returns the type of the return type of the function. `None` means \"void\".\n    pub fn return_type(&self) -> Option<&ValueType> {\n        self.ret_ty.as_ref()\n    }\n}\n\nimpl<'a> From<&'a Signature> for wasmi::FuncType {\n    fn from(sig: &'a Signature) -> wasmi::FuncType {\n        wasmi::FuncType::new(\n            sig.params\n                .iter()\n                .cloned()\n                .map(wasmi::core::ValType::from)\n                .collect::<Vec<_>>(),\n            sig.ret_ty.map(wasmi::core::ValType::from),\n        )\n    }\n}\n\nimpl From<Signature> for wasmi::FuncType {\n    fn from(sig: Signature) -> wasmi::FuncType {\n        wasmi::FuncType::from(&sig)\n    }\n}\n\nimpl<'a> From<&'a wasmi::FuncType> for Signature {\n    fn from(sig: &'a wasmi::FuncType) -> Signature {\n        Signature::new(\n            sig.params().iter().cloned().map(ValueType::from),\n            sig.results().get(0).copied().map(ValueType::from), // TODO: don't ignore if multiple return types\n        )\n    }\n}\n\nimpl From<wasmi::FuncType> for Signature {\n    fn from(sig: wasmi::FuncType) -> Signature {\n        Signature::from(&sig)\n    }\n}\n\nimpl From<ValueType> for wasmi::core::ValType {\n    fn from(ty: ValueType) -> wasmi::core::ValType {\n        match ty {\n            ValueType::I32 => wasmi::core::ValType::I32,\n            ValueType::I64 => wasmi::core::ValType::I64,\n            ValueType::F32 => wasmi::core::ValType::F32,\n            ValueType::F64 => wasmi::core::ValType::F64,\n        }\n    }\n}\n\n/// Value that a Wasm function can accept or produce.\n#[derive(Debug, Copy, Clone)]\npub enum WasmValue {\n    /// A 32-bits integer. There is no fundamental difference between signed and unsigned\n    /// integer, and the signed-ness should be determined depending on the context.\n    I32(i32),\n    /// A 32-bits integer. There is no fundamental difference between signed and unsigned\n    /// integer, and the signed-ness should be determined depending on the context.\n    I64(i64),\n    /// A 32-bits floating point number.\n    ///\n    /// Contains the bits representation of the float.\n    // TODO: which format is this? IEEE 754?\n    F32(u32),\n    /// A 64-bits floating point number.\n    ///\n    /// Contains the bits representation of the float.\n    // TODO: which format is this? IEEE 754?\n    F64(u64),\n}\n\n/// Type of a value passed as parameter or returned by a function.\n#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]\npub enum ValueType {\n    /// A 32-bits integer. Used for both signed and unsigned integers.\n    I32,\n    /// A 64-bits integer. Used for both signed and unsigned integers.\n    I64,\n    /// A 32-bits floating point value.\n    F32,\n    /// A 64-bits floating point value.\n    F64,\n}\n\nimpl WasmValue {\n    /// Returns the type corresponding to this value.\n    pub fn ty(&self) -> ValueType {\n        match self {\n            WasmValue::I32(_) => ValueType::I32,\n            WasmValue::I64(_) => ValueType::I64,\n            WasmValue::F32(_) => ValueType::F32,\n            WasmValue::F64(_) => ValueType::F64,\n        }\n    }\n\n    /// Unwraps [`WasmValue::I32`] into its value.\n    pub fn into_i32(self) -> Option<i32> {\n        if let WasmValue::I32(v) = self {\n            Some(v)\n        } else {\n            None\n        }\n    }\n\n    /// Unwraps [`WasmValue::I64`] into its value.\n    pub fn into_i64(self) -> Option<i64> {\n        if let WasmValue::I64(v) = self {\n            Some(v)\n        } else {\n            None\n        }\n    }\n}\n\nimpl From<wasmi::Val> for WasmValue {\n    fn from(val: wasmi::Val) -> Self {\n        WasmValue::from(&val)\n    }\n}\n\nimpl<'a> From<&'a wasmi::Val> for WasmValue {\n    fn from(val: &'a wasmi::Val) -> Self {\n        match val {\n            wasmi::Val::I32(v) => WasmValue::I32(*v),\n            wasmi::Val::I64(v) => WasmValue::I64(*v),\n            _ => unimplemented!(),\n        }\n    }\n}\n\nimpl From<WasmValue> for wasmi::Val {\n    fn from(val: WasmValue) -> Self {\n        match val {\n            WasmValue::I32(v) => wasmi::Val::I32(v),\n            WasmValue::I64(v) => wasmi::Val::I64(v),\n            _ => unimplemented!(),\n        }\n    }\n}\n\nimpl From<wasmi::core::ValType> for ValueType {\n    fn from(val: wasmi::core::ValType) -> Self {\n        match val {\n            wasmi::core::ValType::I32 => ValueType::I32,\n            wasmi::core::ValType::I64 => ValueType::I64,\n            wasmi::core::ValType::F32 => ValueType::F32,\n            wasmi::core::ValType::F64 => ValueType::F64,\n            _ => unimplemented!(),\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/core/src/scheduler/extrinsics/calls.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Helpers for parsing the hardcoded functions that can be called by the WASM program.\n\nuse crate::scheduler::processes;\nuse crate::{InterfaceHash, InvalidMessageIdErr, MessageId};\n\nuse alloc::vec::Vec;\nuse core::{convert::TryFrom as _, num::NonZeroU64};\nuse redshirt_syscalls::EncodedMessage;\n\n/// Analyzes a call to `next_notification` made by the given thread.\n///\n/// The `thread` parameter is only used in order to read memory from the process. This function\n/// has no side effect.\n///\n/// Returns an error if the call is invalid.\npub fn parse_extrinsic_next_notification<TExtr, TPud, TTud>(\n    thread: &mut processes::ThreadAccess<TExtr, TPud, TTud>,\n    params: Vec<crate::WasmValue>,\n) -> Result<NotificationWait, ExtrinsicNextNotificationErr> {\n    // We use an assert here rather than a runtime check because the WASM VM (rather than us) is\n    // supposed to check the function signature.\n    assert_eq!(params.len(), 5);\n\n    let notifs_ids_ptr = u32::try_from(\n        params[0]\n            .into_i32()\n            .ok_or(ExtrinsicNextNotificationErr::BadParameter)?,\n    )\n    .map_err(|_| ExtrinsicNextNotificationErr::BadParameter)?;\n    // TODO: consider not copying the notification ids and read memory on demand instead\n    let notifs_ids = {\n        let len = u32::try_from(\n            params[1]\n                .into_i32()\n                .ok_or(ExtrinsicNextNotificationErr::BadParameter)?,\n        )\n        .map_err(|_| ExtrinsicNextNotificationErr::BadParameter)?;\n        if len >= 512 {\n            // TODO: arbitrary limit in order to not allocate too much memory below; a bit crappy\n            return Err(ExtrinsicNextNotificationErr::TooManyNotificationIds { requested: len });\n        }\n        let mem = thread\n            .read_memory(notifs_ids_ptr, len * 8)\n            .map_err(|_| ExtrinsicNextNotificationErr::BadParameter)?;\n        let len_usize = usize::try_from(len)\n            .map_err(|_| ExtrinsicNextNotificationErr::TooManyNotificationIds { requested: len })?;\n        let mut out = Vec::with_capacity(len_usize);\n        for i in mem.chunks(8) {\n            let id = u64::from_le_bytes(<[u8; 8]>::try_from(i).unwrap());\n            out.push(match id {\n                0 => WaitEntry::Empty,\n                _ => WaitEntry::Answer(MessageId::try_from(id).unwrap()),\n            });\n        }\n        out\n    };\n\n    let out_pointer = u32::try_from(\n        params[2]\n            .into_i32()\n            .ok_or(ExtrinsicNextNotificationErr::BadParameter)?,\n    )\n    .map_err(|_| ExtrinsicNextNotificationErr::BadParameter)?;\n    if out_pointer % 8 != 0 {\n        return Err(ExtrinsicNextNotificationErr::BadOutAlignment);\n    }\n\n    let out_size = u32::try_from(\n        params[3]\n            .into_i32()\n            .ok_or(ExtrinsicNextNotificationErr::BadParameter)?,\n    )\n    .map_err(|_| ExtrinsicNextNotificationErr::BadParameter)?;\n    let flags = params[4]\n        .into_i64()\n        .ok_or(ExtrinsicNextNotificationErr::BadParameter)?;\n\n    Ok(NotificationWait {\n        notifs_ids,\n        notifs_ids_ptr,\n        out_pointer,\n        out_size,\n        block: (flags & 0x1) != 0,\n    })\n}\n\n/// How a process is waiting for messages.\n#[derive(Debug, PartialEq, Eq)]\npub struct NotificationWait {\n    /// List of notifications the thread is waiting upon. Copy of what is in the process's memory.\n    pub notifs_ids: Vec<WaitEntry>,\n    /// Offset within the memory of the process where the list of notifications to wait upon is\n    /// located. This is required to zero that location.\n    pub notifs_ids_ptr: u32,\n    /// Offset within the memory of the process where to write the received notification.\n    pub out_pointer: u32,\n    /// Size of the memory of the process dedicated to receiving the notification.\n    pub out_size: u32,\n    /// Whether to block the thread if no notification is available.\n    pub block: bool,\n}\n\n/// What a thread is waiting upon.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum WaitEntry {\n    /// An empty entry. Serves no purpose but it might be convenient for the user of this call\n    /// to leave entries empty.\n    Empty,\n    /// Waiting for an answer to the given message.\n    Answer(MessageId),\n}\n\n/// Error that [`parse_extrinsic_next_notification`] can return.\n#[derive(Debug)]\npub enum ExtrinsicNextNotificationErr {\n    /// Too many notification ids requested.\n    TooManyNotificationIds {\n        /// Number of notification IDs that have been requested.\n        requested: u32,\n    },\n    /// The `out` pointer doesn't have the required alignment.\n    BadOutAlignment,\n    /// Bad type or invalid value for a parameter.\n    BadParameter,\n}\n\n/// Analyzes a call to `emit_message` made by the given thread.\n///\n/// The `thread` parameter is only used in order to read memory from the process. This function\n/// has no side effect.\n///\n/// Returns an error if the call is invalid.\npub fn parse_extrinsic_emit_message<TExtr, TPud, TTud>(\n    thread: &mut processes::ThreadAccess<TExtr, TPud, TTud>,\n    params: Vec<crate::WasmValue>,\n) -> Result<EmitMessage, ExtrinsicEmitMessageErr> {\n    // We use an assert here rather than a runtime check because the WASM VM (rather than us) is\n    // supposed to check the function signature.\n    assert_eq!(params.len(), 5);\n\n    let interface: InterfaceHash = {\n        let addr = u32::try_from(\n            params[0]\n                .into_i32()\n                .ok_or(ExtrinsicEmitMessageErr::BadParameter)?,\n        )\n        .map_err(|_| ExtrinsicEmitMessageErr::BadParameter)?;\n        InterfaceHash::from(\n            <[u8; 32]>::try_from(\n                &thread\n                    .read_memory(addr, 32)\n                    .map_err(|_| ExtrinsicEmitMessageErr::BadParameter)?[..],\n            )\n            .map_err(|_| ExtrinsicEmitMessageErr::BadParameter)?,\n        )\n    };\n\n    let message = {\n        let addr = u32::try_from(\n            params[1]\n                .into_i32()\n                .ok_or(ExtrinsicEmitMessageErr::BadParameter)?,\n        )\n        .map_err(|_| ExtrinsicEmitMessageErr::BadParameter)?;\n        let num_bufs = u32::try_from(\n            params[2]\n                .into_i32()\n                .ok_or(ExtrinsicEmitMessageErr::BadParameter)?,\n        )\n        .map_err(|_| ExtrinsicEmitMessageErr::BadParameter)?;\n        let mut out_msg = Vec::new();\n        for buf_n in 0..num_bufs {\n            let sub_buf_ptr = thread\n                .read_memory(addr + 8 * buf_n, 4)\n                .map_err(|_| ExtrinsicEmitMessageErr::BadParameter)?;\n            let sub_buf_ptr = u32::from_le_bytes(<[u8; 4]>::try_from(&sub_buf_ptr[..]).unwrap());\n            let sub_buf_sz = thread\n                .read_memory(addr + 8 * buf_n + 4, 4)\n                .map_err(|_| ExtrinsicEmitMessageErr::BadParameter)?;\n            let sub_buf_sz = u32::from_le_bytes(<[u8; 4]>::try_from(&sub_buf_sz[..]).unwrap());\n            if out_msg.len()\n                + usize::try_from(sub_buf_sz).map_err(|_| ExtrinsicEmitMessageErr::BadParameter)?\n                >= 16 * 1024 * 1024\n            {\n                // TODO: arbitrary maximum message length\n                panic!(\"Max message length reached\");\n                //return Err(());\n            }\n            out_msg.extend_from_slice(\n                &thread\n                    .read_memory(sub_buf_ptr, sub_buf_sz)\n                    .map_err(|_| ExtrinsicEmitMessageErr::BadParameter)?,\n            );\n        }\n        EncodedMessage(out_msg)\n    };\n\n    let flags = params[3]\n        .into_i64()\n        .ok_or(ExtrinsicEmitMessageErr::BadParameter)?;\n    let needs_answer = (flags & 0x1) != 0;\n\n    let message_id_write = if needs_answer {\n        Some(\n            u32::try_from(\n                params[4]\n                    .into_i32()\n                    .ok_or(ExtrinsicEmitMessageErr::BadParameter)?,\n            )\n            .map_err(|_| ExtrinsicEmitMessageErr::BadParameter)?,\n        )\n    } else {\n        None\n    };\n\n    Ok(EmitMessage {\n        interface,\n        message_id_write,\n        message,\n        allow_delay: (flags & 0x2) != 0,\n    })\n}\n\n/// How a process is emitting a message.\n#[derive(Debug, PartialEq, Eq)]\npub struct EmitMessage {\n    /// Interface the process wants to emit the message on.\n    pub interface: InterfaceHash,\n    /// Location in the process' memory where to write the generated message ID, or `None` if no\n    /// answer is expected.\n    pub message_id_write: Option<u32>,\n    /// Message itself. Needs to be delivered to the interface handler.\n    pub message: EncodedMessage,\n    /// True if we're allowed to block the thread to wait for an interface handler to be\n    /// available.\n    pub allow_delay: bool,\n}\n\n/// Error that [`parse_extrinsic_emit_message`] can return.\n#[derive(Debug)]\npub enum ExtrinsicEmitMessageErr {\n    /// Bad type or invalid value for a parameter.\n    BadParameter,\n}\n\n/// Analyzes a call to `cancel_message` made by the given thread.\n/// Returns the message to cancel.\n///\n/// The `thread` parameter is only used in order to read memory from the process. This function\n/// has no side effect.\n///\n/// Returns an error if the call is invalid.\npub fn parse_extrinsic_cancel_message<TExtr, TPud, TTud>(\n    thread: &mut processes::ThreadAccess<TExtr, TPud, TTud>,\n    params: Vec<crate::WasmValue>,\n) -> Result<MessageId, ExtrinsicCancelMessageErr> {\n    // We use an assert here rather than a runtime check because the WASM VM (rather than us) is\n    // supposed to check the function signature.\n    assert_eq!(params.len(), 1);\n\n    let msg_id = {\n        let addr = u32::try_from(\n            params[0]\n                .into_i32()\n                .ok_or(ExtrinsicCancelMessageErr::BadParameter)?,\n        )\n        .map_err(|_| ExtrinsicCancelMessageErr::BadParameter)?;\n        let buf = thread\n            .read_memory(addr, 8)\n            .map_err(|_| ExtrinsicCancelMessageErr::BadParameter)?;\n        let id = u64::from_le_bytes(<[u8; 8]>::try_from(&buf[..]).unwrap());\n        MessageId::try_from(id).map_err(ExtrinsicCancelMessageErr::InvalidMessageId)?\n    };\n\n    Ok(msg_id)\n}\n\n/// Error that [`parse_extrinsic_cancel_message`] can return.\n#[derive(Debug)]\npub enum ExtrinsicCancelMessageErr {\n    /// Bad type or invalid value for a parameter.\n    BadParameter,\n    /// The message id is invalid.\n    InvalidMessageId(InvalidMessageIdErr),\n}\n"
  },
  {
    "path": "kernel/core/src/scheduler/extrinsics.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Collection of VMs representing processes.\n//!\n//! This module wraps around a [`processes::ProcessesCollection`]. The documentation of the\n//! [`processes`] module also applies to this module and it is strongly recommended it read it\n//! first.\n//!\n//! On top of the features of the [`processes`] module, this module also handles the logic related\n//! to extrinsics (in other words, functions that the Wasm modules can import and call).\n//!\n//! In terms of API, the changes compared to [`processes`] are:\n//!\n//! - The collection accepts an extra generic parameter that must implement the [`Extrinsics`]\n//! trait. Implementations of this trait can provide support for additional functions callable by\n//! the Wasm module by translating them into messages.\n//!\n//! - Interrupted threads are more strongly typed and are split into two categories: threads that\n//! are interrupted because they want to emit a message, and threads that are interrupted because\n//! they are waiting for a notification.\n\nuse crate::extrinsics::{\n    Extrinsics, ExtrinsicsAction, ExtrinsicsMemoryAccess, ExtrinsicsMemoryAccessErr,\n};\nuse crate::scheduler::{processes, vm};\nuse crate::sig;\nuse crate::{InterfaceHash, MessageId};\n\nuse alloc::vec::Vec;\nuse core::{convert::TryFrom as _, fmt, iter, mem, ops::Range};\nuse crossbeam_queue::SegQueue;\nuse redshirt_syscalls::{EncodedMessage, Pid, ThreadId};\n\nmod calls;\n\npub use calls::WaitEntry;\npub use processes::Trap; // TODO: redefine locally?\n\n/// Wrapper around [`ProcessesCollection`](processes::ProcessesCollection), but that interprets\n/// the extrinsic calls and keeps track of the state in which pending threads are in.\n///\n/// The generic parameters `TPud` and `TTud` are \"user data\"s that are stored respectively per\n/// process and per thread, and allows the user to put extra information associated to a process\n/// or a thread.\npub struct ProcessesCollectionExtrinsics<TPud, TTud, TExt: Extrinsics> {\n    inner: processes::ProcessesCollection<\n        Extrinsic<TExt::ExtrinsicId>,\n        LocalProcessUserData<TPud, TExt>,\n        LocalThreadUserData<TTud, TExt::Context>,\n    >,\n\n    /// List of threads that `inner` considers \"interrupted\" but that we expose as \"ready\". We\n    /// have to process the external extrinsics for this thread.\n    ///\n    /// The threads here must always be in the [`LocalThreadState::OtherExtrinsicApplyAction`]\n    /// or the [`LocalThreadState::OtherExtrinsicReportWait`] state.\n    // TODO: we have to notify wakers when we push an element\n    local_run_queue: SegQueue<ThreadId>,\n}\n\n/// Prototype for a `ProcessesCollectionExtrinsics` under construction.\npub struct Builder<TExt: Extrinsics> {\n    inner: processes::ProcessesCollectionBuilder<Extrinsic<TExt::ExtrinsicId>>,\n}\n\n/// Access to a process within the collection.\npub struct ProcAccess<'a, TPud, TTud, TExt: Extrinsics> {\n    parent: &'a ProcessesCollectionExtrinsics<TPud, TTud, TExt>,\n    inner: processes::ProcAccess<\n        'a,\n        Extrinsic<TExt::ExtrinsicId>,\n        LocalProcessUserData<TPud, TExt>,\n        LocalThreadUserData<TTud, TExt::Context>,\n    >,\n}\n\n/// Access to a thread within the collection that is in an interrupted state.\n///\n/// Implements the [`ThreadAccessAccess`] trait.\npub enum ThreadAccess<'a, TPud, TTud, TExt: Extrinsics> {\n    EmitMessage(ThreadEmitMessage<'a, TPud, TTud, TExt>),\n    WaitNotification(ThreadWaitNotif<'a, TPud, TTud, TExt>),\n}\n\n/// Access to a thread within the collection.\n///\n/// Implements the [`ThreadAccessAccess`] trait.\npub struct ThreadEmitMessage<'a, TPud, TTud, TExt: Extrinsics> {\n    process: ProcAccess<'a, TPud, TTud, TExt>,\n    inner: processes::ThreadAccess<\n        'a,\n        Extrinsic<TExt::ExtrinsicId>,\n        LocalProcessUserData<TPud, TExt>,\n        LocalThreadUserData<TTud, TExt::Context>,\n    >,\n}\n\n/// Access to a thread within the collection.\n///\n/// Implements the [`ThreadAccessAccess`] trait.\npub struct ThreadWaitNotif<'a, TPud, TTud, TExt: Extrinsics> {\n    process: ProcAccess<'a, TPud, TTud, TExt>,\n    inner: processes::ThreadAccess<\n        'a,\n        Extrinsic<TExt::ExtrinsicId>,\n        LocalProcessUserData<TPud, TExt>,\n        LocalThreadUserData<TTud, TExt::Context>,\n    >,\n}\n\n/// Common trait amongst all the thread accessor structs.\npub trait ThreadAccessAccess<'a> {\n    type ProcessUserData;\n    type ThreadUserData;\n\n    // TODO: make it return handle to process instead?\n\n    /// Returns the id of the thread. Allows later retrieval by calling\n    /// [`interrupted_thread_by_id`](ProcessesCollectionExtrinsics::interrupted_thread_by_id).\n    ///\n    /// [`ThreadId`]s are unique within a [`ProcessesCollectionExtrinsics`], independently from the\n    /// process.\n    fn tid(&self) -> ThreadId;\n\n    /// Returns the [`Pid`] of the process. Allows later retrieval by calling\n    /// [`process_by_id`](ProcessesCollectionExtrinsics::process_by_id).\n    fn pid(&self) -> Pid;\n\n    /// Returns the user data that is associated to the process.\n    fn process_user_data(&self) -> &Self::ProcessUserData;\n\n    /// Returns the user data that is associated to the thread.\n    fn user_data(&mut self) -> &mut Self::ThreadUserData;\n}\n\n/// Error that can happen when calling `interrupted_thread_by_id`.\n#[derive(Debug)]\npub enum ThreadByIdErr {\n    /// Thread is either running, waiting to be run, dead, or has never existed.\n    RunningOrDead,\n    /// Thread is already locked.\n    AlreadyLocked,\n}\n\n/// Possible function available to processes.\n#[derive(Debug, Clone, PartialEq, Eq)]\nenum Extrinsic<TExtId> {\n    NextMessage,\n    EmitMessage,\n    CancelMessage,\n    Other(TExtId),\n}\n\n/// Structure passed to the underlying [`processes::ProcessesCollection`] that tracks the state\n/// of a process.\n#[derive(Debug)]\nstruct LocalProcessUserData<TPud, TExt> {\n    /// User data decided by the user.\n    external_user_data: TPud,\n    /// Extrinsics supported by the process.\n    extrinsics: TExt,\n}\n\n/// Structure passed to the underlying [`processes::ProcessesCollection`] that tracks the state\n/// of a thread.\n#[derive(Debug)]\nstruct LocalThreadUserData<TTud, TExtCtxt> {\n    /// State of a thread.\n    state: LocalThreadState<TExtCtxt>,\n    /// User data decided by the user. When the thread is locked, this user data is extracted\n    /// and stored locally in the lock. The data is put back when the thread is unlocked.\n    external_user_data: TTud,\n}\n\n/// State of a thread. Private. Stored within the [`processes::ProcessesCollection`].\n#[derive(Debug)]\nenum LocalThreadState<TExtCtxt> {\n    /// Thread is ready to run, running, has just called an extrinsic and the call is being\n    /// processed, or has deliberately been put in limbo before the process is being aborted.\n    ReadyToRun,\n\n    /// Thread is in the middle of a non-hardcoded extrinsic. We now need to apply the given\n    /// action on the context.\n    ///\n    /// Threads in this state must be pushed to [`ProcessesCollectionExtrinsics::local_run_queue`].\n    OtherExtrinsicApplyAction {\n        /// Abstract context used to drive the extrinsic call.\n        context: TExtCtxt,\n        /// Action to perform.\n        action: ExtrinsicsAction,\n    },\n\n    /// Thread is running a non-hardcoded extrinsic that wants to emit a message.\n    OtherExtrinsicEmit {\n        /// Abstract context used to drive the extrinsic call.\n        context: TExtCtxt,\n        /// Interface to emit the message on.\n        interface: InterfaceHash,\n        /// Message to emit.\n        message: EncodedMessage,\n        /// True if a message is expected.\n        response_expected: bool,\n    },\n\n    /// Thread must be reported as a waiting thread through the API, then transition to\n    /// [`LocalThreadState::OtherExtrinsicWait`].\n    OtherExtrinsicReportWait {\n        /// Abstract context used to drive the extrinsic call.\n        context: TExtCtxt,\n        /// Message for which we are awaiting a response.\n        message: MessageId,\n    },\n\n    /// Thread is running a non-hardcoded extrinsic waiting for a response.\n    OtherExtrinsicWait {\n        /// Abstract context used to drive the extrinsic call.\n        context: TExtCtxt,\n        /// Message for which we are awaiting a response.\n        message: MessageId,\n    },\n\n    /// The thread is sleeping and waiting for a notification to come.\n    NotificationWait(calls::NotificationWait),\n\n    /// The thread called `emit_message` and wants to emit a message on an interface.\n    EmitMessage(calls::EmitMessage),\n\n    /// Temporary state while we move things around. If encountered unexpectedly, that indicates\n    /// a bug in the code.\n    Poisoned,\n}\n\n/// Event returned by [`ProcessesCollectionExtrinsics::run`].\npub enum ExecuteOut<'a, TPud, TTud, TExt: Extrinsics> {\n    /// Event directly generated.\n    Direct(RunOneOutcome<'a, TPud, TTud, TExt>),\n    /// Ready to execute a bit of a thread.\n    ReadyToRun(ReadyToRun<'a, TPud, TTud, TExt>),\n}\n\n/// Ready to resume one of the threads of a process.\n#[must_use]\npub struct ReadyToRun<'a, TPud, TTud, TExt: Extrinsics> {\n    collection: &'a ProcessesCollectionExtrinsics<TPud, TTud, TExt>,\n    inner: processes::ReadyToRun<\n        'a,\n        Extrinsic<TExt::ExtrinsicId>,\n        LocalProcessUserData<TPud, TExt>,\n        LocalThreadUserData<TTud, TExt::Context>,\n    >,\n}\n\nimpl<'a, TPud, TTud, TExt: Extrinsics> ReadyToRun<'a, TPud, TTud, TExt> {\n    /// Performs the actual execution.\n    ///\n    /// Returns `None` if the execution doesn't lead to any event in particular.\n    pub fn run(mut self) -> Option<RunOneOutcome<'a, TPud, TTud, TExt>> {\n        self.collection.inner_event(self.inner.run())\n    }\n}\n\n/// Outcome of the [`run`](ProcessesCollectionExtrinsics::run) function.\n#[derive(Debug)]\npub enum RunOneOutcome<'a, TPud, TTud, TExt: Extrinsics> {\n    /// Either the main thread of a process has finished, or a fatal error was encountered.\n    ///\n    /// The process no longer exists.\n    ProcessFinished {\n        /// Pid of the process that has finished.\n        pid: Pid,\n\n        /// User data of the process.\n        user_data: TPud,\n\n        /// Id and user datas of all the threads of the process. The first element is the main\n        /// thread's.\n        /// These threads no longer exist.\n        dead_threads: Vec<(ThreadId, TTud)>,\n\n        /// Value returned by the main thread that has finished, or error that happened.\n        outcome: Result<Option<crate::WasmValue>, Trap>,\n    },\n\n    /// A thread in a process has finished.\n    ThreadFinished {\n        /// Thread which has finished.\n        thread_id: ThreadId,\n\n        /// Process whose thread has finished.\n        process: ProcAccess<'a, TPud, TTud, TExt>,\n\n        /// User data of the thread.\n        user_data: TTud,\n\n        /// Value returned by the function that was executed.\n        value: Option<crate::WasmValue>,\n    },\n\n    /// A thread in a process wants to emit a message.\n    ThreadEmitMessage(ThreadEmitMessage<'a, TPud, TTud, TExt>),\n\n    /// A thread in a process is waiting for an incoming message.\n    ThreadWaitNotification(ThreadWaitNotif<'a, TPud, TTud, TExt>),\n\n    /// A thread in a process wants to notify that a message is to be cancelled.\n    ThreadCancelMessage {\n        /// Thread that wants to emit a cancellation.\n        thread_id: ThreadId,\n\n        /// Process that the thread belongs to.\n        process: ProcAccess<'a, TPud, TTud, TExt>,\n\n        /// Message that must be cancelled.\n        message_id: MessageId,\n    },\n}\n\nimpl<TPud, TTud, TExt> ProcessesCollectionExtrinsics<TPud, TTud, TExt>\nwhere\n    TExt: Extrinsics,\n{\n    /// Creates a new process state machine from the given module.\n    ///\n    /// The closure is called for each import that the module has. It must assign a number to each\n    /// import, or return an error if the import can't be resolved. When the VM calls one of these\n    /// functions, this number will be returned back in order for the user to know how to handle\n    /// the call.\n    ///\n    /// A single main thread (whose user data is passed by parameter) is automatically created and\n    /// is paused at the start of the \"_start\" function of the module.\n    pub fn execute(\n        &self,\n        module: &[u8],\n        proc_user_data: TPud,\n        main_thread_user_data: TTud,\n    ) -> Result<(ProcAccess<TPud, TTud, TExt>, ThreadId), vm::NewErr> {\n        let proc_user_data = LocalProcessUserData {\n            extrinsics: Default::default(),\n            external_user_data: proc_user_data,\n        };\n        let main_thread_user_data = LocalThreadUserData {\n            state: LocalThreadState::ReadyToRun,\n            external_user_data: main_thread_user_data,\n        };\n        let (inner, main_tid) =\n            self.inner\n                .execute(module, proc_user_data, main_thread_user_data)?;\n        Ok((\n            ProcAccess {\n                parent: self,\n                inner,\n            },\n            main_tid,\n        ))\n    }\n\n    /// Runs one thread amongst the collection.\n    ///\n    /// Which thread is run is implementation-defined and no guarantee is made.\n    pub async fn run<'a>(&'a self) -> ExecuteOut<'a, TPud, TTud, TExt> {\n        loop {\n            while let Some(tid) = self.local_run_queue.pop() {\n                // It is possible that the thread no longer exists, for example if the process crashed.\n                let mut thread = match self.inner.interrupted_thread_by_id(tid) {\n                    Some(t) => t,\n                    None => continue,\n                };\n\n                match mem::replace(\n                    &mut thread.user_data_mut().state,\n                    LocalThreadState::Poisoned,\n                ) {\n                    LocalThreadState::OtherExtrinsicReportWait { context, message } => {\n                        thread.user_data_mut().state =\n                            LocalThreadState::OtherExtrinsicWait { context, message };\n                        let process = ProcAccess {\n                            parent: self,\n                            inner: thread.process(),\n                        };\n                        return ExecuteOut::Direct(RunOneOutcome::ThreadWaitNotification(\n                            ThreadWaitNotif {\n                                process,\n                                inner: thread,\n                            },\n                        ));\n                    }\n                    LocalThreadState::OtherExtrinsicApplyAction { context, action } => match action\n                    {\n                        ExtrinsicsAction::ProgramCrash => unimplemented!(),\n                        ExtrinsicsAction::Resume(value) => {\n                            thread.user_data_mut().state = LocalThreadState::ReadyToRun;\n                            thread.resume(value)\n                        }\n                        ExtrinsicsAction::EmitMessage {\n                            interface,\n                            message,\n                            response_expected,\n                        } => {\n                            thread.user_data_mut().state = LocalThreadState::OtherExtrinsicEmit {\n                                context,\n                                interface,\n                                message,\n                                response_expected,\n                            };\n                            let process = ProcAccess {\n                                parent: self,\n                                inner: thread.process(),\n                            };\n                            return ExecuteOut::Direct(RunOneOutcome::ThreadEmitMessage(\n                                ThreadEmitMessage {\n                                    process,\n                                    inner: thread,\n                                },\n                            ));\n                        }\n                    },\n                    _ => unreachable!(),\n                }\n            }\n\n            match self.inner.run().await {\n                processes::RunFutureOut::Direct(ev) => {\n                    if let Some(ev) = self.inner_event(ev) {\n                        return ExecuteOut::Direct(ev);\n                    }\n                }\n                processes::RunFutureOut::ReadyToRun(inner) => {\n                    return ExecuteOut::ReadyToRun(ReadyToRun {\n                        collection: self,\n                        inner,\n                    })\n                }\n            }\n        }\n    }\n\n    fn inner_event<'a>(\n        &'a self,\n        mut outcome: processes::RunOneOutcome<\n            'a,\n            Extrinsic<TExt::ExtrinsicId>,\n            LocalProcessUserData<TPud, TExt>,\n            LocalThreadUserData<TTud, TExt::Context>,\n        >,\n    ) -> Option<RunOneOutcome<'a, TPud, TTud, TExt>> {\n        match outcome {\n            processes::RunOneOutcome::ProcessFinished {\n                pid,\n                user_data,\n                dead_threads,\n                outcome,\n            } => {\n                Some(RunOneOutcome::ProcessFinished {\n                    pid,\n                    user_data: user_data.external_user_data,\n                    dead_threads: dead_threads\n                        .into_iter()\n                        .map(|(id, state)| (id, state.external_user_data))\n                        .collect(), // TODO: meh for allocation\n                    outcome,\n                })\n            }\n\n            processes::RunOneOutcome::StartProcessAbort { .. } => None,\n\n            processes::RunOneOutcome::ThreadFinished {\n                process,\n                user_data,\n                value,\n                thread_id,\n            } => {\n                debug_assert!(user_data.state.is_ready_to_run());\n                Some(RunOneOutcome::ThreadFinished {\n                    thread_id,\n                    process: ProcAccess {\n                        parent: self,\n                        inner: process,\n                    },\n                    user_data: user_data.external_user_data,\n                    value,\n                })\n            }\n\n            processes::RunOneOutcome::Interrupted {\n                mut thread,\n                id: Extrinsic::NextMessage,\n                params,\n            } => {\n                debug_assert!(thread.user_data().state.is_ready_to_run());\n                match calls::parse_extrinsic_next_notification(&mut thread, params) {\n                    Ok(next_msg) => {\n                        thread.user_data_mut().state = LocalThreadState::NotificationWait(next_msg);\n                        let process = ProcAccess {\n                            parent: self,\n                            inner: thread.process(),\n                        };\n                        Some(RunOneOutcome::ThreadWaitNotification(ThreadWaitNotif {\n                            process,\n                            inner: thread,\n                        }))\n                    }\n                    Err(_) => {\n                        thread.process().abort();\n                        None\n                    }\n                }\n            }\n\n            processes::RunOneOutcome::Interrupted {\n                mut thread,\n                id: Extrinsic::EmitMessage,\n                params,\n            } => {\n                debug_assert!(thread.user_data().state.is_ready_to_run());\n                match calls::parse_extrinsic_emit_message(&mut thread, params) {\n                    Ok(emit_msg) => {\n                        thread.user_data_mut().state = LocalThreadState::EmitMessage(emit_msg);\n                        let process = ProcAccess {\n                            parent: self,\n                            inner: thread.process(),\n                        };\n                        Some(RunOneOutcome::ThreadEmitMessage(ThreadEmitMessage {\n                            process,\n                            inner: thread,\n                        }))\n                    }\n                    Err(_) => {\n                        thread.process().abort();\n                        None\n                    }\n                }\n            }\n\n            processes::RunOneOutcome::Interrupted {\n                mut thread,\n                id: Extrinsic::CancelMessage,\n                params,\n            } => {\n                debug_assert!(thread.user_data().state.is_ready_to_run());\n                match calls::parse_extrinsic_cancel_message(&mut thread, params) {\n                    Ok(emit_cancel) => {\n                        let process = thread.process();\n                        let thread_id = thread.tid();\n                        thread.resume(None);\n                        Some(RunOneOutcome::ThreadCancelMessage {\n                            process: ProcAccess {\n                                parent: self,\n                                inner: process,\n                            },\n                            thread_id,\n                            message_id: emit_cancel,\n                        })\n                    }\n                    Err(_) => {\n                        thread.process().abort();\n                        None\n                    }\n                }\n            }\n\n            processes::RunOneOutcome::Interrupted {\n                ref mut thread,\n                id: Extrinsic::Other(ext_id),\n                ref params,\n            } => {\n                debug_assert!(thread.user_data().state.is_ready_to_run());\n                let thread_id = thread.tid();\n                let (context, action) = thread.process().user_data().extrinsics.new_context(\n                    thread_id,\n                    ext_id,\n                    params.iter().cloned(),\n                    &mut MemoryAccessImpl(thread),\n                );\n                thread.user_data_mut().state =\n                    LocalThreadState::OtherExtrinsicApplyAction { context, action };\n                self.local_run_queue.push(thread_id);\n                None\n            }\n        }\n    }\n\n    /// Returns a process by its [`Pid`], if it exists.\n    ///\n    /// This function returns a \"lock\".\n    /// While the lock is held, it isn't possible for a [`RunOneOutcome::ProcessFinished`]\n    /// message to be returned.\n    ///\n    /// If a program crashes or finishes while a lock is held, it is marked as dying and the\n    /// termination is delayed until the point when all locks have been released.\n    pub fn process_by_id(&self, pid: Pid) -> Option<ProcAccess<TPud, TTud, TExt>> {\n        Some(ProcAccess {\n            parent: self,\n            inner: self.inner.process_by_id(pid)?,\n        })\n    }\n\n    /// Returns a thread by its [`ThreadId`], if it exists and is not running.\n    ///\n    /// It is only possible to access threads that aren't currently running.\n    ///\n    /// This function returns a \"lock\".\n    /// Calling `interrupted_thread_by_id` again on the same thread will return\n    /// `Err(ThreadByIdErr::AlreadyLocked)`.\n    ///\n    /// This lock is also implicitely a lock against the process that owns the thread.\n    /// See [`ProcessesCollectionExtrinsics::process_by_id`].\n    pub fn interrupted_thread_by_id(\n        &self,\n        id: ThreadId,\n    ) -> Result<ThreadAccess<TPud, TTud, TExt>, ThreadByIdErr> {\n        let inner = self\n            .inner\n            .interrupted_thread_by_id(id)\n            .ok_or(ThreadByIdErr::RunningOrDead)?;\n\n        match inner.user_data().state {\n            LocalThreadState::ReadyToRun => {\n                // TODO: I'm a bit tired while writing this and not sure that's correct\n                unreachable!()\n            }\n            LocalThreadState::OtherExtrinsicApplyAction { .. }\n            | LocalThreadState::OtherExtrinsicReportWait { .. } => {\n                Err(ThreadByIdErr::RunningOrDead)\n            }\n            LocalThreadState::EmitMessage(_) | LocalThreadState::OtherExtrinsicEmit { .. } => {\n                let process = ProcAccess {\n                    parent: self,\n                    inner: inner.process(),\n                };\n                Ok(From::from(ThreadEmitMessage { process, inner }))\n            }\n            LocalThreadState::NotificationWait(_) | LocalThreadState::OtherExtrinsicWait { .. } => {\n                let process = ProcAccess {\n                    parent: self,\n                    inner: inner.process(),\n                };\n                Ok(From::from(ThreadWaitNotif { process, inner }))\n            }\n            LocalThreadState::Poisoned => panic!(),\n        }\n    }\n}\n\nimpl<TExt> Builder<TExt>\nwhere\n    TExt: Extrinsics,\n{\n    /// Initializes a new builder using the given random seed.\n    ///\n    /// The seed is used in determine how [`Pid`]s are generated. The same seed will result in\n    /// the same sequence of [`Pid`]s.\n    pub fn with_seed(seed: [u8; 32]) -> Self {\n        let mut inner = processes::ProcessesCollectionBuilder::with_seed(seed)\n            .with_extrinsic(\n                \"redshirt\",\n                \"next_notification\",\n                sig!((I32, I32, I32, I32, I64) -> I32),\n                Extrinsic::NextMessage,\n            )\n            .with_extrinsic(\n                \"redshirt\",\n                \"emit_message\",\n                sig!((I32, I32, I32, I64, I32) -> I32),\n                Extrinsic::EmitMessage,\n            )\n            .with_extrinsic(\n                \"redshirt\",\n                \"cancel_message\",\n                sig!((I32)),\n                Extrinsic::CancelMessage,\n            );\n\n        for supported in TExt::supported_extrinsics() {\n            inner = inner.with_extrinsic(\n                supported.wasm_interface,\n                supported.function_name,\n                supported.signature,\n                Extrinsic::Other(supported.id),\n            );\n        }\n\n        Builder { inner }\n    }\n\n    /// Allocates a `Pid` that will not be used by any process.\n    ///\n    /// > **Note**: As of the writing of this comment, this feature is only ever used to allocate\n    /// >           `Pid`s that last forever. There is therefore no corresponding \"unreserve_pid\"\n    /// >           method that frees such an allocated `Pid`. If there is ever a need to free\n    /// >           these `Pid`s, such a method should be added.\n    pub fn reserve_pid(&mut self) -> Pid {\n        self.inner.reserve_pid()\n    }\n\n    /// Turns the builder into a [`ProcessesCollectionExtrinsics`].\n    pub fn build<TPud, TTud>(self) -> ProcessesCollectionExtrinsics<TPud, TTud, TExt> {\n        ProcessesCollectionExtrinsics {\n            inner: self.inner.build(),\n            local_run_queue: SegQueue::new(),\n        }\n    }\n}\n\nimpl<'a, TPud, TTud, TExt> ProcAccess<'a, TPud, TTud, TExt>\nwhere\n    TExt: Extrinsics,\n{\n    /// Returns the [`Pid`] of the process. Allows later retrieval by calling\n    /// [`process_by_id`](ProcessesCollectionExtrinsics::process_by_id).\n    pub fn pid(&self) -> Pid {\n        self.inner.pid()\n    }\n\n    /// Returns the user data that is associated to the process.\n    pub fn user_data(&self) -> &TPud {\n        &self.inner.user_data().external_user_data\n    }\n\n    /// Adds a new thread to the process, starting the function with the given index and passing\n    /// the given parameters.\n    ///\n    /// > **Note**: The \"function ID\" is the index of the function in the WASM module. WASM\n    /// >           doesn't have function pointers. Instead, all the functions are part of a single\n    /// >           global array of functions.\n    pub fn start_thread(\n        &self,\n        fn_index: u32,\n        params: Vec<crate::WasmValue>,\n        user_data: TTud,\n    ) -> Result<ThreadId, vm::ThreadStartErr> {\n        self.inner.start_thread(\n            fn_index,\n            params,\n            LocalThreadUserData {\n                state: LocalThreadState::ReadyToRun,\n                external_user_data: user_data,\n            },\n        )\n    }\n\n    /// Marks the process as aborting.\n    ///\n    /// The termination will happen after all locks to this process have been released.\n    ///\n    /// Calling [`abort`](ProcAccess::abort) a second time or more has no\n    /// effect.\n    pub fn abort(&self) {\n        self.inner.abort();\n    }\n}\n\nimpl<'a, TPud, TTud, TExt> fmt::Debug for ProcAccess<'a, TPud, TTud, TExt>\nwhere\n    TExt: Extrinsics + fmt::Debug,\n    TPud: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        fmt::Debug::fmt(&self.inner, f)\n    }\n}\n\nimpl<'a, TPud, TTud, TExt: Extrinsics> From<ThreadEmitMessage<'a, TPud, TTud, TExt>>\n    for ThreadAccess<'a, TPud, TTud, TExt>\n{\n    fn from(thread: ThreadEmitMessage<'a, TPud, TTud, TExt>) -> Self {\n        ThreadAccess::EmitMessage(thread)\n    }\n}\n\nimpl<'a, TPud, TTud, TExt: Extrinsics> From<ThreadWaitNotif<'a, TPud, TTud, TExt>>\n    for ThreadAccess<'a, TPud, TTud, TExt>\n{\n    fn from(thread: ThreadWaitNotif<'a, TPud, TTud, TExt>) -> Self {\n        ThreadAccess::WaitNotification(thread)\n    }\n}\n\nimpl<'a, TPud, TTud, TExt: Extrinsics> ThreadAccessAccess<'a>\n    for ThreadAccess<'a, TPud, TTud, TExt>\n{\n    type ProcessUserData = TPud;\n    type ThreadUserData = TTud;\n\n    fn tid(&self) -> ThreadId {\n        match self {\n            ThreadAccess::EmitMessage(t) => t.tid(),\n            ThreadAccess::WaitNotification(t) => t.tid(),\n        }\n    }\n\n    fn pid(&self) -> Pid {\n        match self {\n            ThreadAccess::EmitMessage(t) => t.pid(),\n            ThreadAccess::WaitNotification(t) => t.pid(),\n        }\n    }\n\n    fn process_user_data(&self) -> &TPud {\n        match self {\n            ThreadAccess::EmitMessage(t) => t.process_user_data(),\n            ThreadAccess::WaitNotification(t) => t.process_user_data(),\n        }\n    }\n\n    fn user_data(&mut self) -> &mut TTud {\n        match self {\n            ThreadAccess::EmitMessage(t) => t.user_data(),\n            ThreadAccess::WaitNotification(t) => t.user_data(),\n        }\n    }\n}\n\nimpl<'a, TPud, TTud, TExt> fmt::Debug for ThreadAccess<'a, TPud, TTud, TExt>\nwhere\n    TExt: Extrinsics,\n{\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            ThreadAccess::EmitMessage(t) => fmt::Debug::fmt(t, f),\n            ThreadAccess::WaitNotification(t) => fmt::Debug::fmt(t, f),\n        }\n    }\n}\n\nimpl<'a, TPud, TTud, TExt: Extrinsics> ThreadEmitMessage<'a, TPud, TTud, TExt> {\n    /// Returns true if the caller wants an answer to the message.\n    pub fn needs_answer(&mut self) -> bool {\n        match self.inner.user_data().state {\n            LocalThreadState::EmitMessage(ref emit) => emit.message_id_write.is_some(),\n            LocalThreadState::OtherExtrinsicEmit {\n                response_expected, ..\n            } => response_expected,\n            _ => unreachable!(),\n        }\n    }\n\n    /// Returns the interface to emit the message on.\n    pub fn emit_interface(&mut self) -> &InterfaceHash {\n        match self.inner.user_data().state {\n            LocalThreadState::EmitMessage(ref emit) => &emit.interface,\n            LocalThreadState::OtherExtrinsicEmit { ref interface, .. } => interface,\n            _ => unreachable!(),\n        }\n    }\n\n    /// True if the caller allows delays.\n    pub fn allow_delay(&mut self) -> bool {\n        match self.inner.user_data().state {\n            LocalThreadState::EmitMessage(ref emit) => emit.allow_delay,\n            LocalThreadState::OtherExtrinsicEmit { .. } => true,\n            _ => unreachable!(),\n        }\n    }\n\n    /// Returns the message to emit and resumes the thread.\n    ///\n    /// # Panic\n    ///\n    /// - Panics if `message_id.is_some() != thread.needs_answer()`. In other words, if\n    /// `needs_answer` is true, then you **must** provide a `MessageId`.\n    ///\n    pub fn accept_emit(mut self, message_id: Option<MessageId>) -> EncodedMessage {\n        match mem::replace(\n            &mut self.inner.user_data_mut().state,\n            LocalThreadState::Poisoned,\n        ) {\n            LocalThreadState::EmitMessage(emit) => {\n                if let Some(message_id_write) = emit.message_id_write {\n                    let message_id = match message_id {\n                        Some(m) => m,\n                        None => panic!(),\n                    };\n\n                    self.inner\n                        .write_memory(message_id_write, &u64::from(message_id).to_le_bytes())\n                        .unwrap();\n                } else {\n                    assert!(message_id.is_none());\n                }\n\n                self.inner.user_data_mut().state = LocalThreadState::ReadyToRun;\n                self.inner.resume(Some(crate::WasmValue::I32(0)));\n                emit.message\n            }\n            LocalThreadState::OtherExtrinsicEmit {\n                mut context,\n                message,\n                response_expected,\n                ..\n            } => {\n                if response_expected {\n                    let message_id = message_id.unwrap();\n                    self.inner.user_data_mut().state = LocalThreadState::OtherExtrinsicReportWait {\n                        context,\n                        message: message_id,\n                    };\n                    self.process.parent.local_run_queue.push(self.inner.tid());\n                } else {\n                    debug_assert!(message_id.is_none());\n                    let action = self\n                        .inner\n                        .process()\n                        .user_data()\n                        .extrinsics\n                        .inject_message_response(\n                            &mut context,\n                            None,\n                            &mut MemoryAccessImpl(&mut self.inner),\n                        );\n                    self.inner.user_data_mut().state =\n                        LocalThreadState::OtherExtrinsicApplyAction { context, action };\n                    self.process.parent.local_run_queue.push(self.inner.tid());\n                }\n\n                message\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    /// Resumes the thread, signalling an error in the emission.\n    pub fn refuse_emit(mut self) {\n        match mem::replace(\n            &mut self.inner.user_data_mut().state,\n            LocalThreadState::Poisoned,\n        ) {\n            LocalThreadState::EmitMessage(_) => {\n                self.inner.user_data_mut().state = LocalThreadState::ReadyToRun;\n                self.inner.resume(Some(crate::WasmValue::I32(1)));\n            }\n            LocalThreadState::OtherExtrinsicEmit { context, .. } => {\n                // TODO: don't know what else to do here than crash the program\n                self.inner.user_data_mut().state = LocalThreadState::OtherExtrinsicApplyAction {\n                    context,\n                    action: ExtrinsicsAction::ProgramCrash,\n                };\n                self.process.parent.local_run_queue.push(self.inner.tid());\n            }\n            _ => unreachable!(),\n        }\n    }\n}\n\nimpl<'a, TPud, TTud, TExt: Extrinsics> ThreadAccessAccess<'a>\n    for ThreadEmitMessage<'a, TPud, TTud, TExt>\n{\n    type ProcessUserData = TPud;\n    type ThreadUserData = TTud;\n\n    fn tid(&self) -> ThreadId {\n        self.inner.tid()\n    }\n\n    fn pid(&self) -> Pid {\n        self.inner.process().pid()\n    }\n\n    fn process_user_data(&self) -> &TPud {\n        self.process.user_data()\n    }\n\n    fn user_data(&mut self) -> &mut TTud {\n        &mut self.inner.user_data_mut().external_user_data\n    }\n}\n\nimpl<'a, TPud, TTud, TExt: Extrinsics> fmt::Debug for ThreadEmitMessage<'a, TPud, TTud, TExt> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        fmt::Debug::fmt(&self.inner, f)\n    }\n}\n\nimpl<'a, TPud, TTud, TExt: Extrinsics> ThreadWaitNotif<'a, TPud, TTud, TExt> {\n    /// Unlocks the thread and returns the process it belongs to.\n    pub fn into_process(self) -> ProcAccess<'a, TPud, TTud, TExt> {\n        self.process\n    }\n\n    /// Returns the list of notifications that the thread is waiting on. In order, and preserving\n    /// empty entries.\n    pub fn wait_entries<'b>(&'b mut self) -> impl Iterator<Item = WaitEntry> + 'b {\n        match self.inner.user_data().state {\n            LocalThreadState::NotificationWait(ref wait) => {\n                either::Either::Left(wait.notifs_ids.iter().cloned())\n            }\n            LocalThreadState::OtherExtrinsicWait { message, .. } => {\n                either::Either::Right(iter::once(WaitEntry::Answer(message)))\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    /// Returns the maximum size allowed for a notification.\n    pub fn allowed_notification_size(&self) -> usize {\n        match self.inner.user_data().state {\n            LocalThreadState::NotificationWait(ref wait) => usize::try_from(wait.out_size).unwrap(),\n            LocalThreadState::OtherExtrinsicWait { .. } => usize::max_value(),\n            _ => unreachable!(),\n        }\n    }\n\n    /// Returns true if we should block the thread waiting for a notification to come.\n    pub fn block(&self) -> bool {\n        match self.inner.user_data().state {\n            LocalThreadState::NotificationWait(ref wait) => wait.block,\n            LocalThreadState::OtherExtrinsicWait { .. } => true,\n            _ => unreachable!(),\n        }\n    }\n\n    /// Resume the thread, sending back a notification.\n    ///\n    /// `index` must be the index within the list returned by\n    /// [`wait_entries`](ThreadWaitNotif::wait_entries).\n    ///\n    /// # Panic\n    ///\n    /// - Panics if the notification is too large. You should make sure this is not the case before\n    /// calling this function.\n    /// - Panics if `index` is too large.\n    ///\n    pub fn resume_notification(mut self, index: usize, notif: EncodedMessage) {\n        match mem::replace(\n            &mut self.inner.user_data_mut().state,\n            LocalThreadState::Poisoned,\n        ) {\n            LocalThreadState::NotificationWait(wait) => {\n                debug_assert!(index < wait.notifs_ids.len());\n                assert_ne!(wait.notifs_ids[index], WaitEntry::Empty);\n                let notif_size_u32 = u32::try_from(notif.0.len()).unwrap();\n                assert!(wait.out_size >= notif_size_u32);\n\n                self.inner.user_data_mut().state = LocalThreadState::ReadyToRun;\n\n                // Write the notification in the process's memory.\n                match self.inner.write_memory(wait.out_pointer, &notif.0) {\n                    Ok(()) => {}\n                    Err(_) => {\n                        self.inner.process().abort();\n                        return;\n                    }\n                };\n\n                // Zero the corresponding entry in the notifications to wait upon.\n                match self.inner.write_memory(\n                    wait.notifs_ids_ptr + u32::try_from(index).unwrap() * 8,\n                    &[0; 8],\n                ) {\n                    Ok(()) => {}\n                    Err(_) => {\n                        self.inner.process().abort();\n                        return;\n                    }\n                };\n\n                self.inner.resume(Some(crate::WasmValue::I32(\n                    i32::try_from(notif_size_u32).unwrap(),\n                )));\n            }\n            LocalThreadState::OtherExtrinsicWait { mut context, .. } => {\n                // TODO: the way this is handled is clearly not great; the API of this method\n                // should be improved\n                let decoded = redshirt_syscalls::ffi::decode_notification(&notif.0).unwrap();\n                let message = decoded.actual_data.unwrap();\n\n                assert_eq!(index, 0);\n                let action = self\n                    .inner\n                    .process()\n                    .user_data()\n                    .extrinsics\n                    .inject_message_response(\n                        &mut context,\n                        Some(message),\n                        &mut MemoryAccessImpl(&mut self.inner),\n                    );\n                self.inner.user_data_mut().state =\n                    LocalThreadState::OtherExtrinsicApplyAction { context, action };\n                self.process.parent.local_run_queue.push(self.inner.tid());\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    /// Resume the thread, indicating that the notification is too large for the provided buffer.\n    pub fn resume_notification_too_big(mut self, notif_size: usize) {\n        debug_assert!({\n            let expected = match &mut self.inner.user_data_mut().state {\n                LocalThreadState::NotificationWait(wait) => wait.out_size,\n                LocalThreadState::OtherExtrinsicWait { .. } => panic!(),\n                _ => unreachable!(),\n            };\n            expected < u32::try_from(notif_size).unwrap()\n        });\n\n        self.inner.user_data_mut().state = LocalThreadState::ReadyToRun;\n        self.inner.resume(Some(crate::WasmValue::I32(\n            i32::try_from(notif_size).unwrap(),\n        )));\n    }\n\n    /// Resume the thread, indicating that no notification is available.\n    ///\n    /// # Panic\n    ///\n    /// - Panics if [`block`](ThreadWaitNotif::block) would\n    /// return `true`.\n    ///\n    pub fn resume_no_notification(mut self) {\n        match self.inner.user_data().state {\n            LocalThreadState::NotificationWait(ref wait) => assert!(!wait.block),\n            LocalThreadState::OtherExtrinsicWait { .. } => panic!(),\n            _ => unreachable!(),\n        }\n\n        self.inner.user_data_mut().state = LocalThreadState::ReadyToRun;\n        self.inner.resume(Some(crate::WasmValue::I32(0)));\n    }\n}\n\nimpl<'a, TPud, TTud, TExt: Extrinsics> ThreadAccessAccess<'a>\n    for ThreadWaitNotif<'a, TPud, TTud, TExt>\n{\n    type ProcessUserData = TPud;\n    type ThreadUserData = TTud;\n\n    fn tid(&self) -> ThreadId {\n        self.inner.tid()\n    }\n\n    fn pid(&self) -> Pid {\n        self.inner.process().pid()\n    }\n\n    fn process_user_data(&self) -> &TPud {\n        self.process.user_data()\n    }\n\n    fn user_data(&mut self) -> &mut TTud {\n        &mut self.inner.user_data_mut().external_user_data\n    }\n}\n\nimpl<'a, TPud, TTud, TExt: Extrinsics> fmt::Debug for ThreadWaitNotif<'a, TPud, TTud, TExt> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        fmt::Debug::fmt(&self.inner, f)\n    }\n}\n\nimpl<TExtCtxt> LocalThreadState<TExtCtxt> {\n    /// True if `self` is equal to [`LocalThreadState::ReadyToRun`].\n    fn is_ready_to_run(&self) -> bool {\n        match self {\n            LocalThreadState::ReadyToRun => true,\n            _ => false,\n        }\n    }\n}\n\n/// Implementation of the [`ExtrinsicsMemoryAccess`] trait for a process.\nstruct MemoryAccessImpl<'a, 'b, TExtr, TPud, TTud>(\n    &'a mut processes::ThreadAccess<'b, TExtr, TPud, TTud>,\n);\n\nimpl<'a, 'b, TExtr, TPud, TTud> ExtrinsicsMemoryAccess\n    for MemoryAccessImpl<'a, 'b, TExtr, TPud, TTud>\n{\n    fn read_memory(&self, range: Range<u32>) -> Result<Vec<u8>, ExtrinsicsMemoryAccessErr> {\n        self.0\n            .read_memory(range.start, range.end.checked_sub(range.start).unwrap())\n            .map_err(|processes::OutOfBoundsError| ExtrinsicsMemoryAccessErr::OutOfRange)\n    }\n\n    fn write_memory(&mut self, offset: u32, data: &[u8]) -> Result<(), ExtrinsicsMemoryAccessErr> {\n        self.0\n            .write_memory(offset, data)\n            .map_err(|processes::OutOfBoundsError| ExtrinsicsMemoryAccessErr::OutOfRange)\n    }\n}\n"
  },
  {
    "path": "kernel/core/src/scheduler/ipc/notifications_queue.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::scheduler::extrinsics::WaitEntry;\nuse crate::{EncodedMessage, MessageId};\n\nuse core::convert::TryFrom as _;\nuse hashbrown::HashMap;\nuse redshirt_syscalls::ffi::NotificationBuilder;\nuse spinning_top::{guard::SpinlockGuard, Spinlock};\n\n/// Queue of notifications waiting to be delivered.\n///\n/// One instance of this struct exists for each alive process.\n#[derive(Debug)]\npub struct NotificationsQueue {\n    // TODO: baka Mutex\n    guarded: Spinlock<Guarded>,\n}\n\n#[derive(Debug)]\nstruct Guarded {\n    /// The actual list.\n    ///\n    /// The [`DecodedNotificationRef::index_in_list`](redshirt_syscalls::ffi::DecodedNotificationRef::index_in_list)\n    /// field is set to a dummy value, and will be filled before actually delivering the\n    /// notification.\n    queue: HashMap<MessageId, NotificationBuilder, nohash_hasher::BuildNoHashHasher<u64>>,\n\n    /// Total number of notifications that have been pushed in the notifications queue.\n    total_notifications_pushed: u64,\n}\n\n/// An entry in the notifications queue.\n#[must_use]\npub struct Entry<'a> {\n    guarded: SpinlockGuard<'a, Guarded>,\n    message_id: MessageId,\n    /// Index within the list that was passed as parameter to [`NotificationsQueue::find`].\n    index_in_msg_ids: usize,\n}\n\nimpl NotificationsQueue {\n    /// Builds a new empty queue.\n    pub fn new() -> NotificationsQueue {\n        NotificationsQueue {\n            guarded: Spinlock::new(Guarded {\n                queue: Default::default(), // TODO: capacity?\n                total_notifications_pushed: 0,\n            }),\n        }\n    }\n\n    /// Returns the total number of notifications that have been pushed to this queue.\n    pub fn total_notifications_pushed(&self) -> u64 {\n        self.guarded.lock().total_notifications_pushed\n    }\n\n    /// Pushes a notification at the end of the queue.\n    pub fn push(&self, message_id: MessageId, response: Result<EncodedMessage, ()>) {\n        let notif = redshirt_syscalls::ffi::build_notification(\n            message_id,\n            // We use a dummy value here and fill it up later when actually delivering the notif.\n            0,\n            match &response {\n                Ok(r) => Ok(From::from(r)),\n                Err(()) => Err(()),\n            },\n        );\n\n        let mut lock = self.guarded.lock();\n        lock.queue.insert(message_id, From::from(notif));\n        lock.total_notifications_pushed += 1;\n    }\n\n    /// Finds a notification in the list that matches the given indices.\n    ///\n    /// If an entry is found, its corresponding index within `indices` is stored in the returned\n    /// `Entry`.\n    // TODO: O(n) complexity!\n    pub fn find<'a>(&self, indices: impl IntoIterator<Item = &'a WaitEntry>) -> Option<Entry> {\n        let notifications_queue = self.guarded.lock();\n\n        let (index_in_msg_ids, message_id) = {\n            indices\n                .into_iter()\n                .enumerate()\n                .filter_map(|(n, e)| match e {\n                    WaitEntry::Answer(id) => Some((n, *id)),\n                    WaitEntry::Empty => None,\n                })\n                .find(|(_, id)| notifications_queue.queue.contains_key(id))?\n        };\n\n        Some(Entry {\n            guarded: notifications_queue,\n            message_id,\n            index_in_msg_ids,\n        })\n    }\n}\n\nimpl<'a> Entry<'a> {\n    /// Returns the size in bytes of the notification.\n    pub fn size(&self) -> usize {\n        self.guarded.queue.get(&self.message_id).unwrap().len()\n    }\n\n    // TODO: better method name and doc\n    pub fn index_in_msg_ids(&self) -> usize {\n        self.index_in_msg_ids\n    }\n\n    // TODO: shouldn't be an `EncodedMessage`, that's wrong\n    pub fn extract(mut self) -> EncodedMessage {\n        let mut notification = self.guarded.queue.remove(&self.message_id).unwrap();\n\n        // Some heuristics in order to reduce memory consumption.\n        if self.guarded.queue.capacity() >= 256\n            && self.guarded.queue.len() < self.guarded.queue.capacity() / 10\n        {\n            self.guarded.queue.shrink_to_fit();\n        }\n\n        notification.set_index_in_list(u32::try_from(self.index_in_msg_ids).unwrap());\n        EncodedMessage(notification.into_bytes())\n    }\n}\n"
  },
  {
    "path": "kernel/core/src/scheduler/ipc/waiting_threads.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! The [`WaitingThreads`] struct contains a list of threads waiting for notifications to come.\n//!\n//! Threads can be added to the list using [`WaitingThreads::push`].\n//!\n//! When a notification is added to the queue (which is outside the scope of this module), one\n//! must go through each thread of this list and check whether it can be waken up.\n//! The tricky part is that new notifications can continue being pushed while we check the list\n//! of threads for wake-ups.\n//!\n//! In the simple single-threaded situation, call [`WaitingThreads::access`] in order to start\n//! iterating over the list. Each thread of the list is returned one by one and can be removed\n//! with [`Entry::remove`].\n//!\n//! In the situation where multiple threads are iterating the list at the same time, the iteration\n//! will be shared between the multiple threads. In other words, each thread of the list will be\n//! generated only by one of the iterators.\n//!\n//! If [`WaitingThreads::access`] is called while another thread is already iterating, all the\n//! threads that have already been checked will be checked again.\n\nuse crate::ThreadId;\n\nuse alloc::{collections::VecDeque, vec::Vec};\nuse core::iter;\nuse spinning_top::Spinlock;\n\n/// List of threads waiting for notifications.\n#[derive(Debug)]\npub struct WaitingThreads {\n    inner: Spinlock<WaitingThreadsInner>,\n}\n\n#[derive(Debug)]\nstruct WaitingThreadsInner {\n    // TODO: call shrink_to_fit from time to time\n    full_list: VecDeque<ThreadId>,\n    checks_remaining: VecDeque<ThreadId>,\n    current_checks: Vec<ThreadId>,\n}\n\n/// An entry in the notifications queue.\n#[must_use]\npub struct Entry<'a> {\n    waiting_threads: &'a WaitingThreads,\n    thread_id: ThreadId,\n}\n\nimpl WaitingThreads {\n    /// Builds a new empty list.\n    pub fn new() -> WaitingThreads {\n        WaitingThreads {\n            inner: Spinlock::new(WaitingThreadsInner {\n                full_list: VecDeque::new(),\n                checks_remaining: VecDeque::new(),\n                current_checks: Vec::new(),\n            }),\n        }\n    }\n\n    /// Adds an element to the list. Will be added to any current iteration if active.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the element was already in the list.\n    pub fn push(&self, thread_id: ThreadId) {\n        let mut inner = self.inner.lock();\n        assert!(!inner.full_list.iter().any(|e| *e == thread_id));\n        debug_assert!(!inner.current_checks.iter().any(|e| *e == thread_id));\n        inner.full_list.push_back(thread_id);\n        inner.checks_remaining.push_back(thread_id);\n    }\n\n    /// Iterate over the content of the container.\n    ///\n    /// As explained in the documentation, calling this method guarantees that each entry will be\n    /// generated by any of the active iterators.\n    ///\n    /// # Example situation\n    ///\n    /// Let's imagine a container with two elements named `A` and `B`.\n    ///\n    /// You call `access` to start iterating. The iterator returns `A`.\n    /// Then you call `access` a second time (while the first iterator is still alive).\n    ///\n    /// Afterwards, any of the situations below is possible:\n    ///\n    /// - The first iterator immediately finishes. The second iterator returns `A` and `B`.\n    /// - The first iterator returns `A` (again) and `B`. The second iterator immediately finishes.\n    /// - The first iterator returns `A` and the second iterator returns `B`. Then they both end.\n    /// - The first iterator returns `B` and the second iterator returns `A`. Then the second\n    /// iterator ends and the first iterator returns `A` again.\n    ///\n    /// What is **not** possible is for multiple iterators to return `A` and `B` simultaneously.\n    /// In other words, there can never be multiple instances of [`Entry`] alive at the same time\n    /// representing the same element.\n    pub fn access(&self) -> impl Iterator<Item = Entry> {\n        // Reset `checks_remaining` to `full_list`.\n        {\n            let mut inner = self.inner.lock();\n            inner.checks_remaining = inner.full_list.iter().cloned().collect();\n        }\n\n        iter::from_fn(move || {\n            let mut inner = self.inner.lock();\n            let pos = inner\n                .checks_remaining\n                .iter()\n                .position(|t| !inner.current_checks.iter().any(|u| u == t));\n            if let Some(pos) = pos {\n                let thread_id = inner.checks_remaining.remove(pos).unwrap();\n                inner.current_checks.push(thread_id);\n                Some(Entry {\n                    waiting_threads: self,\n                    thread_id,\n                })\n            } else {\n                None\n            }\n        })\n    }\n}\n\nimpl<'a> Entry<'a> {\n    /// Returns the [`ThreadId`] in question.\n    pub fn thread_id(&self) -> ThreadId {\n        self.thread_id\n    }\n\n    /// Removes the entry from the list. This entry will **not** be returned by any other\n    /// active iterator, unless it is pushed in the list again.\n    pub fn remove(self) {\n        let mut inner = self.waiting_threads.inner.lock();\n        debug_assert!(!inner.current_checks.iter().any(|e| *e != self.thread_id));\n        let pos = inner\n            .full_list\n            .iter()\n            .position(|e| *e == self.thread_id)\n            .unwrap();\n        inner.full_list.remove(pos);\n    }\n}\n\nimpl<'a> Drop for Entry<'a> {\n    fn drop(&mut self) {\n        let mut inner = self.waiting_threads.inner.lock();\n        let pos = inner\n            .current_checks\n            .iter()\n            .position(|e| *e == self.thread_id)\n            .unwrap();\n        inner.current_checks.remove(pos);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::id_pool::IdPool;\n    use std::{\n        collections::HashSet,\n        sync::{Arc, Mutex},\n    };\n\n    #[test]\n    fn fuzz_unique_entry() {\n        let queue = Arc::new(WaitingThreads::new());\n        let current_accesses = Arc::new(Mutex::new(HashSet::new()));\n        let id_pool = Arc::new(IdPool::with_seed([0; 32]));\n\n        let mut threads = Vec::new();\n\n        for _ in 0..16 {\n            let queue = queue.clone();\n            let current_accesses = current_accesses.clone();\n            let id_pool = id_pool.clone();\n\n            threads.push(std::thread::spawn(move || {\n                for _ in 0..32 {\n                    queue.push(id_pool.assign());\n                }\n\n                for thread in queue.access() {\n                    {\n                        let mut current_accesses = current_accesses.lock().unwrap();\n                        assert!(current_accesses.insert(thread.thread_id()));\n                    }\n                    std::thread::sleep(std::time::Duration::from_millis(5));\n                    {\n                        let mut current_accesses = current_accesses.lock().unwrap();\n                        assert!(current_accesses.remove(&thread.thread_id()));\n                    }\n                    drop(thread);\n                }\n            }));\n        }\n\n        for t in threads {\n            t.join().unwrap();\n        }\n    }\n\n    #[test]\n    fn access_checks_again_when_active() {\n        let queue = WaitingThreads::new();\n        let id_pool = IdPool::with_seed([0; 32]);\n\n        let tid1: ThreadId = id_pool.assign();\n        queue.push(tid1.clone());\n\n        let mut iter1 = queue.access();\n\n        let elem1 = iter1.next().unwrap();\n        assert_eq!(elem1.thread_id(), tid1);\n\n        let mut iter2 = queue.access();\n        drop(elem1);\n\n        match (iter1.next(), iter2.next()) {\n            (Some(t), None) | (None, Some(t)) => assert_eq!(t.thread_id(), tid1),\n            _ => panic!(),\n        };\n    }\n\n    #[test]\n    fn all_are_returned() {\n        let queue = Arc::new(WaitingThreads::new());\n        let mut remaining_to_access = HashSet::new();\n\n        let id_pool = IdPool::with_seed([0; 32]);\n        for _ in 0..32768 {\n            let tid: ThreadId = id_pool.assign();\n            assert!(remaining_to_access.insert(tid));\n            queue.push(tid);\n        }\n\n        let remaining_to_access = Arc::new(Mutex::new(remaining_to_access));\n        let mut threads = Vec::new();\n\n        for _ in 0..16 {\n            let queue = queue.clone();\n            let remaining_to_access = remaining_to_access.clone();\n\n            threads.push(std::thread::spawn(move || {\n                for thread in queue.access() {\n                    remaining_to_access\n                        .lock()\n                        .unwrap()\n                        .remove(&thread.thread_id());\n                }\n            }));\n        }\n\n        for t in threads {\n            t.join().unwrap();\n        }\n\n        assert!(remaining_to_access.lock().unwrap().is_empty());\n    }\n}\n"
  },
  {
    "path": "kernel/core/src/scheduler/ipc.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::{\n    extrinsics::Extrinsics,\n    id_pool::IdPool,\n    scheduler::{\n        extrinsics::{self, ThreadAccessAccess as _},\n        vm,\n    },\n    InterfaceHash,\n};\n\nuse alloc::vec::Vec;\nuse core::convert::TryFrom as _;\nuse crossbeam_queue::SegQueue;\nuse hashbrown::{hash_map::Entry, HashMap};\nuse redshirt_syscalls::{EncodedMessage, MessageId, Pid, ThreadId};\nuse spinning_top::Spinlock;\n\nmod notifications_queue;\nmod waiting_threads;\n\n/// Handles scheduling processes and inter-process communications.\n///\n/// # State of messages\n///\n/// The possible states of a message are as follow:\n///\n/// - Generated by a program but not accepted yet. A [`CoreRunOutcome::InterfaceMessage`] is\n///   emitted. The thread that has generated the message is now sleeping. If the message has the\n///   \"immediate-delivery\" flag on, it can then be refused by calling\n///   [`Core::reject_immediate_interface_message`] in which case the emitting thread is resumed\n///   with an error.\n///\n/// - Accepted by calling [`Core::accept_interface_message`] on a not-accepted-yet message. The\n///   thread that has emitted the message is resumed, and, if the message expects an answer, the\n///   user is responsible for later answering the message with [`Core::answer_message`].\n///\n/// - Answer queued. After calling [`Core::answer_message`], the answer to the message is added\n///   to the queue of notifications that the original emitter of the message can receive. At least\n///   one thread that is sleeping waiting for notifications is resumed.\n///\n/// Note that when a program emits a message that doesn't need an answer, this message is assigned\n/// a [`MessageId`] for API-related purposes. This [`MessageId`] isn't expected to ever reach a\n/// program's user space. As soon as the message is accepted or refused, the [`MessageId`] is\n/// discarded.\n//\n// # Implementation notes\n//\n// This struct synchronizes the following components in a lock-free way:\n//\n// - The underlying VMs, with processes and threads.\n// - For each process, a list of answers waiting to be delivered.\n// - For each process, a list of threads blocked waiting for answers and that we have failed to\n//   resume in the past.\n// - A list of active messages waiting to be answered.\n//\n// While each of these components is updated atomically, there exists no synchronization between\n// them. As such, the implementation heavily relies on the fact that message IDs, process IDs,\n// and thread IDs are unique.\n//\n// For example, delivering a message to an interface consists in atomically looking for the process\n// that handles this interface, then atomically delivering it. If, in parallel, that process has\n// terminated but has not yet been unregistered as the handler of the interface, then we know it\n// from the fact that he process ID is no longer valid. This wouldn't be possible if process IDs\n// were reused.\n//\npub struct Core<TExt: Extrinsics> {\n    /// Pool of identifiers where `MessageId`s are allocated.\n    id_pool: IdPool,\n\n    /// Queue of events to return in priority when `run` is called.\n    pending_events: SegQueue<CoreRunOutcome>,\n\n    /// List of running processes.\n    processes: extrinsics::ProcessesCollectionExtrinsics<Process, (), TExt>,\n\n    /// List of messages that have been emitted by a thread but haven't been accepted or refused\n    /// yet. Stores the emitter of the message.\n    pending_accept_messages:\n        Spinlock<HashMap<MessageId, (Pid, ThreadId), nohash_hasher::BuildNoHashHasher<u64>>>,\n\n    /// List of messages that have been emitted by a process but haven't been answered yet. Stores\n    /// the emitter of the message.\n    pending_answer_messages:\n        Spinlock<HashMap<MessageId, Pid, nohash_hasher::BuildNoHashHasher<u64>>>,\n}\n\n/// Prototype for a `Core` under construction.\npub struct CoreBuilder<TExt: Extrinsics> {\n    /// Builder for the [`processes`][Core::processes] field in [`Core`].\n    inner_builder: extrinsics::Builder<TExt>,\n\n    /// Randomness seed used to initialize [`Core::id_pool`].\n    seed: [u8; 32],\n}\n\n/// Event returned by [`Core::run`].\npub enum ExecuteOut<'a, TExt: Extrinsics> {\n    /// Event directly generated.\n    Direct(CoreRunOutcome),\n    /// Ready to execute a bit of a thread.\n    ReadyToRun(ReadyToRun<'a, TExt>),\n}\n\nimpl<'a, TExt: Extrinsics> ExecuteOut<'a, TExt> {\n    pub fn or_run(self) -> Option<CoreRunOutcome> {\n        match self {\n            ExecuteOut::Direct(ev) => Some(ev),\n            ExecuteOut::ReadyToRun(run) => run.run(),\n        }\n    }\n}\n\n/// Ready to resume one of the threads of a process.\n#[must_use]\npub struct ReadyToRun<'a, TExt: Extrinsics> {\n    core: &'a Core<TExt>,\n    inner: extrinsics::ReadyToRun<'a, Process, (), TExt>,\n}\n\nimpl<'a, TExt: Extrinsics> ReadyToRun<'a, TExt> {\n    /// Performs the actual execution.\n    ///\n    /// Returns `None` if the execution doesn't lead to any event in particular.\n    pub fn run(self) -> Option<CoreRunOutcome> {\n        let core = self.core;\n        self.inner.run().and_then(move |out| core.inner_event(out))\n    }\n}\n\n/// Outcome of calling [`run`](Core::run).\n#[derive(Debug)]\npub enum CoreRunOutcome {\n    /// A program has stopped, either because the main function has stopped or a problem has\n    /// occurred.\n    ProgramFinished {\n        /// Id of the program that has stopped.\n        pid: Pid,\n\n        /// How the program ended. If `Ok`, it has gracefully terminated. If `Err`, something\n        /// bad happened.\n        // TODO: force Ok to i32?\n        // TODO: redefine error instead?\n        outcome: Result<Option<crate::WasmValue>, extrinsics::Trap>,\n    },\n\n    /// A process wants to emit a message on an interface.\n    ///\n    /// If `immediate` is `true`, either [`Core::accept_interface_message`]\n    /// or [`Core::reject_immediate_interface_message`] should be called as soon as possible.\n    ///\n    /// If `immediate` is `false`, [`Core::accept_interface_message`] must be called,\n    /// but this can be delayed indefinitely.\n    InterfaceMessage {\n        /// Id of the program that has emitted the message.\n        pid: Pid,\n        /// Identifier of the message that has been emitted.\n        ///\n        /// > **Note**: A [`MessageId`] is always generated for API-related purposes, even when no\n        /// >           answer is expected.\n        message_id: MessageId,\n        /// True if the message is expecting an answer.\n        needs_answer: bool,\n        /// True if the caller requires an immediate answer by calling either\n        /// [`Core::accept_interface_message`] or [`Core::reject_immediate_interface_message`].\n        immediate: bool,\n        /// Which interface the message has been emitted on.\n        interface: InterfaceHash,\n    },\n}\n\n/// Additional information about a process.\n#[derive(Debug)]\nstruct Process {\n    /// Notifications available for retrieval by the process by calling `next_notification`.\n    notifications_queue: notifications_queue::NotificationsQueue,\n\n    /// List of threads that are frozen waiting for new notifications.\n    wait_notifications_threads: waiting_threads::WaitingThreads,\n}\n\n/// Access to a process within the core.\npub struct CoreProcess<'a, TExt: Extrinsics> {\n    /// Access to the process within the inner collection.\n    process: extrinsics::ProcAccess<'a, Process, (), TExt>,\n}\n\nimpl<TExt: Extrinsics> Core<TExt> {\n    /// Run the core once.\n    pub async fn run<'a>(&'a self) -> ExecuteOut<'a, TExt> {\n        loop {\n            if let Some(ev) = self.run_inner().await {\n                break ev;\n            }\n        }\n    }\n\n    /// Same as [`Core::run`]. Returns `None` if no event should be returned and we should loop\n    /// again.\n    async fn run_inner<'a>(&'a self) -> Option<ExecuteOut<'a, TExt>> {\n        if let Some(ev) = self.pending_events.pop() {\n            return Some(ExecuteOut::Direct(ev));\n        }\n\n        // Note: we use a temporary `run_outcome` variable in order to solve weird borrowing\n        // issues. Feel free to try to remove it if you manage.\n        match self.processes.run().await {\n            extrinsics::ExecuteOut::Direct(event) => {\n                self.inner_event(event).map(ExecuteOut::Direct)\n            }\n            extrinsics::ExecuteOut::ReadyToRun(ready) => Some(ExecuteOut::ReadyToRun(ReadyToRun {\n                core: self,\n                inner: ready,\n            })),\n        }\n    }\n\n    fn inner_event(\n        &self,\n        run_outcome: extrinsics::RunOneOutcome<Process, (), TExt>,\n    ) -> Option<CoreRunOutcome> {\n        match run_outcome {\n            extrinsics::RunOneOutcome::ProcessFinished { pid, outcome, .. } => {\n                Some(CoreRunOutcome::ProgramFinished { pid, outcome })\n            }\n\n            extrinsics::RunOneOutcome::ThreadFinished { .. } => {\n                // TODO: report\n                None\n            }\n\n            extrinsics::RunOneOutcome::ThreadWaitNotification(thread) => {\n                // A thread has asked for new incoming notifications.\n                // Immediately try to resume the thread in case a suitable notification is\n                // available.\n                //\n                // If no suitable notification is available, add the thread to a list for later.\n                //\n                // The process of checking whether any notification is available, and if not\n                // adding the process to a list, is subject to race conditions. It is possible for\n                // a notification to have arrived in-between the two steps. In order to solve this\n                // problem, we compare the total number of notifications pushed to the process'\n                // queue before and after the operations. If it has changed, try wake up again.\n                let total_notifications_pushed_before = thread\n                    .process_user_data()\n                    .notifications_queue\n                    .total_notifications_pushed();\n\n                if let Err(thread) = try_resume_notification_wait_thread(thread) {\n                    // The thread couldn't be resumed.\n                    let tid = thread.tid();\n                    let process = thread.into_process();\n\n                    // It is important for the lock to the thread to have been dropped at this\n                    // point (i.e. `thread` is destroyed), otherwise entries to still-locked\n                    // threads could be found in the list.\n                    process.user_data().wait_notifications_threads.push(tid);\n\n                    // Try resume the thread again if a notification has been pushed in-between.\n                    let total_notifications_pushed_after = process\n                        .user_data()\n                        .notifications_queue\n                        .total_notifications_pushed();\n                    if total_notifications_pushed_before != total_notifications_pushed_after {\n                        self.try_resume_notification_wait(process);\n                    }\n                }\n\n                None\n            }\n\n            extrinsics::RunOneOutcome::ThreadEmitMessage(mut thread) => {\n                let emitter_pid = thread.pid();\n                let interface = thread.emit_interface().clone();\n                let needs_answer = thread.needs_answer();\n                let message_id = self.id_pool.assign();\n\n                self.pending_accept_messages\n                    .lock()\n                    .insert(message_id, (emitter_pid, thread.tid()));\n\n                Some(CoreRunOutcome::InterfaceMessage {\n                    pid: emitter_pid,\n                    message_id,\n                    needs_answer,\n                    immediate: !thread.allow_delay(),\n                    interface,\n                })\n            }\n\n            extrinsics::RunOneOutcome::ThreadCancelMessage {\n                message_id,\n                process,\n                ..\n            } => {\n                let mut pending_answer_messages = self.pending_answer_messages.lock();\n                if let Entry::Occupied(entry) = pending_answer_messages.entry(message_id) {\n                    if *entry.get() == process.pid() {\n                        entry.remove();\n                    }\n                }\n\n                None\n            }\n        }\n    }\n\n    /// Returns an object granting access to a process, if it exists.\n    pub fn process_by_id(&self, pid: Pid) -> Option<CoreProcess<TExt>> {\n        let p = self.processes.process_by_id(pid)?;\n        Some(CoreProcess { process: p })\n    }\n\n    /// After [`CoreRunOutcome::InterfaceMessage`] is generated, use this method to accept the\n    /// message and resume the thread that is emitting the message.\n    ///\n    /// If the message [expects an answer](`CoreRunOutcome::InterfaceMessage::needs_answer`), it\n    /// must later be answered with [`Core::answer_message`].\n    ///\n    /// Returns `None` if the message doesn't exist or no longer exists, which can typically\n    /// happen if the program has been aborted in parallel.\n    pub fn accept_interface_message(&self, message_id: MessageId) -> Option<(Pid, EncodedMessage)> {\n        let (pid, tid) = self.pending_accept_messages.lock().remove(&message_id)?;\n\n        self.pending_answer_messages.lock().insert(message_id, pid);\n\n        match self.processes.interrupted_thread_by_id(tid).unwrap() {\n            extrinsics::ThreadAccess::EmitMessage(mut thread) => {\n                let message = if thread.needs_answer() {\n                    thread.accept_emit(Some(message_id))\n                } else {\n                    thread.accept_emit(None)\n                };\n\n                Some((pid, message))\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    /// After [`CoreRunOutcome::InterfaceMessage`] is generated where `immediate` is true, use\n    /// this method to notify that the message cannot be accepted at the moment.\n    ///\n    /// # Panic\n    ///\n    /// Panics if [`CoreRunOutcome::InterfaceMessage::immediate`] was false.\n    /// Might panic if the message is in the wrong state.\n    ///\n    pub fn reject_immediate_interface_message(&self, message_id: MessageId) {\n        let (_, tid) = match self.pending_accept_messages.lock().remove(&message_id) {\n            Some(v) => v,\n            None => return, // Process might have been killed in-between.\n        };\n\n        match self.processes.interrupted_thread_by_id(tid) {\n            Ok(extrinsics::ThreadAccess::EmitMessage(mut thread)) => {\n                assert!(!thread.allow_delay());\n                thread.refuse_emit();\n            }\n            Err(extrinsics::ThreadByIdErr::RunningOrDead) => {}\n            _ => unreachable!(),\n        }\n    }\n\n    /// Set the answer to a message previously passed to [`Core::accept_interface_message`].\n    ///\n    /// This pushes a notification to the process.\n    pub fn answer_message(&self, message_id: MessageId, response: Result<EncodedMessage, ()>) {\n        let emitter_pid = match self.pending_answer_messages.lock().remove(&message_id) {\n            Some(pid) => pid,\n            None => {\n                // Should happen if and only if the process that emitted the message has been\n                // aborted. MessageIds are never reused, therefore guaranteeing that this answer\n                // cannot reach the wrong message by accident.\n                return;\n            }\n        };\n\n        if let Some(process) = self.processes.process_by_id(emitter_pid) {\n            process\n                .user_data()\n                .notifications_queue\n                .push(message_id, response);\n            self.try_resume_notification_wait(process);\n        } else {\n            // It is possible for the emitter of the message to have stopped or crashed, and we\n            // had not updated `active_messages` yet.\n        }\n    }\n\n    /// Start executing the module passed as parameter.\n    ///\n    /// Each import of the module is resolved.\n    pub fn execute(&self, module: &[u8]) -> Result<(CoreProcess<TExt>, ThreadId), vm::NewErr> {\n        let proc_metadata = Process {\n            notifications_queue: notifications_queue::NotificationsQueue::new(),\n            wait_notifications_threads: waiting_threads::WaitingThreads::new(),\n        };\n\n        let (process, main_tid) = self.processes.execute(module, proc_metadata, ())?;\n\n        Ok((CoreProcess { process }, main_tid))\n    }\n\n    /// Tries to resume all the threads of the process that are waiting for an notification.\n    fn try_resume_notification_wait(&self, process: extrinsics::ProcAccess<Process, (), TExt>) {\n        // The actual work being done here is actually quite complicated in order to ensure that\n        // each `ThreadId` is only accessed once at a time, but the exposed API is very simple.\n        for thread_access in process.user_data().wait_notifications_threads.access() {\n            let thread = match self\n                .processes\n                .interrupted_thread_by_id(thread_access.thread_id())\n            {\n                Ok(extrinsics::ThreadAccess::WaitNotification(thread)) => thread,\n                _ => unreachable!(),\n            };\n\n            if try_resume_notification_wait_thread(thread).is_ok() {\n                thread_access.remove();\n            }\n        }\n    }\n}\n\nimpl<'a, TExt: Extrinsics> CoreProcess<'a, TExt> {\n    /// Returns the [`Pid`] of the process.\n    pub fn pid(&self) -> Pid {\n        self.process.pid()\n    }\n\n    /// Adds a new thread to the process, starting the function with the given index and passing\n    /// the given parameters.\n    pub fn start_thread(\n        self,\n        fn_index: u32,\n        params: Vec<crate::WasmValue>,\n    ) -> Result<(), vm::ThreadStartErr> {\n        self.process.start_thread(fn_index, params, ())?;\n        Ok(())\n    }\n\n    /// Starts killing the process.\n    // TODO: more docs\n    pub fn abort(&self) {\n        self.process.abort();\n    }\n}\n\nimpl<TExt: Extrinsics> CoreBuilder<TExt> {\n    /// Initializes a new [`CoreBuilder`] using the given random seed.\n    ///\n    /// The seed is used in determine how [`Pid`]s and [`MessageId`]s are generated. The same\n    /// seed will result in the same sequence of [`Pid`]s and [`MessageId`]s.\n    pub fn with_seed(seed: [u8; 64]) -> CoreBuilder<TExt> {\n        CoreBuilder {\n            inner_builder: extrinsics::Builder::with_seed(\n                <[u8; 32]>::try_from(&seed[..32]).unwrap(),\n            ),\n            seed: <[u8; 32]>::try_from(&seed[32..]).unwrap(),\n        }\n    }\n\n    /// Allocates a `Pid` that will not be used by any process.\n    ///\n    /// > **Note**: As of the writing of this comment, this feature is only ever used to allocate\n    /// >           `Pid`s that last forever. There is therefore no corresponding \"unreserve_pid\"\n    /// >           method that frees such an allocated `Pid`. If there is ever a need to free\n    /// >           these `Pid`s, such a method should be added.\n    pub fn reserve_pid(&mut self) -> Pid {\n        self.inner_builder.reserve_pid()\n    }\n\n    /// Turns the builder into a [`Core`].\n    pub fn build(self) -> Core<TExt> {\n        Core {\n            pending_events: SegQueue::new(),\n            processes: self.inner_builder.build(),\n            id_pool: IdPool::with_seed(self.seed),\n            pending_accept_messages: Spinlock::new(HashMap::default()),\n            pending_answer_messages: Spinlock::new(HashMap::default()),\n        }\n    }\n}\n\n/// If the given thread is waiting for a notification to arrive, checks the queue and tries to\n/// resume said thread.\n///\n/// Returns back the thread within an `Err` if it couldn't be resumed.\nfn try_resume_notification_wait_thread<TExt: Extrinsics>(\n    mut thread: extrinsics::ThreadWaitNotif<Process, (), TExt>,\n) -> Result<(), extrinsics::ThreadWaitNotif<Process, (), TExt>> {\n    // Note that the code below is a bit weird and unelegant, but this is to bypass spurious\n    // borrowing errors.\n    let (entry_size, index_and_notif) = {\n        // Try to find a notification in the queue that matches something the user is waiting for.\n        // TODO: don't alloc a Vec\n        let messages = thread.wait_entries().collect::<Vec<_>>();\n\n        let entry = thread\n            .process_user_data()\n            .notifications_queue\n            .find(&messages);\n\n        let entry = match entry {\n            Some(e) => e,\n            None => {\n                // No notification found.\n                drop(entry);\n                if !thread.block() {\n                    thread.resume_no_notification();\n                    return Ok(());\n                } else {\n                    return Err(thread);\n                }\n            }\n        };\n\n        let entry_size = entry.size();\n        let index_and_notif = if entry_size <= thread.allowed_notification_size() {\n            // Pop the notification from the queue for delivery.\n            let index_in_msg_ids = entry.index_in_msg_ids();\n            let notification = entry.extract();\n            Some((index_in_msg_ids, notification))\n        } else {\n            None\n        };\n\n        (entry_size, index_and_notif)\n    };\n\n    if let Some((index_in_msg_ids, notification)) = index_and_notif {\n        thread.resume_notification(index_in_msg_ids, notification)\n    } else {\n        thread.resume_notification_too_big(entry_size)\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "kernel/core/src/scheduler/processes/tests.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse super::{ProcessesCollectionBuilder, RunFutureOut, RunOneOutcome};\nuse crate::sig;\n\nuse futures::prelude::*;\nuse hashbrown::HashSet;\nuse std::{\n    sync::{Arc, Barrier, Mutex},\n    thread,\n};\n\n#[test]\n#[should_panic]\nfn panic_duplicate_extrinsic() {\n    ProcessesCollectionBuilder::<()>::with_seed([0; 32])\n        .with_extrinsic(\"foo\", \"test\", sig!(()), ())\n        .with_extrinsic(\"foo\", \"test\", sig!(()), ());\n}\n\n#[test]\nfn basic() {\n    let module = from_wat!(\n        local,\n        r#\"(module\n        (func $_start (result i32)\n            i32.const 5)\n        (export \"_start\" (func $_start)))\n    \"#\n    );\n    let processes = ProcessesCollectionBuilder::<()>::with_seed([0; 32]).build();\n    processes.execute(&module, (), ()).unwrap();\n    loop {\n        let outcome = match futures::executor::block_on(processes.run()) {\n            RunFutureOut::Direct(v) => v,\n            RunFutureOut::ReadyToRun(rtr) => rtr.run(),\n        };\n        match outcome {\n            RunOneOutcome::StartProcessAbort { .. } => {}\n            RunOneOutcome::ProcessFinished { outcome, .. } => {\n                assert!(matches!(outcome.unwrap(), Some(crate::WasmValue::I32(5))));\n                break;\n            }\n            _ => panic!(),\n        };\n    }\n}\n\n#[test]\nfn aborting_works() {\n    let module = from_wat!(\n        local,\n        r#\"(module\n        (func $_start (result i32)\n            i32.const 5)\n        (export \"_start\" (func $_start)))\n    \"#\n    );\n    let processes = ProcessesCollectionBuilder::<()>::with_seed([0; 32]).build();\n    processes.execute(&module, (), ()).unwrap().0.abort();\n    let outcome = match futures::executor::block_on(processes.run()) {\n        RunFutureOut::Direct(v) => v,\n        RunFutureOut::ReadyToRun(rtr) => rtr.run(),\n    };\n    match outcome {\n        RunOneOutcome::ProcessFinished {\n            outcome: Err(_), ..\n        } => {}\n        _ => panic!(),\n    };\n}\n\n#[test]\nfn many_processes() {\n    let module = from_wat!(\n        local,\n        r#\"(module\n        (import \"\" \"test\" (func $test (result i32)))\n        (func $_start (result i32)\n            call $test)\n        (export \"_start\" (func $_start)))\n    \"#\n    );\n    let num_processes = 10000;\n    let num_threads = 8;\n\n    let processes = Arc::new(\n        ProcessesCollectionBuilder::<i32>::with_seed([0; 32])\n            .with_extrinsic(\"\", \"test\", sig!(() -> I32), 98)\n            .build(),\n    );\n    let mut spawned_pids = HashSet::<_, fnv::FnvBuildHasher>::default();\n    for _ in 0..num_processes {\n        let pid = processes.execute(&module, (), ()).unwrap().0.pid();\n        assert!(spawned_pids.insert(pid));\n    }\n\n    let finished_pids = Arc::new(Mutex::new(HashSet::<_, fnv::FnvBuildHasher>::default()));\n    let start_barrier = Arc::new(Barrier::new(num_threads));\n    let end_barrier = Arc::new(Barrier::new(num_threads + 1));\n\n    for _ in 0..num_threads {\n        let processes = processes.clone();\n        let finished_pids = finished_pids.clone();\n        let start_barrier = start_barrier.clone();\n        let end_barrier = end_barrier.clone();\n        thread::spawn(move || {\n            start_barrier.wait();\n\n            let mut local_finished = Vec::with_capacity(num_processes);\n            loop {\n                let outcome = match processes.run().now_or_never() {\n                    Some(RunFutureOut::Direct(v)) => v,\n                    Some(RunFutureOut::ReadyToRun(rtr)) => rtr.run(),\n                    None => break,\n                };\n                match outcome {\n                    RunOneOutcome::ProcessFinished { pid, outcome, .. } => {\n                        assert!(matches!(\n                            outcome.unwrap(),\n                            Some(crate::WasmValue::I32(1234))\n                        ));\n                        local_finished.push(pid);\n                    }\n                    RunOneOutcome::Interrupted {\n                        thread, id: &98, ..\n                    } => {\n                        thread.resume(Some(crate::WasmValue::I32(1234)));\n                    }\n                    RunOneOutcome::StartProcessAbort { .. } => {}\n                    _ => panic!(),\n                };\n            }\n\n            {\n                let mut finished_pids = finished_pids.lock().unwrap();\n                for local in local_finished {\n                    assert!(finished_pids.insert(local));\n                }\n            }\n\n            end_barrier.wait();\n        });\n    }\n\n    end_barrier.wait();\n    for pid in finished_pids.lock().unwrap().drain() {\n        assert!(spawned_pids.remove(&pid));\n    }\n    assert!(spawned_pids.is_empty());\n}\n\n// TODO: add fuzzing here\n"
  },
  {
    "path": "kernel/core/src/scheduler/processes/wakers.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse core::{fmt, task::Waker};\nuse slab::Slab;\nuse spinning_top::Spinlock;\n\n/// Collection of wakers.\n#[derive(Default)]\npub struct Wakers {\n    // TODO: could avoid the mutex by knowing in advance the number of registrations\n    list: Spinlock<Slab<Option<Waker>>>,\n}\n\nimpl Wakers {\n    pub fn register(&self) -> Registration {\n        let mut list = self.list.lock();\n        let index = list.insert(None);\n        Registration {\n            list: &self.list,\n            index,\n        }\n    }\n\n    /// Wakes up one registered waker. Has no effect if the list is empty.\n    pub fn notify_one(&self) {\n        let mut list = self.list.lock();\n        for (_, elem) in list.iter_mut() {\n            if let Some(elem) = elem.take() {\n                elem.wake();\n                return;\n            }\n        }\n    }\n}\n\nimpl fmt::Debug for Wakers {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"Wakers\").finish()\n    }\n}\n\npub struct Registration<'a> {\n    list: &'a Spinlock<Slab<Option<Waker>>>,\n    index: usize,\n}\n\nimpl<'a> Registration<'a> {\n    pub fn set_waker(&mut self, waker: &Waker) {\n        let mut list = self.list.lock();\n        let entry = &mut list[self.index];\n        if let Some(entry) = entry {\n            if entry.will_wake(waker) {\n                return;\n            }\n        }\n        *entry = Some(waker.clone());\n    }\n}\n\nimpl<'a> fmt::Debug for Registration<'a> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"Registration\").finish()\n    }\n}\n\nimpl<'a> Drop for Registration<'a> {\n    fn drop(&mut self) {\n        self.list.lock().remove(self.index);\n    }\n}\n"
  },
  {
    "path": "kernel/core/src/scheduler/processes.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Collection of VMs representing processes.\n//!\n//! This module contains most the of important logic related to parallelism in the scheduler.\n//!\n//! The [`ProcessesCollection`] struct contains a list of processes identified by [`Pid`]s and\n//! threads identified by [`ThreadId`]s. You can add new processes by calling\n//! [`ProcessesCollection::execute`].\n//!\n//! Call [`ProcessesCollection::run`] in order to find a thread in the collection that is ready\n//! to be run, executing it, and obtain an event describing what has just happened. The function\n//! is asynchronous, and if there is nothing to do then its corresponding `Future` will be\n//! pending.\n//!\n//! # Interrupted threads\n//!\n//! If [`RunOneOutcome::Interrupted`] is returned, that means that the given thread has just\n//! called (from within the VM) an external function and is now in an \"interrupted\" state waiting\n//! for the call to that external function to be finished.\n//!\n//! You can:\n//!\n//! - Either process the call immediately and call [`ThreadAccess::resume`], passing\n//! the return value of the call.\n//! - Or decide to resume the thread later. You can drop the [`ThreadAccess`] object,\n//! and later retrieve it by calling [`ProcessesCollection::interrupted_thread_by_id`].\n//!\n//! A [`ThreadAccess`] represents a \"locked access\" to a thread. Only one instance of\n//! [`ThreadAccess`] for any given thread can exist simultaneously. Attempting to access the same\n//! thread multiple times will result in an error, and the upper layers should be designed in such\n//! a way that this is not necessary.\n//!\n//! # Locking processes\n//!\n//! One can access the state of a process through a [`ProcAccess`]. This struct can\n//! be obtained through a [`ThreadAccess`], or by calling\n//! [`ProcessesCollection::process_by_id`] or [`ProcessesCollection::processes`].\n//!\n//! Contrary to threads, multiple instances of [`ProcAccess`] can exist for the same\n//! process.\n//!\n//! If a process finishes (either by normal termination or because of a crash), the emission of\n//! the corresponding [`RunOneOutcome::ProcessFinished`] event will be delayed until no instance\n//! of [`ProcAccess`] corresponding to that process exist anymore.\n\n// Implementation notes.\n//\n// The ownership of each thread is passed between five different structures, as illustrated below.\n//\n//                                            +---> RunOneOutcome::ThreadFinished\n//                                            |\n//                                            +---> ProcessDeadState::dead_threads <-------+\n//                                            |                               ^            |\n//                                            |                               +---------+  |\n//   +--------------------------------+ run   |    +--------------+                     |  |\n//   |                                +-------+--->+              |                     |  |\n//   | ProcessLock::threads_to_resume |            | ThreadAccess |                     |  |\n//   |                                +<-----------+              |                     |  |\n//   +--------------------------------+    resume  +----+-----+---+                     |  |\n//                                                      ^     |                         |  |\n//                                                      |     | ThreadAccess::Drop      |  |\n//                                                      |     |                         |  |\n//                                                      |     |                         |  |\n//                             interrupted_thread_by_id |     +-------------------------+  |\n//                                                      |     v                            |\n//                                   +------------------+-----+-----------------+          |\n//                                   | ProcessesCollection::interrupted_threads +----------+\n//                                   +------------------------------------------+\n//\n// When a thread is created, it is inserted in `ProcessLock::threads_to_resume`. After it is\n// executed, it either terminates or is given to the user as a `ThreadAccess`. If the user drops\n// that `ThreadAccess`, the thread is moved to `ProcessesCollection::interrupted_threads` where it\n// can later be extracted again with `interrupted_thread_by_id`.\n//\n// Whenever a thread is inserted in `ProcessLock::threads_to_resume`, the process itself is also\n// inserted in `ProcessesCollection::execution_queue`. The number of times a process is in\n// `execution_queue` must always be equal to the length of its `threads_to_resume` field.\n//\n// When a process needs to be terminated (because of `ProcessAccess::abort`, the main thread has\n// returned, or an error has happened), we don't immediately report the termination to the user\n// or remove the process from the state. Instead, the process is marked as \"dying\" by putting a\n// `Some` in `ProcessLock::dead`.\n//\n// When a process is marked as dying, normal thread state transitions (between `threads_to_resume`,\n// `ThreadAccess` and `interrupted_threads`) are hijacked. Whenever a state transition would\n// normally occur, the thread is instead moved to `ProcessDeadState::dead_threads`. In other\n// words, whenever a thread state transition needs to happen, we first check the process's dying\n// flag.\n//\n// Processes are always manipulated through an `Arc`, and the lifetime of a process is tracked by\n// that `Arc`. An `Arc<Process>` must never be silently dropped, but instead passed to\n// `try_report_process_death` for destruction. If `try_report_process_death` is called with the\n// last remaining `Arc` containing a process, the content of `dead_threads` is extracted and the\n// information about the death of the process is pushed to `death_reports`.\n//\n// When a death report has been pushed in `death_reports`, the state is entirely clean from that\n// process. The last step is to report that death to the user through a\n// `RunOneOutcome::ProcessFinished`, which happens as soon as `run` is called.\n\nuse crate::{id_pool::IdPool, primitives::Signature, scheduler::vm, Pid, ThreadId};\n\nuse alloc::{\n    borrow::Cow,\n    boxed::Box,\n    collections::VecDeque,\n    string::String,\n    sync::{Arc, Weak},\n    vec,\n    vec::Vec,\n};\nuse core::{\n    fmt,\n    future::Future,\n    mem,\n    pin::Pin,\n    task::{Context, Poll},\n};\nuse crossbeam_queue::SegQueue;\nuse fnv::FnvBuildHasher;\nuse hashbrown::{hash_map::Entry, HashMap};\nuse nohash_hasher::BuildNoHashHasher;\nuse spinning_top::Spinlock;\n\n#[cfg(test)]\nmod tests;\nmod wakers;\n\n/// Minimum capacity of the container of the list of processes.\n///\n/// If we shrink the container too much, then it will have to perform lots of allocations in order\n/// to grow again in the future. We therefore avoid that situation.\nconst PROCESSES_MIN_CAPACITY: usize = 128;\n\n/// Collection of multiple [`ProcessStateMachine`](vm::ProcessStateMachine)s grouped together in a\n/// smart way.\n///\n/// See the module-level documentation for more information.\n///\n/// The generic parameters `TPud` and `TTud` are \"user data\"s that are stored respectively per\n/// process and per thread, and allows the user to put extra information associated to a process\n/// or a thread.\npub struct ProcessesCollection<TExtr, TPud, TTud> {\n    /// Allocations of process IDs and thread IDs.\n    pid_tid_pool: IdPool,\n\n    /// Holds the list of task wakers to wake when an event is ready or that something is ready to\n    /// run.\n    wakers: wakers::Wakers,\n\n    /// Queue of processes with at least one thread to run. Every time a thread starts or is\n    /// resumed, its process gets pushed to the end of this queue. In other words, each process is\n    /// in this queue `N` times, it means that `N` of its threads are ready to run. There isn't\n    /// any unnecessary entry.\n    // TODO: use something better than a naive round robin?\n    execution_queue: SegQueue<Arc<Process<TPud, TTud>>>,\n\n    /// List of threads waiting to be resumed, plus their user data and the process they belong to.\n    /// Doesn't contains threads that have been locked by the user with\n    /// [`ProcessesCollection::interrupted_thread_by_id`], as this method extracts the thread from\n    /// the list.\n    // TODO: find a solution for that mutex?\n    // TODO: call shrink_to_fit from time to time?\n    interrupted_threads:\n        Spinlock<HashMap<ThreadId, (TTud, Arc<Process<TPud, TTud>>), BuildNoHashHasher<u64>>>,\n\n    /// List of all processes currently alive.\n    ///\n    /// We hold `Weak`s to processes rather than `Arc`s. Processes are kept alive by the execution\n    /// queue and the interrupted threads, thereby guaranteeing that they are alive only if they\n    /// can potentially continue running.\n    // TODO: find a solution for that mutex?\n    processes: Spinlock<HashMap<Pid, Weak<Process<TPud, TTud>>, BuildNoHashHasher<u64>>>,\n\n    /// List of functions that processes can call.\n    /// The key of this map is an arbitrary `usize` that we pass to the WASM virtual machine.\n    /// This field is never modified after the [`ProcessesCollection`] is created.\n    extrinsics: Vec<TExtr>,\n\n    /// Map used to resolve imports when starting a process.\n    /// For each module and function name, stores the signature and an arbitrary usize that\n    /// corresponds to the entry in `extrinsics`.\n    /// This field is never modified after the [`ProcessesCollection`] is created.\n    extrinsics_id_assign:\n        HashMap<(Cow<'static, str>, Cow<'static, str>), (usize, Signature), FnvBuildHasher>,\n\n    /// Queue of process deaths to report to the external API.\n    death_reports: SegQueue<(\n        Pid,\n        TPud,\n        Vec<(ThreadId, TTud)>,\n        Result<Option<crate::WasmValue>, Trap>,\n    )>,\n}\n\n/// Description of a process. Always addressed through an `Arc`.\n///\n/// Note that the process might be dead.\nstruct Process<TPud, TTud> {\n    /// Identifier of the process.\n    pid: Pid,\n\n    /// Part of the state behind a mutex.\n    // TODO: it's obviously not great to have a Mutex here; this should be refactored once the\n    // `vm` module supports multithreading\n    lock: Spinlock<ProcessLock<TTud>>,\n\n    /// User-chosen data (opaque to us) that describes the process.\n    user_data: TPud,\n}\n\n/// Part of each process's state that is behind a mutex.\nstruct ProcessLock<TTud> {\n    /// The actual Wasm virtual machine. Do not use if `dead` is `Some`.\n    vm: vm::ProcessStateMachine<Thread>,\n\n    /// Queue of threads that are ready to be resumed.\n    threads_to_resume: VecDeque<(ThreadId, TTud, Option<crate::WasmValue>)>,\n\n    /// If `Some`, then the process has been marked for death. The virtual machine must no longer\n    /// be used (as it might be in a poisoned state), and we are in the process of collecting all\n    /// the threads user datas into the [`ProcessDeadState`] before notifying the user.\n    dead: Option<ProcessDeadState<TTud>>,\n}\n\n/// Additional optional state to a process if it's been marked for destruction.\nstruct ProcessDeadState<TTud> {\n    /// List of dead thread that we will ultimately send to the user.\n    dead_threads: Vec<(ThreadId, TTud)>,\n\n    /// Why the process ended. Never modified once set.\n    outcome: Result<Option<crate::WasmValue>, Trap>,\n}\n\n/// Additional data associated to a thread. Stored within the [`vm::ProcessStateMachine`].\nstruct Thread {\n    /// Identifier of the thread.\n    thread_id: ThreadId,\n}\n\nimpl<TExtr, TPud, TTud> ProcessesCollection<TExtr, TPud, TTud> {\n    /// Creates a new process from the given module.\n    ///\n    /// The closure is called for each import that the module has. It must assign a number to each\n    /// import, or return an error if the import can't be resolved. When the VM calls one of these\n    /// functions, this number will be returned back in order for the user to know how to handle\n    /// the call.\n    ///\n    /// A single main thread (whose user data is passed by parameter) is automatically created and\n    /// is paused at the start of the \"_start\" function of the module.\n    pub fn execute(\n        &self,\n        module: &[u8],\n        proc_user_data: TPud,\n        main_thread_user_data: TTud,\n    ) -> Result<(ProcAccess<TExtr, TPud, TTud>, ThreadId), vm::NewErr> {\n        let main_thread_id = self.pid_tid_pool.assign(); // TODO: check for duplicates?\n\n        let state_machine = {\n            let extrinsics_id_assign = &self.extrinsics_id_assign;\n            vm::ProcessStateMachine::new(\n                module,\n                Thread {\n                    thread_id: main_thread_id,\n                },\n                move |interface, function, obtained_signature| {\n                    if let Some((index, expected_signature)) =\n                        extrinsics_id_assign.get(&(interface.into(), function.into()))\n                    {\n                        if expected_signature == obtained_signature {\n                            return Ok(*index);\n                        } else {\n                            // TODO: way to report the signature mismatch?\n                        }\n                    }\n\n                    Err(())\n                },\n            )?\n        };\n\n        // We only modify `self` at the very end.\n        let new_pid = self.pid_tid_pool.assign();\n        let process = Arc::new(Process {\n            pid: new_pid,\n            lock: Spinlock::new(ProcessLock {\n                vm: state_machine,\n                threads_to_resume: {\n                    let mut queue = VecDeque::new();\n                    queue.push_back((main_thread_id, main_thread_user_data, None));\n                    queue\n                },\n                dead: None,\n            }),\n            user_data: proc_user_data,\n        });\n\n        {\n            let mut processes = self.processes.lock();\n            processes.insert(new_pid, Arc::downgrade(&process));\n            // Shrink the list from time to time so that it doesn't grow too much.\n            if u64::from(new_pid) % 256 == 0 {\n                processes.shrink_to(PROCESSES_MIN_CAPACITY);\n            }\n        }\n\n        self.execution_queue.push(process.clone());\n        self.wakers.notify_one();\n\n        let proc_lock = ProcAccess {\n            collection: self,\n            process: Some(process),\n            pid_tid_pool: &self.pid_tid_pool,\n        };\n\n        Ok((proc_lock, main_thread_id))\n    }\n\n    /// Find a thread that is ready to be run.\n    ///\n    /// Which thread is picked is implementation-defined and no guarantee is made.\n    pub fn run(&self) -> RunFuture<TExtr, TPud, TTud> {\n        RunFuture(self, self.wakers.register())\n    }\n\n    /// Returns an iterator to all the processes that exist in the collection.\n    ///\n    /// This is equivalent to calling [`ProcessesCollection::process_by_id`] for each possible\n    /// ID.\n    pub fn processes<'a>(\n        &'a self,\n    ) -> impl ExactSizeIterator<Item = ProcAccess<'a, TExtr, TPud, TTud>> + 'a {\n        let processes = self.processes.lock();\n\n        // TODO: what if process is in death_reports?\n\n        processes\n            .values()\n            .cloned()\n            .filter_map(|process| {\n                if let Some(process) = process.upgrade() {\n                    Some(ProcAccess {\n                        collection: self,\n                        process: Some(process),\n                        pid_tid_pool: &self.pid_tid_pool,\n                    })\n                } else {\n                    None\n                }\n            })\n            .collect::<Vec<_>>()\n            .into_iter()\n    }\n\n    /// Returns a process by its [`Pid`], if it exists.\n    ///\n    /// This function returns a \"lock\".\n    /// While the lock is held, it isn't possible for a [`RunOneOutcome::ProcessFinished`]\n    /// message to be returned for the given process.\n    ///\n    /// You can call this function mutiple times in order to obtain the lock multiple times.\n    ///\n    /// This method is guaranteed to return `Some` for a process for which you already have an\n    /// existing lock, or if you hold a lock to one of its threads. However, it can return `None`\n    /// for a process that has crashed or finished before said crash or termination has been\n    /// reported with the [`run`](ProcessesCollection::run) method.\n    pub fn process_by_id(&self, pid: Pid) -> Option<ProcAccess<TExtr, TPud, TTud>> {\n        let processes = self.processes.lock();\n\n        // TODO: what if process is in death_reports?\n\n        if let Some(p) = processes.get(&pid)?.upgrade() {\n            debug_assert_eq!(p.pid, pid);\n            Some(ProcAccess {\n                collection: self,\n                process: Some(p),\n                pid_tid_pool: &self.pid_tid_pool,\n            })\n        } else {\n            None\n        }\n    }\n\n    /// Returns a thread by its [`ThreadId`], if it exists and is not running.\n    ///\n    /// Only threads that are currently paused waiting to be resumed can be grabbed using this\n    /// method.\n    ///\n    /// Additionally, the returned object holds an exclusive lock to this thread. Calling this\n    /// method twice for the same thread will fail the second time.\n    pub fn interrupted_thread_by_id(\n        &self,\n        id: ThreadId,\n    ) -> Option<ThreadAccess<TExtr, TPud, TTud>> {\n        let mut interrupted_threads = self.interrupted_threads.lock();\n\n        // TODO: what if thread has been moved in dead_threads?\n\n        if let Some((user_data, process)) = interrupted_threads.remove(&id) {\n            Some(ThreadAccess {\n                collection: self,\n                process: Some(process),\n                tid: id,\n                pid_tid_pool: &self.pid_tid_pool,\n                user_data: Some(user_data),\n            })\n        } else {\n            None\n        }\n    }\n\n    /// If the `process` passed as parameter is the last strong reference, then cleans the state\n    /// of `self` and reports the process's death to the user.\n    fn try_report_process_death(&self, process: Arc<Process<TPud, TTud>>) {\n        let mut process = match Arc::try_unwrap(process) {\n            Ok(p) => p,\n            Err(_) => return,\n        };\n\n        let _was_in = self.processes.lock().remove(&process.pid);\n        debug_assert!(_was_in.is_some());\n        debug_assert_eq!(_was_in.as_ref().unwrap().weak_count(), 0);\n        debug_assert_eq!(_was_in.as_ref().unwrap().strong_count(), 0);\n\n        debug_assert!(process.lock.get_mut().threads_to_resume.is_empty());\n\n        let dead = process.lock.get_mut().dead.take().unwrap();\n        self.death_reports.push((\n            process.pid,\n            process.user_data,\n            dead.dead_threads,\n            dead.outcome,\n        ));\n        self.wakers.notify_one();\n    }\n}\n\n/// Prototype for a [`ProcessesCollection`] under construction.\npub struct ProcessesCollectionBuilder<TExtr> {\n    /// See the corresponding field in `ProcessesCollection`.\n    pid_tid_pool: IdPool,\n    /// See the corresponding field in `ProcessesCollection`.\n    extrinsics: Vec<TExtr>,\n    /// See the corresponding field in `ProcessesCollection`.\n    extrinsics_id_assign:\n        HashMap<(Cow<'static, str>, Cow<'static, str>), (usize, Signature), FnvBuildHasher>,\n}\n\nimpl<TExtr> ProcessesCollectionBuilder<TExtr> {\n    /// Initializes a new builder using the given random seed.\n    ///\n    /// The seed is used in determine how [`Pid`]s are generated. The same seed will result in\n    /// the same sequence of [`Pid`]s.\n    pub fn with_seed(seed: [u8; 32]) -> ProcessesCollectionBuilder<TExtr> {\n        ProcessesCollectionBuilder {\n            pid_tid_pool: IdPool::with_seed(seed),\n            extrinsics: Default::default(),\n            extrinsics_id_assign: Default::default(),\n        }\n    }\n\n    /// Allocates a `Pid` that will not be used by any process.\n    ///\n    /// > **Note**: As of the writing of this comment, this feature is only ever used to allocate\n    /// >           `Pid`s that last forever. There is therefore no corresponding \"unreserve_pid\"\n    /// >           method that frees such an allocated `Pid`. If there is ever a need to free\n    /// >           these `Pid`s, such a method should be added.\n    pub fn reserve_pid(&mut self) -> Pid {\n        // Note that this function accepts `&mut self`. It could be `&self`, but that would\n        // expose implementation details.\n        self.pid_tid_pool.assign()\n    }\n\n    /// Registers a function that is available for processes to call.\n    ///\n    /// The function is registered under the given interface and function name. If a WASM module\n    /// imports a function with the corresponding interface and function name combination and\n    /// calls it, a [`RunOneOutcome::Interrupted`] event will be generated, containing the token\n    /// passed as parameter.\n    ///\n    /// The function signature passed as parameter is enforced when the process is created.\n    ///\n    /// # Panic\n    ///\n    /// Panics if an extrinsic with this interface/name combination has already been registered.\n    ///\n    pub fn with_extrinsic(\n        mut self,\n        interface: impl Into<Cow<'static, str>>,\n        f_name: impl Into<Cow<'static, str>>,\n        signature: Signature,\n        token: impl Into<TExtr>,\n    ) -> Self {\n        let interface = interface.into();\n        let f_name = f_name.into();\n\n        let index = self.extrinsics.len();\n        match self.extrinsics_id_assign.entry((interface, f_name)) {\n            Entry::Occupied(_) => panic!(),\n            Entry::Vacant(e) => e.insert((index, signature)),\n        };\n        self.extrinsics.push(token.into());\n        self\n    }\n\n    /// Turns the builder into a [`ProcessesCollection`].\n    pub fn build<TPud, TTud>(mut self) -> ProcessesCollection<TExtr, TPud, TTud> {\n        // We're not going to modify these fields ever again, so let's free some memory.\n        self.extrinsics.shrink_to_fit();\n        self.extrinsics_id_assign.shrink_to_fit();\n        debug_assert_eq!(self.extrinsics.len(), self.extrinsics_id_assign.len());\n\n        ProcessesCollection {\n            pid_tid_pool: self.pid_tid_pool,\n            wakers: wakers::Wakers::default(),\n            execution_queue: SegQueue::new(),\n            interrupted_threads: Spinlock::new(HashMap::with_capacity_and_hasher(\n                PROCESSES_MIN_CAPACITY, // TODO: no\n                Default::default(),\n            )),\n            processes: Spinlock::new(HashMap::with_capacity_and_hasher(\n                PROCESSES_MIN_CAPACITY,\n                Default::default(),\n            )),\n            extrinsics: self.extrinsics,\n            extrinsics_id_assign: self.extrinsics_id_assign,\n            death_reports: SegQueue::new(),\n        }\n    }\n}\n\n/// Outcome of the [`run`](ReadyToRun::run) function.\n#[derive(Debug)]\npub enum RunOneOutcome<'a, TExtr, TPud, TTud> {\n    /// Either the main thread of a process has finished, or a fatal error was encountered.\n    ///\n    /// The process no longer exists.\n    ProcessFinished {\n        /// Pid of the process that has finished.\n        pid: Pid,\n\n        /// User data of the process.\n        user_data: TPud,\n\n        /// Id and user datas of all the threads of the process. The first element is the main\n        /// thread's.\n        /// These threads no longer exist.\n        dead_threads: Vec<(ThreadId, TTud)>,\n\n        /// Value returned by the main thread that has finished, or error that happened.\n        outcome: Result<Option<crate::WasmValue>, Trap>,\n    },\n\n    /// A thread in a process has finished.\n    ThreadFinished {\n        /// Thread which has finished.\n        thread_id: ThreadId,\n\n        /// Process whose thread has finished.\n        process: ProcAccess<'a, TExtr, TPud, TTud>,\n\n        /// User data of the thread.\n        user_data: TTud,\n\n        /// Value returned by the function that was executed.\n        value: Option<crate::WasmValue>,\n    },\n\n    /// The currently-executed function has been paused due to a call to an external function.\n    ///\n    /// This variant contains the identifier of the external function that is expected to be\n    /// called, and its parameters. When you call [`resume`](ThreadAccess::resume)\n    /// again, you must pass back the outcome of calling that function.\n    Interrupted {\n        /// Thread that has been interrupted.\n        thread: ThreadAccess<'a, TExtr, TPud, TTud>,\n\n        /// Identifier of the function to call. Corresponds to the value provided at\n        /// initialization when resolving imports.\n        id: &'a TExtr,\n\n        /// Parameters of the function call.\n        params: Vec<crate::WasmValue>,\n    },\n\n    /// Running the thread has resulted in a decision to terminate the process. A\n    /// [`RunOneOutcome::ProcessFinished`] will soon be emitted.\n    StartProcessAbort {\n        /// Pid of the process that is going to finish soon.\n        pid: Pid,\n    },\n}\n\n/// Opaque error that happened during execution, such as an `unreachable` instruction.\n#[derive(Debug, Clone)]\npub struct Trap {\n    pub error: String,\n}\n\n/// Future that drives the [`ProcessesCollection::run`] method.\npub struct RunFuture<'a, TExtr, TPud, TTud>(\n    &'a ProcessesCollection<TExtr, TPud, TTud>,\n    wakers::Registration<'a>,\n);\n\nimpl<'a, TExtr, TPud, TTud> Future for RunFuture<'a, TExtr, TPud, TTud> {\n    type Output = RunFutureOut<'a, TExtr, TPud, TTud>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {\n        let this = &mut *self;\n\n        // We track the number of times this `loop` is run and panic if it seems like we're in an\n        // infinite loop.\n        let mut infinite_loop_guard = 0;\n\n        loop {\n            infinite_loop_guard += 1;\n            assert!(\n                infinite_loop_guard < 1_000_000,\n                \"infinite loop detected in scheduler\"\n            );\n\n            // Items are pushed on `death_reports` when a `Process` struct is destroyed.\n            if let Some((pid, user_data, dead_threads, outcome)) = this.0.death_reports.pop() {\n                return Poll::Ready(RunFutureOut::Direct(RunOneOutcome::ProcessFinished {\n                    pid,\n                    user_data,\n                    dead_threads,\n                    outcome,\n                }));\n            }\n\n            // We start by finding a process that is ready to run and lock it by extracting the\n            // state machine.\n            let process = match this.0.execution_queue.pop() {\n                Some(p) => p,\n                None => {\n                    // Register the wake-up for when a new item is pushed to `execution_queue`.\n                    this.1.set_waker(cx.waker());\n\n                    // It is possible for an item to have been pushed to `execution_queue` right\n                    // before we called `set_waker`. Try again to make sure the list is empty.\n                    match this.0.execution_queue.pop() {\n                        Some(p) => p,\n                        None => return Poll::Pending,\n                    }\n                }\n            };\n\n            // \"Lock\" the process's state machine for examination.\n            // TODO: this is ok right now because we only have a single thread per process\n            let mut proc_state = process.lock.lock();\n\n            // If the process was in `this.execution_queue`, then we are guaranteed that a\n            // thread was ready.\n            let (tid, thread_user_data, resume_value) =\n                proc_state.threads_to_resume.pop_front().unwrap();\n            // TODO: a lot of code in this module assumes one thread per process, which this debug_assert checks\n            debug_assert!(proc_state.threads_to_resume.is_empty());\n\n            // If the process is marked as dying, insert the thread in the dying state and see if\n            // we can finalize the destruction.\n            if let Some(proc_dead) = &mut proc_state.dead {\n                proc_dead.dead_threads.push((tid, thread_user_data));\n                drop(proc_state); // Drop the lock.\n                this.0.try_report_process_death(process);\n                continue;\n            }\n\n            drop(proc_state);\n\n            break Poll::Ready(RunFutureOut::ReadyToRun(ReadyToRun {\n                collection: this.0,\n                process: Some(process),\n                tid,\n                thread_user_data: Some(thread_user_data),\n                resume_value,\n            }));\n        }\n    }\n}\n\nimpl<'a, TExtr, TPud, TTud> Unpin for RunFuture<'a, TExtr, TPud, TTud> {}\n\n/// Event returned by [`RunFuture`].\npub enum RunFutureOut<'a, TExtr, TPud, TTud> {\n    /// Event directly generated.\n    Direct(RunOneOutcome<'a, TExtr, TPud, TTud>),\n    /// Ready to execute a bit of a thread.\n    ReadyToRun(ReadyToRun<'a, TExtr, TPud, TTud>),\n}\n\n/// Ready to resume one of the threads of a process.\n#[must_use]\npub struct ReadyToRun<'a, TExtr, TPud, TTud> {\n    /// The parent object.\n    collection: &'a ProcessesCollection<TExtr, TPud, TTud>,\n    /// Process to execute.\n    /// Always `Some` except during destruction.\n    /// Since it isn't possible to safely hold an `Arc<Process>` and `SpinlockGuard<...>`\n    /// referencing that `Arc<Process>` in the same struct, the `lock` field is force-locked while\n    /// the `ReadyToRun` is alive.\n    process: Option<Arc<Process<TPud, TTud>>>,\n    /// Id of the thread that we are going to run.\n    tid: ThreadId,\n    /// User data of the thread. Temporarily extracted from the global state. Always `Some`,\n    /// except right before destruction.\n    thread_user_data: Option<TTud>,\n    /// Value to feed to the virtual machine on resume.\n    resume_value: Option<crate::WasmValue>,\n}\n\nimpl<'a, TExtr, TPud, TTud> ReadyToRun<'a, TExtr, TPud, TTud> {\n    /// Performs the actual execution.\n    pub fn run(mut self) -> RunOneOutcome<'a, TExtr, TPud, TTud> {\n        // Lock the process, this time to execute the virtual machine.\n        let mut proc_state = self.process.as_ref().unwrap().lock.lock();\n\n        // Now run a thread until something happens.\n        // This takes most of the CPU time of this function.\n        let run_outcome = {\n            debug_assert!(!proc_state.vm.is_poisoned());\n            let thread_index = (0..proc_state.vm.num_threads())\n                .find(|n| proc_state.vm.thread(*n).unwrap().user_data().thread_id == self.tid)\n                .unwrap();\n            proc_state\n                .vm\n                .thread(thread_index)\n                .unwrap()\n                .run(self.resume_value)\n        };\n\n        match run_outcome {\n            Err(vm::RunErr::BadValueTy { .. }) => panic!(), // TODO:\n            Err(vm::RunErr::Poisoned) => unreachable!(),\n\n            // The entire process has ended or has crashed.\n            Ok(vm::ExecOutcome::ThreadFinished {\n                thread_index: 0,\n                return_value,\n                user_data: main_thread_user_data,\n            }) => {\n                debug_assert!(proc_state.vm.is_poisoned());\n                debug_assert!(proc_state.dead.is_none());\n\n                // TODO: Vec::with_capacity?\n                let mut dead_threads = vec![(\n                    main_thread_user_data.thread_id,\n                    self.thread_user_data.take().unwrap(),\n                )];\n\n                // TODO: possible deadlock?\n                let mut threads = self.collection.interrupted_threads.lock();\n                // TODO: O(n) complexity\n                while let Some(tid) = threads\n                    .iter()\n                    .find(|(_, (_, p))| Arc::ptr_eq(self.process.as_ref().unwrap(), p))\n                    .map(|(k, _)| *k)\n                {\n                    let (user_data, _) = threads.remove(&tid).unwrap();\n                    dead_threads.push((tid, user_data));\n                }\n\n                proc_state.dead = Some(ProcessDeadState {\n                    dead_threads,\n                    outcome: Ok(return_value),\n                });\n\n                RunOneOutcome::StartProcessAbort {\n                    pid: self.process.as_ref().unwrap().pid,\n                }\n            }\n\n            // The thread has ended.\n            Ok(vm::ExecOutcome::ThreadFinished {\n                return_value,\n                user_data,\n                ..\n            }) => {\n                debug_assert!(Arc::strong_count(&self.process.as_ref().unwrap()) >= 2);\n                drop(proc_state);\n                RunOneOutcome::ThreadFinished {\n                    thread_id: user_data.thread_id,\n                    process: ProcAccess {\n                        collection: self.collection,\n                        process: Some(self.process.as_ref().unwrap().clone()),\n                        pid_tid_pool: &self.collection.pid_tid_pool,\n                    },\n                    user_data: self.thread_user_data.take().unwrap(),\n                    value: return_value,\n                }\n            }\n\n            // Thread wants to call an extrinsic function.\n            Ok(vm::ExecOutcome::Interrupted {\n                mut thread,\n                id,\n                params,\n            }) => {\n                // TODO: check params against signature with a debug_assert?\n                let extrinsic = match self.collection.extrinsics.get(id) {\n                    Some(e) => e,\n                    None => unreachable!(),\n                };\n                let tid = thread.user_data().thread_id;\n                drop(proc_state);\n                RunOneOutcome::Interrupted {\n                    thread: ThreadAccess {\n                        collection: self.collection,\n                        process: Some(self.process.as_ref().unwrap().clone()),\n                        tid,\n                        pid_tid_pool: &self.collection.pid_tid_pool,\n                        user_data: Some(self.thread_user_data.take().unwrap()),\n                    },\n                    id: extrinsic,\n                    params,\n                }\n            }\n\n            // An error happened during the execution. We kill the entire process.\n            Ok(vm::ExecOutcome::Errored { error, mut thread }) => {\n                // TODO: Vec::with_capacity?\n                let mut dead_threads = vec![(\n                    thread.user_data().thread_id,\n                    self.thread_user_data.take().unwrap(),\n                )];\n                drop(thread);\n\n                debug_assert!(proc_state.vm.is_poisoned());\n                debug_assert!(proc_state.dead.is_none());\n\n                // TODO: possible deadlock?\n                let mut threads = self.collection.interrupted_threads.lock();\n                // TODO: O(n) complexity\n                while let Some(tid) = threads\n                    .iter()\n                    .find(|(_, (_, p))| Arc::ptr_eq(self.process.as_ref().unwrap(), p))\n                    .map(|(k, _)| *k)\n                {\n                    let (user_data, _) = threads.remove(&tid).unwrap();\n                    dead_threads.push((tid, user_data));\n                }\n\n                proc_state.dead = Some(ProcessDeadState {\n                    dead_threads,\n                    outcome: Err(Trap { error: error.error }),\n                });\n\n                RunOneOutcome::StartProcessAbort {\n                    pid: self.process.as_ref().unwrap().pid,\n                }\n            }\n        }\n    }\n}\n\nimpl<'a, TExtr, TPud, TTud> Drop for ReadyToRun<'a, TExtr, TPud, TTud> {\n    fn drop(&mut self) {\n        // In the situation where the user didn't call `run`, we push back the thread to the\n        // queue.\n        if let Some(thread_user_data) = self.thread_user_data.take() {\n            let mut proc_state = self.process.as_ref().unwrap().lock.lock();\n\n            proc_state.threads_to_resume.push_back((\n                self.tid,\n                thread_user_data,\n                self.resume_value.take(),\n            ));\n            self.collection\n                .execution_queue\n                .push(self.process.as_ref().unwrap().clone());\n            self.collection.wakers.notify_one();\n        }\n\n        self.collection\n            .try_report_process_death(self.process.take().unwrap());\n    }\n}\n\n/// Access to a process within the collection.\npub struct ProcAccess<'a, TExtr, TPud, TTud> {\n    collection: &'a ProcessesCollection<TExtr, TPud, TTud>,\n    process: Option<Arc<Process<TPud, TTud>>>,\n\n    /// Reference to the same field in [`ProcessesCollection`].\n    pid_tid_pool: &'a IdPool,\n}\n\nimpl<'a, TExtr, TPud, TTud> ProcAccess<'a, TExtr, TPud, TTud> {\n    /// Returns the [`Pid`] of the process. Allows later retrieval by calling\n    /// [`process_by_id`](ProcessesCollection::process_by_id).\n    pub fn pid(&self) -> Pid {\n        self.process.as_ref().unwrap().pid\n    }\n\n    /// Returns the user data that is associated to the process.\n    pub fn user_data(&self) -> &TPud {\n        &self.process.as_ref().unwrap().user_data\n    }\n\n    /// Adds a new thread to the process, starting the function with the given index and passing\n    /// the given parameters.\n    ///\n    /// > **Note**: The \"function ID\" is the index of the function in the WASM module. WASM\n    /// >           doesn't have function pointers. Instead, all the functions are part of a single\n    /// >           global array of functions.\n    pub fn start_thread(\n        &self,\n        fn_index: u32,\n        params: Vec<crate::WasmValue>,\n        user_data: TTud,\n    ) -> Result<ThreadId, vm::ThreadStartErr> {\n        let thread_id = self.pid_tid_pool.assign(); // TODO: check for duplicates\n        let thread_data = Thread { thread_id };\n\n        let mut process_state = self.process.as_ref().unwrap().lock.lock();\n\n        process_state\n            .vm\n            .start_thread_by_id(fn_index, params, thread_data)?;\n\n        process_state\n            .threads_to_resume\n            .push_back((thread_id, user_data, None));\n\n        self.collection\n            .execution_queue\n            .push(self.process.as_ref().unwrap().clone());\n        self.collection.wakers.notify_one();\n\n        Ok(thread_id)\n    }\n\n    /// Marks the process as aborting.\n    ///\n    /// The termination will happen after all locks to this process have been released.\n    ///\n    /// Calling [`abort`](ProcAccess::abort) a second time or more has no effect.\n    pub fn abort(&self) {\n        let mut process_state = self.process.as_ref().unwrap().lock.lock();\n\n        if process_state.dead.is_some() {\n            return;\n        }\n\n        // TODO: possible deadlock?\n        let mut threads = self.collection.interrupted_threads.lock();\n        let mut dead_threads = Vec::new();\n        // TODO: O(n) complexity\n        while let Some(tid) = threads\n            .iter()\n            .find(|(_, (_, p))| Arc::ptr_eq(self.process.as_ref().unwrap(), p))\n            .map(|(k, _)| *k)\n        {\n            let (user_data, _) = threads.remove(&tid).unwrap();\n            dead_threads.push((tid, user_data));\n        }\n\n        process_state.dead = Some(ProcessDeadState {\n            dead_threads,\n            outcome: Err(Trap {\n                // TODO: use an enum for Trap instead?\n                error: String::from(\"Aborted\"),\n            }),\n        });\n    }\n}\n\nimpl<'a, TExtr, TPud, TTud> fmt::Debug for ProcAccess<'a, TExtr, TPud, TTud>\nwhere\n    TPud: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_struct(\"ProcAccess\")\n            .field(\"pid\", &self.pid())\n            .field(\"user_data\", self.user_data())\n            .finish()\n    }\n}\n\nimpl<'a, TExtr, TPud, TTud> Clone for ProcAccess<'a, TExtr, TPud, TTud> {\n    fn clone(&self) -> Self {\n        ProcAccess {\n            collection: self.collection,\n            pid_tid_pool: self.pid_tid_pool,\n            process: self.process.clone(),\n        }\n    }\n}\n\nimpl<'a, TExtr, TPud, TTud> Drop for ProcAccess<'a, TExtr, TPud, TTud> {\n    fn drop(&mut self) {\n        self.collection\n            .try_report_process_death(self.process.take().unwrap());\n    }\n}\n\n/// Access to a thread within the collection.\npub struct ThreadAccess<'a, TExtr, TPud, TTud> {\n    collection: &'a ProcessesCollection<TExtr, TPud, TTud>,\n    process: Option<Arc<Process<TPud, TTud>>>,\n\n    /// Identifier of the thread. Must always match one of the user data in the virtual machine.\n    tid: ThreadId,\n\n    /// Reference to the same field in [`ProcessesCollection`].\n    pid_tid_pool: &'a IdPool,\n\n    /// User data extracted from [`Thread`]. Must be put back when this struct is destroyed.\n    /// Always `Some`, except right before destruction.\n    user_data: Option<TTud>,\n}\n\n/// Error while reading memory.\n#[derive(Debug)]\npub struct OutOfBoundsError;\n\nimpl<'a, TExtr, TPud, TTud> ThreadAccess<'a, TExtr, TPud, TTud> {\n    /// Returns the id of the thread. Allows later retrieval by calling\n    /// [`thread_by_id`](ProcessesCollection::interrupted_thread_by_id).\n    ///\n    /// [`ThreadId`]s are unique within a [`ProcessesCollection`], independently from the process.\n    pub fn tid(&self) -> ThreadId {\n        self.tid\n    }\n\n    /// Returns the [`Pid`] of the process. Allows later retrieval by calling\n    /// [`process_by_id`](ProcessesCollection::process_by_id).\n    pub fn pid(&self) -> Pid {\n        self.process.as_ref().unwrap().pid\n    }\n\n    /// Returns the process this thread belongs to.\n    pub fn process(&self) -> ProcAccess<'a, TExtr, TPud, TTud> {\n        ProcAccess {\n            collection: self.collection,\n            process: self.process.clone(),\n            pid_tid_pool: self.pid_tid_pool,\n        }\n    }\n\n    /// Write the data at the given memory location.\n    ///\n    /// Returns an error if the range is invalid or out of range.\n    ///\n    /// > **Important**: See also the remarks on [`ThreadAccess::write_memory`].\n    ///\n    pub fn read_memory(&self, offset: u32, size: u32) -> Result<Vec<u8>, OutOfBoundsError> {\n        // TODO: if another thread of this process is running, this will block until it has\n        // finished executing ; it isn't really possible right now to do otherwise, as the WASM\n        // memory model isn't properly defined\n        let lock = self.process.as_ref().unwrap().lock.lock();\n        lock.vm\n            .read_memory(offset, size)\n            .map_err(|vm::OutOfBoundsError| OutOfBoundsError)\n    }\n\n    /// Write the data at the given memory location.\n    ///\n    /// Returns an error if the range is invalid or out of range.\n    ///\n    /// # About concurrency\n    ///\n    /// Memory writes made using this method are guaranteed to be visible later by calling\n    /// [`read_memory`](ThreadAccess::read_memory) on the same thread.\n    ///\n    /// However, writes are not guaranteed to be visible by calling\n    /// [`read_memory`](ThreadAccess::read_memory) on a different thread, even when\n    /// they belong to the same process.\n    ///\n    /// It is only when the instance of [`ThreadAccess`] is\n    /// [resume](ThreadAccess::resume)d that the writes are guaranteed to be made\n    /// visible to the rest of the process. This means that it is legal, for example, for this\n    /// method to keep a cache of the changes and flush it later.\n    ///\n    /// As such, just like for \"actual threads\", writing and reading the same memory from multiple\n    /// different threads without any synchronization primitive (which resuming the thread\n    /// provides) will lead to a race condition.\n    ///\n    pub fn write_memory(&mut self, offset: u32, value: &[u8]) -> Result<(), OutOfBoundsError> {\n        // TODO: if another thread of this process is running, this will block until it has\n        // finished executing ; it isn't really possible right now to do otherwise, as the WASM\n        // memory model isn't properly defined\n        let mut lock = self.process.as_ref().unwrap().lock.lock();\n        lock.vm\n            .write_memory(offset, value)\n            .map_err(|vm::OutOfBoundsError| OutOfBoundsError)\n    }\n\n    /// Returns the user data that is associated to the thread.\n    pub fn user_data(&self) -> &TTud {\n        self.user_data.as_ref().unwrap()\n    }\n\n    /// Returns the user data that is associated to the thread.\n    pub fn user_data_mut(&mut self) -> &mut TTud {\n        self.user_data.as_mut().unwrap()\n    }\n\n    /// After [`RunOneOutcome::Interrupted`] is returned, use this function to feed back the value\n    /// to use as the return type of the function that has been called.\n    ///\n    /// This releases the [`ThreadAccess`]. The thread can now potentially be run by\n    /// calling [`ProcessesCollection::run`].\n    pub fn resume(mut self, value: Option<crate::WasmValue>) {\n        let process = self.process.take().unwrap();\n        let user_data = self.user_data.take().unwrap();\n\n        let push_to_exec_q = {\n            let mut process_state = process.lock.lock();\n            let process_state = &mut *process_state;\n            if let Some(death_state) = &mut process_state.dead {\n                debug_assert!(process_state.vm.is_poisoned());\n                death_state.dead_threads.push((self.tid, user_data));\n                false\n            } else {\n                process_state\n                    .threads_to_resume\n                    .push_back((self.tid, user_data, value));\n                true\n            }\n        };\n\n        if push_to_exec_q {\n            self.collection.execution_queue.push(process);\n            self.collection.wakers.notify_one();\n        } else {\n            self.collection.try_report_process_death(process);\n        }\n    }\n}\n\nimpl<'a, TExtr, TPud, TTud> fmt::Debug for ThreadAccess<'a, TExtr, TPud, TTud> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_struct(\"ThreadAccess\")\n            .field(\"pid\", &self.pid())\n            .finish()\n    }\n}\n\nimpl<'a, TExtr, TPud, TTud> Drop for ThreadAccess<'a, TExtr, TPud, TTud> {\n    fn drop(&mut self) {\n        let process = match self.process.take() {\n            Some(p) => p,\n            None => return,\n        };\n\n        // `self.user_data` is `None` if the thread has been resumed, and `Some` if it has been\n        // dropped without being resumed.\n        if let Some(user_data) = self.user_data.take() {\n            let mut process_state_lock = process.lock.lock();\n            let process_state = &mut *process_state_lock;\n\n            if let Some(death_state) = &mut process_state.dead {\n                debug_assert!(process_state.vm.is_poisoned());\n                death_state.dead_threads.push((self.tid, user_data));\n            } else {\n                let mut interrupted_threads = self.collection.interrupted_threads.lock();\n                drop(process_state_lock);\n                let _prev_in = interrupted_threads.insert(self.tid, (user_data, process));\n                debug_assert!(_prev_in.is_none());\n                return;\n            }\n        }\n\n        self.collection.try_report_process_death(process);\n    }\n}\n"
  },
  {
    "path": "kernel/core/src/scheduler/tests/basic_module.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::extrinsics::NoExtrinsics;\nuse crate::scheduler::{CoreBuilder, CoreRunOutcome};\nuse futures::prelude::*;\n\n#[test]\nfn basic_module() {\n    let module = from_wat!(\n        local,\n        r#\"(module\n        (func $_start (result i32)\n            i32.const 5)\n        (export \"_start\" (func $_start)))\n    \"#\n    );\n\n    let core = CoreBuilder::<NoExtrinsics>::with_seed([0; 64]).build();\n    let expected_pid = core.execute(&module).unwrap().0.pid();\n\n    let event = loop {\n        if let Some(ev) = core.run().now_or_never().unwrap().or_run() {\n            break ev;\n        }\n    };\n\n    match event {\n        CoreRunOutcome::ProgramFinished {\n            pid,\n            outcome: Ok(ret_val),\n            ..\n        } => {\n            assert_eq!(pid, expected_pid);\n            assert!(matches!(ret_val, Some(crate::WasmValue::I32(5))));\n        }\n        _ => panic!(),\n    }\n}\n"
  },
  {
    "path": "kernel/core/src/scheduler/tests/emit_not_available.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::extrinsics::NoExtrinsics;\nuse crate::scheduler::{CoreBuilder, CoreRunOutcome};\nuse crate::InterfaceHash;\nuse futures::prelude::*;\n\n#[test]\nfn emit_not_available() {\n    /* Original code:\n\n    let interface = redshirt_syscalls::InterfaceHash::from_raw_hash([\n        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,\n    ]);\n\n    unsafe {\n        let _ = redshirt_syscalls::MessageBuilder::default()\n            .add_data_raw(&[1, 2, 3, 4, 5, 6, 7, 8])\n            .emit_without_response(&interface);\n    }\n\n    */\n    let module = from_wat!(\n        local,\n        r#\"\n(module\n    (type $t0 (func (param i32 i32 i32 i64 i32) (result i32)))\n    (import \"redshirt\" \"emit_message\" (func $_ZN27redshirt_syscalls3ffi12emit_message17h508280f1400e36efE (type $t0)))\n    (func $_start (result i32)\n        (local $l0 i32)\n        global.get $g0\n        i32.const 64\n        i32.sub\n        local.tee $l0\n        global.set $g0\n        local.get $l0\n        i64.const 3978425819141910832\n        i64.store offset=32\n        local.get $l0\n        i64.const 2820983053732684064\n        i64.store offset=24\n        local.get $l0\n        i64.const 1663540288323457296\n        i64.store offset=16\n        local.get $l0\n        i64.const 506097522914230528\n        i64.store offset=8\n        local.get $l0\n        i32.const 1048576\n        i64.extend_i32_s\n        i64.const 34359738368\n        i64.or\n        i64.store offset=41 align=1\n        local.get $l0\n        i32.const 1\n        i32.store8 offset=40\n        local.get $l0\n        i32.const 8\n        i32.add\n        local.get $l0\n        i32.const 40\n        i32.add\n        i32.const 1\n        i32.or\n        i32.const 1\n        i64.const 2\n        local.get $l0\n        i32.const 56\n        i32.add\n        call $_ZN27redshirt_syscalls3ffi12emit_message17h508280f1400e36efE\n        drop\n        local.get $l0\n        i32.const 64\n        i32.add\n        global.set $g0\n        i32.const 0)\n    (table $T0 1 1 funcref)\n    (memory $memory 17)\n    (global $g0 (mut i32) (i32.const 1048576))\n    (export \"memory\" (memory 0))\n    (export \"_start\" (func $_start))\n    (data (i32.const 1048576) \"\\01\\02\\03\\04\\05\\06\\07\\08\"))\"#\n    );\n\n    let core = CoreBuilder::<NoExtrinsics>::with_seed([0; 64]).build();\n    core.execute(&module).unwrap();\n\n    match core.run().now_or_never().unwrap().or_run() {\n        Some(CoreRunOutcome::InterfaceMessage { interface, .. }) => {\n            assert_eq!(\n                interface,\n                InterfaceHash::from_raw_hash([\n                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14,\n                    0x15, 0x16, 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x30, 0x31,\n                    0x32, 0x33, 0x34, 0x35, 0x36, 0x37,\n                ])\n            );\n        }\n        _ => panic!(),\n    }\n\n    assert!(core.run().now_or_never().is_none());\n}\n"
  },
  {
    "path": "kernel/core/src/scheduler/tests/trapping_module.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::extrinsics::NoExtrinsics;\nuse crate::scheduler::{CoreBuilder, CoreRunOutcome};\nuse futures::prelude::*;\n\n#[test]\nfn trapping_module() {\n    let module = from_wat!(\n        local,\n        r#\"(module\n        (func $_start\n            unreachable)\n        (export \"_start\" (func $_start)))\n    \"#\n    );\n\n    let core = CoreBuilder::<NoExtrinsics>::with_seed([0; 64]).build();\n    let expected_pid = core.execute(&module).unwrap().0.pid();\n\n    let event = loop {\n        if let Some(ev) = core.run().now_or_never().unwrap().or_run() {\n            break ev;\n        }\n    };\n\n    match event {\n        CoreRunOutcome::ProgramFinished {\n            pid,\n            outcome: Err(_),\n            ..\n        } => {\n            assert_eq!(pid, expected_pid);\n        }\n        _ => panic!(),\n    }\n}\n"
  },
  {
    "path": "kernel/core/src/scheduler/tests.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n#![cfg(test)]\n\nuse crate::extrinsics::NoExtrinsics;\n\nmod basic_module;\nmod emit_not_available;\nmod trapping_module;\n\n#[test]\nfn send_sync() {\n    fn is_send_sync<T: Send + Sync>() {}\n    is_send_sync::<super::Core<NoExtrinsics>>()\n}\n"
  },
  {
    "path": "kernel/core/src/scheduler/vm.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::{primitives::Signature, ValueType, WasmValue};\n\nuse alloc::{\n    borrow::{Cow, ToOwned as _},\n    boxed::Box,\n    format,\n    string::{String, ToString as _},\n    vec::Vec,\n};\nuse core::{\n    cell::RefCell,\n    convert::{TryFrom as _, TryInto},\n    fmt,\n};\nuse itertools::Itertools as _;\nuse smallvec::SmallVec;\n\n/// WASMI state machine dedicated to a process.\n///\n/// # Initialization\n///\n/// Initializing a state machine is done by passing a module, in other words a WASM binary.\n///\n/// The module might contain a list of functions to import and that the initialization process\n/// must resolve. When such an import is encountered, the closure passed to the\n/// [`new`](ProcessStateMachine::new) function is invoked and must return an opaque integer decided\n/// by the user. This integer is later passed back to the user of this struct in the situation when\n/// the state machine invokes that external function.\n///\n/// # Threads\n///\n/// This struct is composed of one or multiple threads. When initialized, the VM starts with a\n/// single thread at the start of the \"main\" function of the WASM module.\n///\n/// In order to run the VM, grab a thread by calling [`ProcessStateMachine::threads`], then call\n/// [`Thread::run`]. The thread will then run until it either finishes (in which case the thread\n/// is then destroyed), or attempts to call an imported function.\n///\n/// TODO: It is intended that in the future the `run` function stops after a certain period of\n/// time has elapsed, in order to do preemptive multithreading. This requires a lot of changes in\n/// the interpreter, and isn't going to happen any time soon.\n///\n/// The [`run`](Thread::run) method requires passing a value. The first time you call\n/// [`run`](Thread::run) for any given thread, you must pass the value `None`. If that thread is\n/// then interrupted by a call to an imported function, you must execute the imported function and\n/// pass its return value the next time you call [`run`](Thread::run).\n///\n/// The generic parameter of this struct is some userdata that is associated with each thread.\n/// You must pass a value when creating a thread, and can retreive it later by calling\n/// [`user_data`](Thread::user_data) or [`into_user_data`](Thread::into_user_data).\n///\n/// # Poisoning\n///\n/// If the main thread stops, or if any thread encounters an error, then the VM moves into a\n/// \"poisoned\" state. It is then no longer possible to run anything in it. Threads are kept alive\n/// so that you can examine their state, but attempting to call [`run`](Thread::run) will return\n/// an error.\n///\n/// # Single-threaded-ness\n///\n/// The [`ProcessStateMachine`] is single-threaded. In other words, the VM can only ever run one\n/// thread simultaneously. This might change in the future.\n///\npub struct ProcessStateMachine<T> {\n    /// Wasmi store.\n    store: wasmi::Store<()>,\n\n    /// An instance of the module.\n    instance: wasmi::Instance,\n\n    /// Memory of the module instantiation.\n    ///\n    /// Contains `None` if there's no memory.\n    ///\n    /// Right now we only support one unique `Memory` object per process.\n    memory: Option<wasmi::Memory>,\n\n    /// List of threads that this process is running.\n    // TODO: use a Slab instead\n    threads: SmallVec<[ThreadState<T>; 4]>,\n\n    /// If true, the state machine is in a poisoned state and cannot run any code anymore.\n    is_poisoned: bool,\n}\n\n/// State of a single thread within the VM.\nstruct ThreadState<T> {\n    /// State of the thread execution.\n    /// Always `Some`, but wrapped within an `Option` to be temporarily extracted.\n    execution: Option<ThreadExecution>,\n\n    /// Where the return value of the execution will be stored.\n    /// While this could be regenerated every time `run` is called, it is instead kept in the\n    /// `Interpreter` struct for convenience.\n    dummy_output_value: Option<wasmi::Val>,\n\n    /// Opaque user data associated with the thread.\n    user_data: T,\n}\n\nenum ThreadExecution {\n    /// Thread has been created but hasn't been started yet.\n    NotStarted(wasmi::Func, Vec<wasmi::Val>),\n\n    /// Thread has been started.\n    Started(wasmi::ResumableInvocation),\n}\n\n/// Access to a thread within the virtual machine.\npub struct Thread<'a, T> {\n    /// Reference to the parent object.\n    vm: &'a mut ProcessStateMachine<T>,\n\n    // Index within [`ProcessStateMachine::threads`] of the thread we are referencing.\n    index: usize,\n}\n\n/// Outcome of the [`run`](Thread::run) function.\n#[derive(Debug)]\npub enum ExecOutcome<'a, T> {\n    /// A thread has finished. The thread no longer exists in the list.\n    ///\n    /// If this was the main thread (i.e. `thread_index` is 0), then the state machine is now in\n    /// a poisoned state, and calling [`is_poisoned`](ProcessStateMachine::is_poisoned) will\n    /// return true.\n    ///\n    /// > **Note**: Keep in mind that how you want to react to this event is probably very\n    /// >           different depending on whether `thread_index` is 0. If this is the main thread,\n    /// >           then the entire process is now stopped.\n    ///\n    ThreadFinished {\n        /// Index of the thread that has finished.\n        thread_index: usize,\n\n        /// Return value of the thread function.\n        return_value: Option<WasmValue>,\n\n        /// User data that was stored within the thread.\n        user_data: T,\n    },\n\n    /// The currently-executed thread has been paused due to a call to an external function.\n    ///\n    /// This variant contains the identifier of the external function that is expected to be\n    /// called, and its parameters. When you call [`run`](Thread::run) again, you must pass back\n    /// the outcome of calling that function.\n    ///\n    /// > **Note**: The type of the return value of the function is called is not specified, as the\n    /// >           user is supposed to know it based on the identifier. It is an error to call\n    /// >           [`run`](Thread::run) with a value of the wrong type.\n    Interrupted {\n        /// Thread that was interrupted.\n        thread: Thread<'a, T>,\n\n        /// Identifier of the function to call. Corresponds to the value provided at\n        /// initialization when resolving imports.\n        id: usize,\n\n        /// Parameters of the function call.\n        params: Vec<WasmValue>,\n    },\n\n    /// The currently-executed function has finished with an error. The state machine is now in a\n    /// poisoned state.\n    ///\n    /// Calling [`is_poisoned`](ProcessStateMachine::is_poisoned) will return true.\n    Errored {\n        /// Thread that error'd.\n        thread: Thread<'a, T>,\n\n        /// Error that happened.\n        error: Trap,\n    },\n}\n\n/// Opaque error that happened during execution, such as an `unreachable` instruction.\n#[derive(Debug, Clone)]\npub struct Trap {\n    pub error: String,\n}\n\n/// Error that can happen when initializing a VM.\n#[derive(Debug)]\npub enum NewErr {\n    /// Wasm bytecode is invalid.\n    InvalidWasm(String),\n    /// Failed to resolve a function imported by the module.\n    UnresolvedFunctionImport {\n        /// Name of the function that was unresolved.\n        function: String,\n        /// Name of module associated with the unresolved function.\n        module_name: String,\n    },\n    /// The \"_start\" symbol doesn't exist, or isn't a function, or doesn't have the expected\n    /// signature.\n    BadStartFunction,\n    /// A memory object has both been imported and exported.\n    MultipleMemoriesNotSupported,\n    /// Failed to allocate memory for the virtual machine.\n    CouldntAllocateMemory,\n    /// The Wasm module requires importing a global or a table, which isn't supported.\n    ImportTypeNotSupported,\n    /// Error while instantiating the WebAssembly module.\n    Instantiation {\n        /// Opaque error message.\n        error: String,\n    },\n}\n\n/// Error that can happen when starting a new thread.\n#[derive(Debug)]\npub enum ThreadStartErr {\n    /// The state machine is poisoned and cannot run anymore.\n    Poisoned,\n    /// Couldn't find the requested function.\n    FunctionNotFound,\n    /// The requested function has been found in the list of exports, but it is not a function.\n    NotAFunction,\n    /// The signature of the function uses types that aren't supported.\n    SignatureNotSupported,\n    /// The types of the provided parameters don't match the signature.\n    InvalidParameters,\n}\n\n/// Error while reading memory.\n#[derive(Debug)]\npub struct OutOfBoundsError;\n\n/// Error that can happen when resuming the execution of a function.\n#[derive(Debug)]\npub enum RunErr {\n    /// The state machine is poisoned.\n    Poisoned,\n    /// Passed a wrong value back.\n    BadValueTy {\n        /// Type of the value that was expected.\n        expected: Option<ValueType>,\n        /// Type of the value that was actually passed.\n        obtained: Option<ValueType>,\n    },\n}\n\nimpl<T> ProcessStateMachine<T> {\n    /// Creates a new process state machine from the given module.\n    ///\n    /// The closure is called for each import that the module has. It must assign a number to each\n    /// import, or return an error if the import can't be resolved. When the VM calls one of these\n    /// functions, this number will be returned back in order for the user to know how to handle\n    /// the call.\n    ///\n    /// A single main thread (whose user data is passed by parameter) is automatically created and\n    /// is paused at the start of the \"_start\" function of the module.\n    pub fn new(\n        module: &[u8],\n        main_thread_user_data: T,\n        mut symbols: impl FnMut(&str, &str, &Signature) -> Result<usize, ()>,\n    ) -> Result<Self, NewErr> {\n        let engine = {\n            let config = wasmi::Config::default();\n            // TODO: add config here?\n            wasmi::Engine::new(&config)\n        };\n\n        let module = wasmi::Module::new(&engine, module.as_ref())\n            .map_err(|err| NewErr::InvalidWasm(err.to_string()))?;\n\n        let mut store = wasmi::Store::new(&engine, ());\n\n        let mut linker = wasmi::Linker::<()>::new(&engine);\n        let mut imported_memories = Vec::with_capacity(1);\n\n        for import in module.imports() {\n            match import.ty() {\n                wasmi::ExternType::Func(func_type) => {\n                    // Note that if `Signature::try_from` fails, a `UnresolvedFunctionImport` is\n                    // also returned. This is because it is not possible for the function to\n                    // resolve anyway if its signature can't be represented.\n                    let function_index =\n                        match Signature::try_from(func_type)\n                            .ok()\n                            .and_then(|conv_signature| {\n                                symbols(import.module(), import.name(), &conv_signature).ok()\n                            }) {\n                            Some(i) => i,\n                            None => {\n                                return Err(NewErr::UnresolvedFunctionImport {\n                                    module_name: import.module().to_owned(),\n                                    function: import.name().to_owned(),\n                                });\n                            }\n                        };\n\n                    // `func_new` returns an error in case of duplicate definition. Since we\n                    // enumerate over the imports, this can't happen.\n                    linker\n                        .func_new(\n                            import.module(),\n                            import.name(),\n                            func_type.clone(),\n                            move |_caller, parameters, _ret| {\n                                Err(wasmi::Error::host(InterruptedTrap {\n                                    function_index,\n                                    parameters: parameters\n                                        .iter()\n                                        .map(|v| WasmValue::try_from(v).unwrap())\n                                        .collect(),\n                                }))\n                            },\n                        )\n                        .unwrap();\n                }\n                wasmi::ExternType::Memory(memory_type) => {\n                    let memory = wasmi::Memory::new(&mut store, *memory_type)\n                        .map_err(|_| NewErr::CouldntAllocateMemory)?;\n                    imported_memories.push(memory);\n\n                    // `define` returns an error in case of duplicate definition. Since we\n                    // enumerate over the imports, this can't happen.\n                    linker\n                        .define(import.module(), import.name(), memory)\n                        .unwrap();\n                }\n                wasmi::ExternType::Global(_) | wasmi::ExternType::Table(_) => {\n                    return Err(NewErr::ImportTypeNotSupported);\n                }\n            }\n        }\n\n        let instance = linker\n            .instantiate(&mut store, &module)\n            .map_err(|err| NewErr::Instantiation {\n                error: err.to_string(),\n            })?\n            // TODO: implement the special start function\n            .start(&mut store)\n            .map_err(|_| todo!())?;\n\n        let memory = imported_memories\n            .into_iter()\n            .chain(instance.exports(&store).filter_map(|exp| exp.into_memory()))\n            .at_most_one()\n            .map_err(|_| NewErr::MultipleMemoriesNotSupported)?;\n\n        let mut state_machine = ProcessStateMachine {\n            store,\n            instance,\n            memory,\n            is_poisoned: false,\n            threads: SmallVec::new(),\n        };\n\n        // Try to start executing `_start`.\n        match state_machine.start_thread_by_name(\"_start\", &[][..], main_thread_user_data) {\n            Ok(_) => {}\n            Err((\n                ThreadStartErr::FunctionNotFound\n                | ThreadStartErr::NotAFunction\n                | ThreadStartErr::InvalidParameters\n                | ThreadStartErr::SignatureNotSupported,\n                _,\n            )) => return Err(NewErr::BadStartFunction),\n            Err((ThreadStartErr::Poisoned, _)) => unreachable!(),\n        };\n\n        Ok(state_machine)\n    }\n\n    /// Returns true if the state machine is in a poisoned state and cannot run anymore.\n    pub fn is_poisoned(&self) -> bool {\n        self.is_poisoned\n    }\n\n    /// Starts executing a function. Immediately pauses the execution and puts it in an\n    /// interrupted state.\n    ///\n    /// You should call [`run`](Thread::run) afterwards with a value of `None`.\n    ///\n    /// > **Note**: The \"function ID\" is the index of the function in the WASM module. WASM\n    /// >           doesn't have function pointers. Instead, all the functions are part of a single\n    /// >           global array of functions.\n    pub fn start_thread_by_id(\n        &mut self,\n        function_id: u32,\n        params: impl IntoIterator<Item = WasmValue>,\n        user_data: T,\n    ) -> Result<Thread<T>, ThreadStartErr> {\n        if self.is_poisoned {\n            return Err(ThreadStartErr::Poisoned);\n        }\n\n        // TODO: re-implement\n        return Err(ThreadStartErr::FunctionNotFound);\n    }\n\n    /// Same as [`start_thread_by_id`](ProcessStateMachine::start_thread_by_id), but executes a\n    /// symbol by name.\n    fn start_thread_by_name(\n        &mut self,\n        symbol_name: &str,\n        params: &[WasmValue],\n        user_data: T,\n    ) -> Result<Thread<T>, (ThreadStartErr, T)> {\n        if self.is_poisoned {\n            return Err((ThreadStartErr::Poisoned, user_data));\n        }\n\n        let func_to_call = match self.instance.get_export(&self.store, symbol_name) {\n            Some(wasmi::Extern::Func(function)) => {\n                // Try to convert the signature of the function to call, in order to make sure\n                // that the type of parameters and return value are supported.\n                let Ok(signature) = Signature::try_from(function.ty(&self.store)) else {\n                    return Err((ThreadStartErr::SignatureNotSupported, user_data));\n                };\n\n                // Check whether the types of the parameters are correct.\n                // This is necessary to do manually because for API purposes the call immediately\n                //starts, while in the internal implementation it doesn't actually.\n                if params.len() != signature.parameters().len() {\n                    return Err((ThreadStartErr::InvalidParameters, user_data));\n                }\n                for (obtained, expected) in params.iter().zip(signature.parameters()) {\n                    if obtained.ty() != *expected {\n                        return Err((ThreadStartErr::InvalidParameters, user_data));\n                    }\n                }\n\n                function\n            }\n            Some(_) => return Err((ThreadStartErr::NotAFunction, user_data)),\n            None => return Err((ThreadStartErr::FunctionNotFound, user_data)),\n        };\n\n        let dummy_output_value = {\n            let func_to_call_ty = func_to_call.ty(&self.store);\n            let list = func_to_call_ty.results();\n            // We don't support more than one return value. This is enforced by verifying the\n            // function signature above.\n            debug_assert!(list.len() <= 1);\n            list.first().map(|item| match *item {\n                wasmi::core::ValType::I32 => wasmi::Val::I32(0),\n                wasmi::core::ValType::I64 => wasmi::Val::I64(0),\n                wasmi::core::ValType::F32 => wasmi::Val::F32(0.0f32.into()),\n                wasmi::core::ValType::F64 => wasmi::Val::F64(0.0.into()),\n                _ => unreachable!(),\n            })\n        };\n\n        self.threads.push(ThreadState {\n            execution: Some(ThreadExecution::NotStarted(\n                func_to_call,\n                params\n                    .iter()\n                    .map(|v| wasmi::Val::from(*v))\n                    .collect::<Vec<_>>(),\n            )),\n            dummy_output_value,\n            user_data,\n        });\n\n        let thread_id = self.threads.len() - 1;\n        Ok(Thread {\n            vm: self,\n            index: thread_id,\n        })\n    }\n\n    /// Returns the number of threads that are running.\n    pub fn num_threads(&self) -> usize {\n        self.threads.len()\n    }\n\n    /// Returns the thread with the given index. The index is between `0` and\n    /// [`num_threads`](ProcessStateMachine::num_threads).\n    ///\n    /// The main thread is always index `0`, unless it has terminated.\n    ///\n    /// Keep in mind that when a thread finishes, all the indices above its index shift by one.\n    ///\n    /// Returns `None` if the index is superior or equal to what\n    /// [`num_threads`](ProcessStateMachine::num_threads) would return.\n    pub fn thread(&mut self, index: usize) -> Option<Thread<T>> {\n        if index < self.threads.len() {\n            Some(Thread { vm: self, index })\n        } else {\n            None\n        }\n    }\n\n    /// Consumes this VM and returns all the remaining threads' user datas.\n    pub fn into_user_datas(self) -> impl ExactSizeIterator<Item = T> {\n        self.threads.into_iter().map(|thread| thread.user_data)\n    }\n\n    /// Copies the given memory range into a `Vec<u8>`.\n    ///\n    /// Returns an error if the range is invalid or out of range.\n    // TODO: make more zero-cost?\n    pub fn read_memory(&self, offset: u32, size: u32) -> Result<Vec<u8>, OutOfBoundsError> {\n        let mem = match self.memory.as_ref() {\n            Some(m) => m,\n            None => return Err(OutOfBoundsError),\n        };\n\n        let offset = usize::try_from(offset).map_err(|_| OutOfBoundsError)?;\n        let size = usize::try_from(size).map_err(|_| OutOfBoundsError)?;\n\n        let data = mem.data(&self.store);\n        if offset + size > data.len() {\n            return Err(OutOfBoundsError);\n        }\n\n        Ok(data[offset..][..size].to_vec())\n    }\n\n    /// Write the data at the given memory location.\n    ///\n    /// Returns an error if the range is invalid or out of range.\n    pub fn write_memory(&mut self, offset: u32, value: &[u8]) -> Result<(), OutOfBoundsError> {\n        let mem = match self.memory.as_ref() {\n            Some(m) => m,\n            None => return Err(OutOfBoundsError),\n        };\n\n        mem.write(\n            &mut self.store,\n            usize::try_from(offset).map_err(|_| OutOfBoundsError)?,\n            value,\n        )\n        .map_err(|_| OutOfBoundsError)\n    }\n}\n\n// The fields related to `wasmi` do not implement `Send` because they use `std::rc::Rc`. `Rc`\n// does not implement `Send` because incrementing/decrementing the reference counter from\n// multiple threads simultaneously would be racy. It is however perfectly sound to move all the\n// instances of `Rc`s at once between threads, which is what we're doing here.\n//\n// This importantly means that we should never return a `Rc` (even by reference) across the API\n// boundary.\n// TODO: really annoying to have to use unsafe code\nunsafe impl<T: Send> Send for ProcessStateMachine<T> {}\n\nimpl<T> fmt::Debug for ProcessStateMachine<T>\nwhere\n    T: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_list().entries(self.threads.iter()).finish()\n    }\n}\n\nimpl<T> fmt::Debug for ThreadState<T>\nwhere\n    T: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"Thread\").field(&self.user_data).finish()\n    }\n}\n\nimpl<'a, T> Thread<'a, T> {\n    /// Starts or continues execution of this thread.\n    ///\n    /// If this is the first call you call [`run`](Thread::run) for this thread, then you must pass\n    /// a value of `None`.\n    /// If, however, you call this function after a previous call to [`run`](Thread::run) that was\n    /// interrupted by an external function call, then you must pass back the outcome of that call.\n    pub fn run(mut self, value: Option<WasmValue>) -> Result<ExecOutcome<'a, T>, RunErr> {\n        if self.vm.is_poisoned {\n            return Err(RunErr::Poisoned);\n        }\n\n        let thread_state = &mut self.vm.threads[self.index];\n\n        let outputs_storage_ptr =\n            if let Some(output_storage) = thread_state.dummy_output_value.as_mut() {\n                &mut core::array::from_mut(output_storage)[..]\n            } else {\n                &mut []\n            };\n\n        let result = match thread_state.execution.take() {\n            Some(ThreadExecution::NotStarted(func, params)) => {\n                if let Some(value) = value.as_ref() {\n                    return Err(RunErr::BadValueTy {\n                        expected: None,\n                        obtained: Some(value.ty()),\n                    });\n                }\n\n                func.call_resumable(&mut self.vm.store, &params, outputs_storage_ptr)\n            }\n            Some(ThreadExecution::Started(func)) => {\n                let expected = {\n                    let func_type = func.host_func().ty(&self.vm.store);\n                    // We don't support functions with more than one result type. This should have\n                    // been checked at initialization.\n                    debug_assert!(func_type.results().len() <= 1);\n                    func_type\n                        .results()\n                        .iter()\n                        .next()\n                        .map(|r| ValueType::try_from(*r).unwrap())\n                };\n                let obtained = value.as_ref().map(|v| v.ty());\n                if expected != obtained {\n                    return Err(RunErr::BadValueTy { expected, obtained });\n                }\n\n                let value = value.map(wasmi::Val::from);\n                let inputs = match value.as_ref() {\n                    Some(v) => &core::array::from_ref(v)[..],\n                    None => &[],\n                };\n\n                func.resume(&mut self.vm.store, inputs, outputs_storage_ptr)\n            }\n            None => return Err(RunErr::Poisoned),\n        };\n\n        match result {\n            Ok(wasmi::ResumableCall::Finished) => {\n                // Because we have checked the signature of the function, we know that this\n                // conversion can never fail.\n                let thread = self.vm.threads.remove(self.index);\n                let return_value = thread\n                    .dummy_output_value\n                    .map(|r| WasmValue::try_from(r).unwrap());\n                if self.index == 0 {\n                    self.vm.is_poisoned = true;\n                }\n                Ok(ExecOutcome::ThreadFinished {\n                    return_value,\n                    thread_index: self.index,\n                    user_data: thread.user_data,\n                })\n            }\n            Ok(wasmi::ResumableCall::Resumable(next)) => {\n                let trap = next.host_error().downcast_ref::<InterruptedTrap>().unwrap();\n                let function_index = trap.function_index;\n                let params = trap.parameters.clone();\n                thread_state.execution = Some(ThreadExecution::Started(next));\n                Ok(ExecOutcome::Interrupted {\n                    thread: self,\n                    id: function_index,\n                    params,\n                })\n            }\n            Err(err) => {\n                self.vm.is_poisoned = true;\n                Ok(ExecOutcome::Errored {\n                    thread: self,\n                    error: Trap {\n                        error: err.to_string(),\n                    },\n                })\n            }\n        }\n    }\n\n    /// Returns the index of the thread, so that you can retreive the thread later by calling\n    /// [`ProcessStateMachine::thread`].\n    ///\n    /// Keep in mind that when a thread finishes, all the indices above its index shift by one.\n    pub fn index(&self) -> usize {\n        self.index\n    }\n\n    /// Returns the user data associated to that thread.\n    pub fn user_data(&mut self) -> &mut T {\n        &mut self.vm.threads[self.index].user_data\n    }\n\n    /// Turns this thread into the user data associated to it.\n    pub fn into_user_data(self) -> &'a mut T {\n        &mut self.vm.threads[self.index].user_data\n    }\n}\n\nimpl<'a, T> fmt::Debug for Thread<'a, T>\nwhere\n    T: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        fmt::Debug::fmt(&self.vm.threads[self.index], f)\n    }\n}\n\n/// This dummy struct is meant to be converted to a `wasmi::core::Trap` and then back, similar to\n/// `std::any::Any`.\n#[derive(Debug, Clone)]\nstruct InterruptedTrap {\n    function_index: usize,\n    parameters: Vec<WasmValue>,\n}\n\nimpl fmt::Display for InterruptedTrap {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"Interrupted\")\n    }\n}\n\nimpl wasmi::core::HostError for InterruptedTrap {}\n\n#[cfg(test)]\nmod tests {\n    use super::{ExecOutcome, NewErr, ProcessStateMachine};\n    use crate::primitives::WasmValue;\n\n    #[test]\n    fn starts_if_main() {\n        let module = from_wat!(\n            local,\n            r#\"(module\n            (func $_start (result i32)\n                i32.const 5)\n            (export \"_start\" (func $_start)))\n        \"#\n        );\n\n        let _state_machine =\n            ProcessStateMachine::new(&module, (), |_, _, _| unreachable!()).unwrap();\n    }\n\n    #[test]\n    fn error_if_no_main() {\n        let module = from_wat!(\n            local,\n            r#\"(module\n            (func $_start (result i32)\n                i32.const 5)\n            (export \"foo\" (func $_start)))\n        \"#\n        );\n\n        match ProcessStateMachine::new(&module, (), |_, _, _| unreachable!()) {\n            Err(NewErr::BadStartFunction) => {}\n            _ => panic!(),\n        }\n    }\n\n    #[test]\n    fn main_executes() {\n        let module = from_wat!(\n            local,\n            r#\"(module\n            (func $_start (result i32)\n                i32.const 5)\n            (export \"_start\" (func $_start)))\n        \"#\n        );\n\n        let mut state_machine =\n            ProcessStateMachine::new(&module, (), |_, _, _| unreachable!()).unwrap();\n        match state_machine.thread(0).unwrap().run(None) {\n            Ok(ExecOutcome::ThreadFinished {\n                return_value: Some(WasmValue::I32(5)),\n                ..\n            }) => {}\n            _ => panic!(),\n        }\n        assert!(state_machine.thread(0).is_none());\n    }\n\n    #[test]\n    fn external_call_then_resume() {\n        let module = from_wat!(\n            local,\n            r#\"(module\n            (import \"\" \"test\" (func $test (result i32)))\n            (func $_start (result i32)\n                call $test)\n            (export \"_start\" (func $_start)))\n        \"#\n        );\n\n        let mut state_machine = ProcessStateMachine::new(&module, (), |_, _, _| Ok(9876)).unwrap();\n        match state_machine.thread(0).unwrap().run(None) {\n            Ok(ExecOutcome::Interrupted {\n                id: 9876,\n                ref params,\n                ..\n            }) if params.is_empty() => {}\n            _ => panic!(),\n        }\n\n        match state_machine\n            .thread(0)\n            .unwrap()\n            .run(Some(WasmValue::I32(2227)))\n        {\n            Ok(ExecOutcome::ThreadFinished {\n                return_value: Some(WasmValue::I32(2227)),\n                ..\n            }) => {}\n            _ => panic!(),\n        }\n        assert!(state_machine.thread(0).is_none());\n    }\n\n    #[test]\n    fn poisoning_works() {\n        let module = from_wat!(\n            local,\n            r#\"(module\n            (func $_start\n                unreachable)\n            (export \"_start\" (func $_start)))\n        \"#\n        );\n\n        let mut state_machine =\n            ProcessStateMachine::new(&module, (), |_, _, _| unreachable!()).unwrap();\n        match state_machine.thread(0).unwrap().run(None) {\n            Ok(ExecOutcome::Errored { .. }) => {}\n            _ => panic!(),\n        }\n\n        assert!(state_machine.is_poisoned());\n\n        // TODO: start running another function and check that `Poisoned` error is returned\n    }\n\n    // TODO: start mutiple threads\n}\n"
  },
  {
    "path": "kernel/core/src/scheduler.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Core system that includes executing Wasm programs passing messages to each other.\n//!\n//! This module is lower-level than [`system`](super::system). It doesn't hardcode any interface.\n\nmod extrinsics;\nmod ipc;\nmod processes;\nmod tests;\nmod vm;\n\npub use self::ipc::{Core, CoreBuilder, CoreProcess, CoreRunOutcome, ExecuteOut, ReadyToRun};\npub use self::vm::NewErr;\n"
  },
  {
    "path": "kernel/core/src/system/interfaces.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n// TODO: doc\n\nuse alloc::collections::VecDeque;\nuse core::{convert::TryFrom as _, mem, num::NonZeroU64};\nuse hashbrown::{hash_map::Entry, HashMap};\nuse redshirt_syscalls::{InterfaceHash, MessageId, Pid};\n\npub struct Interfaces {\n    // TODO: do something smarter than a spinning lock?\n    inner: spinning_top::Spinlock<Inner>,\n}\n\n#[derive(Debug)]\nstruct Inner {\n    interfaces: HashMap<InterfaceHash, Interface, fnv::FnvBuildHasher>,\n    registrations: slab::Slab<InterfaceRegistration>,\n}\n\n#[derive(Debug)]\nenum Interface {\n    /// Interface has a registered handler.\n    ///\n    /// Contains an index within [`Inner::registrations`].\n    Registered(usize),\n\n    /// Interface has no registered handler yet.\n    NotRegistered {\n        /// Messages emitted by programs and that haven't been accepted yet are pushed to this\n        /// field.\n        ///\n        /// No limit is enforced on the size of this container. However, since each entry\n        /// corresponds to a thread currently being paused, the total number of entries across\n        /// all `pending_accept` fields is bounded by the total number of threads across all\n        /// processes.\n        pending_accept: VecDeque<(MessageId, bool)>,\n    },\n}\n\n#[derive(Debug)]\nstruct InterfaceRegistration {\n    interface: InterfaceHash,\n    pid: Pid,\n    /// Messages of type `NextMessage` sent on the interface interface and that must be answered\n    /// with the next interface message.\n    queries: VecDeque<MessageId>,\n    /// If [`InterfaceRegistration::queries`] is empty, messages emitted by programs and that\n    /// haven't been accepted yet are pushed to this field.\n    pending_accept: VecDeque<(MessageId, bool)>,\n}\n\nimpl Interfaces {\n    pub fn new() -> Self {\n        Interfaces {\n            inner: spinning_top::Spinlock::new(Inner {\n                interfaces: Default::default(),\n                registrations: {\n                    // Registration IDs are of the type `NonZeroU64`.\n                    // The list of registrations starts with an entry at index `0` in order for\n                    // generated registration IDs to never be equal to 0.\n                    let mut registrations = slab::Slab::default();\n                    let _id = registrations.insert(InterfaceRegistration {\n                        interface: InterfaceHash::from_raw_hash(Default::default()),\n                        pid: 0xdeadbeef.into(), // TODO: ?!\n                        queries: VecDeque::new(),\n                        pending_accept: VecDeque::new(),\n                    });\n                    assert_eq!(_id, 0);\n                    registrations\n                },\n            }),\n        }\n    }\n\n    /// Called when a process requests to deliver a message to an interface handler.\n    pub fn emit_interface_message(\n        &self,\n        interface_hash: &InterfaceHash,\n        message_id: MessageId,\n        emitter_pid: Pid,\n        needs_answer: bool,\n        immediate: bool,\n    ) -> EmitInterfaceMessage {\n        let mut interfaces = self.inner.lock();\n        let interfaces = &mut *interfaces; // Avoids borrow errors.\n\n        let entry = match interfaces.interfaces.entry(interface_hash.clone()) {\n            Entry::Occupied(e) => e.into_mut(),\n            Entry::Vacant(_) if immediate => {\n                return EmitInterfaceMessage::Reject;\n            }\n            Entry::Vacant(e) => {\n                e.insert(Interface::NotRegistered {\n                    pending_accept: VecDeque::with_capacity(16), // TODO: capacity\n                })\n            }\n        };\n\n        match entry {\n            Interface::Registered(registration_id) => {\n                let registration = &mut interfaces.registrations[*registration_id];\n                if let Some(query_message_id) = registration.queries.pop_front() {\n                    debug_assert!(registration.pending_accept.is_empty());\n                    EmitInterfaceMessage::Deliver(MessageDelivery {\n                        to_deliver_message_id: message_id,\n                        interface: registration.interface.clone(),\n                        needs_answer,\n                        query_message_id,\n                        recipient_pid: registration.pid,\n                    })\n                } else if immediate {\n                    EmitInterfaceMessage::Reject\n                } else {\n                    registration\n                        .pending_accept\n                        .push_back((message_id, needs_answer));\n                    EmitInterfaceMessage::Queued\n                }\n            }\n            Interface::NotRegistered { pending_accept } => {\n                if immediate {\n                    EmitInterfaceMessage::Reject\n                } else {\n                    // TODO: is this unbounded queue attackable?\n                    pending_accept.push_back((message_id, needs_answer));\n                    EmitInterfaceMessage::Queued\n                }\n            }\n        }\n    }\n\n    /// Called when an interface handler emits a request for the next message that arrives on an\n    /// interface.\n    ///\n    /// Must be passed a [`RegistrationId`] and the [`Pid`] that the registration is expected to\n    /// belong to. The method verifies that the ownership matches.\n    ///\n    /// On success, can return a [`MessageDelivery`] representing a delivery of a certain\n    /// message earlier pushed using [`Interfaces::emit_interface_message`] to\n    /// `expected_registrer_pid` by answering `query_message_id`.\n    pub fn emit_message_query(\n        &self,\n        registration_id: RegistrationId,\n        query_message_id: MessageId,\n        expected_registerer_pid: Pid,\n    ) -> Result<Option<MessageDelivery>, ()> {\n        let registration_id = match usize::try_from(registration_id.0.get()) {\n            Ok(v) => v,\n            Err(_) => return Err(()),\n        };\n\n        let mut inner = self.inner.lock();\n\n        if let Some(registration) = inner.registrations.get_mut(registration_id) {\n            if registration.pid == expected_registerer_pid {\n                if let Some((msg, needs_answer)) = registration.pending_accept.pop_front() {\n                    debug_assert!(registration.queries.is_empty());\n                    Ok(Some(MessageDelivery {\n                        to_deliver_message_id: msg,\n                        interface: registration.interface.clone(),\n                        needs_answer,\n                        query_message_id,\n                        recipient_pid: registration.pid,\n                    }))\n                } else {\n                    registration.queries.push_back(query_message_id);\n                    Ok(None)\n                }\n            } else {\n                Err(())\n            }\n        } else {\n            Err(())\n        }\n    }\n\n    /// Sets the handler of the given interface hash.\n    ///\n    /// On success, returns a [`RegistrationId`] to pass later to refer to that registration.\n    ///\n    /// Returns an error if there already exists a handler for this interface.\n    pub fn set_interface_handler(\n        &self,\n        interface_hash: InterfaceHash,\n        pid: Pid,\n    ) -> Result<NonZeroU64, redshirt_interface_interface::ffi::InterfaceRegisterError> {\n        let mut interfaces = self.inner.lock();\n        let interfaces = &mut *interfaces;\n\n        match interfaces.interfaces.entry(interface_hash) {\n            Entry::Occupied(mut entry) => {\n                let interface = entry.key().clone();\n                match entry.get_mut() {\n                    Interface::Registered(_) =>\n                        Err(redshirt_interface_interface::ffi::InterfaceRegisterError::AlreadyRegistered),\n                    Interface::NotRegistered { pending_accept } => {\n                        let id = interfaces.registrations.insert(InterfaceRegistration {\n                            pid,\n                            interface,\n                            queries: VecDeque::with_capacity(16),  // TODO: be less magic with capacity\n                            pending_accept: mem::take(pending_accept),\n                        });\n                        entry.insert(Interface::Registered(id));\n                        Ok(NonZeroU64::new(u64::try_from(id).unwrap()).unwrap())\n                    }\n                }\n            }\n            Entry::Vacant(entry) => {\n                let id = interfaces.registrations.insert(InterfaceRegistration {\n                    pid,\n                    interface: entry.key().clone(),\n                    queries: VecDeque::with_capacity(16), // TODO: be less magic with capacity\n                    pending_accept: VecDeque::with_capacity(16), // TODO: be less magic with capacity\n                });\n                entry.insert(Interface::Registered(id));\n                Ok(NonZeroU64::new(u64::try_from(id).unwrap()).unwrap())\n            }\n        }\n    }\n}\n\nimpl Default for Interfaces {\n    fn default() -> Self {\n        Interfaces::new()\n    }\n}\n\n/// Delivery of a message to a handler.\npub struct MessageDelivery {\n    /// Identifier of the message to be delivered.\n    pub to_deliver_message_id: MessageId,\n    /// Registered interface the message concerns.\n    // TODO: is this needed? programs should be able to deduce this from the message id\n    pub interface: InterfaceHash,\n    /// True if the message in `to_deliver_message_id` expects an answer.\n    pub needs_answer: bool,\n    pub query_message_id: MessageId,\n    pub recipient_pid: Pid,\n}\n\n/// Outcome of [`Interfaces::emit_interface_message`].\n#[must_use]\npub enum EmitInterfaceMessage {\n    /// Message pushed on the interface can be instantly accepted and delivered.\n    Deliver(MessageDelivery),\n    /// Message should be immediately rejected. Can only happen if `immediate` is `true`.\n    Reject,\n    /// Message has been queued and might later be delivered when\n    /// [`Interfaces::emit_message_query`] is called. Can only happen if `immediate` is `false`.\n    Queued,\n}\n\n/// Identifier of an interface registration.\n///\n/// See [`Interfaces::set_interface_handler`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub struct RegistrationId(NonZeroU64);\n\nimpl From<NonZeroU64> for RegistrationId {\n    fn from(v: NonZeroU64) -> RegistrationId {\n        RegistrationId(v)\n    }\n}\n\nimpl From<RegistrationId> for NonZeroU64 {\n    fn from(v: RegistrationId) -> NonZeroU64 {\n        v.0\n    }\n}\n"
  },
  {
    "path": "kernel/core/src/system/pending_answers.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Delivered messages waiting to be answered.\n//!\n//! The [`PendingAnswers`] struct holds a list of messages that have been successfully delivered\n//! to interface handles but haven't been answered yet.\n\nuse alloc::vec::Vec;\nuse hashbrown::HashMap;\nuse nohash_hasher::BuildNoHashHasher;\nuse redshirt_syscalls::{MessageId, Pid};\n\npub struct PendingAnswers {\n    // TODO: smarter than a spinloop?\n    inner: spinning_top::Spinlock<Inner>,\n}\n\nstruct Inner {\n    // TODO: call shrink_to_fit from time to time?\n    messages: HashMap<MessageId, Pid, BuildNoHashHasher<u64>>,\n}\n\nimpl PendingAnswers {\n    pub fn new() -> Self {\n        PendingAnswers {\n            inner: spinning_top::Spinlock::new(Inner {\n                messages: Default::default(),\n            }),\n        }\n    }\n\n    pub fn add(&self, message_id: MessageId, answerer_pid: Pid) {\n        let _inserted = self.inner.lock().messages.insert(message_id, answerer_pid);\n        debug_assert!(_inserted.is_none());\n    }\n\n    pub fn remove(&self, message_id: &MessageId, if_answerer_equal: &Pid) -> Result<(), ()> {\n        let mut inner = self.inner.lock();\n        match inner.messages.remove(message_id) {\n            Some(pid) if pid == *if_answerer_equal => Ok(()),\n            Some(pid) => {\n                // Cancel the removal.\n                inner.messages.insert(message_id.clone(), pid);\n                Err(())\n            }\n            None => Err(()),\n        }\n    }\n\n    /// Removes from the collection all messages whose answerer is the given PID.\n    pub fn drain_by_answerer(&self, answerer_pid: &Pid) -> Vec<MessageId> {\n        // TODO: O(n) complexity\n        let mut inner = self.inner.lock();\n\n        let list = inner\n            .messages\n            .iter()\n            .filter(|(_, a)| *a == answerer_pid)\n            .map(|(m, _)| *m)\n            .collect::<Vec<_>>();\n\n        for message in &list {\n            let _was_removed = inner.messages.remove(message);\n            debug_assert!(_was_removed.is_some());\n        }\n\n        list\n    }\n}\n\nimpl Default for PendingAnswers {\n    fn default() -> Self {\n        PendingAnswers::new()\n    }\n}\n"
  },
  {
    "path": "kernel/core/src/system.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Core system, alongside with support for native programs, and some predefined interfaces and\n//! features.\n//!\n//! Natively handles the following interfaces:\n//! TODO: indicate hashes\n//! TODO: more details\n//!\n//! - `interface`.\n//!\n\nuse crate::extrinsics;\nuse crate::module::ModuleHash;\nuse crate::scheduler::{self, Core, CoreBuilder, CoreRunOutcome, NewErr};\nuse crate::InterfaceHash;\n\nmod interfaces;\nmod pending_answers;\n\nuse alloc::{borrow::Cow, collections::VecDeque, format, string::String, vec::Vec};\nuse core::{convert::TryFrom as _, fmt, iter, num::NonZeroU64, sync::atomic::Ordering};\nuse crossbeam_queue::SegQueue;\nuse hashbrown::{HashMap, HashSet};\nuse nohash_hasher::BuildNoHashHasher;\nuse redshirt_syscalls::{Decode, Encode, EncodedMessage, MessageId, Pid};\nuse spinning_top::Spinlock;\n\n/// Main struct that handles a system, including the scheduler, program loader,\n/// inter-process communication, and so on.\n///\n/// See [the module-level documentation](super) for more information.\npub struct System<TExtr: extrinsics::Extrinsics> {\n    /// Inner system with inter-process communications.\n    core: Core<TExtr>,\n\n    /// For each interface, which program is fulfilling it.\n    interfaces: interfaces::Interfaces,\n\n    /// Collection of messages that have been delivered but are waiting to be answered.\n    pending_answers: pending_answers::PendingAnswers,\n\n    /// Total number of processes that have been spawned since initialization.\n    num_processes_started: atomic::Atomic<u64>,\n\n    /// Total number of processes that have successfully ended since initialization.\n    num_processes_finished: atomic::Atomic<u64>,\n\n    /// Total number of processes that have ended because of a problem, since initialization.\n    num_processes_trap: atomic::Atomic<u64>,\n\n    /// Interfaces handled natively.\n    native_interfaces: HashSet<InterfaceHash, fnv::FnvBuildHasher>,\n\n    /// Registration ID (i.e. index in [`Interfaces::registrations`]) that handles the `loader`\n    /// interface, or `None` is no such program exists yet.\n    // TODO: add timeout for loader interface availability?\n    loader_registration_id: atomic::Atomic<Option<usize>>,\n\n    /// List of programs to load if the loader interface handler is available.\n    programs_to_load: SegQueue<ModuleHash>,\n\n    /// \"Virtual\" pid for the process that sends messages towards the loader.\n    load_source_virtual_pid: Pid,\n\n    /// Set of messages that we emitted of requests to load a program from the loader interface.\n    /// All these messages expect a `redshirt_loader_interface::ffi::LoadResponse` as answer.\n    // TODO: call shink_to_fit from time to time\n    loading_programs: Spinlock<HashSet<MessageId, BuildNoHashHasher<u64>>>,\n}\n\n#[derive(Debug)]\nstruct Interfaces {\n    interfaces: HashMap<InterfaceHash, Interface, fnv::FnvBuildHasher>,\n    registrations: slab::Slab<InterfaceRegistration>,\n}\n\n#[derive(Debug)]\nenum Interface {\n    /// Interface has a registered handler.\n    ///\n    /// Contains an index within [`Interfaces::registrations`].\n    Registered(usize),\n\n    /// Interface has no registered handler yet.\n    NotRegistered {\n        /// Messages emitted by programs and that haven't been accepted yet are pushed to this\n        /// field.\n        ///\n        /// No limit is enforced on the size of this container. However, since each entry\n        /// corresponds to a thread currently being paused, the total number of entries across\n        /// all `pending_accept` fields is bounded by the total number of threads across all\n        /// processes.\n        pending_accept: VecDeque<(MessageId, bool)>,\n    },\n}\n\n#[derive(Debug)]\nstruct InterfaceRegistration {\n    pid: Pid,\n    is_native: bool,\n    /// Messages of type `NextMessage` sent on the interface interface and that must be answered\n    /// with the next interface message.\n    queries: VecDeque<MessageId>,\n    /// If [`InterfaceRegistration::queries`] is empty, messages emitted by programs and that\n    /// haven't been accepted yet are pushed to this field.\n    pending_accept: VecDeque<(MessageId, bool)>,\n}\n\n/// Prototype for a [`System`].\npub struct SystemBuilder<TExtr: extrinsics::Extrinsics> {\n    /// Builder for the inner core.\n    core: CoreBuilder<TExtr>,\n\n    /// \"Virtual\" pid for the process that sends messages towards the loader.\n    load_source_virtual_pid: Pid,\n\n    /// Interfaces handled natively.\n    native_interfaces: HashSet<InterfaceHash, fnv::FnvBuildHasher>,\n\n    /// List of programs to start executing immediately after construction.\n    startup_processes: Vec<Cow<'static, [u8]>>,\n\n    /// Same field as [`System::programs_to_load`].\n    programs_to_load: SegQueue<ModuleHash>,\n}\n\n/// Event returned by [`System::run`].\npub enum ExecuteOut<'a, TExtr: extrinsics::Extrinsics> {\n    /// Event directly generated.\n    Direct(SystemRunOutcome<'a, TExtr>),\n    /// Ready to execute a bit of a thread.\n    ReadyToRun(ReadyToRun<'a, TExtr>),\n}\n\n/// Ready to resume one of the threads of a process.\n#[must_use]\npub struct ReadyToRun<'a, TExtr: extrinsics::Extrinsics> {\n    system: &'a System<TExtr>,\n    inner: scheduler::ReadyToRun<'a, TExtr>,\n}\n\nimpl<'a, TExtr: extrinsics::Extrinsics> ReadyToRun<'a, TExtr> {\n    /// Performs the actual execution.\n    ///\n    /// Returns `None` if the execution doesn't lead to any event in particular.\n    pub fn run(self) -> Option<SystemRunOutcome<'a, TExtr>> {\n        let system = self.system;\n        self.inner\n            .run()\n            .and_then(move |out| system.inner_event(out))\n    }\n}\n\n/// Outcome of running the [`System`] once.\n#[derive(Debug)]\npub enum SystemRunOutcome<'a, TExtr: extrinsics::Extrinsics> {\n    /// A program has ended, either successfully or after an error.\n    ProgramFinished {\n        /// Identifier of the process that has stopped.\n        pid: Pid,\n        /// Either `Ok(())` if the main thread has ended, or the error that happened in the\n        /// process.\n        // TODO: change error type\n        outcome: Result<(), String>,\n    },\n\n    /// A program has requested metrics from the kernel. Use the [`KernelDebugMetricsRequest`] to\n    /// report them.\n    KernelDebugMetricsRequest(KernelDebugMetricsRequest<'a, TExtr>),\n\n    /// A program has emitted a message on a native interface.\n    NativeInterfaceMessage {\n        /// Hash of the interface. Guaranteed to be one of the interfaces that were passed to\n        /// [`SystemBuilder::with_native_interface_handler`].\n        interface: InterfaceHash,\n\n        /// [`Pid`] of the process that has emitted the message.\n        emitter_pid: Pid,\n\n        /// Identifier of the message. Must be passed back in order to answer it. `None` if no\n        /// response is expected.\n        message_id: Option<MessageId>,\n\n        /// Body of the message. Extractable by calling [`NativeInterfaceMessage::extract`].\n        message: NativeInterfaceMessage<'a, TExtr>,\n    },\n}\n\n/// See [`SystemRunOutcome::NativeInterfaceMessage::message`].\npub struct NativeInterfaceMessage<'a, TExtr: extrinsics::Extrinsics> {\n    system: &'a System<TExtr>,\n    message_id: MessageId,\n}\n\nimpl<'a, TExtr: extrinsics::Extrinsics> NativeInterfaceMessage<'a, TExtr> {\n    /// Extracts the message and resumes the execution of the program.\n    ///\n    /// > **Note**: Since the program that has emitted the message can now resume when calling\n    /// >           [`System::run`] from another thread, it is possible for that program to emit\n    /// >           another interface message soon after. In order to avoid race conditions, make\n    /// >           sure to lock some mutex prior to calling this method to ensure that a\n    /// >           follow-up message isn't processed earlier than the one returned here.\n    pub fn extract(self) -> EncodedMessage {\n        self.system\n            .core\n            .accept_interface_message(self.message_id)\n            .unwrap()\n            .1\n    }\n}\n\nimpl<'a, TExtr: extrinsics::Extrinsics> fmt::Debug for NativeInterfaceMessage<'a, TExtr> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"NativeInterfaceMessage\").finish()\n    }\n}\n\nimpl<TExtr> System<TExtr>\nwhere\n    TExtr: extrinsics::Extrinsics,\n{\n    /// Start executing a program.\n    pub fn execute(&self, program: &[u8]) -> Result<Pid, NewErr> {\n        self.num_processes_started.fetch_add(1, Ordering::Relaxed);\n        Ok(self.core.execute(program)?.0.pid())\n    }\n\n    /// Runs the [`System`] once and returns the outcome.\n    ///\n    /// > **Note**: For now, it can a long time for this `Future` to be `Ready` because it is also\n    /// >           waiting for the native programs to produce events in case there's nothing to\n    /// >           do. In other words, this function can be seen more as a generator that whose\n    /// >           `Future` becomes `Ready` only when something needs to be notified.\n    // TODO: revisit comment\n    pub async fn run<'a>(&'a self) -> ExecuteOut<'a, TExtr> {\n        loop {\n            match self.core.run().await {\n                scheduler::ExecuteOut::Direct(event) => {\n                    if let Some(event) = self.inner_event(event) {\n                        return ExecuteOut::Direct(event);\n                    }\n                }\n                scheduler::ExecuteOut::ReadyToRun(ready_to_run) => {\n                    return ExecuteOut::ReadyToRun(ReadyToRun {\n                        system: self,\n                        inner: ready_to_run,\n                    })\n                }\n            }\n        }\n    }\n\n    fn inner_event<'a>(\n        &'a self,\n        event: scheduler::CoreRunOutcome,\n    ) -> Option<SystemRunOutcome<'a, TExtr>> {\n        match event {\n            CoreRunOutcome::ProgramFinished { pid, outcome, .. } => {\n                // TODO: cancel interface registrations ; update loader_registration_id\n                // TODO: notify interface registrations of process destruction\n\n                for _message_id in self.pending_answers.drain_by_answerer(&pid) {\n                    // TODO: notify emitter of cancellation\n                }\n\n                if outcome.is_ok() {\n                    self.num_processes_finished.fetch_add(1, Ordering::Relaxed);\n                } else {\n                    self.num_processes_trap.fetch_add(1, Ordering::Relaxed);\n                }\n\n                return Some(SystemRunOutcome::ProgramFinished {\n                    pid,\n                    outcome: outcome.map(|_| ()).map_err(|err| err.error),\n                });\n            }\n\n            CoreRunOutcome::InterfaceMessage {\n                pid,\n                needs_answer,\n                immediate: _,\n                message_id,\n                interface,\n            } if interface == redshirt_interface_interface::ffi::INTERFACE => {\n                // Handling messages on the `interface` interface.\n                let (_, message) = match self.core.accept_interface_message(message_id) {\n                    Some(v) => v,\n                    None => return None,\n                };\n\n                match redshirt_interface_interface::ffi::InterfaceMessage::decode(message) {\n                    Ok(redshirt_interface_interface::ffi::InterfaceMessage::Register(\n                        interface_hash,\n                    )) => {\n                        // Set the process as interface handler, if possible.\n                        let result = self.set_interface_handler(&interface_hash, pid);\n\n                        let response =\n                            redshirt_interface_interface::ffi::InterfaceRegisterResponse {\n                                result: result.clone(),\n                            };\n                        if needs_answer {\n                            self.core.answer_message(message_id, Ok(response.encode()));\n                        }\n\n                        None\n                    }\n                    Ok(redshirt_interface_interface::ffi::InterfaceMessage::NextMessage(\n                        registration_id,\n                    )) => {\n                        // TODO: silently discard a message if !needs_answer?\n                        if needs_answer {\n                            loop {\n                                // TODO: immediate not taken into account\n                                match self.interfaces.emit_message_query(\n                                    registration_id.into(),\n                                    message_id,\n                                    pid,\n                                ) {\n                                    Ok(Some(delivery)) => {\n                                        if self.deliver(delivery).is_err() {\n                                            continue;\n                                        }\n                                    }\n                                    Ok(None) => {}\n                                    Err(()) => {\n                                        self.core.answer_message(message_id, Err(()));\n                                    }\n                                }\n\n                                break;\n                            }\n                        } else {\n                            todo!()\n                        }\n\n                        None\n                    }\n                    Ok(redshirt_interface_interface::ffi::InterfaceMessage::Answer(\n                        answered_message_id,\n                        answer_bytes,\n                    )) => {\n                        // TODO: handle errors here\n                        // TODO: handle `needs_answer` equal true?\n                        if self\n                            .pending_answers\n                            .remove(&answered_message_id, &pid)\n                            .is_ok()\n                        {\n                            // TODO: must handle emitter is native\n                            self.core.answer_message(\n                                answered_message_id,\n                                answer_bytes.map(EncodedMessage),\n                            );\n                        }\n\n                        None\n\n                        // TODO: reimplement\n                        /*if self.loading_programs.lock().remove(&message_id) {\n                            let redshirt_loader_interface::ffi::LoadResponse { result } =\n                                Decode::decode(answer.unwrap()).unwrap();\n                            // TODO: don't unwrap\n                            let module = Module::from_bytes(&result.expect(\"loader returned error\"))\n                                .expect(\"module isn't proper wasm\");\n                            self.num_processes_started.fetch_add(1, Ordering::Relaxed);\n                            match self.core.execute(&module) {\n                                Ok(_) => {}\n                                Err(_) => panic!(),\n                            }\n                        }*/\n                    }\n                    Err(_) => {\n                        if needs_answer {\n                            self.core.answer_message(message_id, Err(()));\n                        }\n                        None\n                    }\n                }\n            }\n\n            CoreRunOutcome::InterfaceMessage {\n                pid: _,\n                needs_answer,\n                immediate: _,\n                message_id,\n                interface,\n            } if interface == redshirt_kernel_debug_interface::INTERFACE => {\n                // Handling messages on the `kernel_debug` interface.\n                let (_, message) = match self.core.accept_interface_message(message_id) {\n                    Some(v) => v,\n                    None => return None,\n                };\n\n                if needs_answer {\n                    if message.0.is_empty() {\n                        return Some(SystemRunOutcome::KernelDebugMetricsRequest(\n                            KernelDebugMetricsRequest {\n                                system: self,\n                                message_id,\n                            },\n                        ));\n                    } else {\n                        self.core.answer_message(message_id, Err(()));\n                    }\n                }\n\n                None\n            }\n\n            CoreRunOutcome::InterfaceMessage {\n                pid: emitter_pid,\n                needs_answer,\n                message_id,\n                interface,\n                ..\n            } if self.native_interfaces.contains(&interface) => {\n                return Some(SystemRunOutcome::NativeInterfaceMessage {\n                    interface,\n                    emitter_pid,\n                    message_id: if needs_answer { Some(message_id) } else { None },\n                    message: NativeInterfaceMessage {\n                        system: self,\n                        message_id,\n                    },\n                });\n            }\n\n            CoreRunOutcome::InterfaceMessage {\n                pid,\n                needs_answer,\n                immediate,\n                message_id,\n                interface,\n            } => {\n                match self.interfaces.emit_interface_message(\n                    &interface,\n                    message_id,\n                    pid,\n                    needs_answer,\n                    immediate,\n                ) {\n                    interfaces::EmitInterfaceMessage::Deliver(delivery) => {\n                        match self.deliver(delivery) {\n                            Ok(()) => {}\n                            Err(()) => todo!(), // TODO: ouch, that is complex\n                        }\n                    }\n                    interfaces::EmitInterfaceMessage::Reject => {\n                        debug_assert!(immediate);\n                        self.core.reject_immediate_interface_message(message_id);\n                    }\n                    interfaces::EmitInterfaceMessage::Queued => {\n                        debug_assert!(!immediate);\n                    }\n                }\n\n                None\n            }\n        }\n    }\n\n    /// Answers a message previously emitted using [`SystemRunOutcome::NativeInterfaceMessage`].\n    ///\n    /// > **Note**: The validity of the [`MessageId`] is not checked, for performance reasons.\n    /// >           Passing a wrong value can lead to logic errors.\n    pub fn answer_message(&self, message_id: MessageId, response: Result<EncodedMessage, ()>) {\n        self.core.answer_message(message_id, response);\n    }\n\n    fn set_interface_handler(\n        &self,\n        interface_hash: &InterfaceHash,\n        pid: Pid,\n    ) -> Result<NonZeroU64, redshirt_interface_interface::ffi::InterfaceRegisterError> {\n        let result = self\n            .interfaces\n            .set_interface_handler(interface_hash.clone(), pid);\n\n        // Special handling if the registered interface is the loader.\n        if *interface_hash == redshirt_loader_interface::ffi::INTERFACE {\n            if let Ok(registration_id) = result {\n                self.loader_registration_id.store(\n                    Some(usize::try_from(registration_id.get()).unwrap()),\n                    Ordering::Release,\n                );\n\n                while let Some(h) = self.programs_to_load.pop() {\n                    todo!() // TODO:\n                }\n            }\n        }\n\n        result\n    }\n\n    /// Applies an [`interfaces::MessageDelivery`].\n    ///\n    /// Returns `Ok` if the message still exists, or an error if the message to deliver was no\n    /// longer valid.\n    fn deliver(&self, delivery: interfaces::MessageDelivery) -> Result<(), ()> {\n        let (emitter_pid, message) = match self\n            .core\n            .accept_interface_message(delivery.to_deliver_message_id)\n        {\n            Some(v) => v,\n            None => return Err(()),\n        };\n\n        let notification = redshirt_interface_interface::ffi::build_interface_notification(\n            &delivery.interface,\n            if delivery.needs_answer {\n                Some(delivery.to_deliver_message_id)\n            } else {\n                None\n            },\n            emitter_pid,\n            &message,\n        );\n\n        // The message is added to `pending_answers` before being actually delivered, in order to\n        // avoid a situation where the recipient manages to answer the message before it is added\n        // to `pending_answers`.\n        self.pending_answers\n            .add(delivery.to_deliver_message_id, delivery.recipient_pid);\n\n        self.core.answer_message(\n            delivery.query_message_id,\n            Ok(EncodedMessage(notification.into_bytes())),\n        );\n\n        Ok(())\n    }\n}\n\n/// Object to use to report kernel metrics to a requesting process.\n#[must_use]\npub struct KernelDebugMetricsRequest<'a, TExtr: extrinsics::Extrinsics> {\n    system: &'a System<TExtr>,\n    message_id: MessageId,\n}\n\nimpl<'a, TExtr: extrinsics::Extrinsics> KernelDebugMetricsRequest<'a, TExtr> {\n    /// Indicate the metrics. Must pass a Prometheus-compatible metrics.\n    /// See [this document](https://prometheus.io/docs/instrumenting/exposition_formats/#text-format-details)\n    /// for more information.\n    ///\n    /// The metrics will be concatenated with other metrics tracked internally by the `System`.\n    pub fn respond(self, metrics: &str) {\n        let mut metrics_bytes = metrics.as_bytes().to_vec();\n\n        // `processes_started_total`\n        metrics_bytes.extend_from_slice(\n            b\"# HELP redshirt_processes_started_total Number of processes that have \\\n            been spawned since initialization.\\n\",\n        );\n        metrics_bytes.extend_from_slice(b\"# TYPE redshirt_processes_started_total counter\\n\");\n        metrics_bytes.extend_from_slice(\n            format!(\n                \"redshirt_processes_started_total {}\\n\",\n                self.system.num_processes_started.load(Ordering::Relaxed)\n            )\n            .as_bytes(),\n        );\n        metrics_bytes.extend_from_slice(b\"\\n\");\n\n        // `processes_ended_total`\n        metrics_bytes.extend_from_slice(\n            b\"# HELP redshirt_processes_ended_total Number of processes that have \\\n            ended, since initialization.\\n\",\n        );\n        metrics_bytes.extend_from_slice(b\"# TYPE redshirt_processes_ended_total counter\\n\");\n        metrics_bytes.extend_from_slice(\n            format!(\n                \"redshirt_processes_ended_total{{reason=\\\"graceful\\\"}} {}\\n\",\n                self.system.num_processes_finished.load(Ordering::Relaxed)\n            )\n            .as_bytes(),\n        );\n        metrics_bytes.extend_from_slice(\n            format!(\n                \"redshirt_processes_ended_total{{reason=\\\"crash\\\"}} {}\\n\",\n                self.system.num_processes_trap.load(Ordering::Relaxed)\n            )\n            .as_bytes(),\n        );\n        metrics_bytes.extend_from_slice(b\"\\n\");\n\n        // TODO: add more metrics?\n\n        let response = EncodedMessage(metrics_bytes);\n        self.system\n            .core\n            .answer_message(self.message_id, Ok(response));\n    }\n}\n\nimpl<'a, TExtr: extrinsics::Extrinsics> fmt::Debug for KernelDebugMetricsRequest<'a, TExtr> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"KernelDebugMetricsRequest\").finish()\n    }\n}\n\nimpl<TExtr> SystemBuilder<TExtr>\nwhere\n    TExtr: extrinsics::Extrinsics,\n{\n    /// Initializes a new builder.\n    ///\n    /// The seed is used in determine how [`Pid`]s and [`MessageId`]s are generated. The same\n    /// seed will result in the same sequence of [`Pid`]s and [`MessageId`]s.\n    pub fn new(seed: [u8; 64]) -> Self {\n        let mut core = CoreBuilder::with_seed(seed);\n        let load_source_virtual_pid = core.reserve_pid();\n\n        SystemBuilder {\n            core,\n            startup_processes: Vec::new(),\n            native_interfaces: Default::default(),\n            load_source_virtual_pid,\n            programs_to_load: SegQueue::new(),\n        }\n    }\n\n    /// Registers the given interface as an interface handled by a native program.\n    ///\n    /// Duplicates are ignored.\n    pub fn with_native_interface_handler(mut self, hash: InterfaceHash) -> Self {\n        self.native_interfaces.insert(hash);\n        self\n    }\n\n    /// Adds a process to the list of processes that the [`System`] must start as part of the\n    /// startup process.\n    ///\n    /// > **Note**: The startup processes are started in the order in which they are added here,\n    /// >           but you should not rely on this fact for making the system work.\n    ///\n    /// By default, the list is empty. Should at least contain a process that handles the `loader`\n    /// interface.\n    pub fn with_startup_process(mut self, process: Cow<'static, [u8]>) -> Self {\n        let process = process.into();\n        self.startup_processes.push(process);\n        self\n    }\n\n    /// Shortcut for calling [`with_main_program`](SystemBuilder::with_main_program) multiple\n    /// times.\n    pub fn with_main_programs(self, hashes: impl IntoIterator<Item = ModuleHash>) -> Self {\n        for hash in hashes {\n            self.programs_to_load.push(hash);\n        }\n        self\n    }\n\n    /// Adds a program that the [`System`] must execute after startup. Can be called multiple times\n    /// to add multiple programs.\n    ///\n    /// The program will be loaded through the `loader` interface. The loading starts as soon as\n    /// the `loader` interface has been registered by one of the processes passed to\n    /// [`with_startup_process`](SystemBuilder::with_startup_process).\n    ///\n    /// Messages are sent to the `loader` interface in the order in which this function has been\n    /// called. The implementation of `loader`, however, might not deliver the responses in the\n    /// same order.\n    pub fn with_main_program(self, hash: ModuleHash) -> Self {\n        self.with_main_programs(iter::once(hash))\n    }\n\n    /// Builds the [`System`].\n    ///\n    /// Returns an error if any of the programs passed through\n    /// [`SystemBuilder::with_startup_process`] fails to start.\n    pub fn build(mut self) -> Result<System<TExtr>, NewErr> {\n        let core = self.core.build();\n\n        let num_processes_started = u64::try_from(self.startup_processes.len()).unwrap();\n        for program in self.startup_processes {\n            core.execute(&program)?;\n        }\n\n        self.native_interfaces.shrink_to_fit();\n\n        Ok(System {\n            core,\n            load_source_virtual_pid: self.load_source_virtual_pid,\n            interfaces: Default::default(),\n            pending_answers: Default::default(),\n            num_processes_started: atomic::Atomic::new(num_processes_started),\n            num_processes_finished: atomic::Atomic::new(0),\n            num_processes_trap: atomic::Atomic::new(0),\n            native_interfaces: self.native_interfaces,\n            loader_registration_id: atomic::Atomic::new(None),\n            loading_programs: Spinlock::new(Default::default()),\n            programs_to_load: self.programs_to_load,\n        })\n    }\n}\n#[cfg(test)]\nmod tests {\n    use crate::extrinsics;\n\n    #[test]\n    fn send_sync() {\n        fn is_send_sync<T: Send + Sync>() {}\n        is_send_sync::<super::System<extrinsics::NoExtrinsics>>()\n    }\n}\n"
  },
  {
    "path": "kernel/core-proc-macros/Cargo.toml",
    "content": "[package]\nname = \"redshirt-core-proc-macros\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[lib]\nproc-macro = true\n\n[dependencies]\ncargo_metadata = \"0.12\"\nproc-macro2 = \"1.0\"\nserde_json = \"1.0\"\nsyn = \"1.0\"\nwat = \"1.0.36\"\n\n[features]\ndefault = []\nnightly = []\n"
  },
  {
    "path": "kernel/core-proc-macros/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n#![cfg_attr(feature = \"nightly\", feature(proc_macro_span))] // TODO: https://github.com/rust-lang/rust/issues/54725\n\nuse std::{env, fs, path::Path, process::Command};\n\n/// Turns a string of WebAssembly text representation into a binary representation.\n#[proc_macro]\npub fn wat_to_bin(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {\n    let wat = syn::parse_macro_input!(tokens as syn::LitStr);\n    let wat = wat.value();\n\n    let wasm = match wat::parse_bytes(wat.as_ref()) {\n        Ok(w) => w,\n        Err(err) => {\n            return format!(\n                \"compile_error!(\\\"Failed to convert WAT to Wasm.\\n\\n{}\\\")\",\n                err\n            )\n            .parse()\n            .unwrap();\n        }\n    };\n\n    // Final output.\n    let rust_out = format!(\n        \"{{\n            const MODULE_BYTES: [u8; {}] = [{}];\n            &MODULE_BYTES[..]\n        }}\",\n        wasm.len(),\n        wasm.iter()\n            .map(|c| format!(\"0x{:x}\", c))\n            .collect::<Vec<String>>()\n            .join(\", \"),\n    );\n\n    // Uncomment to debug.\n    //panic!(\"{}\", rust_out);\n\n    rust_out.parse().unwrap()\n}\n\n/// Compiles a WASM module and includes it similar to `include_bytes!`.\n///\n/// Must be passed the path to a directory containing a `Cargo.toml`.\n/// Can be passed an optional second argument containing the binary name to compile. Mandatory if\n/// the package contains multiple binaries.\n#[cfg(feature = \"nightly\")]\n#[proc_macro]\npub fn build_wasm_module(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {\n    // Find the absolute path requested by the user, and optionally the binary target.\n    let (wasm_crate_path, requested_bin_target) = {\n        struct Params {\n            path: String,\n            bin_target: Option<String>,\n        }\n\n        impl syn::parse::Parse for Params {\n            fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {\n                let path: syn::LitStr = input.parse()?;\n                let bin_target = if input.is_empty() {\n                    None\n                } else {\n                    let _: syn::Token![,] = input.parse()?;\n                    let bin_target: syn::LitStr = input.parse()?;\n                    Some(bin_target)\n                };\n\n                Ok(Params {\n                    path: path.value(),\n                    bin_target: bin_target.map(|s| s.value()),\n                })\n            }\n        }\n\n        let macro_params = syn::parse_macro_input!(tokens as Params);\n        let macro_call_file = {\n            // We go up the stack of Spans to find the one with a file path.\n            let mut span = proc_macro::Span::call_site();\n            span = span.parent().unwrap();\n            loop {\n                let src_file = span.source_file();\n                if src_file.is_real() {\n                    break src_file.path().parent().unwrap().to_owned();\n                }\n                span = span.parent().unwrap();\n            }\n        };\n\n        (\n            macro_call_file.join(macro_params.path),\n            macro_params.bin_target,\n        )\n    };\n\n    // Get the package ID of the package requested by the user.\n    let pkg_id = {\n        let output = Command::new(env::var(\"CARGO\").unwrap())\n            .arg(\"read-manifest\")\n            .current_dir(&wasm_crate_path)\n            .output()\n            .expect(\"Failed to execute `cargo read-manifest`\");\n        assert!(output.status.success());\n        let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();\n        json.as_object()\n            .unwrap()\n            .get(\"id\")\n            .unwrap()\n            .as_str()\n            .unwrap()\n            .to_owned()\n    };\n\n    // Determine the path to the `.wasm` and `.d` files that Cargo will generate.\n    let (wasm_output, dependencies_output, bin_target) = {\n        let metadata = cargo_metadata::MetadataCommand::new()\n            .current_dir(&wasm_crate_path)\n            .no_deps()\n            .exec()\n            .unwrap();\n        let package = metadata\n            .packages\n            .iter()\n            .find(|p| p.id.repr == pkg_id)\n            .unwrap();\n        let mut bin_targets_iter = package\n            .targets\n            .iter()\n            .filter(|t| t.kind.iter().any(|k| k == \"bin\"));\n        let bin_target = if let Some(requested_bin_target) = requested_bin_target {\n            match bin_targets_iter.find(|t| t.name == requested_bin_target) {\n                Some(t) => t.name.clone(),\n                None => {\n                    return format!(\n                        \"compile_error!(\\\"Can't find binary target `{}` in `{}`\\\")\",\n                        requested_bin_target,\n                        wasm_crate_path.display()\n                    )\n                    .parse()\n                    .unwrap();\n                }\n            }\n        } else {\n            let target = bin_targets_iter.next().unwrap();\n            if bin_targets_iter.next().is_some() {\n                return format!(\n                    \"compile_error!(\\\"Multiple binary targets available, please mention the one you want:\\n{}\\\")\",\n                    package\n                        .targets\n                        .iter()\n                        .filter(|t| t.kind.iter().any(|k| k == \"bin\"))\n                        .map(|t| format!(\"- {}\", t.name))\n                        .collect::<Vec<_>>()\n                        .join(\"\\n\")\n                )\n                .parse()\n                .unwrap();\n            }\n            target.name.clone()\n        };\n        let base = metadata\n            .target_directory\n            .join(\"wasm32-wasip1\")\n            .join(\"release\");\n        let wasm = base.join(format!(\"{}.wasm\", bin_target));\n        let deps = base.join(format!(\"{}.d\", bin_target));\n        (wasm, deps, bin_target)\n    };\n\n    // Actually build the module.\n    let build_status = Command::new(env::var(\"CARGO\").unwrap())\n        .arg(\"rustc\")\n        .args(&[\"--color\", \"always\"]) // TODO: enable conditionnally?\n        .args(&[\"--bin\", &bin_target])\n        .arg(\"--release\")\n        .args(&[\"--target\", \"wasm32-wasip1\"])\n        .arg(\"--\")\n        .args(&[\"-C\", \"link-arg=--export-table\"])\n        .args(&[\"-C\", \"link-arg=--import-memory\"])\n        .current_dir(&wasm_crate_path)\n        .status()\n        .unwrap();\n\n    if !build_status.success() {\n        return format!(\n            \"compile_error!(\\\"Failed to compile module `{}`. See above errors.\\\")\",\n            wasm_crate_path.display()\n        )\n        .parse()\n        .unwrap();\n    }\n\n    // Read the list of source files that we must depend upon.\n    let dependended_files: Vec<String> = {\n        // Read the output `.d` file.\n        let dependencies_content = fs::read_to_string(dependencies_output).unwrap();\n        let mut list_iter = dependencies_content.lines().next().unwrap().split(\" \");\n        let _ = list_iter.next(); // First entry is the output file.\n                                  // TODO: this is missing Cargo.tomls and stuff I think\n        list_iter\n            .filter_map(|file| {\n                if !Path::new(file).is_absolute() {\n                    // TODO: relative paths cause issues ; figure out why some paths are relative\n                    None\n                } else if Path::new(file).exists() {\n                    // TODO: figure out why some files are missing\n                    Some(file.to_owned())\n                } else {\n                    None\n                }\n            })\n            .collect()\n    };\n\n    // Final output.\n    // TODO: handle if the user renames `redshirt_core` to something else?\n    let rust_out = format!(\n        \"{{\n            extern crate alloc;\n            const MODULE_BYTES: &'static [u8] = include_bytes!(\\\"{}\\\");\n            {}\n            alloc::borrow::Cow::Borrowed(&MODULE_BYTES[..])\n        }}\",\n        wasm_output\n            .display()\n            .to_string()\n            .escape_default()\n            .to_string(),\n        dependended_files\n            .iter()\n            .map(|v| format!(\"include_str!(\\\"{}\\\");\", v.escape_default().to_string()))\n            .collect::<Vec<_>>()\n            .join(\"\\n\"),\n    );\n\n    // Uncomment to debug.\n    //panic!(\"{}\", rust_out);\n\n    rust_out.parse().unwrap()\n}\n"
  },
  {
    "path": "kernel/standalone/Cargo.toml",
    "content": "[package]\nname = \"redshirt-standalone-kernel\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[dependencies]\natomic = { version = \"0.5.0\", default-features = false }\nblake3 = { version = \"1.6.1\", default-features = false }\ncrossbeam-queue = { version = \"0.3.1\", default-features = false, features = [\"alloc\"] }\nderive_more = { version = \"2.0.0\", default-features = false, features = [\"full\"] }\neither = { version = \"1.6.1\", default-features = false }\nfnv = { version = \"1.0.7\", default-features = false }\nfutures = { version = \"0.3.13\", default-features = false, features = [\"alloc\"] }\nhashbrown = { version = \"0.9.1\", default-features = false }\nlazy_static = \"1.4\"\nlibm = \"0.2.1\"\nlinked_list_allocator = { version = \"0.9.0\", features = [\"alloc_ref\"] }\nnohash-hasher = { version = \"0.2.0\", default-features = false }\npin-project = \"1.0.5\"\nrand_chacha = { version = \"0.2.0\", default-features = false }\nrand_core = { version = \"0.5.1\", default-features = false }\nrand_jitter = { version = \"0.3.0\", default-features = false }\nredshirt-core = { path = \"../core\", features = [\"nightly\"] }\nredshirt-hardware-interface = { path = \"../../interface-wrappers/hardware\", default-features = false }\nredshirt-interface-interface = { path = \"../../interface-wrappers/interface\", default-features = false }\nredshirt-kernel-log-interface = { path = \"../../interface-wrappers/kernel-log\", default-features = false }\nredshirt-log-interface = { path = \"../../interface-wrappers/log\", default-features = false }\nredshirt-pci-interface = { path = \"../../interface-wrappers/pci\", default-features = false }\nredshirt-random-interface = { path = \"../../interface-wrappers/random\", default-features = false }\nredshirt-syscalls = { path = \"../../interface-wrappers/syscalls\", default-features = false }\nredshirt-time-interface = { path = \"../../interface-wrappers/time\", default-features = false }\nrlibc = \"1.0.0\"\nsmallvec = { version = \"1.6.1\", default-features = false }\nspinning_top = \"0.3.0\"\n\n[build-dependencies]\nrusttype = \"0.9.2\"\n\n[target.'cfg(target_arch = \"x86_64\")'.dependencies]\nacpi = \"4.1.0\"\naml = \"0.16.4\"\ncrossbeam-utils = { version = \"0.8.3\", default-features = false }\nmultiboot2 = \"0.23.1\"\nrdrand = { version = \"0.7.0\", default-features = false }\nx86_64 = \"0.15.2\"\n"
  },
  {
    "path": "kernel/standalone/build.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse std::{convert::TryFrom as _, env, fs, path::Path};\n\nfn main() {\n    let font_data = gen_font();\n    assert_eq!(font_data.len(), 128 * 8 * 8);\n\n    let out_dir = env::var(\"OUT_DIR\").unwrap();\n    fs::write(Path::new(&out_dir).join(\"font.bin\"), &font_data).unwrap();\n}\n\n/// Generates a font sprite sheet of the 128 ASCII characters.\n///\n/// Each character is 8x8 pixel. Each pixel is a single byte indicating its opacity. A value\n/// of 0x0 means transparent, and a value of 0xff means opaque.\n///\n/// In other words, the returned data is 128 * 8 * 8 bytes.\nfn gen_font() -> Vec<u8> {\n    let font_data: &[u8] = include_bytes!(\"vcr_osd_mono.ttf\");\n    let font = rusttype::Font::try_from_bytes(font_data).unwrap();\n\n    let mut out_data = vec![0; 128 * 8 * 8];\n    for ascii_chr in 0..128u8 {\n        let glyph = font\n            .glyph(char::from(ascii_chr))\n            .scaled(rusttype::Scale { x: 8.0, y: 8.0 })\n            .positioned(rusttype::Point { x: 0.0, y: 0.0 });\n\n        // `pixel_bound_box` returns `None` for glyphs that are empty (like the space character)\n        let bbox = match glyph.pixel_bounding_box() {\n            Some(b) => b,\n            None => continue,\n        };\n\n        glyph.draw(|x, y, value| {\n            let x = i32::try_from(x).unwrap() + bbox.min.x;\n            let y = 8 + i32::try_from(y).unwrap() + bbox.min.y;\n            if x < 0 || x >= 8 || y < 0 || y >= 8 {\n                return;\n            }\n\n            // Sometimes the value is negative zero or slightly above 1.0 (e.g. 1.000000001)\n            // We clamp it to be certain that the conversion below works as expected.\n            let value = value.clamp(0.0, 1.0);\n\n            let value = (value * 255.0) as u8;\n            let b_pos = usize::from(ascii_chr) * 8 * 8 + usize::try_from(x + y * 8).unwrap();\n            out_data[b_pos] = value;\n        });\n    }\n\n    out_data\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/arm/executor.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Futures executor that works on bare metal.\n\nuse alloc::sync::Arc;\nuse core::{\n    arch::asm,\n    future::Future,\n    sync::atomic,\n    task::{Context, Poll},\n};\nuse futures::task::{waker, ArcWake};\n\n/// Waits for the `Future` to resolve to a value.\n///\n/// This function is similar to [`futures::executor::block_on`].\npub fn block_on<R>(future: impl Future<Output = R>) -> R {\n    futures::pin_mut!(future);\n\n    let local_wake = Arc::new(LocalWake {\n        woken_up: atomic::AtomicBool::new(false),\n    });\n\n    let waker = waker(local_wake.clone());\n    let mut context = Context::from_waker(&waker);\n\n    loop {\n        if let Poll::Ready(val) = Future::poll(future.as_mut(), &mut context) {\n            return val;\n        }\n\n        // Loop until `woken_up` is true.\n        loop {\n            if local_wake\n                .woken_up\n                .compare_exchange(\n                    true,\n                    false,\n                    atomic::Ordering::Acquire,\n                    atomic::Ordering::Acquire,\n                )\n                .is_ok()\n            {\n                break;\n            }\n\n            // Enter a low-power state and wait for an event to happen.\n            //\n            // ARM CPUs have a non-accessible 1bit \"event register\" that is set when an event\n            // happens and cleared only by the `wfe` instruction.\n            //\n            // Thanks to this, if an event happens between the moment when we check the value of\n            // `local_waken.woken_up` and the moment when we call `wfe`, then the `wfe`\n            // instruction will immediately return and we will check the value again.\n            unsafe { asm!(\"wfe\", options(nomem, nostack, preserves_flags)) }\n        }\n    }\n}\n\nstruct LocalWake {\n    woken_up: atomic::AtomicBool,\n}\n\nimpl ArcWake for LocalWake {\n    fn wake_by_ref(arc_self: &Arc<Self>) {\n        unsafe {\n            arc_self.woken_up.store(true, atomic::Ordering::Release);\n            // Wakes up all the CPUs that called `wfe`.\n            // Note that this wakes up *all* CPUs, but the ARM architecture doesn't provide any\n            // way to target a single CPU for wake-up.\n            asm!(\"dsb sy ; sev\", options(nomem, nostack, preserves_flags))\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/arm/log.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Panic handling code.\n\nuse crate::klog::KLogger;\n\nuse core::{\n    arch::asm,\n    fmt::{self, Write as _},\n};\nuse redshirt_kernel_log_interface::ffi::KernelLogMethod;\nuse spinning_top::Spinlock;\n\npub static PANIC_LOGGER: KLogger = KLogger::disabled();\n\n#[cfg(not(any(test, doc, doctest)))]\n#[panic_handler]\nfn panic(panic_info: &core::panic::PanicInfo) -> ! {\n    // TODO: somehow freeze all CPUs?\n\n    let mut printer = PANIC_LOGGER.panic_printer();\n    let _ = writeln!(printer, \"Kernel panic!\");\n    let _ = writeln!(printer, \"{}\", panic_info);\n    let _ = writeln!(printer, \"\");\n\n    // Freeze forever.\n    loop {\n        unsafe {\n            asm!(\"wfe\", options(nomem, nostack, preserves_flags));\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/arm/misc.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n// TODO: figure out how to remove these\n\n#[cfg(target_arch = \"aarch64\")]\n#[no_mangle]\npub extern \"C\" fn fmod(x: f64, y: f64) -> f64 {\n    libm::fmod(x, y)\n}\n#[cfg(target_arch = \"aarch64\")]\n#[no_mangle]\npub extern \"C\" fn fmodf(x: f32, y: f32) -> f32 {\n    libm::fmodf(x, y)\n}\n#[no_mangle]\npub extern \"C\" fn fmin(a: f64, b: f64) -> f64 {\n    libm::fmin(a, b)\n}\n#[no_mangle]\npub extern \"C\" fn fminf(a: f32, b: f32) -> f32 {\n    libm::fminf(a, b)\n}\n#[no_mangle]\npub extern \"C\" fn fmax(a: f64, b: f64) -> f64 {\n    libm::fmax(a, b)\n}\n#[no_mangle]\npub extern \"C\" fn fmaxf(a: f32, b: f32) -> f32 {\n    libm::fmaxf(a, b)\n}\n#[no_mangle]\npub extern \"C\" fn __aeabi_d2f(a: f64) -> f32 {\n    libm::trunc(a) as f32 // TODO: correct?\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/arm/time_aarch64.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n#![cfg(target_arch = \"aarch64\")]\n\n//! This module is a draft.\n// TODO: implement properly\n\nuse alloc::sync::Arc;\nuse core::{\n    arch::asm,\n    future::Future,\n    pin::Pin,\n    task::{Context, Poll},\n};\n\npub struct TimeControl {}\n\npub struct TimerFuture {}\n\nimpl TimeControl {\n    pub unsafe fn init() -> Arc<TimeControl> {\n        Arc::new(TimeControl {})\n    }\n\n    pub fn monotonic_clock(self: &Arc<Self>) -> u128 {\n        unsafe {\n            // TODO: stub\n            let val: u64;\n            asm!(\"mrs {}, CNTPCT_EL0\", out(reg) val, options(nostack, nomem, preserves_flags));\n            u128::from(val)\n        }\n    }\n\n    pub fn timer(self: &Arc<Self>, deadline: u128) -> TimerFuture {\n        TimerFuture {}\n    }\n}\n\nimpl Future for TimerFuture {\n    type Output = ();\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {\n        Poll::Pending\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/arm/time_arm.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n#![cfg(target_arch = \"arm\")]\n\n/// Time management on ARM platforms.\n///\n/// See chapter \"B8.1.1 System counter\" of the ARM® Architecture Reference Manual\n/// (ARMv7-A and ARMv7-R edition).\n///\n/// The monotonic clock is implemented by reading the `CNTPCT` register.\n/// Some characteristics about this register:\n///\n/// - It is at least 56 bits wide. The value is zero-extended to 64bits.\n/// - Roll-over must be no less than 40 years, which is acceptable.\n/// - There is no strict requirement on the accuracy, but it is recommended that the timer\n///   does not gain or lose more than 10 seconds in a 24 hours period.\n///\n// TODO: it is unclear whether the counter is global, or per CPU. The manual mentions,\n//       however, it is impossible to observe time rolling back even across CPUs\nuse alloc::{sync::Arc, vec::Vec};\nuse core::{\n    arch::asm,\n    convert::TryFrom as _,\n    num::NonZeroUsize,\n    pin::Pin,\n    sync::atomic,\n    task::{Context, Poll, Waker},\n};\nuse futures::prelude::*;\nuse spinning_top::Spinlock;\n\n/// All the time-related functionalities.\npub struct TimeControl {\n    /// List of timers, ordered by ascending deadline.\n    ///\n    /// This is a subset of the list of alive [`TimerFuture`]s created through this\n    /// [`TimeControl`]. All the elements of this list correspond to a [`TimerFuture`], but not\n    /// all [`TimerFuture`]s have an entry in this list.\n    ///\n    /// The first timer in the list must always match what the hardware timer is configured for.\n    /// Any operation that modifies the first element must also update the hardware timer by\n    /// calling [`update_hardware`].\n    timers: Spinlock<Vec<Timer>>,\n\n    /// Each timer in [`TimerControl::timers`] is assigned a private id for identification. This\n    /// counter increases linearly and contains the ID to assign to the next timer to put in the\n    /// list.\n    next_timer_id: atomic::AtomicUsize,\n}\n\nstruct Timer {\n    id: NonZeroUsize,\n    /// Value of the physical counter that the timer wants to reach.\n    counter_value: u64,\n    /// Waker to wake when the timer is fired.\n    waker: Option<Waker>,\n}\n\n/// Implementation of the `Future` trait returned by [`TimeControl::timer`].\npub struct TimerFuture {\n    /// Time controller this future has been created from.\n    time_control: Arc<TimeControl>,\n    /// Identifier assigned to this timer, or `None` if this timer is not in\n    /// [`TimerControl::timers`].\n    id: Option<NonZeroUsize>,\n    /// Value of the physical counter that the timer wants to reach.\n    counter_value: u64,\n}\n\n/// Value that we put in the CNTFRQ register on start-up.\n///\n/// Frequency in Hz. The value of the ARM hardware counter is increased by this value every\n/// second.\n// TODO: if the timer is only 56bits, then this will overflow after 388 days, which is a bit short\n//       for prime time\nconst CNTFRQ: u32 = 0x80000000;\n\nimpl TimeControl {\n    /// Initializes the time control system.\n    ///\n    /// # Safety\n    ///\n    /// No other code must access the ARM system-timer-related registers for as long as the\n    /// `TimeControl` is alive.\n    ///\n    pub unsafe fn init() -> Arc<TimeControl> {\n        // Initialize the physical counter frequency.\n        // TODO: I think this is a global setting, but make sure it's the case?\n        asm!(\"mcr p15, 0, {}, c14, c0, 0\", in(reg) CNTFRQ, options(nomem, nostack, preserves_flags));\n\n        // TODO: this code doesn't work, as we have to register some IRQ handler or something to\n        //       check the state of the timers and fire the wakers\n\n        Arc::new(TimeControl {\n            timers: Spinlock::new(Vec::new()),\n            next_timer_id: From::from(1),\n        })\n    }\n\n    /// Implementation suitable for [`arch::PlatformSpecific::monotonic_clock`].\n    pub fn monotonic_clock(self: &Arc<Self>) -> u128 {\n        let counter_value = physical_counter();\n\n        // We have to turn this into a number of nanoseconds.\n        1_000_000_000 * u128::from(counter_value) / u128::from(CNTFRQ)\n    }\n\n    /// Implementation suitable for [`arch::PlatformSpecific::timer`].\n    pub fn timer(self: &Arc<Self>, deadline: u128) -> TimerFuture {\n        // Since `deadline` is a number of nanoseconds, we have to find the value of the physical\n        // counter that corresponds to it.\n        //\n        // Note that in case of an overflow, we cap to the maximum value. The maximum value is\n        // expected to never be reached. TODO: this isn't necessarily true\n        let counter_value = u64::try_from(deadline * u128::from(CNTFRQ) / 1_000_000_000)\n            .unwrap_or(u64::max_value());\n\n        // Note that we don't immediately put the timer in our list of timers. This is done\n        // lazily because:\n        //\n        // - If the deadline has already passed, we immediately return `Ready` without going\n        //   through the process of adding an entry and removing it.\n        // - If the deadline has no already passed, polling will need to update the list anyway\n        //   in order to update the `Waker`. We might therefore as well just insert the value\n        //   then.\n\n        TimerFuture {\n            time_control: self.clone(),\n            id: None,\n            counter_value,\n        }\n    }\n}\n\nimpl Future for TimerFuture {\n    type Output = ();\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {\n        let this = &mut *self;\n\n        let cnt_value = physical_counter();\n        if cnt_value >= this.counter_value {\n            return Poll::Ready(());\n        }\n\n        // TODO: the timer should asynchronously wait for a lock, rather than spin-lock the mutex\n        //       this is too difficult to do before https://github.com/rust-lang/rust/issues/56974\n\n        // If we have already registered ourselves, update the waker.\n        if let Some(id) = this.id {\n            let mut timers = this.time_control.timers.lock();\n            let mut my_entry = timers.iter_mut().find(|t| t.id == id).unwrap();\n            my_entry.waker = Some(cx.waker().clone());\n            return Poll::Pending;\n        }\n\n        // If the timer hasn't registered itself in the list of timers of the `time_control`,\n        // do so now.\n        let assigned_id = {\n            let assigned_id = this\n                .time_control\n                .next_timer_id\n                .fetch_add(1, atomic::Ordering::Relaxed);\n            assert_ne!(assigned_id, usize::max_value());\n            assert_ne!(assigned_id, 0);\n            NonZeroUsize::new(assigned_id).unwrap()\n        };\n\n        let to_insert = Timer {\n            id: assigned_id,\n            counter_value: this.counter_value,\n            waker: Some(cx.waker().clone()),\n        };\n\n        let mut timers = this.time_control.timers.lock();\n        if let Some(pos) = timers\n            .iter()\n            .position(|t| t.counter_value > this.counter_value)\n        {\n            timers.insert(pos, to_insert);\n            if pos == 0 {\n                update_hardware(&mut timers);\n            }\n        } else {\n            let was_empty = timers.is_empty();\n            timers.push(to_insert);\n            if was_empty {\n                update_hardware(&mut timers);\n            }\n        }\n\n        this.id = Some(assigned_id);\n\n        Poll::Pending\n    }\n}\n\nimpl Drop for TimerFuture {\n    fn drop(&mut self) {\n        if let Some(my_id) = self.id {\n            // Clean up behind us.\n            let mut timers = self.time_control.timers.lock();\n\n            // It is possible that we are not in the list anymore, in case a different timer has.  TODO: is that true? finish\n            if let Some(pos) = timers.iter().position(|t| t.id == my_id) {\n                timers.remove(pos);\n                if pos == 0 {\n                    update_hardware(&mut timers);\n                }\n            }\n        }\n    }\n}\n\n/// Reads the value of the `CNTPCT` register.\nfn physical_counter() -> u64 {\n    unsafe {\n        let lo: u32;\n        let hi: u32;\n        asm!(\"mrrc p15, 0, {}, {}, c14\", out(reg) lo, out(reg) hi, options(nostack, nomem, preserves_flags));\n        u64::from(hi) << 32 | u64::from(lo)\n    }\n}\n\n/// Updates the state of the hardware timer according to the content of `timers`.\nfn update_hardware(timers: &mut Vec<Timer>) {\n    unsafe {\n        // See chapter \"B8.1.5 Timers\" of the ARM® Architecture Reference Manual (ARMv7-A and\n        // ARMv7-R edition).\n\n        // If there's no active timer, disable the timer firing by updating the `CNTP_CTL`\n        // register.\n        if timers.is_empty() {\n            asm!(\"mcr p15, 0, {}, c14, c2, 1\", in(reg) 0);\n            return;\n        }\n\n        // Make sure that the timer is enabled by updating the `CNTP_CTL` register.\n        // TODO: don't do this every single time\n        asm!(\"mcr p15, 0, {}, c14, c2, 1\", in(reg) 0b01);\n\n        // Write the `CNTP_CVAL` register with the value to compare with.\n        // The timer will fire when the physical counter (`CNTPCT`) reaches the given value.\n        {\n            let cmp_value = timers.get(0).unwrap().counter_value;\n            let lo = u32::try_from(cmp_value & 0xffffffff).unwrap();\n            let hi = u32::try_from(cmp_value >> 32).unwrap();\n            asm!(\"mcrr p15, 2, {}, {}, c14\", in(reg) lo, in(reg) hi);\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/arm.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::arch::{PlatformSpecific, PortErr};\nuse crate::klog::KLogger;\n\nuse alloc::sync::Arc;\nuse core::{arch::asm, convert::TryFrom as _, fmt, iter, num::NonZeroU32, pin::Pin};\nuse futures::prelude::*;\nuse redshirt_kernel_log_interface::ffi::{KernelLogMethod, UartAccess, UartInfo};\n\n#[cfg(target_arch = \"aarch64\")]\npub use time_aarch64 as time;\n#[cfg(target_arch = \"arm\")]\npub use time_arm as time;\n\npub mod executor;\npub mod log;\npub mod time_aarch64;\npub mod time_arm;\n\nmod misc;\n\n#[macro_export]\nmacro_rules! __gen_boot {\n    (\n        entry: $entry:path,\n        memory_zeroing_start: $memory_zeroing_start:path,\n        memory_zeroing_end: $memory_zeroing_end:path,\n    ) => {\n        const _: () = {\n            extern crate alloc;\n\n            use alloc::sync::Arc;\n            use core::{\n                arch::asm, convert::TryFrom as _, fmt::Write as _, iter, num::NonZeroU32, pin::Pin,\n            };\n            use $crate::futures::prelude::*;\n            use $crate::klog::KLogger;\n            use $crate::redshirt_kernel_log_interface::ffi::{KernelLogMethod, UartInfo};\n\n            /// This is the main entry point of the kernel for ARM 32bits architectures.\n            #[cfg(target_arch = \"arm\")]\n            #[export_name = \"_start\"]\n            #[naked]\n            unsafe extern \"C\" fn entry_point_arm32() -> ! {\n                // TODO: always fails :-/\n                /*#[cfg(not(any(target_feature = \"armv7-a\", target_feature = \"armv7-r\")))]\n                compile_error!(\"The ARMv7-A or ARMv7-R instruction sets must be enabled\");*/\n\n                // Detect which CPU we are.\n                //\n                // See sections B4.1.106 and B6.1.67 of the ARM® Architecture Reference Manual\n                // (ARMv7-A and ARMv7-R edition).\n                //\n                // This is specific to ARMv7-A and ARMv7-R, hence the compile_error! above.\n                asm!(\n                    \"\n                    mrc p15, 0, r5, c0, c0, 5\n                    and r5, r5, #3\n                    cmp r5, #0\n                    bne {}\n                    \",\n                    sym halt,\n                    out(\"r3\") _, out(\"r5\") _,\n                    options(nomem, nostack, preserves_flags)\n                );\n\n                // Only one CPU reaches here.\n\n                // Zero the memory requested to be zero'ed.\n                // TODO: that's illegal ; naked functions must only contain an asm! block (for good reasons)\n                let mut ptr = &mut $memory_zeroing_start as *mut u8;\n                while ptr < &mut $memory_zeroing_end as *mut u8 {\n                    ptr.write_volatile(0);\n                    ptr = ptr.add(1);\n                }\n\n                // Set up the stack and jump to the entry point.\n                asm!(\"\n                    .comm stack, 0x400000, 8\n                    ldr sp, =stack+0x400000\n                    b {}\n                    \",\n                    sym cpu_enter,\n                    options(noreturn)\n                )\n            }\n\n            /// This is the main entry point of the kernel for ARM 64bits architectures.\n            #[cfg(target_arch = \"aarch64\")]\n            #[export_name = \"_start\"]\n            #[naked]\n            unsafe extern \"C\" fn entry_point_arm64() -> ! {\n                // TODO: review this\n                asm!(\n                    \"\n                        mrs x6, MPIDR_EL1\n                        and x6, x6, #0x3\n                        cbz x6, L0\n                        b {}\n                    L0: nop\n                        \",\n                    sym halt,\n                    out(\"x6\") _,\n                    options(nomem, nostack)\n                );\n\n                // Only one CPU reaches here.\n\n                // Zero the memory requested to be zero'ed.\n                // TODO: that's illegal ; naked functions must only contain an asm! block (for good reasons)\n                let mut ptr = &mut $memory_zeroing_start as *mut u8;\n                while ptr < &mut $memory_zeroing_end as *mut u8 {\n                    ptr.write_volatile(0);\n                    ptr = ptr.add(1);\n                }\n\n                // Set up the stack and jump to `cpu_enter`.\n        asm!(\n                    \"\n                        .comm stack, 0x400000, 8\n                        ldr x5, =stack+0x400000\n                        mov sp, x5\n                        b {}\n                \", sym cpu_enter, options(noreturn))\n            }\n\n            /// Main Rust entry point.\n            #[no_mangle]\n            unsafe fn cpu_enter() -> ! {\n                // Initialize the logging system.\n                $crate::arch::arm::log::PANIC_LOGGER.set_method(KernelLogMethod {\n                    enabled: true,\n                    framebuffer: None,\n                    uart: Some($crate::arch::arm::init_uart()),\n                });\n\n                // TODO: RAM starts at 0, but we start later to avoid the kernel\n                // TODO: make this is a cleaner way\n                $crate::mem_alloc::initialize(iter::once(0xa000000..0x40000000));\n\n                let time = $crate::arch::arm::time::TimeControl::init();\n\n                writeln!(\n                    $crate::arch::arm::log::PANIC_LOGGER.log_printer(),\n                    \"[boot] boot successful\"\n                )\n                .unwrap();\n\n                let platform = Arc::pin($crate::arch::PlatformSpecific::from(\n                    $crate::arch::arm::PlatformSpecificImpl { time },\n                ));\n                $crate::arch::arm::executor::block_on($entry(platform))\n            }\n\n            #[naked]\n            fn halt() -> ! {\n                unsafe {\n                    loop {\n                        asm!(\"wfe\", options(nomem, nostack, preserves_flags));\n                    }\n                }\n            }\n        };\n    };\n}\n\n/// Implementation of [`PlatformSpecific`].\n#[doc(hidden)]\npub struct PlatformSpecificImpl {\n    #[doc(hidden)]\n    pub time: Arc<time::TimeControl>,\n}\n\nimpl From<PlatformSpecificImpl> for super::PlatformSpecific {\n    fn from(ps: PlatformSpecificImpl) -> Self {\n        Self(ps)\n    }\n}\n\nimpl PlatformSpecificImpl {\n    pub fn num_cpus(self: Pin<&Self>) -> NonZeroU32 {\n        NonZeroU32::new(1).unwrap()\n    }\n\n    pub fn monotonic_clock(self: Pin<&Self>) -> u128 {\n        self.time.monotonic_clock()\n    }\n\n    pub fn timer(self: Pin<&Self>, deadline: u128) -> TimerFuture {\n        self.time.timer(deadline)\n    }\n\n    pub fn next_irq(self: Pin<&Self>) -> IrqFuture {\n        future::pending()\n    }\n\n    pub fn write_log(&self, message: &str) {\n        fmt::Write::write_str(&mut log::PANIC_LOGGER.log_printer(), message).unwrap();\n    }\n\n    pub fn set_logger_method(&self, method: KernelLogMethod) {\n        log::PANIC_LOGGER.set_method(method);\n    }\n\n    pub unsafe fn write_port_u8(self: Pin<&Self>, _: u32, _: u8) -> Result<(), PortErr> {\n        Err(PortErr::Unsupported)\n    }\n\n    pub unsafe fn write_port_u16(self: Pin<&Self>, _: u32, _: u16) -> Result<(), PortErr> {\n        Err(PortErr::Unsupported)\n    }\n\n    pub unsafe fn write_port_u32(self: Pin<&Self>, _: u32, _: u32) -> Result<(), PortErr> {\n        Err(PortErr::Unsupported)\n    }\n\n    pub unsafe fn read_port_u8(self: Pin<&Self>, _: u32) -> Result<u8, PortErr> {\n        Err(PortErr::Unsupported)\n    }\n\n    pub unsafe fn read_port_u16(self: Pin<&Self>, _: u32) -> Result<u16, PortErr> {\n        Err(PortErr::Unsupported)\n    }\n\n    pub unsafe fn read_port_u32(self: Pin<&Self>, _: u32) -> Result<u32, PortErr> {\n        Err(PortErr::Unsupported)\n    }\n}\n\npub type TimerFuture = time::TimerFuture;\npub type IrqFuture = future::Pending<()>;\n\nconst GPIO_BASE: usize = 0x3F200000;\nconst UART0_BASE: usize = 0x3F201000;\n\n#[doc(hidden)]\npub fn init_uart() -> UartInfo {\n    unsafe {\n        ((UART0_BASE + 0x30) as *mut u32).write_volatile(0x0);\n        ((GPIO_BASE + 0x94) as *mut u32).write_volatile(0x0);\n        delay(150);\n\n        ((GPIO_BASE + 0x98) as *mut u32).write_volatile((1 << 14) | (1 << 15));\n        delay(150);\n\n        ((GPIO_BASE + 0x98) as *mut u32).write_volatile(0x0);\n\n        ((UART0_BASE + 0x44) as *mut u32).write_volatile(0x7FF);\n\n        ((UART0_BASE + 0x24) as *mut u32).write_volatile(1);\n        ((UART0_BASE + 0x28) as *mut u32).write_volatile(40);\n\n        ((UART0_BASE + 0x2C) as *mut u32).write_volatile((1 << 4) | (1 << 5) | (1 << 6));\n\n        ((UART0_BASE + 0x38) as *mut u32).write_volatile(\n            (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10),\n        );\n\n        ((UART0_BASE + 0x30) as *mut u32).write_volatile((1 << 0) | (1 << 8) | (1 << 9));\n\n        UartInfo {\n            wait_address: UartAccess::MemoryMappedU32(u64::try_from(UART0_BASE + 0x18).unwrap()),\n            wait_mask: 1 << 5,\n            wait_compare_equal_if_ready: 0,\n            write_address: UartAccess::MemoryMappedU32(u64::try_from(UART0_BASE + 0x0).unwrap()),\n        }\n    }\n}\n\nfn delay(count: i32) {\n    unsafe {\n        for _ in 0..count {\n            asm!(\"nop\", options(nostack, nomem, preserves_flags));\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/riscv/executor.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Futures executor that works on bare metal.\n\nuse alloc::sync::Arc;\nuse core::arch::asm;\nuse core::future::Future;\nuse core::sync::atomic;\nuse core::task::{Context, Poll};\nuse futures::task::{waker, ArcWake};\n\n/// Waits for the `Future` to resolve to a value.\n///\n/// This function is similar to [`futures::executor::block_on`].\npub fn block_on<R>(future: impl Future<Output = R>) -> R {\n    futures::pin_mut!(future);\n\n    let local_wake = Arc::new(LocalWake {\n        woken_up: atomic::AtomicBool::new(false),\n    });\n\n    let waker = waker(local_wake.clone());\n    let mut context = Context::from_waker(&waker);\n\n    loop {\n        if let Poll::Ready(val) = Future::poll(future.as_mut(), &mut context) {\n            return val;\n        }\n\n        // Loop until `woken_up` is true.\n        loop {\n            if local_wake\n                .woken_up\n                .compare_exchange(\n                    true,\n                    false,\n                    atomic::Ordering::Acquire,\n                    atomic::Ordering::Acquire,\n                )\n                .is_ok()\n            {\n                break;\n            }\n\n            // Enter a low-power state and wait for an event to happen.\n            // TODO: can an interrupt happen between `local_wake` and here?\n            // contrary to other platforms, the manual doesn't mention anything about enabling\n            // instructions having a delay\n            unsafe { asm!(\"wfi\", options(nomem, nostack, preserves_flags)) }\n        }\n    }\n}\n\nstruct LocalWake {\n    woken_up: atomic::AtomicBool,\n}\n\nimpl ArcWake for LocalWake {\n    fn wake_by_ref(arc_self: &Arc<Self>) {\n        arc_self.woken_up.store(true, atomic::Ordering::Release);\n        // TODO: there doesn't seem to be a standard way to wake up another processor\n        // For now we are single-CPUed.\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/riscv/interrupts.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Interrupts handling for RISC-V.\n\nuse core::arch::asm;\n\n/// Initializes interrupts handling.\npub unsafe fn init() -> Interrupts {\n    let value = trap_handler as unsafe extern \"C\" fn() as usize;\n    assert_eq!(value % 4, 0);\n    // The 2 less significant bits defined the mode. We keep 0, which means that all\n    // exceptions/interrupts go to the same handler.\n    asm!(\"csrw mtvec, {}\", in(reg) value, options(nomem, nostack, preserves_flags));\n    Interrupts {}\n}\n\npub struct Interrupts {}\n\nimpl Drop for Interrupts {\n    fn drop(&mut self) {\n        // We really don't want that to be destroyed.\n        panic!();\n    }\n}\n\n/// Main interrupt handler.\n#[cfg(target_pointer_width = \"32\")]\n#[naked]\nunsafe extern \"C\" fn trap_handler() {\n    // It is important for all the registers to be restored to their previous values at the end\n    // of the interrupt handler. The code below saves all the caller-saved registers according to\n    // the RISC-V calling conventions.\n    // TODO: what about float registers?\n    asm!(r#\"\n    .align 4\n        addi sp, sp, -64\n\n        sw x1, 0(sp)\n        sw x5, 4(sp)\n        sw x6, 8(sp)\n        sw x7, 12(sp)\n        sw x10, 16(sp)\n        sw x11, 20(sp)\n        sw x12, 24(sp)\n        sw x13, 28(sp)\n        sw x14, 32(sp)\n        sw x15, 36(sp)\n        sw x16, 40(sp)\n        sw x17, 44(sp)\n        sw x28, 48(sp)\n        sw x29, 52(sp)\n        sw x30, 56(sp)\n        sw x31, 60(sp)\n\n        jal ra, {trap_handler_rust}\n\n        lw x1, 0(sp)\n        lw x5, 4(sp)\n        lw x6, 8(sp)\n        lw x7, 12(sp)\n        lw x10, 16(sp)\n        lw x11, 20(sp)\n        lw x12, 24(sp)\n        lw x13, 28(sp)\n        lw x14, 32(sp)\n        lw x15, 36(sp)\n        lw x16, 40(sp)\n        lw x17, 44(sp)\n        lw x28, 48(sp)\n        lw x29, 52(sp)\n        lw x30, 56(sp)\n        lw x31, 60(sp)\n\n        addi sp, sp, 64\n        mret\n    \"#,\n        trap_handler_rust = sym trap_handler_rust,\n        options(noreturn));\n}\n\n/// Equivalent to the `trap_handler` above, for 64bits.\n#[cfg(target_pointer_width = \"64\")]\n#[naked]\nunsafe extern \"C\" fn trap_handler() {\n    // TODO: what about float registers?\n    asm!(r#\"\n    .align 4\n        addi sp, sp, -128\n\n        sd x1, 0(sp)\n        sd x5, 8(sp)\n        sd x6, 16(sp)\n        sd x7, 24(sp)\n        sd x10, 32(sp)\n        sd x11, 40(sp)\n        sd x12, 48(sp)\n        sd x13, 56(sp)\n        sd x14, 64(sp)\n        sd x15, 72(sp)\n        sd x16, 80(sp)\n        sd x17, 88(sp)\n        sd x28, 96(sp)\n        sd x29, 104(sp)\n        sd x30, 112(sp)\n        sd x31, 120(sp)\n\n        jal ra, {trap_handler_rust}\n\n        ld x1, 0(sp)\n        ld x5, 8(sp)\n        ld x6, 16(sp)\n        ld x7, 24(sp)\n        ld x10, 32(sp)\n        ld x11, 40(sp)\n        ld x12, 48(sp)\n        ld x13, 56(sp)\n        ld x14, 64(sp)\n        ld x15, 72(sp)\n        ld x16, 80(sp)\n        ld x17, 88(sp)\n        ld x28, 96(sp)\n        ld x29, 104(sp)\n        ld x30, 112(sp)\n        ld x31, 120(sp)\n\n        addi sp, sp, 128\n        mret\n    \"#,\n        trap_handler_rust = sym trap_handler_rust,\n        options(noreturn));\n}\n\n/// Called on interrupt after all registers have been saved on the stack.\n///\n/// The function is marked as `extern \"C\"` in order to be sure that it respects the C\n/// calling conventions.\nunsafe extern \"C\" fn trap_handler_rust() {\n    let mcause: usize;\n    asm!(\"csrr {}, mcause\", out(reg) mcause, options(nomem, nostack, preserves_flags));\n\n    // TODO: the code below is note keeping; depending on the interrupt we must increment mepc, otherwise `mret` will jump back to the same instruction that triggered the interrupt\n    let mepc: usize;\n    asm!(\"csrr {}, mepc\", out(reg) mepc, options(nomem, nostack, preserves_flags));\n    asm!(\"csrw mepc, {}\", in(reg) mepc + 4, options(nomem, nostack, preserves_flags));\n\n    // TODO:\n    panic!(\"Interrupt with mcause = 0x{:x}\", mcause);\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/riscv/log.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Panic handling code.\n\nuse crate::klog::KLogger;\n\nuse core::arch::asm;\nuse core::fmt::{self, Write as _};\nuse redshirt_kernel_log_interface::ffi::KernelLogMethod;\nuse spinning_top::Spinlock;\n\npub static PANIC_LOGGER: KLogger = KLogger::disabled();\n\n#[cfg(not(any(test, doc, doctest)))]\n#[panic_handler]\nfn panic(panic_info: &core::panic::PanicInfo) -> ! {\n    // TODO: somehow freeze all CPUs?\n\n    let mut printer = PANIC_LOGGER.panic_printer();\n    let _ = writeln!(printer, \"Kernel panic!\");\n    let _ = writeln!(printer, \"{}\", panic_info);\n    let _ = writeln!(printer, \"\");\n\n    // Freeze forever.\n    loop {\n        unsafe {\n            asm!(\"ebreak ; wfi\", options(nomem, nostack, preserves_flags));\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/riscv/misc.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n// TODO: figure out how to remove these\n\n#[no_mangle]\npub extern \"C\" fn fmod(x: f64, y: f64) -> f64 {\n    libm::fmod(x, y)\n}\n#[no_mangle]\npub extern \"C\" fn fmodf(x: f32, y: f32) -> f32 {\n    libm::fmodf(x, y)\n}\n#[no_mangle]\npub extern \"C\" fn fmin(a: f64, b: f64) -> f64 {\n    libm::fmin(a, b)\n}\n#[no_mangle]\npub extern \"C\" fn fminf(a: f32, b: f32) -> f32 {\n    libm::fminf(a, b)\n}\n#[no_mangle]\npub extern \"C\" fn fmax(a: f64, b: f64) -> f64 {\n    libm::fmax(a, b)\n}\n#[no_mangle]\npub extern \"C\" fn fmaxf(a: f32, b: f32) -> f32 {\n    libm::fmaxf(a, b)\n}\n#[no_mangle]\npub extern \"C\" fn __aeabi_d2f(a: f64) -> f32 {\n    libm::trunc(a) as f32 // TODO: correct?\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/riscv.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::arch::{PlatformSpecific, PortErr};\nuse crate::klog::KLogger;\n\nuse core::{fmt, iter, num::NonZeroU32, pin::Pin};\nuse futures::prelude::*;\nuse redshirt_kernel_log_interface::ffi::{KernelLogMethod, UartInfo};\n\n// Modules that are used by the macro must be public, but their content isn't meant to be used\n// apart from the macro.\n#[doc(hidden)]\npub mod executor;\n#[doc(hidden)]\npub mod interrupts;\n#[doc(hidden)]\npub mod log;\n\nmod misc;\n\n#[macro_export]\nmacro_rules! __gen_boot {\n    (\n        entry: $entry:path,\n        memory_zeroing_start: $memory_zeroing_start:path,\n        memory_zeroing_end: $memory_zeroing_end:path,\n    ) => {\n        const _: () = {\n            extern crate alloc;\n\n            use $crate::arch::{PlatformSpecific, PortErr};\n            use $crate::arch::riscv::*;\n            use $crate::klog::KLogger;\n\n            use alloc::sync::Arc;\n            use core::{arch::asm, fmt::Write as _, iter, num::NonZeroU32, pin::Pin};\n            use $crate::futures::prelude::*;\n            use $crate::redshirt_kernel_log_interface::ffi::{KernelLogMethod, UartAccess, UartInfo};\n\n            /// This is the main entry point of the kernel for RISC-V architectures.\n            #[naked]\n            #[export_name = \"_start\"]\n            unsafe extern \"C\" fn entry_point() {\n                asm!(r#\"\n                    // Disable interrupts and clear pending interrupts.\n                    csrw mie, 0\n                    csrw mip, 0\n\n                    // TODO: ???\n                    .option push\n                    .option norelax\n                    la gp, __global_pointer$\n                    .option pop\n\n                    // Zero the memory requested to be zero'ed.\n                    la a0, {memory_zeroing_start}\n                    la a1, {memory_zeroing_end}\n                .L0:sb zero, 0(a0)\n                    addi a0, a0, 1\n                    bltu a0, a1, .L0\n\n                    // Set up the stack.\n                    // TODO: make stack size configurable\n                    // TODO: we don't have any stack protection in place\n                    .comm stack, 0x2000, 8\n                    la sp, stack\n                    li t0, 0x2000\n                    add sp, sp, t0\n                    add fp, sp, zero\n\n                    j {after_boot}\n                \"#,\n                    memory_zeroing_start = sym $memory_zeroing_start,\n                    memory_zeroing_end = sym $memory_zeroing_end,\n                    after_boot = sym after_boot,\n                    options(noreturn));\n            }\n\n            /// Main Rust entry point.\n            unsafe fn after_boot() -> ! {\n                // Initialize the logging system.\n                log::PANIC_LOGGER.set_method(KernelLogMethod {\n                    enabled: true,\n                    framebuffer: None,\n                    uart: Some(init_uart()),\n                });\n\n                // Initialize the memory allocator.\n                // TODO: make this is a cleaner way; this is specific to the hifive\n                $crate::mem_alloc::initialize(iter::once({\n                    let free_mem_start = &$memory_zeroing_end as *const u8 as usize;\n                    let ram_end = 0x80000000 + 16 * 1024;\n                    free_mem_start..ram_end\n                }));\n\n                // Initialize interrupts.\n                let _interrupts = interrupts::init();\n\n                writeln!(log::PANIC_LOGGER.log_printer(), \"[boot] boot successful\").unwrap();\n\n                // TODO: there's a stack overflow in practice when we call `kernel.run()`; the interrupt\n                // handler fails to show that because it uses the stack\n                panic!(\"We pre-emptively panic because running the kernel is known to overflow the stack\");\n\n                // Call the entry point specified by the user of the macro.\n                // `` is used in order to jump out of the `__gen_boot` macro.\n                let platform_specific = Arc::pin(PlatformSpecific::from(PlatformSpecificImpl {}));\n                executor::block_on($entry(platform_specific))\n            }\n\n            // TODO: this is architecture-specific and very hacky\n            fn init_uart() -> UartInfo {\n                unsafe {\n                    let prci_hfrosccfg = (0x10008000 as *mut u32).read_volatile();\n                    (0x10008000 as *mut u32).write_volatile(prci_hfrosccfg | (1 << 30));\n\n                    let prci_pllcfg = (0x10008008 as *mut u32).read_volatile();\n                    (0x10008008 as *mut u32).write_volatile(prci_pllcfg | (1 << 18) | (1 << 17));\n                    let prci_pllcfg = (0x10008008 as *mut u32).read_volatile();\n                    (0x10008008 as *mut u32).write_volatile(prci_pllcfg | (1 << 16));\n\n                    let prci_hfrosccfg = (0x10008000 as *mut u32).read_volatile();\n                    (0x10008000 as *mut u32).write_volatile(prci_hfrosccfg & !(1 << 30));\n\n                    let gpio_iof_sel = (0x1001203c as *mut u32).read_volatile();\n                    (0x1001203c as *mut u32).write_volatile(gpio_iof_sel & !0x00030000);\n\n                    let gpio_iof_en = (0x10012038 as *mut u32).read_volatile();\n                    (0x10012038 as *mut u32).write_volatile(gpio_iof_en | 0x00030000);\n\n                    (0x10013018 as *mut u32).write_volatile(138);\n\n                    let uart_reg_tx_ctrl = (0x10013008 as *mut u32).read_volatile();\n                    (0x10013008 as *mut u32).write_volatile(uart_reg_tx_ctrl | 1);\n\n                    UartInfo {\n                        wait_address: UartAccess::MemoryMappedU32(0x10013000),\n                        wait_mask: 0x80000000,\n                        wait_compare_equal_if_ready: 0,\n                        write_address: UartAccess::MemoryMappedU32(0x10013000),\n                    }\n                }\n            }\n        };\n    }\n}\n\n/// Implementation of [`PlatformSpecific`].\npub struct PlatformSpecificImpl {}\n\nimpl From<PlatformSpecificImpl> for super::PlatformSpecific {\n    fn from(ps: PlatformSpecificImpl) -> Self {\n        Self(ps)\n    }\n}\n\nimpl PlatformSpecificImpl {\n    pub fn num_cpus(self: Pin<&Self>) -> NonZeroU32 {\n        // TODO:\n        NonZeroU32::new(1).unwrap()\n    }\n\n    #[cfg(target_pointer_width = \"32\")]\n    pub fn monotonic_clock(self: Pin<&Self>) -> u128 {\n        // TODO: unit is probably the wrong unit; we're supposed to return nanoseconds\n        // TODO: this is only supported in the \"I\" version of RISC-V; check that\n        unsafe {\n            // Because we can't read the entire register atomically, we have to carefully handle\n            // the possibility of an overflow of the lower bits during the reads. This is also\n            // shown as the example that the manual uses for reading the clock on RV32I.\n            let val = loop {\n                let lo: u32;\n                let hi1: u32;\n                let hi2: u32;\n\n                // Note that we put all three instructions in the same `asm!`, to prevent the\n                // compiler from possibly reordering them.\n                asm!(\"rdtimeh {} ; rdtime {} ; rdtimeh {}\", out(reg) hi1, out(reg) lo, out(reg) hi2);\n\n                if hi1 == hi2 {\n                    break (u64::from(hi1) << 32) | u64::from(lo);\n                }\n            };\n\n            u128::from(val)\n        }\n    }\n\n    #[cfg(target_pointer_width = \"64\")]\n    pub fn monotonic_clock(self: Pin<&Self>) -> u128 {\n        // TODO: unit is probably the wrong unit; we're supposed to return nanoseconds\n        // TODO: this is only supported in the \"I\" version of RISC-V; check that\n        unsafe {\n            let val: u64;\n            asm!(\"rdtime {}\", out(reg) reg);\n            u128::from(val)\n        }\n    }\n\n    pub fn timer(self: Pin<&Self>, _deadline: u128) -> TimerFuture {\n        todo!()\n    }\n\n    pub fn next_irq(self: Pin<&Self>) -> IrqFuture {\n        future::pending()\n    }\n\n    pub fn write_log(&self, message: &str) {\n        fmt::Write::write_str(&mut log::PANIC_LOGGER.log_printer(), message).unwrap();\n    }\n\n    pub fn set_logger_method(&self, method: KernelLogMethod) {\n        log::PANIC_LOGGER.set_method(method);\n    }\n\n    pub unsafe fn write_port_u8(self: Pin<&Self>, _: u32, _: u8) -> Result<(), PortErr> {\n        Err(PortErr::Unsupported)\n    }\n\n    pub unsafe fn write_port_u16(self: Pin<&Self>, _: u32, _: u16) -> Result<(), PortErr> {\n        Err(PortErr::Unsupported)\n    }\n\n    pub unsafe fn write_port_u32(self: Pin<&Self>, _: u32, _: u32) -> Result<(), PortErr> {\n        Err(PortErr::Unsupported)\n    }\n\n    pub unsafe fn read_port_u8(self: Pin<&Self>, _: u32) -> Result<u8, PortErr> {\n        Err(PortErr::Unsupported)\n    }\n\n    pub unsafe fn read_port_u16(self: Pin<&Self>, _: u32) -> Result<u16, PortErr> {\n        Err(PortErr::Unsupported)\n    }\n\n    pub unsafe fn read_port_u32(self: Pin<&Self>, _: u32) -> Result<u32, PortErr> {\n        Err(PortErr::Unsupported)\n    }\n}\n\npub type TimerFuture = future::Pending<()>;\npub type IrqFuture = future::Pending<()>;\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/acpi.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse alloc::boxed::Box;\nuse core::{convert::TryFrom as _, mem, ptr::NonNull};\nuse x86_64::structures::port::{PortRead as _, PortWrite as _};\n\n/// Loads ACPI tables from physical memory.\n///\n/// # Panic\n///\n/// Panics if the multiboot header doesn't contain any information about the ACPI tables, or if\n/// the ACPI tables are invalid.\n///\npub fn load_acpi_tables(\n    multiboot_info: &multiboot2::BootInformation,\n) -> acpi::AcpiTables<DummyAcpiHandler> {\n    unsafe {\n        let mut err = None;\n\n        if let Some(rsdp_v2) = multiboot_info.rsdp_v2_tag() {\n            match acpi::AcpiTables::from_rsdt(\n                DummyAcpiHandler,\n                rsdp_v2.revision(),\n                rsdp_v2.xsdt_address(),\n            ) {\n                Ok(acpi) => return acpi,\n                Err(e) => err = Some(e),\n            }\n        }\n\n        if let Some(rsdp_v1) = multiboot_info.rsdp_v1_tag() {\n            match acpi::AcpiTables::from_rsdt(\n                DummyAcpiHandler,\n                rsdp_v1.revision(),\n                rsdp_v1.rsdt_address(),\n            ) {\n                Ok(acpi) => return acpi,\n                Err(e) => {\n                    if err.is_none() {\n                        err = Some(e);\n                    }\n                }\n            }\n        }\n\n        if let Some(err) = err {\n            panic!(\"Couldn't parse ACPI tables: {:?}\", err)\n        } else {\n            panic!(\"Can't find ACPI tables\")\n        }\n    }\n}\n\n/// Loads and parses ACPI tables from physical memory.\n///\n/// # Panic\n///\n/// Panics if the multiboot header doesn't contain any information about the ACPI tables, or if\n/// the ACPI tables are invalid.\n///\npub fn parse_acpi_tables(\n    multiboot_info: &multiboot2::BootInformation,\n) -> acpi::AcpiTables<DummyAcpiHandler> {\n    let acpi_tables = load_acpi_tables(multiboot_info);\n    let mut aml = aml::AmlContext::new(Box::new(DummyAmlHandler), aml::DebugVerbosity::None);\n\n    if let Some(dsdt) = &acpi_tables.dsdt {\n        let stream = unsafe {\n            core::slice::from_raw_parts(\n                dsdt.address as *const u8,\n                usize::try_from(dsdt.length).unwrap(),\n            )\n        };\n\n        // TODO: AML tables parsing currently fails on VirtualBox\n        let _ = aml.parse_table(stream);\n    }\n\n    acpi_tables\n}\n\n/// Implementation of the `AcpiHandler` trait that is responsible for mapping physical memory\n/// into virtual memory.\n///\n/// We use identity mapping over the whole address space, therefore this is a dummy.\n#[derive(Debug, Clone)]\npub struct DummyAcpiHandler;\n\nimpl acpi::AcpiHandler for DummyAcpiHandler {\n    unsafe fn map_physical_region<T>(\n        &self,\n        addr: usize,\n        size: usize,\n    ) -> acpi::PhysicalMapping<DummyAcpiHandler, T> {\n        acpi::PhysicalMapping::new(\n            addr,\n            NonNull::new(addr as *mut _).unwrap(),\n            size,\n            size,\n            self.clone(),\n        )\n    }\n\n    fn unmap_physical_region<T>(_: &acpi::PhysicalMapping<DummyAcpiHandler, T>) {}\n}\n\n/// Implementation of the `Handler` trait of `aml`.\n///\n/// We use identity mapping over the whole address space, therefore this is a dummy.\nstruct DummyAmlHandler;\n\nimpl aml::Handler for DummyAmlHandler {\n    fn read_u8(&self, address: usize) -> u8 {\n        assert_eq!(address % mem::align_of::<u8>(), 0);\n        unsafe { (address as *const u8).read() }\n    }\n\n    fn read_u16(&self, address: usize) -> u16 {\n        assert_eq!(address % mem::align_of::<u16>(), 0);\n        unsafe { (address as *const u16).read() }\n    }\n\n    fn read_u32(&self, address: usize) -> u32 {\n        assert_eq!(address % mem::align_of::<u32>(), 0);\n        unsafe { (address as *const u32).read() }\n    }\n\n    fn read_u64(&self, address: usize) -> u64 {\n        assert_eq!(address % mem::align_of::<u64>(), 0);\n        unsafe { (address as *const u64).read() }\n    }\n\n    fn write_u8(&mut self, address: usize, value: u8) {\n        assert_eq!(address % mem::align_of::<u8>(), 0);\n        unsafe { (address as *mut u8).write(value) }\n    }\n\n    fn write_u16(&mut self, address: usize, value: u16) {\n        assert_eq!(address % mem::align_of::<u16>(), 0);\n        unsafe { (address as *mut u16).write(value) }\n    }\n\n    fn write_u32(&mut self, address: usize, value: u32) {\n        assert_eq!(address % mem::align_of::<u32>(), 0);\n        unsafe { (address as *mut u32).write(value) }\n    }\n\n    fn write_u64(&mut self, address: usize, value: u64) {\n        assert_eq!(address % mem::align_of::<u64>(), 0);\n        unsafe { (address as *mut u64).write(value) }\n    }\n\n    fn read_io_u8(&self, port: u16) -> u8 {\n        unsafe { u8::read_from_port(port) }\n    }\n\n    fn read_io_u16(&self, port: u16) -> u16 {\n        unsafe { u16::read_from_port(port) }\n    }\n\n    fn read_io_u32(&self, port: u16) -> u32 {\n        unsafe { u32::read_from_port(port) }\n    }\n\n    fn write_io_u8(&self, port: u16, value: u8) {\n        unsafe {\n            u8::write_to_port(port, value);\n        }\n    }\n\n    fn write_io_u16(&self, port: u16, value: u16) {\n        unsafe {\n            u16::write_to_port(port, value);\n        }\n    }\n\n    fn write_io_u32(&self, port: u16, value: u32) {\n        unsafe {\n            u32::write_to_port(port, value);\n        }\n    }\n\n    fn read_pci_u8(&self, _: u16, _: u8, _: u8, _: u8, _: u16) -> u8 {\n        todo!()\n    }\n\n    fn read_pci_u16(&self, _: u16, _: u8, _: u8, _: u8, _: u16) -> u16 {\n        todo!()\n    }\n\n    fn read_pci_u32(&self, _: u16, _: u8, _: u8, _: u8, _: u16) -> u32 {\n        todo!()\n    }\n\n    fn write_pci_u8(&self, _: u16, _: u8, _: u8, _: u8, _: u16, _: u8) {\n        todo!()\n    }\n\n    fn write_pci_u16(&self, _: u16, _: u8, _: u8, _: u8, _: u16, _: u16) {\n        todo!()\n    }\n\n    fn write_pci_u32(&self, _: u16, _: u8, _: u8, _: u8, _: u16, _: u32) {\n        todo!()\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/ap_boot.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Bootstrapping associated processors.\n//!\n//! On x86 and x86_64 platforms, processors are divided in two categories: one BSP (bootstrap\n//! processor) and zero or more APs (associated processors). Only the BSP initially starts,\n//! and the APs have to be manually started either from the BSP or an AP that has previously\n//! been started. This what this module is responsible for doing.\n//!\n//! # Usage\n//!\n//! - Create an [`ApBootAlloc`] using the [`filter_build_ap_boot_alloc`] function.\n//! - Determine the [`ApicId`] of the processors we want to wake up.\n//! - Call [`boot_associated_processor`] for each processor one by one.\n//!\n\nuse crate::arch::x86_64::apic::{local::LocalApicsControl, timers::Timers, tsc_sync, ApicId};\nuse crate::arch::x86_64::{executor, interrupts};\n\nuse alloc::{alloc::Layout, boxed::Box, sync::Arc};\nuse core::{arch::asm, convert::TryFrom as _, fmt, ops::Range, ptr, slice, time::Duration};\nuse futures::{channel::oneshot, prelude::*};\n\n/// Allocator required by the [`boot_associated_processor`] function.\npub struct ApBootAlloc {\n    inner: linked_list_allocator::LockedHeap,\n}\n\n/// Accepts as input an iterator to a list of free memory ranges. If the `Option` is `None`,\n/// filters out a range of memory, builds an [`ApBootAlloc`] out of it and puts it in the\n/// `Option`.\n///\n/// # Usage\n///\n/// ```norun\n/// use core::iter;\n/// let mut alloc = None;\n/// let remaining_ranges = filter_build_ap_boot_alloc(iter::once(0 .. 0x1000000), &mut alloc);\n/// let alloc = alloc.expect(\"Couldn't find free memory range\");\n/// ```\n///\n/// # Safety\n///\n/// The memory ranges have to be RAM or behave like RAM (i.e. both readable and writable,\n/// consistent, and so on). The memory ranges must not be touched by anything (other than the\n/// allocator) afterwards.\n///\npub unsafe fn filter_build_ap_boot_alloc<'a>(\n    ranges: impl Iterator<Item = Range<usize>> + 'a,\n    alloc: &'a mut Option<ApBootAlloc>,\n) -> impl Iterator<Item = Range<usize>> + 'a {\n    // Size that we grab from the ranges.\n    // TODO: This value is kind of arbitrary for now. Once\n    // https://github.com/rust-lang/rust/issues/51910 is stabilized, we can instead compute this\n    // value from `code_end - code_start`.\n    const WANTED: usize = 0x4000;\n\n    ranges.filter_map(move |range| {\n        if alloc.is_none() {\n            let range_size = range.end.checked_sub(range.start).unwrap();\n            if range.start.saturating_add(WANTED) <= 0x100000 && range_size >= WANTED {\n                *alloc = Some(ApBootAlloc {\n                    inner: linked_list_allocator::LockedHeap::new(range.start, WANTED),\n                });\n                if range_size > WANTED {\n                    return Some(range.start + WANTED..range.end);\n                }\n                return None;\n            }\n        }\n\n        Some(range)\n    })\n}\n\n/// Error that can happen during initialization.\n#[derive(Debug, Clone)]\npub enum Error {\n    /// Associated processor is unresponsive.\n    Timeout,\n}\n\nimpl fmt::Display for Error {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            Error::Timeout => write!(f, \"associated processor is unresponsive\"),\n        }\n    }\n}\n\n/// Bootstraps the given processor, making it execute `boot_code`.\n///\n/// This function returns once the target processor has been successfully initialized and has\n/// started (or will soon start) to execute `boot_code`.\n///\n/// This function also takes care to enable the local APIC and interrupts on the newly-started\n/// processor.\n///\n/// > **Note**: It is safe to call this function multiple times simultaneously with multiple\n/// >           different targets. For example, processor 0 can boot up processor 2 while\n/// >           processor 1 simultaneously boots up processor 3.\n///\n/// # Safety\n///\n/// `target` must not be the local processor.\n///\n/// This function must only be called once per `target`, and no other code has sent or attempted\n/// to send an INIT or SIPI to the target processor.\n///\n// TODO: it kind of sucks that an important detail such as \"we also initialize the local APIC and\n// interrupts\" is just part of the documentation, but we need them for the implementation to work\n// TODO: replace `Infallible` with `!` when stable\npub unsafe fn boot_associated_processor(\n    alloc: &mut ApBootAlloc,\n    executor: &executor::Executor,\n    local_apics: &'static LocalApicsControl,\n    timers: &Arc<Timers>,\n    target: ApicId,\n    boot_code: impl FnOnce() -> core::convert::Infallible + Send + 'static,\n) -> Result<(), Error> {\n    // In order to boot an associated processor, we must send to it an inter-processor interrupt\n    // (IPI) containing the offset of a 4kiB memory page containing the code that it must start\n    // executing. The CS register of the target processor will take the value that we send, the\n    // IP register will be set to 0, and the processor will start running in 16 bits mode.\n    //\n    // Since this is 16 bits mode, the processor cannot execute any code (or access any data)\n    // above one megabyte of physical memory. Most, if not all, of the kernel is loaded above\n    // that limit, and therefore we cannot simply ask the processor to start executing a certain\n    // function as we would like to.\n    //\n    // Instead, what we must do is allocate a buffer below that one megabyte limit, write some\n    // x86 machine code in that buffer, and then we can ask the processor to run it. This is\n    // implemented by copying a template code into that buffer and tweaking the constants.\n\n    // Get information about the template.\n    let code_template = get_template();\n    assert!(code_template.marker1_offset < code_template.code.len());\n    assert!(code_template.marker2_offset < code_template.code.len());\n    assert!(code_template.marker3_offset < code_template.code.len());\n\n    // We start by allocating the buffer where to write the bootstrap code.\n    let mut bootstrap_code_buf = {\n        let size = code_template.code.len();\n        // Basic sanity check to make sure that nothing's fundamentally wrong.\n        assert!(size <= 0x1000);\n        let layout = Layout::from_size_align(size, 0x1000).unwrap();\n        Allocation::new(&mut alloc.inner, layout)\n    };\n\n    // Start by sending an INIT IPI to the target so that it reboots.\n    local_apics.send_interprocessor_init(target);\n\n    // Later we will wait for 10ms to have elapsed since the INIT.\n    let wait_after_init = timers.register_timer_after(Duration::from_millis(10));\n\n    // Write the template code to the buffer.\n    ptr::copy_nonoverlapping(\n        code_template.code.as_ptr(),\n        bootstrap_code_buf.as_mut_ptr(),\n        bootstrap_code_buf.size(),\n    );\n\n    // Later, we will want to wait until the AP has finished initializing. To do so, we create\n    // a channel and modify `boot_code` to signal that channel before doing anything more.\n    let (boot_code, mut init_finished_future, mut tsc_sync_src) = {\n        let (tx, rx) = oneshot::channel();\n        // TODO: not great that the TSC sync is hidden in there\n        let (tsc_sync_src, mut tsc_sync_dst) = tsc_sync::tsc_sync();\n        let boot_code = move || {\n            local_apics.init_local();\n            interrupts::load_idt();\n            let _ = tx.send(());\n            tsc_sync_dst.sync();\n            boot_code()\n        };\n        (boot_code, rx, tsc_sync_src)\n    };\n\n    // We want the processor we bootstrap to call the `ap_after_boot` function defined below.\n    // `ap_after_boot` will cast its first parameter into a `Box<Box<dyn FnOnce()>>` and call it.\n    // We therefore cast `boot_code` into the proper format, then leak it with the intent to pass\n    // this value to `ap_after_boot`, which will then \"unleak\" it and call it.\n    let ap_after_boot_param = {\n        let boxed = Box::new(Box::new(boot_code) as Box<_>);\n        let param_value: ApAfterBootParam = Box::into_raw(boxed);\n        u64::try_from(param_value as usize).unwrap()\n    };\n\n    // Allocate a stack for the processor. This is the one and unique stack that will be used for\n    // everything by this processor.\n    let stack_size = 10 * 1024 * 1024usize;\n    let stack_top = {\n        let layout = Layout::from_size_align(stack_size, 0x1000).unwrap();\n        let ptr = alloc::alloc::alloc(layout);\n        assert!(!ptr.is_null());\n        u64::try_from(ptr as usize + stack_size).unwrap()\n    };\n\n    // There exists several placeholders within the template code that we must adjust before it\n    // can be executed.\n    //\n    // The code at marker 1 starts with the following instruction:\n    //\n    // ```\n    // 66 ea ad de ad de 08    ljmpl  $0x8, $0xdeaddead\n    // ```\n    //\n    // The code at marker 3 starts with the following instruction:\n    //\n    // ```\n    // 66 ba dd ba 00 ff    mov $0xff00badd, %edx\n    // ```\n    //\n    // The code at marker 2 starts with the following instructions:\n    //\n    // ```\n    // 48 bc ef cd ab 90 78 56 34 12    movabs $0x1234567890abcdef, %rsp\n    // 48 b8 ff ff 22 22 cc cc 99 99    movabs $0x9999cccc2222ffff, %rax\n    // ```\n    //\n    // The values `0xdeaddead`, `0xff00badd`, `0x1234567890abcdef`, and `0x9999cccc2222ffff` are\n    // placeholders that we overwrite in the block below.\n    {\n        let ap_boot_marker1_loc: *mut u8 = {\n            let offset = code_template.marker1_offset;\n            bootstrap_code_buf.as_mut_ptr().add(offset)\n        };\n        let ap_boot_marker2_loc: *mut u8 = {\n            let offset = code_template.marker2_offset;\n            bootstrap_code_buf.as_mut_ptr().add(offset)\n        };\n        let ap_boot_marker3_loc: *mut u8 = {\n            let offset = code_template.marker3_offset;\n            bootstrap_code_buf.as_mut_ptr().add(offset)\n        };\n\n        // Perform some sanity check. Since we're doing dark magic, we really want to be sure\n        // that we're overwriting the correct code, or we will run into issues that are very hard\n        // to debug.\n        assert_eq!(\n            slice::from_raw_parts(ap_boot_marker1_loc as *const u8, 7),\n            &[0x66, 0xea, 0xad, 0xde, 0xad, 0xde, 0x08]\n        );\n        assert_eq!(\n            slice::from_raw_parts(ap_boot_marker2_loc as *const u8, 20),\n            &[\n                0x48, 0xbc, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56, 0x34, 0x12, 0x48, 0xb8, 0xff, 0xff,\n                0x22, 0x22, 0xcc, 0xcc, 0x99, 0x99\n            ]\n        );\n        assert_eq!(\n            slice::from_raw_parts(ap_boot_marker3_loc as *const u8, 6),\n            &[0x66, 0xba, 0xdd, 0xba, 0x00, 0xff]\n        );\n\n        // Write first constant at marker 2.\n        let stack_ptr_ptr = (ap_boot_marker2_loc.add(2)) as *mut u64;\n        assert_eq!(stack_ptr_ptr.read_unaligned(), 0x1234567890abcdef);\n        stack_ptr_ptr.write_unaligned(stack_top);\n\n        // Write second constant at marker 2.\n        let param_ptr = (ap_boot_marker2_loc.add(12)) as *mut u64;\n        assert_eq!(param_ptr.read_unaligned(), 0x9999cccc2222ffff);\n        param_ptr.write_unaligned(ap_after_boot_param);\n\n        // Write the location of marker 2 into the constant at marker 1.\n        let ljmp_target_ptr = (ap_boot_marker1_loc.add(2)) as *mut u32;\n        assert_eq!(ljmp_target_ptr.read_unaligned(), 0xdeaddead);\n        ljmp_target_ptr.write_unaligned(u32::try_from(ap_boot_marker2_loc as usize).unwrap());\n\n        // Write the value of our `cr3` register to the constant at marker 3.\n        let pml_addr_ptr = (ap_boot_marker3_loc.add(2)) as *mut u32;\n        assert_eq!(pml_addr_ptr.read_unaligned(), 0xff00badd);\n        pml_addr_ptr.write_unaligned({\n            let pml_addr = x86_64::registers::control::Cr3::read()\n                .0\n                .start_address()\n                .as_u64();\n            u32::try_from(pml_addr).unwrap()\n        });\n    }\n\n    // Wait for 10ms to have elapsed since we sent the INIT IPI.\n    executor.block_on(wait_after_init);\n\n    // Because the APIC doesn't automatically try submitting the SIPI in case the target CPU was\n    // busy, we might have to try multiple times.\n    let mut attempts = 0;\n    let result = loop {\n        // Failure to initialize.\n        if attempts >= 2 {\n            // Before returning an error, we free the closure that was destined to be run by\n            // the AP.\n            let param = ap_after_boot_param as ApAfterBootParam;\n            let _ = Box::from_raw(param);\n            break Err(Error::Timeout);\n        }\n        attempts += 1;\n\n        // Send the SINIT IPI, pointing to the bootstrap code that we have carefully crafted.\n        local_apics.send_interprocessor_sipi(target, bootstrap_code_buf.as_mut_ptr() as *const _);\n\n        // Wait for the processor initialization to finish, but with a timeout in order to not\n        // wait forever if nothing happens.\n        let ap_ready_timeout = timers.register_timer_after(Duration::from_secs(1));\n        futures::pin_mut!(ap_ready_timeout);\n        match executor.block_on(future::select(ap_ready_timeout, &mut init_finished_future)) {\n            future::Either::Left(_) => continue,\n            future::Either::Right(_) => {\n                tsc_sync_src.sync();\n                break Ok(());\n            }\n        }\n    };\n\n    // Make sure the buffer is dropped at the end.\n    drop(bootstrap_code_buf);\n\n    result\n}\n\n/// Information about the template code.\nstruct Template {\n    code: &'static [u8],\n    marker1_offset: usize,\n    marker2_offset: usize,\n    marker3_offset: usize,\n}\n\n/// Returns information about the template code.\nfn get_template() -> Template {\n    let code_start: usize;\n    let code_end: usize;\n    let marker1: usize;\n    let marker2: usize;\n    let marker3: usize;\n\n    // The code here is the template in question. Just like any code, is included in the kernel\n    // and will be loaded in memory. However, it is not actually meant be executed. Instead it\n    // is meant to be used as a template.\n    // Because the associated processor (AP) boot code must be in the first megabyte of memory,\n    // we first copy this code somewhere in this first megabyte and adjust it.\n    //\n    // The `code_start` and `code_end` addresses encompass the template. There exist three other\n    // symbols `marker1`, `marker2` and `marker3` that point to instructions that must be adjusted\n    // before execution.\n    //\n    // Within this module, we must be careful to not use any absolute address referring to\n    // anything between `code_start` and `code_end`, and to not use any relative address referring\n    // to anything outside of this range, as the addresses will then be wrong when the code gets\n    // copied.\n    unsafe {\n        asm!(r#\"\n            // This jmp is **not** part of the template. It is reached only when `get_template`\n            // is called.\n            jmp 5f\n\n        .code16\n        .align 0x1000\n        4:\n            // When we enter here, the CS register is set to the value that we passed through the\n            // SIPI, and the IP register is set to `0`.\n\n            movw %cs, %ax\n            movw %ax, %ds\n            movw %ax, %es\n            movw %ax, %fs\n            movw %ax, %gs\n            movw %ax, %ss\n\n            movl $0, %eax\n            or $(1 << 10), %eax             // Set SIMD floating point exceptions bit.\n            or $(1 << 9), %eax              // Set OSFXSR bit, which enables SIMD.\n            or $(1 << 5), %eax              // Set physical address extension (PAE) bit.\n            movl %eax, %cr4\n\n        3:\n            // The `0xff00badd` constant below is replaced with the address of a PML4 table when\n            // the template gets adjusted.\n            mov $0xff00badd, %edx\n            mov %edx, %cr3\n\n            // Enable the EFER.LMA bit, which enables compatibility mode and will make us switch\n            // to long mode when we update the CS register.\n            mov $0xc0000080, %ecx\n            rdmsr\n            or $(1 << 8), %eax\n            wrmsr\n\n            // Set the appropriate CR0 flags: Paging, Extension Type (math co-processor), and\n            // Protected Mode.\n            movl $((1 << 31) | (1 << 4) | (1 << 0)), %eax\n            movl %eax, %cr0\n\n            // Set up the GDT. Since the absolute address of the tempalte start is effectively 0\n            // according to the CPU in this 16 bits context, we pass an \"absolute\" address to the\n            // GDT by substracting `code_start` from its 32 bits address.\n            lgdtl (6f - 4b)\n\n        1:\n            // A long jump is necessary in order to update the CS registry and properly switch to\n            // long mode.\n            // The `0xdeaddead` constant below is replaced with the location of the marker `2`\n            // below the template gets adjusted.\n            ljmpl $8, $0xdeaddead\n\n        .code64\n        2:\n            // The constants below are replaced with an actual stack location when the template\n            // gets adjusted.\n            // Set up the stack.\n            movq $0x1234567890abcdef, %rsp\n            // This is an opaque value for the purpose of this assembly code. It is the parameter\n            // that we pass to `ap_after_boot`\n            movq $0x9999cccc2222ffff, %rax\n\n            movw $0, %bx\n            movw %bx, %ds\n            movw %bx, %es\n            movw %bx, %fs\n            movw %bx, %gs\n            movw %bx, %ss\n\n            // In the x86-64 calling convention, the RDI register is used to store the value of\n            // the first parameter to pass to a function.\n            movq %rax, %rdi\n\n            // We do an indirect call in order to force the assembler to use the absolute address\n            // rather than a relative call.\n            lea {ap_after_boot}, %rdx\n            call *%rdx\n\n            cli\n            hlt\n\n            // Small structure whose location is passed to the CPU in order to load the GDT.\n            // Because we call `lgdt` from 16bits code, we have to define the GDT pointer\n            // locally.\n        .align 8\n        6:\n            .short 15\n            .long {gdt}\n\n        5:\n            // This code is not part of the template and is executed by `get_template`.\n            lea (4b), {code_start}\n            lea (5b), {code_end}\n            lea (1b), {marker1}\n            lea (2b), {marker2}\n            lea (3b), {marker3}\n        \"#,\n            ap_after_boot = sym ap_after_boot,\n            gdt = sym super::gdt::GDT,\n            code_start = out(reg) code_start,\n            code_end = out(reg) code_end,\n            marker1 = out(reg) marker1,\n            marker2 = out(reg) marker2,\n            marker3 = out(reg) marker3,\n            options(pure, nostack, nomem, preserves_flags, att_syntax) // TODO: translate to Intel syntax\n        );\n\n        Template {\n            code: slice::from_raw_parts(code_start as *const u8, code_end - code_start),\n            marker1_offset: marker1 - code_start,\n            marker2_offset: marker2 - code_start,\n            marker3_offset: marker3 - code_start,\n        }\n    }\n}\n\n/// Holds an allocation with the given layout.\n///\n/// There is surprisingly no type in the Rust standard library that keeps track of an allocation.\n// TODO: use a `Box` or something once it's possible to pass a custom allocator\nstruct Allocation<'a, T: alloc::alloc::Allocator> {\n    alloc: &'a mut T,\n    inner: ptr::NonNull<u8>,\n    layout: Layout,\n}\n\nimpl<'a, T: alloc::alloc::Allocator> Allocation<'a, T> {\n    fn new(alloc: &'a mut T, layout: Layout) -> Self {\n        let inner = alloc.allocate(layout).unwrap();\n        Allocation {\n            alloc,\n            inner: inner.cast(),\n            layout,\n        }\n    }\n\n    fn as_mut_ptr(&mut self) -> *mut u8 {\n        self.inner.as_ptr()\n    }\n\n    fn size(&self) -> usize {\n        self.layout.size()\n    }\n}\n\nimpl<'a, T: alloc::alloc::Allocator> Drop for Allocation<'a, T> {\n    fn drop(&mut self) {\n        unsafe { self.alloc.deallocate(self.inner, self.layout) }\n    }\n}\n\n/// Actual type of the parameter passed to `ap_after_boot`.\ntype ApAfterBootParam = *mut Box<dyn FnOnce() -> core::convert::Infallible + Send + 'static>;\n\n/// Called by the template code after setup.\n///\n/// When this function is called, the stack and paging have already been properly set up. The\n/// first parameter is gathered from the `rdi` register according to the x86_64 calling\n/// convention.\nextern \"C\" fn ap_after_boot(to_exec: usize) -> ! {\n    unsafe {\n        let to_exec = to_exec as ApAfterBootParam;\n        let to_exec = Box::from_raw(to_exec);\n        let _ret = (*to_exec)();\n        match _ret {} // TODO: remove this `ret` thingy once `!` is stable\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/apic/io_apic.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! I/O APIC management.\n//!\n//! When a piece of hardware (for example a PCI device) wants to notify the CPU of something,\n//! it emits an **IRQ** (Interrupt ReQuest). IRQs have a number associated for identification.\n//!\n//! For example: if a machine has a network device and a sound device, the network device can be\n//! configured to emit an IRQ 3 when a network packet arrive, while a sound device can be\n//! configured to emit an IRQ 5 when the sound buffer has space for a new frame. When an IRQ 3 is\n//! received, we know that it is because the network device has received a network packet.\n//!\n//! When an IRQ is emitted, it is received by an **I/O APIC**, which is what this module is about.\n//! If the I/O APIC has been configured as such, it will then in turn emit an interrupt with the\n//! chosen number on the chosen CPU.\n//!\n//! We are totally free to associate any interrupt number and CPU we want to an IRQ. It is also\n//! possible for multiple IRQs to be configured to produce an identical interrupt.\n//! Keep in mind that the CPU has no way to know what is the source of an interrupt. In\n//! particular, a CPU can't know if an interrupt comes from an IRQ or which IRQ.\n//!\n//! A machine is often composed of multiple I/O APICs, each dedicated to a different range of\n//! IRQs. See also the [../io_apics] module.\n\n// # Implementation notes.\n//\n// Reference document for the I/O APIC:\n// https://pdos.csail.mit.edu/6.828/2016/readings/ia32/io_apic.pdf\n//\n// The I/O APIC exposes two memory-mapped registers: one selector, and one window.\n// One must write a register number in the selector, then the value of the register is accessible\n// through the window.\n\nuse crate::arch::x86_64::apic::ApicId;\nuse core::convert::TryFrom as _;\n\n/// Control over a single I/O APIC.\npub struct IoApicControl {\n    /// Pointer to the memory-mapped selection register.\n    /// See the implementation notes above.\n    io_reg_sel_register: *mut u32,\n\n    /// Pointer to the memory-mapped window register.\n    /// See the implementation notes above.\n    io_win_register: *mut u32,\n\n    /// First IRQ that this I/O APIC handles. For example if some hardware triggers IRQ 12, and\n    /// the value of this field is 9, then how the IRQ is handled will be in field 3.\n    global_system_interrupt_base: u8,\n\n    /// Maximum IRQ offset relative to `global_system_interrupt_base` that this I/O APIC\n    /// handles.\n    maximum_redirection_entry: u8,\n}\n\n/// Description of an I/O APIC on the hardware.\n///\n/// Correct description is normally obtained from the ACPI tables provided by the firmware.\npub struct IoApicDescription {\n    /// Physical memory address where the I/O APIC is mapped.\n    ///\n    /// > **Note**: This code expects that memory is identity-mapped. In other words, it will\n    /// >           convert this address into a pointer and perform memory reads and writes.\n    pub address: usize,\n\n    /// First interrupt.\n    pub global_system_interrupt_base: u8,\n}\n\n/// Access to the configuration of an IRQ in this controller.\npub struct Irq<'a> {\n    control: &'a mut IoApicControl,\n    irq_offset: u8,\n}\n\n/// Initializes a single I/O APIC.\n///\n/// # Safety\n///\n/// The parameters must be valid and refer to a correct I/O APIC. This information is normally\n/// fetched from the ACPI tables.\n///\n/// Must only be called once per I/O APIC.\n///\npub unsafe fn init_io_apic(config: IoApicDescription) -> IoApicControl {\n    let io_reg_sel_register = config.address as *mut u32;\n    let io_win_register = config.address.checked_add(0x10).unwrap() as *mut u32;\n\n    let maximum_redirection_entry = {\n        io_reg_sel_register.write_volatile(0x1);\n        let io_apic_ver = io_win_register.read_volatile();\n        u8::try_from((io_apic_ver >> 16) & 0xff).unwrap()\n    };\n\n    assert!(config\n        .global_system_interrupt_base\n        .checked_add(maximum_redirection_entry)\n        .is_some());\n\n    IoApicControl {\n        io_reg_sel_register,\n        io_win_register,\n        global_system_interrupt_base: config.global_system_interrupt_base,\n        maximum_redirection_entry,\n    }\n}\n\nimpl IoApicControl {\n    /// Returns all the IRQs supported by this I/O APIC.\n    pub fn irqs<'a>(&'a self) -> impl Iterator<Item = u8> + 'a {\n        let max = self\n            .global_system_interrupt_base\n            .checked_add(self.maximum_redirection_entry)\n            .unwrap();\n        self.global_system_interrupt_base..=max\n    }\n\n    /// Gives access to an object designating the configuration of an IRQ in this I/O APIC.\n    ///\n    /// Returns `None` if this I/O APIC doesn't handle the given IRQ.\n    pub fn irq(&mut self, irq: u8) -> Option<Irq> {\n        let irq_offset = irq.checked_sub(self.global_system_interrupt_base)?;\n\n        if irq_offset > self.maximum_redirection_entry {\n            return None;\n        }\n\n        Some(Irq {\n            control: self,\n            irq_offset,\n        })\n    }\n\n    /// Modifies the IRQ definition.\n    ///\n    /// Keep in mind that `irq_offset` is relative to `self.global_system_interrupt_base`.\n    // TODO: do we need to be able to set Edge/Level and that kind of stuff?\n    fn set_irq(&mut self, irq_offset: u8, destination: ApicId, destination_interrupt: u8) {\n        assert!(irq_offset <= self.maximum_redirection_entry);\n        assert!(destination_interrupt >= 32);\n\n        assert!(destination.get() < (1 << 4)); // Only 4bits are valid.\n        let value = (u64::from(destination.get()) << 56) | u64::from(destination_interrupt);\n\n        let register_base = 0x10u8\n            .checked_add(irq_offset.checked_mul(2).unwrap())\n            .unwrap();\n\n        // Disable interrupts while we're writing the registers, in order to avoid any IRQ\n        // happening in-between the two writes.\n        let interrupts_enabled = x86_64::instructions::interrupts::are_enabled();\n        x86_64::instructions::interrupts::disable();\n\n        unsafe {\n            self.write_register(register_base, u32::try_from(value & 0xffffffff).unwrap());\n            self.write_register(register_base + 1, u32::try_from(value >> 32).unwrap());\n        }\n\n        if interrupts_enabled {\n            x86_64::instructions::interrupts::enable();\n        }\n    }\n\n    unsafe fn write_register(&mut self, reg_num: u8, value: u32) {\n        self.io_reg_sel_register.write_volatile(u32::from(reg_num));\n        self.io_win_register.write_volatile(value)\n    }\n}\n\nimpl<'a> Irq<'a> {\n    /// Sets what happens when this IRQ is triggered.\n    ///\n    /// # Panic\n    ///\n    /// Panics if `destination_interrupt` is inferior to 32.\n    ///\n    pub fn set_destination(&mut self, destination: ApicId, destination_interrupt: u8) {\n        self.control\n            .set_irq(self.irq_offset, destination, destination_interrupt)\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/apic/io_apics.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! I/O APICs management.\n//!\n//! Collection of all the I/O APICs together.\n//!\n//! See also the documentation of the [`../io_apic`] module for more information.\n\nuse crate::arch::x86_64::apic::{io_apic, ApicId};\n\nuse core::convert::TryFrom as _;\nuse smallvec::SmallVec;\n\n/// Control over all the I/O APICs.\npub struct IoApicsControl {\n    io_apics: SmallVec<[io_apic::IoApicControl; 4]>,\n    legacy_redirects: SmallVec<[IsaRedirectConfig; 16]>,\n}\n\n/// Configuration of a ISA interrupt redirection.\n///\n/// *ISA* IRQs are a legacy mechanism but that is still used by some hardware.\n/// In order to use this hardware, we must know which \"new IRQ\" they now use.\npub struct IsaRedirectConfig {\n    /// The ISA interrupt.\n    pub isa_interrupt: u8,\n    /// What it's redirected to.\n    pub new_interrupt: u8,\n}\n\n/// Access to the configuration of an IRQ.\npub struct Irq<'a> {\n    inner: io_apic::Irq<'a>,\n}\n\n/// Initializes all the I/O APICs.\n///\n/// # Safety\n///\n/// The parameters must be valid and refer to a correct list of I/O APICs. This information is\n/// normally fetched from the ACPI tables.\n///\n/// Must only be called once.\n///\n// TODO: document legacy_redirects\npub unsafe fn init_io_apics(\n    list: impl IntoIterator<Item = io_apic::IoApicDescription>,\n    legacy_redirects: impl IntoIterator<Item = IsaRedirectConfig>,\n) -> IoApicsControl {\n    IoApicsControl {\n        io_apics: list\n            .into_iter()\n            .map(|cfg| io_apic::init_io_apic(cfg))\n            .collect(),\n        // TODO: is u8/u32 correct? we convert from the u32 to u8 later, that's bad\n        legacy_redirects: legacy_redirects.into_iter().collect(),\n    }\n}\n\n/// Initializes the I/O APICs from information gathered through the ACPI tables.\n///\n/// # Safety\n///\n/// This function is unsafe for the same reasons as [`init_io_apics`]. The parameter is not\n/// guaranteed to be authentic.\n///\n// TODO: meh for this method; depends on external library\npub unsafe fn init_from_acpi(info: &acpi::platform::interrupt::Apic) -> IoApicsControl {\n    init_io_apics(\n        info.io_apics\n            .iter()\n            .map(|io_apic| io_apic::IoApicDescription {\n                address: usize::try_from(io_apic.address).unwrap(),\n                global_system_interrupt_base: u8::try_from(io_apic.global_system_interrupt_base)\n                    .unwrap(),\n            }),\n        info.interrupt_source_overrides\n            .iter()\n            .map(|ov| IsaRedirectConfig {\n                isa_interrupt: ov.isa_source,\n                new_interrupt: u8::try_from(ov.global_system_interrupt).unwrap(),\n            }),\n    )\n}\n\nimpl IoApicsControl {\n    /// Gives access to an object designating the configuration for an ISA IRQ.\n    ///\n    /// ISA IRQs are considered legacy, but are still used by some hardware.\n    pub fn isa_irq(&mut self, isa_irq: u8) -> Option<Irq> {\n        let target = self\n            .legacy_redirects\n            .iter()\n            .find(|red| red.isa_interrupt == isa_irq)\n            .map(|red| red.new_interrupt);\n\n        if let Some(dest) = target {\n            self.irq(dest)\n        } else {\n            self.irq(isa_irq)\n        }\n    }\n\n    /// Returns all the IRQs supported by the I/O APICs.\n    pub fn irqs<'a>(&'a self) -> impl Iterator<Item = u8> + 'a {\n        self.io_apics\n            .iter()\n            .map(io_apic::IoApicControl::irqs)\n            .flatten()\n    }\n\n    /// Gives access to an object designating the configuration of an IRQ.\n    ///\n    /// Returns `None` if none of the I/O APICs can handle the given IRQ.\n    pub fn irq(&mut self, irq: u8) -> Option<Irq> {\n        for io_apic in self.io_apics.iter_mut() {\n            if let Some(inner) = io_apic.irq(irq) {\n                return Some(Irq { inner });\n            }\n        }\n\n        None\n    }\n}\n\nimpl<'a> Irq<'a> {\n    /// Sets what happens when this IRQ is triggered.\n    ///\n    /// # Panic\n    ///\n    /// Panics if `destination_interrupt` is inferior to 32.\n    ///\n    // TODO: add some kind of assignment system, so that we don't accidentally erase a previous assignment\n    pub fn set_destination(&mut self, destination: ApicId, destination_interrupt: u8) {\n        self.inner\n            .set_destination(destination, destination_interrupt);\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/apic/local.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse super::super::interrupts;\n\nuse alloc::sync::Arc;\nuse core::{\n    convert::TryFrom as _,\n    num::{NonZeroU32, NonZeroU64},\n};\nuse x86_64::registers::model_specific::Msr;\n\n// TODO: \"For correct APIC operation, this address space must be mapped to an area of memory that has been designated as strong uncacheable (UC)\"\n//       For now everything is Strong Uncachable anyway, but care must be taken once we properly\n//       handle caching.\n\n/// Represents the local APICs of all CPUs.\npub struct LocalApicsControl {\n    /// True if the CPUs support TSC-Deadline mode.\n    tsc_deadline_supported: bool,\n    /// Interrupt vector triggered when an APIC error happens.\n    error_interrupt_vector: interrupts::ReservedInterruptVector,\n}\n\n/// Opaque type representing the APIC ID of a processor.\n///\n/// Since we never modify the APIC ID of processors, an instance of this struct is a guarantee\n/// that a processor with the given ID exists.\n#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]\npub struct ApicId(u8);\n\n/// Makes sure that the current CPU supports an APIC.\n///\n/// After this, you have to call [`LocalApicsControl::init_local`].\n///\n/// # Panic\n///\n/// Panics if the CPU doesn't support the APIC.\n///\n/// # Safety\n///\n/// Must only be initialized once, and assumes that no other piece of code reads or writes\n/// to the MSR registers related to the local APIC or x2APIC, or the registers mapped to\n/// physical memory.\n///\npub unsafe fn init() -> LocalApicsControl {\n    // We don't support platforms without an APIC or without the TSC.\n    assert!(is_apic_supported());\n    assert!(is_tsc_supported());\n\n    // We reserve an interrupt vector for errors triggered by the APIC.\n    // Each APIC, when it gets initialized, will set this interrupt vector in its LVT.\n    let error_interrupt_vector = interrupts::reserve_any_vector(240).unwrap();\n    // We don't have any intent of actually processing the interrupts, instead we just set up a\n    // one-time panicking waker.\n    error_interrupt_vector.register_waker(&{\n        struct ErrWaker;\n        impl futures::task::ArcWake for ErrWaker {\n            fn wake_by_ref(_: &Arc<Self>) {\n                unsafe {\n                    // The errors reported are found in the Error Status Register (ESR).\n                    let esr_addr = usize::try_from(APIC_BASE_ADDR + 0xf0).unwrap() as *mut u32;\n                    // Before reading from the ESR, we must first write to it.\n                    esr_addr.write_volatile(0b11111111);\n                    let status = esr_addr.read_volatile();\n                    panic!(\n                        \"Local APIC error; Error Status Register value: 0x{:x}\",\n                        status\n                    );\n                }\n            }\n        }\n        futures::task::waker(Arc::new(ErrWaker))\n    });\n\n    LocalApicsControl {\n        tsc_deadline_supported: is_tsc_deadline_supported(),\n        error_interrupt_vector,\n    }\n}\n\n// TODO: bad API ; should be a method on LocalApisControl, and a &'static ref passed when\n// initializing the IDT\n// TODO: document that no mutex is being locked; important because it's called from within an\n// interrupt handler\npub unsafe fn end_of_interrupt() {\n    let addr = usize::try_from(APIC_BASE_ADDR + 0xB0).unwrap() as *mut u32;\n    addr.write_volatile(0x0);\n}\n\npub enum Timer {\n    /// Default state.\n    Disabled,\n    Timer {\n        /// Number of ticks before the timer triggers.\n        value: NonZeroU32,\n        /// `value` will be multiplied by `value_multiplier`.\n        /// Must be a power of two.\n        value_multiplier: u8,\n        /// If `true`, the timer will continue firing periodically.\n        /// If `false`, it will switch back to `Disabled` after the first trigger.\n        periodic: bool,\n        /// Interrupt vector to trigger when the timer fires.\n        vector: u8,\n    },\n    TscDeadline {\n        /// Timer fires when the `rdtsc` value goes over this threshold.\n        threshold: NonZeroU64,\n        /// Interrupt vector to trigger when the timer fires.\n        vector: u8,\n    },\n}\n\nimpl ApicId {\n    /// Builds an [`ApicId`] from a raw identifier without checking the value.\n    ///\n    /// # Safety\n    ///\n    /// There must be a processor with the given APIC ID.\n    ///\n    pub const unsafe fn from_unchecked(val: u8) -> Self {\n        ApicId(val)\n    }\n\n    /// Returns the integer value of this ID.\n    pub const fn get(&self) -> u8 {\n        self.0\n    }\n}\n\nimpl LocalApicsControl {\n    /// Initializes the APIC of the local CPU.\n    ///\n    /// # Safety\n    ///\n    /// Must only be called once per CPU.\n    ///\n    // TODO: add debug_assert!s in all the other methods that check if the local APIC is initialized\n    pub unsafe fn init_local(&self) {\n        assert!(is_apic_supported());\n        assert_eq!(self.tsc_deadline_supported, is_tsc_deadline_supported());\n\n        // Set up the APIC.\n        {\n            const APIC_BASE_MSR: Msr = Msr::new(0x1b);\n            let base_addr = APIC_BASE_MSR.read() & !0xfff;\n            // We never re-map the APIC. For safety, we ensure that nothing weird has happened here.\n            assert_eq!(usize::try_from(base_addr), Ok(APIC_BASE_ADDR));\n            APIC_BASE_MSR.write(base_addr | (1 << 11)); // Enable the APIC.\n            base_addr\n        };\n\n        // Enable spurious interrupts.\n        {\n            let svr_addr = usize::try_from(APIC_BASE_ADDR + 0xf0).unwrap() as *mut u32;\n            let val = svr_addr.read_volatile();\n            svr_addr.write_volatile(val | 0x100); // Enable spurious interrupts.\n        }\n\n        // Set the error handling interrupt vector.\n        {\n            let lvt_addr = usize::try_from(APIC_BASE_ADDR + 0x370).unwrap() as *mut u32;\n            lvt_addr.write_volatile(u32::from(self.error_interrupt_vector.interrupt_num()));\n        }\n    }\n\n    /// Returns the [`ApicId`] of the calling processor.\n    pub fn current_apic_id(&self) -> ApicId {\n        current_apic_id()\n    }\n\n    /// Returns true if the hardware supports TSC deadline mode.\n    pub fn is_tsc_deadline_supported(&self) -> bool {\n        self.tsc_deadline_supported\n    }\n\n    /// Configures the timer of the local APIC of the current CPU.\n    ///\n    /// # Panic\n    ///\n    /// Panics if `TscDeadline` is passed and `is_tsc_deadline_supported` is false.\n    /// Panics if the `value_multiplier` is not either one or a power of two.\n    pub fn set_local_timer(&self, timer: Timer) {\n        unsafe {\n            match timer {\n                Timer::Disabled => {\n                    let addr = usize::try_from(APIC_BASE_ADDR + 0x320).unwrap() as *mut u32;\n                    addr.write_volatile(0x00010000);\n                }\n                Timer::Timer {\n                    value,\n                    value_multiplier,\n                    periodic,\n                    vector,\n                } => {\n                    let divide_config_addr =\n                        usize::try_from(APIC_BASE_ADDR + 0x3e0).unwrap() as *mut u32;\n                    divide_config_addr.write_volatile(match value_multiplier {\n                        1 => 0b1011,\n                        2 => 0b0000,\n                        4 => 0b0001,\n                        8 => 0b0010,\n                        16 => 0b0011,\n                        32 => 0b1000,\n                        64 => 0b1001,\n                        128 => 0b1010,\n                        _ => panic!(),\n                    });\n\n                    let lvt_addr = usize::try_from(APIC_BASE_ADDR + 0x320).unwrap() as *mut u32;\n                    let flags = if periodic { 1 << 17 } else { 0 };\n                    assert!(vector >= 32);\n                    lvt_addr.write_volatile(flags | u32::from(vector));\n\n                    let value_addr = usize::try_from(APIC_BASE_ADDR + 0x380).unwrap() as *mut u32;\n                    value_addr.write_volatile(value.get());\n                }\n                Timer::TscDeadline { threshold, vector } => {\n                    assert!(self.tsc_deadline_supported);\n                    debug_assert!(is_tsc_deadline_supported());\n\n                    assert!(vector >= 32);\n                    let lvt_addr = usize::try_from(APIC_BASE_ADDR + 0x320).unwrap() as *mut u32;\n                    let flag = 0b10 << 17;\n                    lvt_addr.write_volatile(flag | u32::from(vector));\n\n                    const TIMER_MSR: Msr = Msr::new(0x6e0);\n                    TIMER_MSR.write(threshold.get());\n                }\n            }\n        }\n    }\n\n    /// Causes the processor with the target APIC ID to wake up.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the interrupt vector is inferior to 32.\n    ///\n    pub fn send_interprocessor_interrupt(&self, target_apic_id: ApicId, vector: u8) {\n        assert!(vector >= 32);\n        send_ipi_inner(target_apic_id, 0, vector)\n    }\n\n    // TODO: documentation\n    ///\n    ///\n    /// # Panic\n    ///\n    /// Panics if `target_apic_id` is the local APIC.\n    ///\n    pub fn send_interprocessor_init(&self, target_apic_id: ApicId) {\n        assert_ne!(current_apic_id(), target_apic_id);\n        send_ipi_inner(target_apic_id, 0b101, 0);\n    }\n\n    // TODO: documentation\n    ///\n    ///\n    /// # Panic\n    ///\n    /// Panics if `target_apic_id` is the local APIC.\n    ///\n    pub fn send_interprocessor_sipi(&self, target_apic_id: ApicId, boot_fn: *const u8) {\n        assert_ne!(current_apic_id(), target_apic_id);\n\n        let boot_fn = boot_fn as usize;\n        assert_eq!((boot_fn >> 12) << 12, boot_fn);\n        assert!((boot_fn >> 12) <= usize::from(u8::max_value()));\n        send_ipi_inner(target_apic_id, 0b110, u8::try_from(boot_fn >> 12).unwrap());\n    }\n}\n\n/// Address where the APIC registers are mapped.\n///\n/// While it is possible to remap these registers, this remapping has been made possible by Intel\n/// only because of legacy systems and we never use this feature.\nconst APIC_BASE_ADDR: usize = 0xfee00000;\n\n// Internal implementation of sending an inter-process interrupt.\nfn send_ipi_inner(target_apic_id: ApicId, delivery: u8, vector: u8) {\n    // Check conformance.\n    debug_assert!(delivery <= 0b110);\n    debug_assert_ne!(delivery, 0b011);\n    debug_assert_ne!(delivery, 0b001);\n    debug_assert!(delivery != 0b010 || vector == 0);\n    debug_assert!(delivery != 0b101 || vector == 0);\n\n    // TODO: if P6 architecture, then only 4 bits of the target are valid; do we care about that?\n    let level_bit = if delivery == 0b101 { 0 } else { 1 << 14 };\n    let value_lo = level_bit | (u32::from(delivery) << 8) | u32::from(vector);\n    let value_hi = u32::from(target_apic_id.0) << (56 - 32);\n\n    let value_lo_addr = usize::try_from(APIC_BASE_ADDR + 0x300).unwrap() as *mut u32;\n    let value_hi_addr = usize::try_from(APIC_BASE_ADDR + 0x310).unwrap() as *mut u32;\n\n    // We want the write to be atomic.\n    unsafe {\n        if x86_64::instructions::interrupts::are_enabled() {\n            x86_64::instructions::interrupts::disable();\n            value_hi_addr.write_volatile(value_hi);\n            value_lo_addr.write_volatile(value_lo);\n            x86_64::instructions::interrupts::enable();\n        } else {\n            value_hi_addr.write_volatile(value_hi);\n            value_lo_addr.write_volatile(value_lo);\n        }\n    }\n}\n\n/// Returns the [`ApicId`] of the calling processor.\nfn current_apic_id() -> ApicId {\n    unsafe {\n        // Note: this is correct because we never modify the local APIC ID.\n        let apic_id_addr = usize::try_from(APIC_BASE_ADDR + 0x20).unwrap() as *mut u32;\n        let apic_id = u8::try_from(apic_id_addr.read_volatile() >> 24).unwrap();\n        ApicId(apic_id)\n    }\n}\n\n/// Checks in the CPUID whether the APIC is supported.\nfn is_apic_supported() -> bool {\n    unsafe {\n        let cpuid = core::arch::x86_64::__cpuid(0x1);\n        cpuid.edx & (1 << 9) != 0\n    }\n}\n\n/// Checks in the CPUID whether the TSC is supported.\nfn is_tsc_supported() -> bool {\n    unsafe {\n        let cpuid = core::arch::x86_64::__cpuid(0x1);\n        cpuid.edx & (1 << 4) != 0\n    }\n}\n\n/// Checks in the CPUID whether the APIC timer supports TSC deadline mode.\nfn is_tsc_deadline_supported() -> bool {\n    unsafe {\n        let cpuid = core::arch::x86_64::__cpuid(0x1);\n        cpuid.ecx & (1 << 24) != 0\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/apic/pic.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse x86_64::structures::port::PortWrite as _;\n\n/// Remap and disable the PIC.\n///\n/// The PIC (Programmable Interrupt Controller) is the old chip responsible for triggering\n/// on the CPU interrupts coming from the hardware.\n///\n/// Because of poor design decisions, it will by default trigger interrupts 0 to 15 on the CPU,\n/// which are normally reserved for software-related concerns. For example, the timer will by\n/// default trigger interrupt 8, which is also the double fault exception handler.\n///\n/// In order to solve this issue, one has to reconfigure the PIC in order to make it trigger\n/// interrupts between 32 and 47 rather than 0 to 15.\n///\n/// Note that this code disables the PIC altogether. Despite the PIC being disabled, it is\n/// still possible to receive spurious interrupts. Hence the remapping.\n///\n/// # Safety\n///\n/// This function is not thread-safe. It must only be called once simultaneously and while nothing\n/// else is accessing the PIC.\n///\npub unsafe fn init_and_disable_pic() {\n    u8::write_to_port(0xa1, 0xff);\n    u8::write_to_port(0x21, 0xff);\n    u8::write_to_port(0x20, 0x10 | 0x01);\n    u8::write_to_port(0xa0, 0x10 | 0x01);\n    u8::write_to_port(0x21, 0x20);\n    u8::write_to_port(0xa1, 0x28);\n    u8::write_to_port(0x21, 4);\n    u8::write_to_port(0xa1, 2);\n    u8::write_to_port(0x21, 0x01);\n    u8::write_to_port(0xa1, 0x01);\n    u8::write_to_port(0xa1, 0xff);\n    u8::write_to_port(0x21, 0xff);\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/apic/timers.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Timers handling on x86/x86_64.\n//!\n//! # Overview\n//!\n//! When it comes to monotonic time (as opposed to a real-life time clock), multiple mechanisms\n//! exist:\n//!\n//! - The PIT (Programmable Interrupt Timer) is a legacy way of triggering an interrupt after a\n//! certain amount of timer has elapsed. The PIT is unique on the system and is shared between\n//! all the CPUs.\n//! - x86/x86_64 CPUs optionally provide a register named TSC (TimeStamp Counter) whose value is\n//! accessible using the `RDTSC` instruction. The value is increased at a uniform rate, even if\n//! the processor is halted (`hlt` instruction). Each CPU on the system has a separate TSC value.\n//! - Each CPU also has a local APIC that can trigger an interrupt after a certain number of\n//! timer cycles has passed, or, if supported, when the TSC reaches a certain value. Each CPU has\n//! its own local APIC, and the interrupt will only concern this CPU in particular.\n//! - The HPET is a more recent version of the PIT. Like the PIT, there only exists at most one\n//! HPET per machine.\n//!\n//! # Timers management\n//!\n//! ## One timer at a time\n//!\n//! In order to fire a single timer after a certain duration, we use the TSC as a reference point.\n//! As part of the initialization process, we measure the rate at which the TSC increases, and\n//! thus can determine at which TSC value the requested duration will have elapsed.\n//!\n//! We then use the local APIC in TSC deadline value mode if supported, or regular mode if not, to\n//! fire an interrupt.\n//!\n//! In regular mode, considering that the timer value is 32bits, it might be necessary to chain\n//! multiple timers before the desired TSC value is reached.\n//!\n//! By using the TSC as the reference value, we can check at any time whether the timer has been\n//! fired. The local APIC's timer is use solely for its capability to wake up a halted CPU.\n//!\n//! Keep in mind that each CPU has its own TSC value, which is why we try to keep the TSCs of all\n//! CPUs synchronized (see the [`../tsc_sync`] module). It is however possible that moving a TSC\n//! value to a different CPU leads to this value being slightly superior to the current value of\n//! the local TSC.\n// TODO: ^ somehow enforce in the API that the TSC sync is indeed performed?\n//!\n//! ## Multiple timers\n//!\n//! In a perfect world we would like to either distribute timers uniformly amongst the multiple\n//! CPUs, so that the overhead of handling interrupts is distributed uniformly, or alternatively\n//! we would like to setup a timer directly on the CPU that is actually waiting for the timer to\n//! be fired.\n//!\n//! In practice, though, we cannot directly configure the local APICs of other CPUs, and for the\n//! sake of simplicity we employ the following strategy:\n//!\n//! - There exists a list of timers shared between all CPUs.\n//! - When a timer is created:\n//!   - If the current CPU is already handling a timer:\n//!      - If the currently-handled timer will fire sooner than the newly-created timer, add the\n//!        newly-created timer to this shared list.\n//!      - If instead the currently-handled timer would fire later than the newly-created timer,\n//!        add the current timer to this shared list and configure the current CPU for the\n//!        newly-created timer.\n//!   - If the current CPU is not currently handling any timer, configure the current CPU for the\n//!        newly-created timer.\n//! - When a timer interrupt is fired, the CPU that has been interrupted picks the next pending\n//!   timer from the shared list and configures itself for it.\n//!\n//! In other words, we only ever configure the current CPU, and, after a timer has fired, CPUs try\n//! to steal work from others.\n//!\n//! In order to make the code more simple, creating a timer doesn't actually do anything. It is\n//! only when a timer is polled for the first time that we properly initialize it. This guarantees\n//! that all timers in the list have a [`core::task::Waker`] associated to them.\n//!\n\n// TODO: this entire module should be audited for race conditions (good luck!)\n\nuse crate::arch::x86_64::{\n    apic::{local, tsc_sync},\n    interrupts, pit,\n};\n\nuse alloc::{collections::VecDeque, sync::Arc};\nuse core::{\n    cmp,\n    convert::TryFrom as _,\n    fmt,\n    num::{NonZeroU32, NonZeroU64},\n    pin::Pin,\n    sync::atomic,\n    task::{Context, Poll, Waker},\n    time::Duration,\n};\nuse futures::prelude::*;\nuse hashbrown::{hash_map::Entry, HashMap};\nuse spinning_top::Spinlock;\n\n/// Initializes the timers system for x86_64.\npub async fn init(\n    local_apics: &'static local::LocalApicsControl,\n    pit: &mut pit::PitControl,\n    num_cpus: NonZeroU32,\n) -> Arc<Timers> {\n    // We don't support systems without the TSC.\n    assert!(is_tsc_supported());\n\n    // We use the PIT to figure out approximately how many RDTSC ticks happen per second.\n    // TODO: instead of using the PIT, we can use CPUID[EAX=0x15] to find the frequency, but that\n    // might not be available and does AMD support it?\n    let rdtsc_ticks_per_sec = unsafe {\n        // We use fences in order to guarantee that the RDTSC instructions don't get moved around.\n        let before = tsc_sync::volatile_rdtsc();\n        pit.timer(Duration::from_secs(1)).await;\n        let after = tsc_sync::volatile_rdtsc();\n\n        assert!(after > before);\n        NonZeroU64::new(after - before).unwrap()\n    };\n\n    let monotonic_clock_zero = NonZeroU64::new(tsc_sync::volatile_rdtsc()).unwrap();\n\n    Arc::new(Timers {\n        local_apics,\n        interrupt_vector: interrupts::reserve_any_vector(160).unwrap(),\n        monotonic_clock_zero,\n        rdtsc_ticks_per_sec,\n        next_unique_timer_id: atomic::AtomicU64::new(0),\n        monotonic_clock_min: atomic::AtomicU64::new(monotonic_clock_zero.get()),\n        shared: Spinlock::new(Shared {\n            active_timers: HashMap::with_capacity_and_hasher(\n                usize::try_from(num_cpus.get()).unwrap(),\n                Default::default(),\n            ),\n            pending_timers: VecDeque::with_capacity(32), // TODO: which capacity?\n        }),\n    })\n}\n\n/// Timers management for x86/x86_64.\npub struct Timers {\n    local_apics: &'static local::LocalApicsControl,\n\n    /// Reservation for an interrupt vector in the interrupts table.\n    ///\n    /// This is the interrupt that the timer will fire.\n    interrupt_vector: interrupts::ReservedInterruptVector,\n\n    /// Number of RDTSC ticks when we initialized the struct. Never modified.\n    monotonic_clock_zero: NonZeroU64,\n\n    /// Approximate number of RDTSC ticks per second. Never modified.\n    rdtsc_ticks_per_sec: NonZeroU64,\n\n    /// Each spawned timer has a unique identifier to identify it. This is the identifier of the\n    /// next timer to spawn.\n    next_unique_timer_id: atomic::AtomicU64,\n\n    /// Since each CPU has its own TSC register, it is possible that they are not always in sync.\n    /// If a user calls [`Timers::monotonic_clock`] from one CPU, then calls it again from a\n    /// different CPU, we want the value returned the second time to always be superior or equal\n    /// to the value returned the first time.\n    /// In order to guarantee this, we store here the last returned value of\n    /// [`Timers::monotonic_clock`] and make sure to never return a value inferior to this.\n    ///\n    /// This mechanism is also necessary in order to avoid the situation where CPU A wakes up a\n    /// task because a certain TSC value has been reached, only for the woken up CPU to think that\n    /// the same TSC value has not being reached yet.\n    monotonic_clock_min: atomic::AtomicU64,\n\n    /// Everything behind a lock.\n    shared: Spinlock<Shared>,\n}\n\n/// Everything behind a lock.\n#[derive(Debug)]\nstruct Shared {\n    /// For each CPU, the timer that is currently being configured in its APIC.\n    active_timers: HashMap<local::ApicId, ActiveTimerEntry, fnv::FnvBuildHasher>,\n\n    /// Timers that aren't being processed by any CPU. Must be picked up.\n    ///\n    /// Always ordered by ascending `target_tsc_value` value.\n    pending_timers: VecDeque<TimerEntry>,\n}\n\n/// Timer registered in [`Shared::active_timers`].\n#[derive(Debug)]\nstruct ActiveTimerEntry {\n    /// Fields in common with [`TimerEntry`].\n    timer: TimerEntry,\n\n    /// TSC value at which the APIC timer will fire. This is normally always equal to\n    /// `target_tsc_value` if the APIC supports TSC-deadline-mode timers. Otherwise, this is\n    /// inferior or equal to `target_tsc_value`.\n    /// After this TSC value has been reached, we need to refresh the APIC timer.\n    apic_timer_firing_tsc_value: NonZeroU64,\n}\n\n/// Timer registered in [`Shared`].\n#[derive(Debug)]\nstruct TimerEntry {\n    /// Identifier of the [`TimerFuture`].\n    timer_id: u64,\n    /// TSC value to reach before waking up the [`Waker`].\n    target_tsc_value: NonZeroU64,\n    /// Waker for when the timer fires.\n    waker: Waker,\n}\n\nimpl Timers {\n    /// Returns a `Future` that fires when the given amount of time has elapsed.\n    pub fn register_timer_after(self: &Arc<Self>, after: Duration) -> TimerFuture {\n        let now = self.monotonic_clock();\n        self.register_timer_at(now + after)\n    }\n\n    /// Returns a `Future` that fires when the monotonic clock reaches the given value.\n    pub fn register_timer_at(self: &Arc<Self>, when: Duration) -> TimerFuture {\n        // Find out the TSC value corresponding to the requested `Duration`.\n        let tsc_value = when\n            .as_secs()\n            .checked_mul(self.rdtsc_ticks_per_sec.get())\n            .unwrap()\n            .checked_add(\n                u64::from(when.subsec_nanos())\n                    .checked_mul(self.rdtsc_ticks_per_sec.get())\n                    .unwrap()\n                    .checked_div(1_000_000_000)\n                    .unwrap(),\n            )\n            .unwrap()\n            .checked_add(self.monotonic_clock_zero.get())\n            .unwrap();\n\n        TimerFuture {\n            timers: self.clone(),\n            tsc_value: NonZeroU64::new(tsc_value).unwrap(),\n            timer_id: None,\n        }\n    }\n\n    /// Returns the time elapsed since the initialization of this struct.\n    ///\n    /// Guaranteed to always return a `Duration` greater or equal to the one returned the previous\n    /// time.\n    pub fn monotonic_clock(&self) -> Duration {\n        let rdtsc_value = {\n            let local_val = tsc_sync::volatile_rdtsc();\n            self.monotonic_clock_min\n                .fetch_max(local_val, atomic::Ordering::AcqRel)\n                .max(local_val)\n        };\n\n        debug_assert!(rdtsc_value >= self.monotonic_clock_zero.get());\n        let diff_ticks = rdtsc_value - self.monotonic_clock_zero.get();\n        let whole_secs = diff_ticks / self.rdtsc_ticks_per_sec.get();\n        // TODO: The multiplication below can realistically panic if `rdtsc_ticks_per_sec` is a\n        // very large value. A 16 GHz CPU for example might overflow here.\n        let nanos = 1_000_000_000u64\n            .checked_mul(diff_ticks % self.rdtsc_ticks_per_sec.get())\n            .unwrap()\n            / self.rdtsc_ticks_per_sec.get();\n        Duration::new(whole_secs, u32::try_from(nanos).unwrap())\n    }\n}\n\nimpl fmt::Debug for Timers {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_struct(\"Timers\")\n            .field(\"rdtsc_ticks_per_sec\", &self.rdtsc_ticks_per_sec)\n            .finish()\n    }\n}\n\n/// Future that triggers when the TSC reaches a certain value.\n#[must_use]\npub struct TimerFuture {\n    /// Reference to the [`Timers`] struct that has created this timer.\n    timers: Arc<Timers>,\n    /// The TSC value after which the future will be ready.\n    tsc_value: NonZeroU64,\n    /// Unique identifier of the timer within the [`Timers`]. `None` if it hasn't been put in the\n    /// list yet.\n    timer_id: Option<u64>,\n}\n\nimpl Future for TimerFuture {\n    type Output = ();\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {\n        let this = &mut *self;\n\n        // Grab the current RDTSC value, after adjustment.\n        let now: u64 = {\n            let local_val = unsafe { core::arch::x86_64::_rdtsc() };\n            this.timers\n                .monotonic_clock_min\n                .fetch_max(local_val, atomic::Ordering::AcqRel)\n                .max(local_val)\n        };\n\n        if now >= this.tsc_value.get() {\n            return Poll::Ready(());\n        }\n\n        // We need either to register the timer in the lists, or update the current registration\n        // with the waker passed as parameter.\n        let mut shared = this.timers.shared.lock();\n        let shared = &mut *shared;\n\n        // Timer is already somewhere in a list.\n        if let Some(timer_id) = this.timer_id {\n            for active_timer in shared\n                .active_timers\n                .values_mut()\n                .map(|t| &mut t.timer)\n                .chain(shared.pending_timers.iter_mut())\n            {\n                if active_timer.timer_id == timer_id {\n                    debug_assert_eq!(this.tsc_value, active_timer.target_tsc_value);\n                    if !active_timer.waker.will_wake(cx.waker()) {\n                        active_timer.waker = cx.waker().clone();\n                    }\n                    return Poll::Pending;\n                }\n            }\n\n            // Here is a subtle corner case. It is possible that the target TSC value gets reached\n            // while we're waiting to lock `shared` (see above), and that another CPU has detected\n            // that and removed the timer from the list as a result.\n            // Note that this `assert!` should rather be a `debug_assert!`, but considering the\n            // complexity of the whole machinery, we prefer to always detect bugs here.\n            assert!(\n                this.timers\n                    .monotonic_clock_min\n                    .load(atomic::Ordering::SeqCst)\n                    >= this.tsc_value.get()\n            );\n            return Poll::Ready(());\n        }\n\n        // Timer has never been registered within `shared`.\n        // Allocate a new identifier.\n        let timer_id = this\n            .timers\n            .next_unique_timer_id\n            .fetch_add(1, atomic::Ordering::Relaxed);\n        assert_ne!(timer_id, u64::max_value()); // Check for overflow.\n        this.timer_id = Some(timer_id);\n\n        let to_insert = TimerEntry {\n            timer_id,\n            target_tsc_value: this.tsc_value,\n            waker: cx.waker().clone(),\n        };\n\n        // Try to insert in `active_timers`.\n        match shared\n            .active_timers\n            .entry(this.timers.local_apics.current_apic_id())\n        {\n            Entry::Occupied(e) if e.get().timer.target_tsc_value <= to_insert.target_tsc_value => {\n                // `active_timers` is already busy with a shorter timer. Add as pending.\n                // Reminder: `pending_timers` is always ordered by ascending `target_tsc_value`.\n                if let Some(pos) = shared\n                    .pending_timers\n                    .iter()\n                    .position(|t| t.target_tsc_value >= to_insert.target_tsc_value)\n                {\n                    shared.pending_timers.insert(pos, to_insert);\n                } else {\n                    shared.pending_timers.push_back(to_insert);\n                }\n            }\n\n            Entry::Occupied(mut e) => {\n                // The currently active timer should fire later than the one to insert, so we\n                // modify the current configuration.\n                // We don't need to call `register_waker` to update the waker, as it is already\n                // registered.\n                debug_assert!(e.get().timer.target_tsc_value > to_insert.target_tsc_value);\n\n                let previous_timer = e\n                    .insert(configure_apic(\n                        now,\n                        &this.timers.local_apics,\n                        this.timers.interrupt_vector.interrupt_num(),\n                        to_insert,\n                    ))\n                    .timer;\n\n                // Reminder: `pending_timers` is always ordered by ascending `target_tsc_value`.\n                if let Some(pos) = shared\n                    .pending_timers\n                    .iter()\n                    .position(|t| t.target_tsc_value >= previous_timer.target_tsc_value)\n                {\n                    shared.pending_timers.insert(pos, previous_timer);\n                } else {\n                    shared.pending_timers.push_back(previous_timer);\n                }\n            }\n\n            Entry::Vacant(e) => {\n                // Important: we register the waker before configuring the APIC, otherwise the\n                // interrupt could fire in-between the two operations.\n                this.timers\n                    .interrupt_vector\n                    .register_waker(&futures::task::waker(Arc::new(TimerWaker {\n                        timers: this.timers.clone(),\n                    })));\n                e.insert(configure_apic(\n                    now,\n                    &this.timers.local_apics,\n                    this.timers.interrupt_vector.interrupt_num(),\n                    to_insert,\n                ));\n            }\n        }\n\n        Poll::Pending\n    }\n}\n\nimpl fmt::Debug for TimerFuture {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_struct(\"TimerFuture\")\n            .field(\"tsc_value\", &self.tsc_value)\n            .finish()\n    }\n}\n\n/// Waker that is woken up as the outcome of an interrupt.\nstruct TimerWaker {\n    /// [`Timers`] struct this waker belongs to.\n    timers: Arc<Timers>,\n}\n\nimpl futures::task::ArcWake for TimerWaker {\n    fn wake_by_ref(arc_self: &Arc<Self>) {\n        // Note: keep in mind that there no guarantee that this method gets called from a specific\n        // CPU. It is possible for a timer interrupt to happen on CPU A, then this function gets\n        // called on CPU B.\n\n        let mut shared = arc_self.timers.shared.lock();\n        let shared = &mut *shared;\n\n        // Grab the current RDTSC value, after adjustment.\n        let now: u64 = {\n            let local_val = unsafe { core::arch::x86_64::_rdtsc() };\n            arc_self\n                .timers\n                .monotonic_clock_min\n                .fetch_max(local_val, atomic::Ordering::AcqRel)\n                .max(local_val)\n        };\n\n        // Remove from `active_timers` all the timers that have fired.\n        for (_, timer) in shared\n            .active_timers\n            .drain_filter(|_, timer| timer.apic_timer_firing_tsc_value.get() <= now)\n        {\n            debug_assert!(timer.apic_timer_firing_tsc_value.get() <= now);\n            if timer.timer.target_tsc_value.get() <= now {\n                timer.timer.waker.wake();\n                continue;\n            }\n\n            // If we reach this point, we have reached `apic_timer_firing_tsc_value` but not yet\n            // `target_tsc_value`. Add the timer back in the pending queue that we process below.\n            if let Some(pos) = shared\n                .pending_timers\n                .iter()\n                .position(|t| t.target_tsc_value >= timer.timer.target_tsc_value)\n            {\n                shared.pending_timers.insert(pos, timer.timer);\n            } else {\n                shared.pending_timers.push_back(timer.timer);\n            }\n        }\n\n        let current_apic_id = arc_self.timers.local_apics.current_apic_id();\n\n        // Now process the pending timers.\n        loop {\n            let next_timer = match shared.pending_timers.pop_front() {\n                Some(t) => t,\n                None => break,\n            };\n\n            // Checking the correct ascending ordering.\n            debug_assert!(shared\n                .pending_timers\n                .front()\n                .map_or(true, |second_next| second_next.target_tsc_value\n                    >= next_timer.target_tsc_value));\n\n            if next_timer.target_tsc_value.get() <= now {\n                next_timer.waker.wake();\n                continue;\n            }\n\n            // Try to register the next timer as the current one of the local CPU.\n            if let Entry::Vacant(e) = shared.active_timers.entry(current_apic_id) {\n                // Important: we register the waker before configuring the APIC, otherwise the\n                // interrupt could fire in-between the two operations.\n                arc_self\n                    .timers\n                    .interrupt_vector\n                    .register_waker(&futures::task::waker_ref(arc_self));\n                e.insert(configure_apic(\n                    now,\n                    &arc_self.timers.local_apics,\n                    arc_self.timers.interrupt_vector.interrupt_num(),\n                    next_timer,\n                ));\n            } else {\n                // If the current CPU is already processing a timer, re-add the one we extracted\n                // back in the queue.\n                shared.pending_timers.push_front(next_timer);\n                break;\n            }\n        }\n\n        // Some memory footprint reduction.\n        if shared.pending_timers.is_empty() && shared.pending_timers.capacity() >= 32 {\n            // TODO: use shrink_to once stable and use a minimum capacity\n            shared.pending_timers.shrink_to_fit();\n        }\n    }\n}\n\n/// Configures the timer of the local CPU, and turns a [`TimerEntry`] into an [`ActiveTimerEntry`].\nfn configure_apic(\n    tsc_now: u64,\n    local_apic: &local::LocalApicsControl,\n    interrupt_vector: u8,\n    entry: TimerEntry,\n) -> ActiveTimerEntry {\n    // Sanity check.\n    debug_assert!(entry.target_tsc_value.get() > tsc_now);\n\n    // If TSC deadline mode is supported, then it's easy: pass the target TSC value to the APIC\n    // and return.\n    if local_apic.is_tsc_deadline_supported() {\n        local_apic.set_local_timer(local::Timer::TscDeadline {\n            threshold: entry.target_tsc_value,\n            vector: interrupt_vector,\n        });\n        let apic_timer_firing_tsc_value = entry.target_tsc_value;\n        return ActiveTimerEntry {\n            apic_timer_firing_tsc_value,\n            timer: entry,\n        };\n    }\n\n    // If TSC deadline mode is not supported, then the timer requires a number of ticks as a\n    // 32-bits number, and `entry.target_tsc_value - tsc_now` might be too large to be accepted.\n\n    // Calculate `target_tsc_value - tsc_now`, but cap it to the maximum value that can fit the\n    // timer.\n    let ticks_to_timer = cmp::min(\n        entry.target_tsc_value.get().checked_sub(tsc_now).unwrap(),\n        u64::from(u32::max_value()) * 127,\n    );\n\n    // The timer accepts a value and a multiplier. The timer will fire after `value * multiplier`\n    // ticks. The larger the multiplier, the more imprecise the timer is.\n    // We try to find the smallest multiplier that is acceptable for `ticks_to_timer` to still\n    // fit into a 32-bits value.\n    let (ticks, multiplier) = (0..7)\n        .filter_map(|multiplier| {\n            // Adding `1` to round up.\n            let ticks = 1 + (ticks_to_timer / (2 << multiplier));\n            if let Ok(ticks) = u32::try_from(ticks) {\n                Some((ticks, 2 << multiplier))\n            } else {\n                None\n            }\n        })\n        .next()\n        .unwrap();\n    debug_assert!(u64::from(ticks) * u64::from(multiplier) >= ticks_to_timer);\n\n    // Success.\n    local_apic.set_local_timer(local::Timer::Timer {\n        value: NonZeroU32::new(ticks).unwrap(),\n        value_multiplier: multiplier,\n        periodic: false,\n        vector: interrupt_vector,\n    });\n\n    ActiveTimerEntry {\n        apic_timer_firing_tsc_value: NonZeroU64::new(tsc_now.checked_add(ticks_to_timer).unwrap())\n            .unwrap(),\n        timer: entry,\n    }\n}\n\n/// Checks in the CPUID whether the TSC is supported.\nfn is_tsc_supported() -> bool {\n    unsafe {\n        let cpuid = core::arch::x86_64::__cpuid(0x1);\n        cpuid.edx & (1 << 4) != 0\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/apic/tsc_sync.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Synchronization of the TSC between multiple CPUs.\n//!\n//! The TSC (Time Stamp Counter) is a counter that is automatically incremented by the CPU either\n//! at each clock cycle (for older CPUs), or at a constant rate (for more recent CPUs).\n//!\n//! It is the primary mechanism that can be used in order to approximate how much time has passed.\n//!\n//! However, each CPU has a different TSC, which means that a value read on one CPU has no meaning\n//! on another one.\n//!\n//! In order to remedy to this, this module makes it possible to synchronize the value of the TSC\n//! between two processors. This is typically done whenever we start a new processor to\n//! synchronize its TSC to the one of the startup CPU.\n//!\n//! Keep in mind, however, that this synchronization is not perfect. It is possible to read the\n//! TSC on a CPU, move this value to another CPU, and observe the value being greater than the TSC\n//! of the new CPU. Code that uses the TSC must be aware of that and cannot assume that the TSC is\n//! strictly monotonic if moving values between threads is involved.\n//!\n//! # Usage\n//!\n//! Call [`tsc_sync`] to obtain a \"sender\" and a \"receiver\". Call [`TscSyncSrc::sync`] and\n//! [`TscSyncDst::sync`] from two different CPUs. The TSC of the CPU that has called\n//! [`TscSyncDst::sync`] will have its TSC synchronized with the one of the CPU that has called\n//! [`TscSyncSrc::sync`].\n//!\n\n// Implementation strategy:\n//\n// Before `sync` actually starts, we use a barrier to ensure that the two CPUs start executing\n// `sync` at the same time.\n//\n// Then, for a short period of time, the source repeatedly writes its TSC value in a shared\n// variable, which is continuously read by the destination. The destination repeatedly compares\n// the value it reads to its own value.\n//\n// At the end of the measurement, the destination CPU knows the maximum difference between its own\n// value and the source value, and updates its own value accordingly.\n\nuse alloc::sync::Arc;\nuse core::{fmt, hint, sync::atomic};\nuse crossbeam_utils::CachePadded;\nuse spinning_top::Spinlock;\nuse x86_64::registers::model_specific::Msr;\n\n/// Returns a \"sender\" and a \"receiver\". Call [`TscSyncSrc::sync`] and [`TscSyncDst::sync`] from\n/// two different CPUs, so that the TSC of the CPU that called [`TscSyncDst::sync`] synchronizes\n/// with the TSC of the CPU that called [`TscSyncSrc::sync`].\npub fn tsc_sync() -> (TscSyncSrc, TscSyncDst) {\n    let shared = Arc::new(CachePadded::from(Shared {\n        start_barrier: atomic::AtomicU8::new(0),\n        src_rdtsc_storage: Spinlock::new(0),\n    }));\n\n    let src = TscSyncSrc {\n        shared: shared.clone(),\n    };\n    let dst = TscSyncDst { shared };\n    (src, dst)\n}\n\n/// Use on the CPU with the reference clock to sync from.\npub struct TscSyncSrc {\n    shared: Arc<CachePadded<Shared>>,\n}\n\n/// Use on the CPU to be synced.\npub struct TscSyncDst {\n    shared: Arc<CachePadded<Shared>>,\n}\n\nstruct Shared {\n    /// Number of CPUs (0, 1, or 2) that have entered `sync`.\n    /// Note that this should be a barrier, but there isn't any spinlock-based barrier in the\n    /// Rust ecosystem at the time of writing this code.\n    start_barrier: atomic::AtomicU8,\n\n    /// Mutex where the source CPU will repeatedly store its TSC value. A value of 0 means\n    /// \"hasn't been written yet\" and should be ignored.\n    src_rdtsc_storage: Spinlock<u64>,\n}\n\nimpl TscSyncSrc {\n    /// Perform the synchronization.\n    ///\n    /// > **Important**: This will wait for the corresponding [`TscSyncDst`] to call\n    /// >                [`sync`](`TscSyncDst::sync`).\n    pub fn sync(&mut self) {\n        assert!(Arc::strong_count(&self.shared) >= 2);\n\n        // Barrier to synchronize the source and destination.\n        self.shared\n            .start_barrier\n            .fetch_add(1, atomic::Ordering::SeqCst);\n        // TODO: add some guarantee that we don't spin forever? do something in the Drop impl?\n        while self.shared.start_barrier.load(atomic::Ordering::SeqCst) != 2 {\n            hint::spin_loop();\n        }\n\n        for _ in 0..100000 {\n            let mut lock = self.shared.src_rdtsc_storage.lock();\n            // We grab the local RDTSC value *after* grabbing the lock.\n            *lock = volatile_rdtsc();\n        }\n    }\n}\n\nimpl fmt::Debug for TscSyncSrc {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"TscSyncSrc\")\n            .field(&Arc::as_ptr(&self.shared))\n            .finish()\n    }\n}\n\nimpl TscSyncDst {\n    /// Perform the synchronization.\n    ///\n    /// > **Important**: This will wait for the corresponding [`TscSyncSrc`] to call\n    /// >                [`sync`](`TscSyncSrc::sync`).\n    pub fn sync(&mut self) {\n        assert!(Arc::strong_count(&self.shared) >= 2);\n\n        // Barrier to synchronize the source and destination.\n        self.shared\n            .start_barrier\n            .fetch_add(1, atomic::Ordering::SeqCst);\n        // TODO: add some guarantee that we don't spin forever? do something in the Drop impl?\n        while self.shared.start_barrier.load(atomic::Ordering::SeqCst) != 2 {\n            hint::spin_loop();\n        }\n\n        // Maximum value for `local - remote`.\n        let mut max_over = 0;\n        // Maximum value for `remote - local`.\n        let mut max_under = 0;\n\n        for _ in 0..100000 {\n            let lock = self.shared.src_rdtsc_storage.lock();\n            // We grab the local RDTSC value *after* grabbing the lock.\n            let local_value = volatile_rdtsc();\n            let remote_value = *lock;\n            drop(lock);\n\n            if remote_value == 0 {\n                // Source hasn't written its value yet.\n                continue;\n            }\n\n            // Because of the way this is implemented, there is inevitably a small delay between\n            // the moment the other CPU writes its RDTSC and the moment when we read this value.\n            // We do a slight adjustment of the remote CPU's value to compensate for that.\n            let remote_value = remote_value.saturating_add(20);\n\n            if let Some(over) = local_value.checked_sub(remote_value) {\n                if over > max_over {\n                    max_over = over;\n                }\n            }\n            if let Some(under) = remote_value.checked_sub(local_value) {\n                if under > max_under {\n                    max_under = under;\n                }\n            }\n        }\n\n        // FIXME: we just assume that the \"ADJUST\" register is supported; this is wrong\n\n        const TSC_ADJUST_REGISTER: Msr = Msr::new(0x3b);\n        let current_adjust = unsafe { TSC_ADJUST_REGISTER.read() };\n        let new_adjust = if max_over > max_under {\n            current_adjust.wrapping_sub(max_over)\n        } else {\n            current_adjust.wrapping_add(max_under)\n        };\n        unsafe { TSC_ADJUST_REGISTER.write(new_adjust) }\n    }\n}\n\nimpl fmt::Debug for TscSyncDst {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"TscSyncDst\")\n            .field(&Arc::as_ptr(&self.shared))\n            .finish()\n    }\n}\n\n/// Reads the TSC value of the current CPU while trying to force the CPU to not re-order the\n/// execution of the `rdtsc` opcode.\n// TODO: preferably use `rdtscp` instead if supported, which has this property by default\npub fn volatile_rdtsc() -> u64 {\n    #[cfg(target_arch = \"x86\")]\n    fn inner() -> u64 {\n        unsafe {\n            core::arch::x86::_mm_lfence();\n            core::arch::x86::_rdtsc()\n        }\n    }\n    #[cfg(target_arch = \"x86_64\")]\n    fn inner() -> u64 {\n        unsafe {\n            core::arch::x86_64::_mm_lfence();\n            core::arch::x86_64::_rdtsc()\n        }\n    }\n    inner()\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/apic.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n// TODO: do re-exports here instead\n\npub use local::ApicId;\n\npub mod io_apic;\npub mod io_apics;\npub mod local;\npub mod pic;\npub mod timers;\npub mod tsc_sync;\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/boot.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! This file contains the entry point of our kernel.\n//!\n//! Once the bootloader finishes loading the kernel (as an ELF file), it will run its entry point,\n//! which is the `_start` function defined in this file.\n//!\n//! Since we are conforming to the multiboot2 specifications, the bootloader is expected to set the\n//! ebx register to the memory address of a data structure containing information about the\n//! environment.\n//!\n//! The environment in which we start in is the protected mode where the kernel is identity-mapped.\n//!\n//! The role of the `_start` function below is to perform some checks, set up everything that is\n//! needed to run freestanding 64bits Rust code (i.e. a stack, paging, long mode), and call the\n//! [`super::entry_point_step3`] Rust function.\n\n#[macro_export]\nmacro_rules! __gen_boot {\n    (\n        entry: $entry:path,\n        memory_zeroing_start: $memory_zeroing_start:path,\n        memory_zeroing_end: $memory_zeroing_end:path,\n    ) => {\n        const _: () = {\n            use core::arch::naked_asm;\n\n            // TODO: this should be used only for 32bits kernels? ; technically, 64bits multiboot2 isn't supported\n            #[naked]\n            #[export_name = \"_start\"]\n            unsafe extern \"C\" fn entry_point_step1() {\n                naked_asm!(r#\"\n                .code32\n                    // Disabling interruptions as long as we are not ready to accept them.\n                    // This is normally already done by the bootloader, but it costs nothing to\n                    // do it here again just in case.\n                    cli\n\n                    // Check that we have been loaded by a multiboot2 bootloader.\n                    cmp $0x36d76289, %eax\n                    jne 5f\n\n                    // Zero the memory requested to be zero'ed.\n                    // While the code here is generic, this is typically the BSS segment of the\n                    // generated ELF executable. Clearing the BSS segment is normally not\n                    // required (it has already been done by the bootloader), but we do it\n                    // anyway \"just in case\".\n                    mov ${memory_zeroing_start}, %edi\n                    mov ${memory_zeroing_end}, %ecx\n                    sub ${memory_zeroing_start}, %ecx\n                    jb 5f\n                    mov $0, %al\n                    cld\n                    rep stosb %al, (%edi)\n\n                    // Put the value of EBX in a temporary location, to retrieve it later.\n                    // Note that this is done after the memory zero-ing, as it is likely that this\n                    // symbol is included in the zero-ing.\n                    mov %ebx, ({multiboot_info_ptr})\n\n                    // Check that our CPU supports extended CPUID instructions.\n                    mov $0x80000000, %eax\n                    cpuid\n                    cmp $0x80000001, %eax\n                    jb 5f\n\n                    // Check that our CPU supports the features that we need.\n                    mov $0x80000001, %eax\n                    cpuid\n                    test $(1 << 29), %edx     // Test for long mode.\n                    jz 5f\n\n                    // Everything is good. CPU is compatible.\n\n                    // Fill the first PML4 entry to point to the PDPT.\n                    movl ${pdpt}, %eax\n                    or $(1 << 0), %eax    // Present bit. Indicates that the entry is valid.\n                    or $(1 << 1), %eax    // Read/write bit. Indicates that the entry is writable.\n                    movl %eax, {pml4}\n\n                    // Fill the PDPT entries to point to the PDs.\n                    mov $0, %ecx\n                2:  mov %ecx, %eax\n                    shl $12, %eax           // EAX <- ECX * 4096\n                    addl ${pds}, %eax       // EAX <- address of `pds` + ECX * 4096\n                    or $(1 << 0), %eax      // Present bit. Indicates that the entry is valid.\n                    or $(1 << 1), %eax      // Read/write bit. Indicates that the entry is writable.\n                    movl %eax, {pdpt}(, %ecx, 8)      // PDPT[ECX * 8] <- EAX\n                    inc %ecx\n                    cmp $32, %ecx\n                    jne 2b\n\n                    // Fill the PD entries to point to 2MiB pages.\n                    mov $0, %ecx\n                3:  mov %ecx, %eax\n                    shr $12, %eax          // EAX <- ECX >> 12\n                    movl %eax, {pds}+4(, %ecx, 8)     // PDs[4 + ECX * 8] <- EAX\n                    mov %ecx, %eax         // EAX <- ECX\n                    shl $21, %eax          // EAX <- ECX << 21\n                    or $(1 << 0), %eax     // Present bit. Indicates that the entry is valid.\n                    or $(1 << 1), %eax     // Read/write bit. Indicates that the entry is writable.\n                    or $(1 << 7), %eax     // Indicates a 2MiB page.\n                    movl %eax, {pds}(, %ecx, 8)       // PDs[ECX * 8] <- EAX\n                    inc %ecx\n                    cmp $(32 * 512), %ecx\n                    jne 3b\n\n                    // Set up the control registers.\n                    mov %cr0, %eax\n                    and $(~(1 << 2)), %eax          // Clear emulation bit.\n                    and $(~(1 << 31)), %eax         // Clear paging bit.\n                    movl %eax, %cr0\n\n                    movl ${pml4}, %eax\n                    movl %eax, %cr3\n\n                    movl $0, %eax\n                    or $(1 << 10), %eax             // Set SIMD floating point exceptions bit.\n                    or $(1 << 9), %eax              // Set OSFXSR bit, which enables SIMD.\n                    or $(1 << 5), %eax              // Set physical address extension (PAE) bit.\n                    movl %eax, %cr4\n\n                    // Set long mode with the EFER bit.\n                    movl $0xc0000080, %ecx\n                    rdmsr\n                    or $(1 << 8), %eax\n                    wrmsr\n\n                    // Set up the GDT. It will become active only after we do the `ljmp` below.\n                    lgdtl {gdt_ptr}\n                \n                    // Activate long mode, and jump to the new segment.\n                    mov %cr0, %eax\n                    or $(1 << 0), %eax              // Set protected mode bit.\n                    or $(1 << 1), %eax              // Set co-processor bit.\n                    or $(1 << 4), %eax              // Set co-processor extension bit.\n                    or $(1 << 31), %eax             // Set paging bit.\n                    // The official manual says that instruction right after long mode switch must\n                    // be a branch. Tutorials typically don't do that and it might not be strictly\n                    // necessary, but to be safe let's follow what the manual says.\n                    movl %eax, %cr0\n\n                    ljmp $8, $4f\n\n                .code64\n                .align 8\n                4:\n                    // Set up the stack.\n                    movq ${stack} + {stack_size}, %rsp\n\n                    movw $0, %ax\n                    movw %ax, %ds\n                    movw %ax, %es\n                    movw %ax, %fs\n                    movw %ax, %gs\n                    movw %ax, %ss\n\n                    // Jump to our Rust code.\n                    // Pass as parameter the value that the `ebx` register had at initialization,\n                    // which is where the multiboot information will be found.\n                    mov ({multiboot_info_ptr}), %rdi\n                    call {entry_point_step2}\n                    cli\n                    hlt\n\n                .code32\n                // Called if an unrecoverable error happens, such as an incompatible CPU.\n                5:\n                    movb $'E', 0xb8000\n                    movb $0xf, 0xb8001\n                    movb $'r', 0xb8002\n                    movb $0xf, 0xb8003\n                    movb $'r', 0xb8004\n                    movb $0xf, 0xb8005\n                    movb $'o', 0xb8006\n                    movb $0xf, 0xb8007\n                    movb $'r', 0xb8008\n                    movb $0xf, 0xb8009\n                    cli\n                    hlt\n                \"#,\n                    entry_point_step2 = sym entry_point_step2,\n                    memory_zeroing_start = sym $memory_zeroing_start,\n                    memory_zeroing_end = sym $memory_zeroing_end,\n                    multiboot_info_ptr = sym $crate::arch::x86_64::boot::MULTIBOOT_INFO_PTR,\n                    gdt_ptr = sym $crate::arch::x86_64::gdt::GDT_POINTER,\n                    stack = sym $crate::arch::x86_64::boot::MAIN_PROCESSOR_STACK,\n                    stack_size = const $crate::arch::x86_64::boot::MAIN_PROCESSOR_STACK_SIZE,\n                    pml4 = sym $crate::arch::x86_64::boot::PML4,\n                    pdpt = sym $crate::arch::x86_64::boot::PDPT,\n                    pds = sym $crate::arch::x86_64::boot::PDS,\n                    options(att_syntax)); // TODO: convert to Intel syntax\n            }\n\n            /// Called by `entry_point_step1` after basic initialization has been performed.\n            ///\n            /// When this function is called, a stack has been set up and as much memory space as\n            /// possible has been identity-mapped (i.e. the virtual memory is equal to the physical\n            /// memory).\n            ///\n            /// Since the kernel was loaded by a multiboot2 bootloader, the first parameter is the\n            /// memory address of the multiboot header.\n            ///\n            /// # Safety\n            ///\n            /// `multiboot_info` must be a valid memory address that contains valid information.\n            ///\n            unsafe fn entry_point_step2(multiboot_info: usize) -> ! {\n                $crate::arch::x86_64::entry_point_step3(multiboot_info, $entry)\n            }\n        };\n    }\n}\n\n/// Used as a temporary variable during the boot process.\n#[doc(hidden)]\npub static mut MULTIBOOT_INFO_PTR: u64 = 0;\n\n#[doc(hidden)]\npub const MAIN_PROCESSOR_STACK_SIZE: usize = 0x800000;\n\n/// Stack used by the main processor.\n///\n/// As per x64 calling convention, the stack pointer must always be a multiple of 16. The stack\n/// must therefore have an alignment of 16 as well.\n#[doc(hidden)]\n#[repr(align(16), C)]\npub struct Stack([u8; MAIN_PROCESSOR_STACK_SIZE]);\npub static mut MAIN_PROCESSOR_STACK: Stack = Stack([0; MAIN_PROCESSOR_STACK_SIZE]);\n\n// TODO: handle this in a more proper way\n// TODO: fill the paging from the Rust code, and not in assembly\n\n#[repr(align(0x1000), C)]\n#[doc(hidden)]\n#[derive(Copy, Clone)]\npub struct PagingEntry([u8; 0x1000]);\n/// PML4. The entry point for our paging system.\n#[doc(hidden)]\npub static mut PML4: PagingEntry = PagingEntry([0; 0x1000]);\n/// One PDPT. Maps 512GB of memory. Only the first thirty-two entries are used.\n#[doc(hidden)]\npub static mut PDPT: PagingEntry = PagingEntry([0; 0x1000]);\n/// Thirty-two PDs for the first thirty-two entries in the PDPT. Each PD maps 1GB of memory.\n#[doc(hidden)]\npub static mut PDS: [PagingEntry; 32] = [PagingEntry([0; 0x1000]); 32];\n\n// TODO: figure out how to remove these\n#[no_mangle]\npub extern \"C\" fn fmod(a: f64, b: f64) -> f64 {\n    libm::fmod(a, b)\n}\n#[no_mangle]\npub extern \"C\" fn fmodf(a: f32, b: f32) -> f32 {\n    libm::fmodf(a, b)\n}\n#[no_mangle]\npub extern \"C\" fn fmin(a: f64, b: f64) -> f64 {\n    libm::fmin(a, b)\n}\n#[no_mangle]\npub extern \"C\" fn fminf(a: f32, b: f32) -> f32 {\n    libm::fminf(a, b)\n}\n#[no_mangle]\npub extern \"C\" fn fmax(a: f64, b: f64) -> f64 {\n    libm::fmax(a, b)\n}\n#[no_mangle]\npub extern \"C\" fn fmaxf(a: f32, b: f32) -> f32 {\n    libm::fmaxf(a, b)\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/executor.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Futures executor that works on bare metal.\n\nuse crate::arch::x86_64::{\n    apic::{local::LocalApicsControl, ApicId},\n    interrupts,\n};\n\nuse alloc::sync::Arc;\nuse core::arch::asm;\nuse core::future::Future;\nuse core::sync::atomic;\nuse core::task::{Context, Poll};\nuse futures::task::{waker, ArcWake};\n\n// TODO: we use SeqCst everywhere, but we can probably use a better ordering\n\n/// Contains all the necessary information to executor futures.\npub struct Executor {\n    /// Reserved interrupt vector. Used to wake up other processors.\n    interrupt_vector: interrupts::ReservedInterruptVector,\n\n    /// The local APIC, to send IPIs.\n    apic: &'static LocalApicsControl,\n}\n\nimpl Executor {\n    /// Initializes a new [`Executor`].\n    pub fn new(local_apic: &'static LocalApicsControl) -> Self {\n        Executor {\n            interrupt_vector: interrupts::reserve_any_vector(0).unwrap(),\n            apic: local_apic,\n        }\n    }\n\n    /// Waits for the `Future` to resolve to a value.\n    ///\n    /// This function is similar to [`futures::executor::block_on`].\n    pub fn block_on<R>(&self, future: impl Future<Output = R>) -> R {\n        futures::pin_mut!(future);\n\n        let local_wake = Arc::new(Waker {\n            apic: self.apic,\n            processor_to_wake: self.apic.current_apic_id(),\n            interrupt_vector: self.interrupt_vector.interrupt_num(),\n            need_ipi: atomic::AtomicBool::new(false),\n            woken_up: atomic::AtomicBool::new(false),\n        });\n\n        let waker = waker(local_wake.clone());\n        let mut context = Context::from_waker(&waker);\n\n        loop {\n            // Poll the future.\n            // Starting from here, the `wake_by_ref` function defined below can be called at\n            // any time.\n            if let Poll::Ready(val) = Future::poll(future.as_mut(), &mut context) {\n                return val;\n            }\n\n            loop {\n                // As documented in the [`../interrupts`] module, we have to manually wake up the\n                // `Future`s that were waiting for an interrupt to happen.\n                interrupts::process_wakers();\n\n                debug_assert!(x86_64::instructions::interrupts::are_enabled());\n                unsafe {\n                    // Note: `cli` modifies a flag, meaning that `preserves_flags` might seem\n                    // incorrect. However the rules of `preserves_flags` do not include the\n                    // interrupt flag.\n                    asm!(\"cli\", options(nomem, nostack, preserves_flags));\n                }\n\n                // Remember that `wake_by_ref` might be called at any time.\n                // We're going to check `woken_up` below. If `woken_up` is false, we're going to\n                // execute an `hlt` instruction. We need to put `true` in `need_ipi`, so that\n                // `wake_by_ref` gets called from a different core and sends an IPI to the\n                // current processor to wake it up.\n                //\n                // However, we need to store `true` in `need_ipi` before checking `woken_up`,\n                // otherwise there could be a state where `need_ipi` is `false` but we've already\n                // checked `woken_up`.\n                local_wake.need_ipi.store(true, atomic::Ordering::SeqCst);\n\n                if local_wake\n                    .woken_up\n                    .compare_exchange(\n                        true,\n                        false,\n                        atomic::Ordering::SeqCst,\n                        atomic::Ordering::SeqCst,\n                    )\n                    .is_ok()\n                {\n                    // We're going to poll the `Future` again, so `need_ipi` can be set to `false`.\n                    local_wake.need_ipi.store(false, atomic::Ordering::SeqCst);\n                    unsafe {\n                        // Note: `sti` modifies a flag, meaning that `preserves_flags` might seem\n                        // incorrect. However the rules of `preserves_flags` do not include the\n                        // interrupt flag.\n                        asm!(\"sti\", options(nomem, nostack, preserves_flags));\n                    }\n                    break;\n                }\n\n                // According to the x86 specificiation, an `sti` opcode only takes effect after\n                // the *next* opcode, which is `hlt` here.\n                // It is therefore not possible for an interrupt to happen between `sti` and `hlt`.\n                unsafe {\n                    // Note: `sti` modifies a flag, meaning that `preserves_flags` might seem\n                    // incorrect. However the rules of `preserves_flags` do not include the\n                    // interrupt flag.\n                    asm!(\"sti; hlt\", options(nomem, nostack, preserves_flags));\n                }\n            }\n        }\n    }\n}\n\nstruct Waker {\n    /// Reference to the APIC, for sending IPIs.\n    apic: &'static LocalApicsControl,\n\n    /// Identifier of the processor that this waker must wake up.\n    processor_to_wake: ApicId,\n\n    /// Which interrupt vector to send to the processor to wake it up.\n    interrupt_vector: u8,\n\n    /// Flag set to true if the processor has entered or has a chance to enter a halted state,\n    /// and that an interprocess interrupt (IPI) is necessary in order to wake up the processor.\n    ///\n    /// If this is true, then you must set `woken_up` to true and send an IPI.\n    /// If this is false, then setting `woken_up` to true is enough.\n    need_ipi: atomic::AtomicBool,\n\n    /// Flag to set to true in order to wake up the processor.\n    woken_up: atomic::AtomicBool,\n}\n\nimpl ArcWake for Waker {\n    fn wake_by_ref(arc_self: &Arc<Self>) {\n        arc_self.woken_up.store(true, atomic::Ordering::SeqCst);\n\n        if arc_self\n            .need_ipi\n            .compare_exchange(\n                true,\n                false,\n                atomic::Ordering::SeqCst,\n                atomic::Ordering::SeqCst,\n            )\n            .is_ok()\n        {\n            if arc_self.processor_to_wake != arc_self.apic.current_apic_id() {\n                arc_self.apic.send_interprocessor_interrupt(\n                    arc_self.processor_to_wake,\n                    arc_self.interrupt_vector,\n                );\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/gdt.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! In the 16bits and 32bits modes of the x86/x86_64 architecture, memory can be divided into\n//! *segments*. Each segment has a base address, a length, and a few miscellaneous\n//! characteristics.\n//!\n//! In 32bits modes, the processor holds in a register called the GDTR the location of a data\n//! structure named the GDT (Global Descriptor Table). When the CS, DS, ES, FS, GS, or SS register\n//! is loaded with a non-zero value, the processor loads from the GDT the characteristics of the\n//! corresponding segment.\n//!\n//! Segmentation is a deprecated feature in 64bits mode. While loading the value of the segment\n//! registers works the same ways as in 32bits mode, the processor then ignores these registers\n//! altogether when performing memory accesses.\n//! For this reason, most operating systems don't rely on memory segmentation, even in 32bits\n//! modes.\n//!\n//! However, because processors don't immediately start in 64bits mode, one can never completely\n//! ignore segmentation.\n//! In order to switch to 64bits mode, one must load the CS register with a segment whose\n//! descriptor has a certain bit set. This bit determined whether the processor should run in\n//! extended-32bits or 64bits mode.\n\n/// Global Descriptor Table (GDT) with two entries:\n///\n/// - Since loading a zero value in a segment register doesn't perform any actual loading, the\n/// first entry is a dummy entry.\n/// - The second entry is a code segment with the `L` bit set to 1, indicating a 64-bit code\n/// segment.\n///\n/// In order to switch to 64bits mode, load the `GDTR` with this table, then load the value `8` in\n/// the `CS` register.\n///\n/// The memory address is guaranteed to fit in 32bits.\npub static GDT: Gdt = Gdt([0, (1 << 53) | (1 << 47) | (1 << 44) | (1 << 43)]);\n\n// TODO: assert that GDT has a 32bits memory address, once Rust makes this possible\n//       see https://github.com/rust-lang/rust/issues/51910\n\n/// Opaque type of the GDT table.\npub struct Gdt([u64; 2]);\n\n/// Pointer to [`GDT`] suitable for the `lgdt` instruction.\n///\n/// # 32-bit vs 64-bit LGDT instruction\n///\n/// In 32-bit mode the LGDT instruction expects a 32-bits GDT address, while in 64-bit mode it\n/// expects as 64-bits GDT address.\n///\n/// The pointer below contains a 64-bits-long address, but with an address that is guaranteed to\n/// fit in 32 bits. In other words, the 32 upper bits are 0s. Since x86/x86_64 is a little endian\n/// platform, this pointer works for both the 32-bits and 64-bits versions of the LGDT\n/// instruction.\n///\n/// # Example\n///\n/// ```ignore\n/// asm!(\"lgdt {gdt_ptr}\", gdt_ptr = sym GDT_POINTER);\n/// ```\n///\npub static GDT_POINTER: GdtPtr = GdtPtr(GdtPtr2 {\n    _size: 15,\n    _pointer: &GDT,\n});\n\n/// Opaque type of the GDT pointer.\n#[repr(align(8))]\npub struct GdtPtr(GdtPtr2);\n\n// We need a second inner type in order to be able to apply both `repr(packed)` and\n// `repr(align(8))`.\n#[repr(packed)]\nstruct GdtPtr2 {\n    _size: u16,\n    // TODO: must be 64bits, as explained above; see https://github.com/rust-lang/rust/issues/51910\n    _pointer: *const Gdt,\n}\n\n// TODO: remove once `GdtPtr2::_pointer` is a u64\nunsafe impl Send for GdtPtr {}\nunsafe impl Sync for GdtPtr {}\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/interrupts.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! x86_64 interrupts handling.\n//!\n//! This module provides handling of interrupts on x86_64. It sets up the interrupts table (IDT)\n//! and allows reserving interrupt vectors. Once done, you can register a\n//! [`Waker`](core::task::Waker) that is waken up when an interrupt happens. This is done by\n//! calling [`ReservedInterruptVector::register_waker`].\n//!\n//! Because interrupts can happen at any time, it is important that interrupt handlers do not use\n//! any mutex whatsoever, unless interrupts are disabled before locking the mutex and re-enabled\n//! after unlocking it.\n//! Unfortunately, waking up a [`Waker`] might (and often does) lock a mutex. For this reasons,\n//! when an interrupt happens we only queue the corresponding waker, and wakers are only actually\n//! woken up when you later call [`process_wakers`].\n//! It is expected that [`process_wakers`] gets called by the tasks executor.\n//!\n//! Note that this API is racy. Once a `Waker` has been woken up, it gets discarded and needs to\n//! be registered again. It is possible that an interrupt gets triggered between the discard and\n//! the re-registration.\n//!\n//! This is not considered to be a problem, as hardware normally lets you know why an interrupt\n//! has happened and/or requires you to notify the hardware when you processed an interrupt before\n//! the next one can be issued. By re-registering a `Waker` before looking for the interrupt\n//! reason, there is no risk of losing information.\n//!\n\nuse crate::arch::x86_64::apic::local;\n\nuse core::{\n    arch::asm,\n    convert::TryFrom as _,\n    fmt,\n    sync::atomic::{AtomicBool, Ordering},\n    task::Waker,\n};\nuse crossbeam_queue::ArrayQueue;\nuse futures::task::AtomicWaker;\nuse x86_64::structures::idt;\n\n/// Reserves an interrupt in the table.\n///\n/// `min_vector` is the minimum desired interrupt vector.\n/// When two interrupts are ready to be served at the same time, the one with the highest\n/// interrupt vector gets served in priority. As such, the value passed to this function\n/// represents a value of importance of the interrupt.\n///\n/// > **Note**: The values passed as parameter to this function have no meaning in the absolute\n/// >           and only make sense relative to each other. This API is far from ideal, but\n/// >           considering that this method isn't publicly exposed, one can simply search the\n/// >           source code for all occurrences of [`reserve_any_vector`] and compare the values.\n///\npub fn reserve_any_vector(min_vector: u8) -> Result<ReservedInterruptVector, ReserveErr> {\n    // TODO: maybe we should rotate the reservations, so that de-allocated vectors\n    // don't get immediately reused\n    for (n, reservation) in RESERVATIONS\n        .iter()\n        .enumerate()\n        .skip(usize::from(min_vector.saturating_sub(32)))\n    {\n        let was_reserved = reservation.swap(true, Ordering::Relaxed);\n        if !was_reserved {\n            return Ok(ReservedInterruptVector {\n                interrupt: u8::try_from(n + 32).unwrap(),\n            });\n        }\n    }\n\n    Err(ReserveErr::Full)\n}\n\n/// Represents control over an interrupt vector.\npub struct ReservedInterruptVector {\n    interrupt: u8,\n}\n\n/// Error returned by [`reserve_any_vector`].\n#[derive(Debug, derive_more::Display)]\npub enum ReserveErr {\n    /// No free interrupt vector available.\n    Full,\n}\n\n/// Wake up all the wakers that have been marked as ready by all the interrupt(s) that have\n/// happened since the last call to this function.\npub fn process_wakers() {\n    while let Some(waker) = WAKERS_QUEUE.pop() {\n        waker.wake();\n    }\n}\n\n/// Loads the global IDT on the local processor and enables interrupts.\n///\n/// Has to be called once per CPU.\n///\n/// Before this is called, the waker passed to [`ReservedInterruptVector::register_waker`] will\n/// never work.\npub fn load_idt() {\n    IDT.load();\n    x86_64::instructions::interrupts::enable();\n}\n\nimpl ReservedInterruptVector {\n    /// Returns the interrupt vector number that is reserved.\n    pub fn interrupt_num(&self) -> u8 {\n        self.interrupt\n    }\n\n    /// Registers a `Waker` to wake up when the interrupt happens.\n    ///\n    /// Only the latest registered `Waker` will be waken up.\n    ///\n    /// > **Note**: It is possible for the waker to be waken up spuriously.\n    // TODO: talk about masking interrupts; is it possible for interrupts to be \"absorbed\"\n    // and never get delivered?\n    pub fn register_waker(&self, waker: &Waker) {\n        debug_assert!(self.interrupt >= 32);\n        WAKERS[usize::from(self.interrupt - 32)].register(waker);\n    }\n}\n\nimpl fmt::Debug for ReservedInterruptVector {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_tuple(\"ReservedInterruptVector\")\n            .field(&self.interrupt)\n            .finish()\n    }\n}\n\nimpl Drop for ReservedInterruptVector {\n    fn drop(&mut self) {\n        // TODO: should we actually unreserve interrupts? it means that it could later be\n        //       re-registered, and spurious interrupts triggered\n        let _was_reserved =\n            RESERVATIONS[usize::from(self.interrupt - 32)].swap(false, Ordering::Relaxed);\n        debug_assert!(_was_reserved);\n    }\n}\n\nlazy_static::lazy_static! {\n    /// When an interrupt happens, we push the corresponding waker here. This list is emptied by\n    /// [`process_wakers`]\n    static ref WAKERS_QUEUE: ArrayQueue<Waker> = ArrayQueue::new(512);\n\n    /// Table read by the hardware in order to determine what to do when an interrupt happens.\n    static ref IDT: idt::InterruptDescriptorTable = {\n        let mut idt = idt::InterruptDescriptorTable::new();\n\n        // We first set the first 32 interrupts.\n        idt[0].set_handler_fn(int0).disable_interrupts(false);\n        idt[1].set_handler_fn(int1).disable_interrupts(false);\n        idt[2].set_handler_fn(int2).disable_interrupts(false);\n        idt[3].set_handler_fn(int3).disable_interrupts(false);\n        idt[4].set_handler_fn(int4).disable_interrupts(false);\n        idt[5].set_handler_fn(int5).disable_interrupts(false);\n        idt[6].set_handler_fn(int6).disable_interrupts(false);\n        idt[7].set_handler_fn(int7).disable_interrupts(false);\n        idt.double_fault.set_handler_fn(int8).disable_interrupts(false);\n        idt[9].set_handler_fn(int9).disable_interrupts(false);\n        idt.invalid_tss.set_handler_fn(int10).disable_interrupts(false);\n        idt.segment_not_present.set_handler_fn(int11).disable_interrupts(false);\n        idt.stack_segment_fault.set_handler_fn(int12).disable_interrupts(false);\n        idt.general_protection_fault.set_handler_fn(int13).disable_interrupts(false);\n        idt.page_fault.set_handler_fn(int14).disable_interrupts(false);\n        // 15 is reserved\n        idt[16].set_handler_fn(int16).disable_interrupts(false);\n        idt.alignment_check.set_handler_fn(int17).disable_interrupts(false);\n        idt.machine_check.set_handler_fn(int18).disable_interrupts(false);\n        idt[19].set_handler_fn(int19).disable_interrupts(false);\n        idt[20].set_handler_fn(int20).disable_interrupts(false);\n        // 21 is reserved\n        // 22 is reserved\n        // 23 is reserved\n        // 24 is reserved\n        // 25 is reserved\n        // 26 is reserved\n        // 27 is reserved\n        // 28 is reserved\n        // 29 is reserved\n        idt.security_exception.set_handler_fn(int30).disable_interrupts(false);\n        // 31 is reserved\n\n        macro_rules! set_entry {\n            ($idt:ident[$n:expr]) => {{\n                set_entry!($idt[$n], $n);\n            }};\n            ($entry:expr, $n:expr) => {{\n                extern \"x86-interrupt\" fn handler(_: idt::InterruptStackFrame) {\n                    // Because interrupts can happen at any time, it is important the code below\n                    // doesn't lock any mutex.\n                    if let Some(waker) = WAKERS[$n - 32].take() {\n                        // TODO: what if queue is legitimately full?\n                        WAKERS_QUEUE.push(waker).unwrap();\n                    }\n\n                    unsafe { local::end_of_interrupt(); }\n                }\n                $entry.set_handler_fn(handler);\n            }};\n        }\n\n        set_entry!(idt[32]);\n        set_entry!(idt[33]);\n        set_entry!(idt[34]);\n        set_entry!(idt[35]);\n        set_entry!(idt[36]);\n        set_entry!(idt[37]);\n        set_entry!(idt[38]);\n        set_entry!(idt[39]);\n        set_entry!(idt[40]);\n        set_entry!(idt[41]);\n        set_entry!(idt[42]);\n        set_entry!(idt[43]);\n        set_entry!(idt[44]);\n        set_entry!(idt[45]);\n        set_entry!(idt[46]);\n        set_entry!(idt[47]);\n        set_entry!(idt[48]);\n        set_entry!(idt[49]);\n        set_entry!(idt[50]);\n        set_entry!(idt[51]);\n        set_entry!(idt[52]);\n        set_entry!(idt[53]);\n        set_entry!(idt[54]);\n        set_entry!(idt[55]);\n        set_entry!(idt[56]);\n        set_entry!(idt[57]);\n        set_entry!(idt[58]);\n        set_entry!(idt[59]);\n        set_entry!(idt[60]);\n        set_entry!(idt[61]);\n        set_entry!(idt[62]);\n        set_entry!(idt[63]);\n        set_entry!(idt[64]);\n        set_entry!(idt[65]);\n        set_entry!(idt[66]);\n        set_entry!(idt[67]);\n        set_entry!(idt[68]);\n        set_entry!(idt[69]);\n        set_entry!(idt[70]);\n        set_entry!(idt[71]);\n        set_entry!(idt[72]);\n        set_entry!(idt[73]);\n        set_entry!(idt[74]);\n        set_entry!(idt[75]);\n        set_entry!(idt[76]);\n        set_entry!(idt[77]);\n        set_entry!(idt[78]);\n        set_entry!(idt[79]);\n        set_entry!(idt[80]);\n        set_entry!(idt[81]);\n        set_entry!(idt[82]);\n        set_entry!(idt[83]);\n        set_entry!(idt[84]);\n        set_entry!(idt[85]);\n        set_entry!(idt[86]);\n        set_entry!(idt[87]);\n        set_entry!(idt[88]);\n        set_entry!(idt[89]);\n        set_entry!(idt[90]);\n        set_entry!(idt[91]);\n        set_entry!(idt[92]);\n        set_entry!(idt[93]);\n        set_entry!(idt[94]);\n        set_entry!(idt[95]);\n        set_entry!(idt[96]);\n        set_entry!(idt[97]);\n        set_entry!(idt[98]);\n        set_entry!(idt[99]);\n        set_entry!(idt[100]);\n        set_entry!(idt[101]);\n        set_entry!(idt[102]);\n        set_entry!(idt[103]);\n        set_entry!(idt[104]);\n        set_entry!(idt[105]);\n        set_entry!(idt[106]);\n        set_entry!(idt[107]);\n        set_entry!(idt[108]);\n        set_entry!(idt[109]);\n        set_entry!(idt[110]);\n        set_entry!(idt[111]);\n        set_entry!(idt[112]);\n        set_entry!(idt[113]);\n        set_entry!(idt[114]);\n        set_entry!(idt[115]);\n        set_entry!(idt[116]);\n        set_entry!(idt[117]);\n        set_entry!(idt[118]);\n        set_entry!(idt[119]);\n        set_entry!(idt[120]);\n        set_entry!(idt[121]);\n        set_entry!(idt[122]);\n        set_entry!(idt[123]);\n        set_entry!(idt[124]);\n        set_entry!(idt[125]);\n        set_entry!(idt[126]);\n        set_entry!(idt[127]);\n        set_entry!(idt[128]);\n        set_entry!(idt[129]);\n        set_entry!(idt[130]);\n        set_entry!(idt[131]);\n        set_entry!(idt[132]);\n        set_entry!(idt[133]);\n        set_entry!(idt[134]);\n        set_entry!(idt[135]);\n        set_entry!(idt[136]);\n        set_entry!(idt[137]);\n        set_entry!(idt[138]);\n        set_entry!(idt[139]);\n        set_entry!(idt[140]);\n        set_entry!(idt[141]);\n        set_entry!(idt[142]);\n        set_entry!(idt[143]);\n        set_entry!(idt[144]);\n        set_entry!(idt[145]);\n        set_entry!(idt[146]);\n        set_entry!(idt[147]);\n        set_entry!(idt[148]);\n        set_entry!(idt[149]);\n        set_entry!(idt[150]);\n        set_entry!(idt[151]);\n        set_entry!(idt[152]);\n        set_entry!(idt[153]);\n        set_entry!(idt[154]);\n        set_entry!(idt[155]);\n        set_entry!(idt[156]);\n        set_entry!(idt[157]);\n        set_entry!(idt[158]);\n        set_entry!(idt[159]);\n        set_entry!(idt[160]);\n        set_entry!(idt[161]);\n        set_entry!(idt[162]);\n        set_entry!(idt[163]);\n        set_entry!(idt[164]);\n        set_entry!(idt[165]);\n        set_entry!(idt[166]);\n        set_entry!(idt[167]);\n        set_entry!(idt[168]);\n        set_entry!(idt[169]);\n        set_entry!(idt[170]);\n        set_entry!(idt[171]);\n        set_entry!(idt[172]);\n        set_entry!(idt[173]);\n        set_entry!(idt[174]);\n        set_entry!(idt[175]);\n        set_entry!(idt[176]);\n        set_entry!(idt[177]);\n        set_entry!(idt[178]);\n        set_entry!(idt[179]);\n        set_entry!(idt[180]);\n        set_entry!(idt[181]);\n        set_entry!(idt[182]);\n        set_entry!(idt[183]);\n        set_entry!(idt[184]);\n        set_entry!(idt[185]);\n        set_entry!(idt[186]);\n        set_entry!(idt[187]);\n        set_entry!(idt[188]);\n        set_entry!(idt[189]);\n        set_entry!(idt[190]);\n        set_entry!(idt[191]);\n        set_entry!(idt[192]);\n        set_entry!(idt[193]);\n        set_entry!(idt[194]);\n        set_entry!(idt[195]);\n        set_entry!(idt[196]);\n        set_entry!(idt[197]);\n        set_entry!(idt[198]);\n        set_entry!(idt[199]);\n        set_entry!(idt[200]);\n        set_entry!(idt[201]);\n        set_entry!(idt[202]);\n        set_entry!(idt[203]);\n        set_entry!(idt[204]);\n        set_entry!(idt[205]);\n        set_entry!(idt[206]);\n        set_entry!(idt[207]);\n        set_entry!(idt[208]);\n        set_entry!(idt[209]);\n        set_entry!(idt[210]);\n        set_entry!(idt[211]);\n        set_entry!(idt[212]);\n        set_entry!(idt[213]);\n        set_entry!(idt[214]);\n        set_entry!(idt[215]);\n        set_entry!(idt[216]);\n        set_entry!(idt[217]);\n        set_entry!(idt[218]);\n        set_entry!(idt[219]);\n        set_entry!(idt[220]);\n        set_entry!(idt[221]);\n        set_entry!(idt[222]);\n        set_entry!(idt[223]);\n        set_entry!(idt[224]);\n        set_entry!(idt[225]);\n        set_entry!(idt[226]);\n        set_entry!(idt[227]);\n        set_entry!(idt[228]);\n        set_entry!(idt[229]);\n        set_entry!(idt[230]);\n        set_entry!(idt[231]);\n        set_entry!(idt[232]);\n        set_entry!(idt[233]);\n        set_entry!(idt[234]);\n        set_entry!(idt[235]);\n        set_entry!(idt[236]);\n        set_entry!(idt[237]);\n        set_entry!(idt[238]);\n        set_entry!(idt[239]);\n        set_entry!(idt[240]);\n        set_entry!(idt[241]);\n        set_entry!(idt[242]);\n        set_entry!(idt[243]);\n        set_entry!(idt[244]);\n        set_entry!(idt[245]);\n        set_entry!(idt[246]);\n        set_entry!(idt[247]);\n        set_entry!(idt[248]);\n        set_entry!(idt[249]);\n        set_entry!(idt[250]);\n        set_entry!(idt[251]);\n        set_entry!(idt[252]);\n        set_entry!(idt[253]);\n        set_entry!(idt[254]);\n        set_entry!(idt[255]);\n\n        idt\n    };\n}\n\n// TODO: properly document all interrupts\n\nmacro_rules! interrupt_panic {\n    ($msg:expr, $frame:expr) => {\n        panic!(\n            \"Exception: {} at 0x{:x}\",\n            $msg,\n            $frame.instruction_pointer.as_u64()\n        )\n    };\n}\n\nextern \"x86-interrupt\" fn int0(frame: idt::InterruptStackFrame) {\n    interrupt_panic!(\"Division by zero\", frame);\n}\n\nextern \"x86-interrupt\" fn int1(_frame: idt::InterruptStackFrame) {\n    let dr0: u64;\n    let dr1: u64;\n    let dr2: u64;\n    let dr3: u64;\n    let dr6: u64;\n    let dr7: u64;\n\n    unsafe {\n        asm!(\"mov {}, dr0\", out(reg) dr0, options(nomem, nostack, preserves_flags));\n        asm!(\"mov {}, dr1\", out(reg) dr1, options(nomem, nostack, preserves_flags));\n        asm!(\"mov {}, dr2\", out(reg) dr2, options(nomem, nostack, preserves_flags));\n        asm!(\"mov {}, dr3\", out(reg) dr3, options(nomem, nostack, preserves_flags));\n        asm!(\"mov {}, dr6\", out(reg) dr6, options(nomem, nostack, preserves_flags));\n        asm!(\"mov {}, dr7\", out(reg) dr7, options(nomem, nostack, preserves_flags));\n    }\n\n    panic!(\n        r#\"Debug interrupt\nDR0 = 0x{:016x} ; DR1 = 0x{:016x}\nDR2 = 0x{:016x} ; DR3 = 0x{:016x}\nDR6 = 0x{:016x}\nDR7 = 0x{:016x}\n\"#,\n        dr0, dr1, dr2, dr3, dr6, dr7\n    )\n}\n\nextern \"x86-interrupt\" fn int2(frame: idt::InterruptStackFrame) {\n    interrupt_panic!(\"NMI\", frame); // TODO: there might be additional trickery here\n}\n\nextern \"x86-interrupt\" fn int3(frame: idt::InterruptStackFrame) {\n    interrupt_panic!(\"Breakpoint\", frame);\n}\n\nextern \"x86-interrupt\" fn int4(frame: idt::InterruptStackFrame) {\n    interrupt_panic!(\"Overflow\", frame);\n}\n\nextern \"x86-interrupt\" fn int5(frame: idt::InterruptStackFrame) {\n    interrupt_panic!(\"Bounds\", frame);\n}\n\nextern \"x86-interrupt\" fn int6(frame: idt::InterruptStackFrame) {\n    interrupt_panic!(\"Invalid opcode\", frame);\n}\n\nextern \"x86-interrupt\" fn int7(frame: idt::InterruptStackFrame) {\n    interrupt_panic!(\"Coprocessor not available\", frame);\n}\n\nextern \"x86-interrupt\" fn int8(_frame: idt::InterruptStackFrame, _: u64) -> ! {\n    // A double fault happens when an exception happens while an exception was already\n    // being handled.\n    //\n    // We don't panic, as it's likely that it's the panic handler that trigger this.\n    x86_64::instructions::interrupts::disable();\n    x86_64::instructions::bochs_breakpoint();\n    loop {\n        x86_64::instructions::hlt();\n    }\n}\n\nextern \"x86-interrupt\" fn int9(frame: idt::InterruptStackFrame) {\n    // Since the 486, this exception is instead a GPF.\n    interrupt_panic!(\"Coprocessor segment overrun\", frame);\n}\n\nextern \"x86-interrupt\" fn int10(frame: idt::InterruptStackFrame, _: u64) {\n    interrupt_panic!(\"Invalid TSS\", frame);\n}\n\nextern \"x86-interrupt\" fn int11(frame: idt::InterruptStackFrame, _: u64) {\n    interrupt_panic!(\"Segment not present\", frame);\n}\n\nextern \"x86-interrupt\" fn int12(frame: idt::InterruptStackFrame, _: u64) {\n    interrupt_panic!(\"Stack segment fault\", frame);\n}\n\nextern \"x86-interrupt\" fn int13(frame: idt::InterruptStackFrame, _: u64) {\n    interrupt_panic!(\"General protection fault\", frame);\n}\n\nextern \"x86-interrupt\" fn int14(frame: idt::InterruptStackFrame, _: idt::PageFaultErrorCode) {\n    interrupt_panic!(\"Page fault\", frame);\n}\n\nextern \"x86-interrupt\" fn int16(frame: idt::InterruptStackFrame) {\n    interrupt_panic!(\"x87 exception\", frame);\n}\n\nextern \"x86-interrupt\" fn int17(frame: idt::InterruptStackFrame, _: u64) {\n    interrupt_panic!(\"Alignment error\", frame);\n}\n\nextern \"x86-interrupt\" fn int18(frame: idt::InterruptStackFrame) -> ! {\n    interrupt_panic!(\"Machine check\", frame);\n}\n\nextern \"x86-interrupt\" fn int19(frame: idt::InterruptStackFrame) {\n    interrupt_panic!(\"SIMD error\", frame);\n}\n\nextern \"x86-interrupt\" fn int20(frame: idt::InterruptStackFrame) {\n    interrupt_panic!(\"Virtualization exception\", frame);\n}\n\nextern \"x86-interrupt\" fn int30(frame: idt::InterruptStackFrame, _: u64) {\n    interrupt_panic!(\"Security exception\", frame);\n}\n\n/// For each interrupt vector, a [`Waker`](core::task::Waker) that must be waken up when that\n/// interrupt happens.\nstatic WAKERS: [AtomicWaker; 256 - 32] = [\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n    AtomicWaker::new(),\n];\n\n/// For each interrupt vector, a boolean indicating whether or not this vector is reserved.\n///\n/// Note that this could be a smaller array by grouping all the booleans into bytes, for this\n/// is a risky optimization with a very low reward potential.\nstatic RESERVATIONS: [AtomicBool; 256 - 32] = [\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n    AtomicBool::new(false),\n];\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/panic.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Panic handling code.\n\nuse crate::klog::KLogger;\n\nuse core::fmt::Write as _;\n\npub static PANIC_LOGGER: KLogger = KLogger::disabled();\n\n#[cfg(not(any(test, doc, doctest)))]\n#[panic_handler]\nfn panic(panic_info: &core::panic::PanicInfo) -> ! {\n    let mut printer = PANIC_LOGGER.panic_printer();\n    let _ = writeln!(printer, \"Kernel panic!\");\n    let _ = writeln!(printer, \"{}\", panic_info);\n    let _ = writeln!(printer, \"\");\n    drop(printer);\n\n    // Freeze forever.\n    loop {\n        x86_64::instructions::interrupts::disable();\n        x86_64::instructions::hlt();\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64/pit.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Programmable Interrupt Timer (PIT)\n//!\n//! The PIT is a chip that allows raising an Interrupt ReQuest (IRQ) after a certain time has\n//! elapsed. This IRQ is propagated to [the I/O APIC], which then delivers an interrupt to one\n//! or more processors.\n//!\n//! In order to determine which IRQ is raised, one need to look at the interrupt source overrides\n//! of the ACPI tables for an entry corresponding to ISA IRQ 0.\n//!\n//! # About performances\n//!\n//! The implementation below is very inefficient and very restrictive. The PIT in general\n//! should only be used in limited circumstances and not under regular load.\n//!\n\nuse crate::arch::x86_64::{\n    apic::{io_apics, local},\n    interrupts,\n};\n\nuse alloc::sync::Arc;\nuse core::{\n    convert::TryFrom as _,\n    future::Future,\n    mem,\n    pin::Pin,\n    sync::atomic::{AtomicBool, Ordering},\n    task::{Context, Poll, Waker},\n    time::Duration,\n};\nuse futures::task::ArcWake;\nuse x86_64::structures::port::PortWrite as _;\n\npub struct PitControl {\n    /// Reservation for an interrupt vector in the table.\n    interrupt_vector: interrupts::ReservedInterruptVector,\n}\n\n/// Future created with [`PitControl::timer`].\npub struct PitFuture<'a> {\n    pit: &'a mut PitControl,\n\n    /// If `true`, then the PIT interrupt has fired and we must decrease the number of\n    /// ticks the next time we're polled.\n    raised: Arc<AtomicBool>,\n\n    /// We must first wait this value times `u16::max_value()` ticks.\n    num_major_ticks: u128,\n\n    /// After [`PitFuture::num_major_ticks`] is zero, we must wait an additional\n    /// number of ticks indicated below.\n    minor_modulus: u16,\n}\n\n/// Initializes the PIT.\n///\n/// There should only ever be one [`PitControl`] alive at any given point in time. Creating\n/// multiple [`PitControl`] is safe, but will lead to logic errors.\npub fn init_pit(\n    local_apics: &local::LocalApicsControl,\n    io_apics: &mut io_apics::IoApicsControl,\n) -> PitControl {\n    let interrupt_vector = interrupts::reserve_any_vector(224).unwrap();\n    io_apics.isa_irq(0).unwrap().set_destination(\n        local_apics.current_apic_id(), // TODO: instead dispatch to any CPU?\n        interrupt_vector.interrupt_num(),\n    );\n\n    PitControl { interrupt_vector }\n}\n\nimpl PitControl {\n    /// Creates a new future that will trigger when the given amount of time has elapsed.\n    ///\n    /// The implementation only allows one timer at a time, thus the future mutably borrows\n    /// the PIT.\n    ///\n    /// You must call [`interrupts::load_idt`] on at least one CPU for the timer to work.\n    pub fn timer(&mut self, after: Duration) -> PitFuture {\n        // Calculate the number of ticks that we will for the PIT to produce before the duration\n        // has elapsed.\n        // TODO: probably rounding errors below\n        const TICKS_PER_SEC: u64 = 1_193_182;\n        const NANOS_PER_TICK: u128 = 1 + 1_000_000_000 / TICKS_PER_SEC as u128;\n        let nanos = after.as_nanos();\n        let num_ticks = if nanos == 0 {\n            0\n        } else {\n            1 + after.as_nanos() / NANOS_PER_TICK\n        };\n\n        // The PIT only accepts a 16bits number of ticks, and `num_ticks` probably won't fit\n        // in 16bits. We therefore do some euclidian division and remainder.\n        // The `Future` will need to be awakened `num_major_ticks` times.\n        let num_major_ticks = num_ticks / u128::from(u16::max_value());\n        let minor_modulus = u16::try_from(num_ticks % u128::from(u16::max_value())).unwrap();\n\n        PitFuture {\n            pit: self,\n            raised: Arc::new(AtomicBool::new(true)),\n            num_major_ticks,\n            minor_modulus,\n        }\n    }\n}\n\n// TODO: there are fundamental design questions here:\n// - if an interrupt is not delivered, then the entire logic fails\n// - if a spurious interrupt is delivered, same\n// we need to make sure that interrupts cannot be missed\n\nimpl<'a> Future for PitFuture<'a> {\n    type Output = ();\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {\n        if !self.raised.swap(false, Ordering::Relaxed) {\n            return Poll::Pending;\n        }\n\n        let num_ticks = if self.num_major_ticks == 0 {\n            mem::replace(&mut self.minor_modulus, 0)\n        } else {\n            self.num_major_ticks -= 1;\n            u16::max_value()\n        };\n\n        if num_ticks == 0 {\n            return Poll::Ready(());\n        }\n\n        // TODO: rather than register a Waker, put an implementation of Future that is raised\n        // only when an interrupt has actually triggered\n        self.pit\n            .interrupt_vector\n            .register_waker(&futures::task::waker(Arc::new(RaisingArc {\n                inner: cx.waker().clone(),\n                raised: self.raised.clone(),\n            })));\n\n        channel0_one_shot(num_ticks);\n        Poll::Pending\n    }\n}\n\n/// Instructs the PIT to trigger an IRQ0 after the specified number of ticks have elapsed.\n/// The tick frequency is approximately equal to 1.193182 MHz.\nfn channel0_one_shot(ticks: u16) {\n    unsafe {\n        // Set channel 0 to \"interrupt on terminal count\" mode and prepare for writing the value.\n        u8::write_to_port(0x43, 0b00110000);\n\n        let bytes = ticks.to_le_bytes();\n        u8::write_to_port(0x40, bytes[0]);\n        u8::write_to_port(0x40, bytes[1]);\n    }\n}\n\n/// Implementation of `ArcWake` that additionally sets `raised` to true when it is awakened.\nstruct RaisingArc {\n    inner: Waker,\n    raised: Arc<AtomicBool>,\n}\n\nimpl ArcWake for RaisingArc {\n    fn wake_by_ref(arc_self: &Arc<Self>) {\n        let _was_raised = arc_self.raised.swap(true, Ordering::Relaxed);\n        // If `_was_raised` is true here, then we will miss a interrupt. We prefer to panic\n        // rather than miss an interrupt.\n        assert!(!_was_raised);\n        arc_self.inner.wake_by_ref();\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch/x86_64.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::arch::PortErr;\n\nuse alloc::{boxed::Box, sync::Arc, vec::Vec};\nuse core::{\n    convert::TryFrom as _,\n    fmt::Write as _,\n    future::Future,\n    iter,\n    num::NonZeroU32,\n    ops::Range,\n    pin::Pin,\n    sync::atomic,\n    task::{Context, Poll, Waker},\n    time::Duration,\n};\nuse futures::channel::oneshot;\nuse hashbrown::HashMap;\nuse redshirt_kernel_log_interface::ffi::{\n    FramebufferFormat, FramebufferInfo, KernelLogMethod, UartAccess, UartInfo,\n};\nuse spinning_top::Spinlock;\nuse x86_64::structures::port::{PortRead as _, PortWrite as _};\n\nuse super::PlatformSpecific;\n\n// Modules that are used by the macro must be public, but their content isn't meant to be used\n// apart from the macro.\n#[macro_use]\n#[doc(hidden)]\npub mod boot;\n#[doc(hidden)]\npub mod gdt;\n\nmod acpi;\nmod ap_boot;\nmod apic;\nmod executor;\nmod interrupts;\nmod panic;\nmod pit;\n\nconst DEFAULT_LOG_METHOD: KernelLogMethod = KernelLogMethod {\n    enabled: true,\n    framebuffer: Some(FramebufferInfo {\n        address: 0xb8000,\n        width: 80,\n        height: 25,\n        pitch: 160,\n        bytes_per_character: 2,\n        format: FramebufferFormat::Text,\n    }),\n    uart: None,\n};\n\n/// Called by `boot.rs` after basic set up has been performed.\n///\n/// When this function is called, a stack has been set up and as much memory space as possible has\n/// been identity-mapped (i.e. the virtual memory is equal to the physical memory).\n///\n/// Since the kernel was loaded by a multiboot2 bootloader, the first parameter is the memory\n/// address of the multiboot header.\n///\n/// # Safety\n///\n/// `multiboot_info` must be a valid memory address that contains valid information.\n///\n#[doc(hidden)]\n// TODO: use `Future<Output = !>` once stable\npub unsafe fn entry_point_step3<\n    F: Fn(Pin<Arc<super::PlatformSpecific>>) -> C + Clone + Send + 'static,\n    C: Future,\n>(\n    multiboot_info: usize,\n    run: F,\n) -> ! {\n    panic::PANIC_LOGGER.set_method(DEFAULT_LOG_METHOD);\n\n    let multiboot_info = multiboot2::BootInformation::load(\n        multiboot_info as *const multiboot2::BootInformationHeader,\n    )\n    .unwrap();\n\n    // Initialization of the memory allocator.\n    let mut ap_boot_alloc = {\n        let mut ap_boot_alloc = None;\n        // The associated processors (AP) boot code requires its own allocator. We take all\n        // the free ranges reported by the multiboot header and pass them to the `ap_boot`\n        // allocator initialization code so that it can filter out one that it needs.\n        let remaining_ranges = ap_boot::filter_build_ap_boot_alloc(\n            find_free_memory_ranges(&multiboot_info),\n            &mut ap_boot_alloc,\n        );\n\n        // Pass the free remaining ranges to the main allocator of the kernel.\n        crate::mem_alloc::initialize(remaining_ranges);\n\n        match ap_boot_alloc {\n            Some(b) => b,\n            None => panic!(\"Couldn't find free memory range for the AP allocator\"),\n        }\n    };\n\n    // Now that we have a memory allocator, initialize the logging system.\n    panic::PANIC_LOGGER.set_method(\n        if let Some(Ok(fb_info)) = multiboot_info.framebuffer_tag() {\n            if let Ok(ty) = fb_info.buffer_type() {\n                KernelLogMethod {\n                    enabled: true,\n                    framebuffer: Some(FramebufferInfo {\n                        address: fb_info.address(),\n                        width: fb_info.width(),\n                        height: fb_info.height(),\n                        pitch: u64::from(fb_info.pitch()),\n                        bytes_per_character: fb_info.bpp() / 8,\n                        format: match ty {\n                            multiboot2::FramebufferType::Text => FramebufferFormat::Text,\n                            multiboot2::FramebufferType::Indexed { .. } => FramebufferFormat::Rgb {\n                                // FIXME: that is completely wrong\n                                red_size: 8,\n                                red_position: 0,\n                                green_size: 8,\n                                green_position: 16,\n                                blue_size: 8,\n                                blue_position: 24,\n                            },\n                            multiboot2::FramebufferType::RGB { red, green, blue } => {\n                                FramebufferFormat::Rgb {\n                                    red_size: red.size,\n                                    red_position: red.position,\n                                    green_size: green.size,\n                                    green_position: green.position,\n                                    blue_size: blue.size,\n                                    blue_position: blue.position,\n                                }\n                            }\n                        },\n                    }),\n                    // TODO: COM port should be discovered through the ACPI tables instead of hardcoded\n                    uart: init_com(0x3f8).ok(),\n                }\n            } else {\n                DEFAULT_LOG_METHOD.clone()\n            }\n        } else {\n            DEFAULT_LOG_METHOD.clone()\n        },\n    );\n\n    writeln!(\n        panic::PANIC_LOGGER.log_printer(),\n        \"[boot] basic initialization ok\"\n    )\n    .unwrap();\n\n    // The first thing that gets executed when a x86 or x86_64 machine starts up is the\n    // motherboard's firmware. Before giving control to the operating system, this firmware writes\n    // into memory a set of data called the **ACPI tables**.\n    // It then (indirectly) passes the memory address of this table to the operating system. This\n    // is part of [the UEFI standard](https://en.wikipedia.org/wiki/UEFI).\n    //\n    // However, this code is not loaded directly by the operating system but rather by a\n    // bootloader. This bootloader must save the information about the ACPI tables and propagate it\n    // as part of the multiboot2 header passed to the operating system.\n    // TODO: remove these tables from the memory ranges used as heap? `acpi_tables` is a copy of\n    // the table, so once we are past this line there's no problem anymore. But in theory,\n    // the `acpi_tables` variable might allocate over the actual ACPI tables.\n    let acpi_tables = acpi::parse_acpi_tables(&multiboot_info);\n\n    // This function is only executed by the main processor of the machine, called the **boot\n    // processor**. The other processors are called the **associated processors** and must be\n    // manually started.\n    let application_processors = acpi_tables\n        .platform_info()\n        .unwrap()\n        .processor_info\n        .unwrap()\n        .application_processors;\n\n    // The ACPI tables indicate us information about how to interface with the I/O APICs.\n    // We use this information and initialize the I/O APICs.\n    let mut io_apics = match &acpi_tables.platform_info().ok().map(|i| i.interrupt_model) {\n        Some(::acpi::platform::interrupt::InterruptModel::Apic(apic)) => {\n            // The PIC is the legacy equivalent of I/O APICs.\n            apic::pic::init_and_disable_pic();\n            apic::io_apics::init_from_acpi(apic)\n        }\n        Some(_) => panic!(\"Legacy PIC mode not supported\"),\n        None => panic!(\"Interrupt model ACPI table not found\"),\n    };\n\n    // We then initialize the local APIC.\n    // `Box::leak` gives us a `&'static` reference to the object.\n    let local_apics = Box::leak(Box::new(apic::local::init()));\n    local_apics.init_local();\n\n    // Initialize an object that can execute futures between CPUs.\n    let executor = Box::leak(Box::new(executor::Executor::new(&*local_apics)));\n\n    // The PIT is an old mechanism for triggering interrupts after a certain delay.\n    // Despite being old, it is still present on all hardware.\n    let mut pit = pit::init_pit(&*local_apics, &mut io_apics);\n\n    // Initialize interrupts so that all the elements initialize above function properly.\n    // TODO: make this more fool-proof\n    interrupts::load_idt();\n\n    // Initialize the timers state machine.\n    // This allows us to create `Future`s that resolve after a certain amount of time has passed.\n    let timers = executor.block_on(apic::timers::init(\n        local_apics,\n        &mut pit,\n        NonZeroU32::new(u32::try_from(application_processors.len()).unwrap() + 1).unwrap(),\n    ));\n\n    // We no longer need the `pit`. Since we overwrite all the IRQs below, and the PIT uses an IRQ,\n    // the PIT will stop working. We destroy it to make sure that we're not going to attempt to\n    // use it.\n    // TODO: add some safety mechanism regarding overwriting IRQs? ^\n    drop(pit);\n\n    // Considering that it is quite complicated to determine which IRQ a PCI device is going to\n    // use (it requires parsing and executing AML tables), we instead go with the strategy of\n    // redirecting all IRQs to a single interrupt vector. This single interrupt vector, when\n    // triggered, notifies all the components that were waiting for a PCI interrupt.\n    // TODO: make this better ^\n    let pci_interrupt_vector = interrupts::reserve_any_vector(40).unwrap();\n    for irq in io_apics.irqs().collect::<Vec<_>>() {\n        io_apics.irq(irq).unwrap().set_destination(\n            local_apics.current_apic_id(),\n            pci_interrupt_vector.interrupt_num(),\n        );\n    }\n\n    // This Vec will contain one `oneshort::Sender<Arc<Kernel>>` for each associated processor\n    // that has been started. Once the kernel is initialized, we send a reference-counted copy of\n    // it to each sender.\n    let mut barrier_channels = Vec::with_capacity(application_processors.len());\n\n    writeln!(\n        panic::PANIC_LOGGER.log_printer(),\n        \"[boot] initializing associated processors\"\n    )\n    .unwrap();\n    for ap in application_processors.iter() {\n        debug_assert!(ap.is_ap);\n        // It is possible for some associated processors to be in a disabled state, in which case\n        // they **must not** be started. This is generally the case of defective processors.\n        if ap.state != ::acpi::platform::ProcessorState::WaitingForSipi {\n            continue;\n        }\n\n        let (plat_spec_tx, plat_spec_rx) = oneshot::channel::<Pin<Arc<PlatformSpecific>>>();\n\n        let ap_boot_result = ap_boot::boot_associated_processor(\n            &mut ap_boot_alloc,\n            &*executor,\n            &*local_apics,\n            &timers,\n            apic::ApicId::from_unchecked(u8::try_from(ap.local_apic_id).unwrap()),\n            {\n                let executor = &*executor;\n                let run = run.clone();\n                move || {\n                    executor.block_on(async move {\n                        let platform_specific = plat_spec_rx.await.unwrap();\n                        let _ = run(platform_specific).await;\n                        unreachable!() // TODO: remove after `!` is stable\n                    })\n                }\n            },\n        );\n\n        match ap_boot_result {\n            Ok(()) => barrier_channels.push(plat_spec_tx),\n            Err(err) => writeln!(\n                panic::PANIC_LOGGER.log_printer(),\n                \"[boot] error while initializing AP#{}: {}\",\n                ap.processor_uid,\n                err\n            )\n            .unwrap(),\n        }\n    }\n\n    // Now that everything has been initialized and all the processors started, we can initialize\n    // the platform-specific object.\n    let platform_specific = {\n        /// Waker registered for `pci_interrupt_vector`. Re-registers itself automatically\n        /// whenever it is woken up.\n        struct NextIrqWaker {\n            pci_interrupt_vector: interrupts::ReservedInterruptVector,\n            next_irq_futures: Arc<\n                Spinlock<\n                    HashMap<u64, (Arc<atomic::AtomicBool>, Option<Waker>), fnv::FnvBuildHasher>,\n                >,\n            >,\n        }\n\n        impl futures::task::ArcWake for NextIrqWaker {\n            fn wake_by_ref(arc_self: &Arc<Self>) {\n                let mut next_irq_futures = arc_self.next_irq_futures.lock();\n\n                // Re-register ourselves for the next time.\n                arc_self\n                    .pci_interrupt_vector\n                    .register_waker(&futures::task::waker_ref(arc_self));\n\n                for (_, (atomic_bool, waker)) in next_irq_futures.drain() {\n                    atomic_bool.store(true, atomic::Ordering::Release);\n                    if let Some(waker) = waker {\n                        waker.wake();\n                    }\n                }\n            }\n        }\n\n        let next_irq_futures = Arc::new(Spinlock::new(Default::default()));\n\n        let waker = Arc::new(NextIrqWaker {\n            pci_interrupt_vector,\n            next_irq_futures: next_irq_futures.clone(),\n        });\n\n        waker\n            .pci_interrupt_vector\n            .register_waker(&futures::task::waker(waker.clone()));\n\n        let platform_specific = PlatformSpecificImpl {\n            timers,\n            num_cpus: NonZeroU32::new(\n                u32::try_from(barrier_channels.len())\n                    .unwrap()\n                    .checked_add(1)\n                    .unwrap(),\n            )\n            .unwrap(),\n            next_irq_futures,\n            next_next_irq_id: From::from(0),\n        };\n\n        Arc::pin(super::PlatformSpecific::from(platform_specific))\n    };\n\n    writeln!(panic::PANIC_LOGGER.log_printer(), \"[boot] boot successful\").unwrap();\n\n    // Send an `Arc<Kernel>` to the other processors so that they can run it too.\n    for tx in barrier_channels {\n        if tx.send(platform_specific.clone()).is_err() {\n            panic!(\"failed to send kernel to associated processor\");\n        }\n    }\n\n    // Start the kernel on the boot processor too.\n    // This function never returns.\n    let _ = executor.block_on(run(platform_specific));\n    unreachable!() // TODO: remove after `!` is stable\n}\n\n/// Reads the boot information and find the memory ranges that can be used as a heap.\n///\n/// # Panic\n///\n/// Panics if the information is wrong or if there isn't enough information available.\n///\nfn find_free_memory_ranges<'a>(\n    multiboot_info: &'a multiboot2::BootInformation,\n) -> impl Iterator<Item = Range<usize>> + 'a {\n    let mem_map = multiboot_info.memory_map_tag().unwrap();\n    let elf_sections = multiboot_info.elf_sections_tag();\n\n    mem_map.memory_areas().iter().filter_map(move |area| {\n        // Some parts of the memory have to be avoided, such as the kernel, non-RAM memory,\n        // RAM that might contain important information, and so on.\n        let to_avoid = {\n            // TODO: for now, the code in boot.rs only maps the first 32GiB of memory. We avoid\n            // anything above this limit\n            //let unmapped = iter::once(0x2000000000 .. u64::max_value());\n            // TODO: linked_list_allocator seems to misbehave when we use a lot of memory, so for\n            // now we restrict ourselves to the first 2GiB.\n            let unmapped = iter::once(0x80000000..u64::max_value());\n\n            // We don't want to write over the kernel that has been loaded in memory.\n            let elf = elf_sections\n                .into_iter()\n                .flat_map(|tag| tag.sections())\n                .map(|s| s.start_address()..s.end_address());\n\n            // We don't want to use the memory-mapped ROM or video memory.\n            let rom_video_ram = iter::once(0xa0000..0xfffff);\n\n            // Some areas in the first megabyte were used during the booting process. This\n            // includes the 16bits interrupt vector table and the memory used by the BIOS to keep\n            // track of its state.\n            // Note that since we have total control over the hardware there is no fundamental\n            // reason to not overwrite these areas. In practice, however, there are situations\n            // where we would like to read these information later (for example if a VBE driver\n            // wants to access the content of the video BIOS).\n            let important_info = iter::once(0..0x500).chain(iter::once(0x80000..0xa0000));\n\n            // Avoid writing over the multiboot header.\n            let multiboot = iter::once(\n                u64::try_from(multiboot_info.start_address()).unwrap()\n                    ..u64::try_from(multiboot_info.end_address()).unwrap(),\n            );\n\n            // Apart from the areas above, there are other areas that we want to avoid, in\n            // particular memory-mapped hardware. We trust the multiboot information to not\n            // include them.\n            elf.chain(rom_video_ram)\n                .chain(important_info)\n                .chain(multiboot)\n                .chain(unmapped)\n        };\n\n        let mut area_start = area.start_address();\n        let mut area_end = area.end_address();\n        debug_assert!(area_start <= area_end);\n\n        for section in to_avoid {\n            if section.start >= area_start && section.end <= area_end {\n                /*         ↓ section_start    section_end ↓\n                ==================================================\n                    ↑ area_start                      area_end ↑\n                */\n                let off_bef = section.start - area_start;\n                let off_aft = area_end - section.end;\n                if off_bef > off_aft {\n                    area_end = section.start;\n                } else {\n                    area_start = section.end;\n                }\n            } else if section.start < area_start && section.end > area_end {\n                /*    ↓ section_start             section_end ↓\n                ==================================================\n                        ↑ area_start         area_end ↑\n                */\n                // We have no memory available!\n                return None;\n            } else if section.start <= area_start && section.end > area_start {\n                /*    ↓ section_start     section_end ↓\n                ==================================================\n                        ↑ area_start                 area_end ↑\n                */\n                area_start = section.end;\n            } else if section.start < area_end && section.end >= area_end {\n                /*         ↓ section_start      section_end ↓\n                ==================================================\n                    ↑ area_start         area_end ↑\n                */\n                area_end = section.start;\n            }\n        }\n\n        let area_start = usize::try_from(area_start).unwrap();\n        let area_end = usize::try_from(area_end).unwrap();\n        Some(area_start..area_end)\n    })\n}\n\n/// Initializes a COM port for later usage. Returns a [`UartInfo`] suitable for the klogging\n/// system that will output logs to that COM port.\n///\n/// Code taken from https://wiki.osdev.org/Serial_Ports#Example_Code.\n///\n/// # Safety\n///\n/// The port must point to the base port of a valid COM interface. This function performs I/O\n/// writes which could have averse effects if done on a different ports range.\n///\nunsafe fn init_com(base_port: u16) -> Result<UartInfo, ()> {\n    u8::write_to_port(base_port + 1, 0x00);\n    u8::write_to_port(base_port + 3, 0x80);\n    u8::write_to_port(base_port + 0, 0x03);\n    u8::write_to_port(base_port + 1, 0x00);\n    u8::write_to_port(base_port + 3, 0x03);\n    u8::write_to_port(base_port + 2, 0xC7);\n    u8::write_to_port(base_port + 4, 0x0B);\n    u8::write_to_port(base_port + 4, 0x1E);\n    u8::write_to_port(base_port + 0, 0xAE);\n\n    if u8::read_from_port(base_port + 0) != 0xAE {\n        return Err(());\n    }\n\n    u8::write_to_port(base_port + 4, 0x0F);\n\n    Ok(UartInfo {\n        wait_address: UartAccess::IoPortU8(base_port + 5),\n        wait_mask: 0x20,\n        wait_compare_equal_if_ready: 0x20,\n        write_address: UartAccess::IoPortU8(base_port),\n    })\n}\n\n/// Implementation of [`PlatformSpecific`].\npub struct PlatformSpecificImpl {\n    timers: Arc<apic::timers::Timers>,\n    num_cpus: NonZeroU32,\n\n    next_next_irq_id: atomic::AtomicU64,\n    /// List of active futures waiting for the next IRQ.\n    /// Contains an `AtomicBool` to set to true when the IRQ happens, and the waker to wake up.\n    next_irq_futures:\n        Arc<Spinlock<HashMap<u64, (Arc<atomic::AtomicBool>, Option<Waker>), fnv::FnvBuildHasher>>>,\n}\n\nimpl From<PlatformSpecificImpl> for super::PlatformSpecific {\n    fn from(ps: PlatformSpecificImpl) -> Self {\n        Self(ps)\n    }\n}\n\nimpl PlatformSpecificImpl {\n    pub fn num_cpus(self: Pin<&Self>) -> NonZeroU32 {\n        self.num_cpus\n    }\n\n    pub fn monotonic_clock(self: Pin<&Self>) -> u128 {\n        self.timers.monotonic_clock().as_nanos()\n    }\n\n    pub fn timer(self: Pin<&Self>, clock_value: u128) -> TimerFuture {\n        self.timers.register_timer_at({\n            // `unwrap_or(u64::max_value())` means that any wait longer than 2^64 seconds will be\n            // clamped to 2^64 seconds. We don't expect any system to ever run for 2^64 seconds.\n            let secs = u64::try_from(clock_value / 1_000_000_000).unwrap_or(u64::max_value());\n            let nanos = u32::try_from(clock_value % 1_000_000_000).unwrap();\n            Duration::new(secs, nanos)\n        })\n    }\n\n    pub fn next_irq(self: Pin<&Self>) -> IrqFuture {\n        let done = Arc::new(atomic::AtomicBool::new(false));\n        let id = self\n            .next_next_irq_id\n            .fetch_add(1, atomic::Ordering::Relaxed);\n\n        // We register the future here, otherwise an IRQ that happens before the first time the\n        // future gets polled won't be detected.\n        self.next_irq_futures\n            .lock()\n            .insert(id, (done.clone(), None));\n\n        IrqFuture {\n            next_irq_futures: self.next_irq_futures.clone(),\n            done,\n            id,\n        }\n    }\n\n    pub fn write_log(&self, message: &str) {\n        writeln!(panic::PANIC_LOGGER.log_printer(), \"{}\", message).unwrap();\n    }\n\n    pub fn set_logger_method(&self, method: KernelLogMethod) {\n        panic::PANIC_LOGGER.set_method(method)\n    }\n\n    pub unsafe fn write_port_u8(self: Pin<&Self>, port: u32, data: u8) -> Result<(), PortErr> {\n        if let Ok(port) = u16::try_from(port) {\n            u8::write_to_port(port, data);\n            Ok(())\n        } else {\n            Err(PortErr::OutOfRange)\n        }\n    }\n\n    pub unsafe fn write_port_u16(self: Pin<&Self>, port: u32, data: u16) -> Result<(), PortErr> {\n        if let Ok(port) = u16::try_from(port) {\n            u16::write_to_port(port, data);\n            Ok(())\n        } else {\n            Err(PortErr::OutOfRange)\n        }\n    }\n\n    pub unsafe fn write_port_u32(self: Pin<&Self>, port: u32, data: u32) -> Result<(), PortErr> {\n        if let Ok(port) = u16::try_from(port) {\n            u32::write_to_port(port, data);\n            Ok(())\n        } else {\n            Err(PortErr::OutOfRange)\n        }\n    }\n\n    pub unsafe fn read_port_u8(self: Pin<&Self>, port: u32) -> Result<u8, PortErr> {\n        if let Ok(port) = u16::try_from(port) {\n            Ok(u8::read_from_port(port))\n        } else {\n            Err(PortErr::OutOfRange)\n        }\n    }\n\n    pub unsafe fn read_port_u16(self: Pin<&Self>, port: u32) -> Result<u16, PortErr> {\n        if let Ok(port) = u16::try_from(port) {\n            Ok(u16::read_from_port(port))\n        } else {\n            Err(PortErr::OutOfRange)\n        }\n    }\n\n    pub unsafe fn read_port_u32(self: Pin<&Self>, port: u32) -> Result<u32, PortErr> {\n        if let Ok(port) = u16::try_from(port) {\n            Ok(u32::read_from_port(port))\n        } else {\n            Err(PortErr::OutOfRange)\n        }\n    }\n}\n\npub type TimerFuture = apic::timers::TimerFuture;\n\npub struct IrqFuture {\n    next_irq_futures:\n        Arc<Spinlock<HashMap<u64, (Arc<atomic::AtomicBool>, Option<Waker>), fnv::FnvBuildHasher>>>,\n    done: Arc<atomic::AtomicBool>,\n    id: u64,\n}\n\nimpl Future for IrqFuture {\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {\n        if self.done.load(atomic::Ordering::SeqCst) {\n            return Poll::Ready(());\n        }\n\n        {\n            let mut next_irq_futures = self.next_irq_futures.lock();\n            let entry = match next_irq_futures.get_mut(&self.id) {\n                Some(e) => e,\n                None => {\n                    // TODO: debug_assert! instead\n                    assert!(self.done.load(atomic::Ordering::SeqCst));\n                    return Poll::Ready(());\n                }\n            };\n            if entry.1.as_ref().map_or(true, |w| !w.will_wake(cx.waker())) {\n                entry.1 = Some(cx.waker().clone());\n            }\n        }\n\n        if self.done.load(atomic::Ordering::SeqCst) {\n            Poll::Ready(())\n        } else {\n            Poll::Pending\n        }\n    }\n}\n\nimpl Drop for IrqFuture {\n    fn drop(&mut self) {\n        let mut next_irq_futures = self.next_irq_futures.lock();\n        let _ = next_irq_futures.remove(&self.id);\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/arch.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Platform-specific code and kernel entry point.\n//!\n//! This module contains all the platform-specific code of the stand-alone kernel, plus the entry\n//! point and initialization code.\n//!\n//! Its main API is a macro called `__gen_boot` whose implementation depends on the platform. This\n//! macro, when invoked, generates a bunch of items, including a function exported under the\n//! `_start`. It is the role of the user to ensure that this `_start` symbol gets executed once\n//! the kernel is loaded in memory.\n//!\n//! The initialization triggered by the `_start` function (generated by the `__gen_boot` macro)\n//! includes:\n//!\n//! - Initializing all CPU cores.\n//! - Setting up a stack for each CPU core.\n//! - Setting up the memory allocator in the [`mem_alloc`](crate::mem_alloc) module.\n//! - Setting up a panic handler.\n//!\n//! The `__gen_boot` macro must be passed a function whose signature must be the following:\n//!\n//! ```\n//! async fn(platform_specific: Pin<Arc<arch::PlatformSpecific>>) -> !;\n//! ```\n//!\n//! After the initialization has been performed, this function gets called once per CPU and gets\n//! passed an implementation of the [`PlatformSpecific`] trait. If the machine has for example\n//! four CPUs, the function gets called four times, once on each CPU.\n\nuse core::{\n    fmt,\n    future::Future,\n    num::NonZeroU32,\n    pin::Pin,\n    task::{Context, Poll},\n};\nuse redshirt_kernel_log_interface::ffi::KernelLogMethod;\n\n#[macro_use]\n#[cfg(any(target_arch = \"arm\", target_arch = \"aarch64\"))]\n#[doc(hidden)]\npub mod arm;\n#[macro_use]\n#[cfg(any(target_arch = \"riscv32\", target_arch = \"riscv64\"))]\n#[doc(hidden)]\npub mod riscv;\n#[macro_use]\n#[cfg(target_arch = \"x86_64\")]\n#[doc(hidden)]\npub mod x86_64;\n\n#[cfg(any(target_arch = \"arm\", target_arch = \"aarch64\"))]\nuse self::arm as plat;\n#[cfg(any(target_arch = \"riscv32\", target_arch = \"riscv64\"))]\nuse self::riscv as plat;\n#[cfg(target_arch = \"x86_64\")]\nuse self::x86_64 as plat;\n\n/// `Future` that fires when the monotonic clock reaches a certain value.\n#[pin_project::pin_project]\npub struct TimerFuture(#[pin] plat::TimerFuture);\n\nimpl Future for TimerFuture {\n    type Output = ();\n    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {\n        self.project().0.poll(cx)\n    }\n}\n\n/// `Future` that fires when an IRQ is triggered.\n#[pin_project::pin_project]\npub struct IrqFuture(#[pin] plat::IrqFuture);\n\nimpl Future for IrqFuture {\n    type Output = ();\n    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {\n        self.project().0.poll(cx)\n    }\n}\n\n/// Access to all the platform-specific information.\n#[pin_project::pin_project]\npub struct PlatformSpecific(#[pin] plat::PlatformSpecificImpl);\n\nimpl PlatformSpecific {\n    /// Returns the number of CPUs available.\n    pub fn num_cpus(self: Pin<&Self>) -> NonZeroU32 {\n        Pin::new(&self.as_ref().0).num_cpus()\n    }\n\n    /// Prints a log message. You are strongly encouraged to only use ASCII characters. The\n    /// implementation is free to discard any non-supported character.\n    pub fn write_log(&self, message: &str) {\n        self.0.write_log(message)\n    }\n\n    /// Modifies the way logs should be printed. This also influences panics.\n    ///\n    /// Even if you are not using the logging system, it is important to call this method when for\n    /// example the video mode changes, so that the kernel knows how to print panic messages.\n    pub fn set_logger_method(&self, method: KernelLogMethod) {\n        self.0.set_logger_method(method)\n    }\n\n    /// Returns the number of nanoseconds that happened since an undeterminate moment in time.\n    ///\n    /// > **Note**: The returned value is provided on a \"best effort\" basis and is not\n    /// >           necessarily exact (it is, in fact, rarely exact).\n    pub fn monotonic_clock(self: Pin<&Self>) -> u128 {\n        Pin::new(&self.as_ref().0).monotonic_clock()\n    }\n\n    /// Returns a `Future` that fires when the monotonic clock reaches the given value.\n    ///\n    /// > **Important**: The returned future is not guaranteed to function properly with an\n    /// >                executor other than the ones in the platform-specific code.\n    pub fn timer(self: Pin<&Self>, clock_value: u128) -> TimerFuture {\n        TimerFuture(Pin::new(&self.as_ref().0).timer(clock_value))\n    }\n\n    /// Returns a `Future` that fires the next time the given IRQ is triggered.\n    ///\n    /// > **Important**: The returned future is not guaranteed to function properly with an\n    /// >                executor other than the ones in the platform-specific code.\n    // TODO: pass some IRQ number and define what this number exactly means\n    pub fn next_irq(self: Pin<&Self>) -> IrqFuture {\n        IrqFuture(Pin::new(&self.as_ref().0).next_irq())\n    }\n\n    /// Writes a `u8` on a port. Returns an error if the operation is not supported or if the port\n    /// is out of range.\n    pub unsafe fn write_port_u8(self: Pin<&Self>, port: u32, data: u8) -> Result<(), PortErr> {\n        Pin::new(&self.as_ref().0).write_port_u8(port, data)\n    }\n    /// Writes a `u16` on a port. Returns an error if the operation is not supported or if the\n    /// port is out of range.\n    pub unsafe fn write_port_u16(self: Pin<&Self>, port: u32, data: u16) -> Result<(), PortErr> {\n        Pin::new(&self.as_ref().0).write_port_u16(port, data)\n    }\n    /// Writes a `u32` on a port. Returns an error if the operation is not supported or if the\n    /// port is out of range.\n    pub unsafe fn write_port_u32(self: Pin<&Self>, port: u32, data: u32) -> Result<(), PortErr> {\n        Pin::new(&self.as_ref().0).write_port_u32(port, data)\n    }\n    /// Reads a `u8` from a port. Returns an error if the operation is not supported or if the\n    /// port is out of range.\n    pub unsafe fn read_port_u8(self: Pin<&Self>, port: u32) -> Result<u8, PortErr> {\n        Pin::new(&self.as_ref().0).read_port_u8(port)\n    }\n    /// Reads a `u16` from a port. Returns an error if the operation is not supported or if the\n    /// port is out of range.\n    pub unsafe fn read_port_u16(self: Pin<&Self>, port: u32) -> Result<u16, PortErr> {\n        Pin::new(&self.as_ref().0).read_port_u16(port)\n    }\n    /// Reads a `u32` from a port. Returns an error if the operation is not supported or if the\n    /// port is out of range.\n    pub unsafe fn read_port_u32(self: Pin<&Self>, port: u32) -> Result<u32, PortErr> {\n        Pin::new(&self.as_ref().0).read_port_u32(port)\n    }\n}\n\n/// Error when requesting to read/write a hardware port.\n#[derive(Debug)]\npub enum PortErr {\n    /// Operation is not supported by the hardware.\n    Unsupported,\n    /// Port is out of range.\n    OutOfRange,\n}\n\nimpl fmt::Display for PortErr {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            PortErr::Unsupported => write!(f, \"Operation is not supported by the hardware\"),\n            PortErr::OutOfRange => write!(f, \"Port is out of range\"),\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/hardware.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Implements the `hardware` interface.\n//!\n//! The `hardware` interface is particular in that it can only be implemented using a \"hosted\"\n//! implementation.\n\nuse crate::arch::PlatformSpecific;\n\nuse alloc::{sync::Arc, vec::Vec};\nuse core::{convert::TryFrom as _, pin::Pin};\nuse hashbrown::HashMap;\nuse nohash_hasher::BuildNoHashHasher;\nuse redshirt_core::{\n    extrinsics::Extrinsics, system::NativeInterfaceMessage, Decode as _, Encode as _,\n    EncodedMessage, Pid,\n};\nuse redshirt_hardware_interface::ffi::{HardwareAccessResponse, HardwareMessage, Operation};\nuse spinning_top::Spinlock;\n\n/// State machine for `hardware` interface messages handling.\npub struct HardwareHandler {\n    /// Platform-specific hooks.\n    platform_specific: Pin<Arc<PlatformSpecific>>,\n    /// For each PID, a list of memory allocations.\n    // TODO: optimize\n    allocations: Spinlock<HashMap<Pid, Vec<Vec<u8>>, BuildNoHashHasher<u64>>>,\n}\n\nimpl HardwareHandler {\n    /// Initializes the new state machine for hardware accesses.\n    pub fn new(platform_specific: Pin<Arc<PlatformSpecific>>) -> Self {\n        HardwareHandler {\n            platform_specific,\n            allocations: Spinlock::new(HashMap::default()),\n        }\n    }\n\n    pub fn process_destroyed(&self, pid: Pid) {\n        self.allocations.lock().remove(&pid);\n    }\n\n    pub fn interface_message<TExtr: Extrinsics>(\n        &self,\n        emitter_pid: Pid,\n        message: NativeInterfaceMessage<TExtr>,\n    ) -> Option<Result<EncodedMessage, ()>> {\n        match HardwareMessage::decode(message.extract()) {\n            Ok(HardwareMessage::HardwareAccess(operations)) => {\n                let mut response = Vec::with_capacity(operations.len());\n                for operation in operations {\n                    unsafe {\n                        if let Some(outcome) =\n                            perform_operation(self.platform_specific.as_ref(), operation)\n                        {\n                            response.push(outcome);\n                        }\n                    }\n                }\n\n                Some(Ok(response.encode()))\n            }\n            Ok(HardwareMessage::Malloc { size, alignment }) => {\n                // TODO: this is obviously badly written\n                let size = match usize::try_from(size) {\n                    Ok(s) => s,\n                    Err(_) => panic!(),\n                };\n                let align = match usize::try_from(alignment) {\n                    Ok(s) => s,\n                    Err(_) => panic!(),\n                };\n                let buffer = Vec::with_capacity(size + align - 1);\n                let mut ptr = match u64::try_from(buffer.as_ptr() as usize) {\n                    Ok(p) => p,\n                    Err(_) => panic!(),\n                };\n                while ptr % alignment != 0 {\n                    ptr += 1;\n                }\n\n                let mut allocations = self.allocations.lock();\n                allocations.entry(emitter_pid).or_default().push(buffer);\n\n                Some(Ok(ptr.encode()))\n            }\n            Ok(HardwareMessage::Free { ptr }) => {\n                if let Ok(ptr) = usize::try_from(ptr) {\n                    let mut allocations = self.allocations.lock();\n                    if let Some(list) = allocations.get_mut(&emitter_pid) {\n                        // Since we adjust the returned pointer to match the alignment.\n                        list.retain(|e| {\n                            ptr < e.as_ptr() as usize || ptr >= (e.as_ptr() as usize) + e.len()\n                        });\n                    }\n                }\n                None\n            }\n            Ok(HardwareMessage::InterruptWait(_int_id)) => unimplemented!(), // TODO:\n            Err(_) => Some(Err(())),\n        }\n    }\n}\n\nunsafe fn perform_operation(\n    platform_specific: Pin<&PlatformSpecific>,\n    operation: Operation,\n) -> Option<HardwareAccessResponse>\nwhere\n{\n    match operation {\n        Operation::PhysicalMemoryMemset {\n            address,\n            len,\n            value,\n        } => {\n            if let Ok(mut address) = usize::try_from(address) {\n                for _ in 0..len {\n                    if address != 0 {\n                        (address as *mut u8).write_volatile(value);\n                    }\n                    if let Some(addr_next) = address.checked_add(1) {\n                        address = addr_next;\n                    } else {\n                        break;\n                    }\n                }\n            }\n            None\n        }\n        Operation::PhysicalMemoryWriteU8 { address, data } => {\n            if let Ok(mut address) = usize::try_from(address) {\n                for byte in data {\n                    if address != 0 {\n                        (address as *mut u8).write_volatile(byte);\n                    }\n                    if let Some(addr_next) = address.checked_add(1) {\n                        address = addr_next;\n                    } else {\n                        break;\n                    }\n                }\n            }\n            None\n        }\n        Operation::PhysicalMemoryWriteU16 { address, data } => {\n            if let Ok(mut address) = usize::try_from(address) {\n                for word in data {\n                    if address != 0 {\n                        (address as *mut u16).write_volatile(word);\n                    }\n                    if let Some(addr_next) = address.checked_add(2) {\n                        address = addr_next;\n                    } else {\n                        break;\n                    }\n                }\n            }\n            None\n        }\n        Operation::PhysicalMemoryWriteU32 { address, data } => {\n            if let Ok(mut address) = usize::try_from(address) {\n                for dword in data {\n                    if address != 0 {\n                        (address as *mut u32).write_volatile(dword);\n                    }\n                    if let Some(addr_next) = address.checked_add(4) {\n                        address = addr_next;\n                    } else {\n                        break;\n                    }\n                }\n            }\n            None\n        }\n        Operation::PhysicalMemoryReadU8 { address, len } => {\n            // TODO: try allocate `len` but don't panic if `len` is too large\n            let mut out = Vec::with_capacity(len as usize); // TODO: don't use `as`\n            let mut address = Some(address);\n            for _ in 0..len {\n                if let Some(addr) = address {\n                    if addr == 0 {\n                        out.push(0);\n                    } else {\n                        out.push((addr as *mut u8).read_volatile());\n                    }\n                    address = addr.checked_add(1);\n                } else {\n                    out.push(0);\n                }\n            }\n            Some(HardwareAccessResponse::PhysicalMemoryReadU8(out))\n        }\n        Operation::PhysicalMemoryReadU16 { address, len } => {\n            // TODO: try allocate `len` but don't panic if `len` is too large\n            let mut out = Vec::with_capacity(len as usize); // TODO: don't use `as`\n            let mut address = Some(address);\n            for _ in 0..len {\n                if let Some(addr) = address {\n                    if addr == 0 {\n                        out.push(0);\n                    } else {\n                        out.push((addr as *mut u16).read_volatile());\n                    }\n                    address = addr.checked_add(2);\n                } else {\n                    out.push(0);\n                }\n            }\n            Some(HardwareAccessResponse::PhysicalMemoryReadU16(out))\n        }\n        Operation::PhysicalMemoryReadU32 { address, len } => {\n            // TODO: try allocate `len` but don't panic if `len` is too large\n            let mut out = Vec::with_capacity(len as usize); // TODO: don't use `as`\n            let mut address = Some(address);\n            for _ in 0..len {\n                if let Some(addr) = address {\n                    if addr == 0 {\n                        out.push(0);\n                    } else {\n                        out.push((addr as *mut u32).read_volatile());\n                    }\n                    address = addr.checked_add(4);\n                } else {\n                    out.push(0);\n                }\n            }\n            Some(HardwareAccessResponse::PhysicalMemoryReadU32(out))\n        }\n        Operation::PortWriteU8 { port, data } => {\n            let _ = platform_specific.write_port_u8(port, data);\n            None\n        }\n        Operation::PortWriteU16 { port, data } => {\n            let _ = platform_specific.write_port_u16(port, data);\n            None\n        }\n        Operation::PortWriteU32 { port, data } => {\n            let _ = platform_specific.write_port_u32(port, data);\n            None\n        }\n        Operation::PortReadU8 { port } => Some(HardwareAccessResponse::PortReadU8(\n            platform_specific.read_port_u8(port).unwrap_or(0),\n        )),\n        Operation::PortReadU16 { port } => Some(HardwareAccessResponse::PortReadU16(\n            platform_specific.read_port_u16(port).unwrap_or(0),\n        )),\n        Operation::PortReadU32 { port } => Some(HardwareAccessResponse::PortReadU32(\n            platform_specific.read_port_u32(port).unwrap_or(0),\n        )),\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/kernel.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Main kernel module.\n//!\n//! # Usage\n//!\n//! - Create a type that implements the [`PlatformSpecific`] trait.\n//! - From one CPU, create a [`Kernel`] with [`Kernel::init`].\n//! - Share the newly-created [`Kernel`] between CPUs, and call [`Kernel::run`] once for each CPU.\n//!\n\nuse crate::{\n    arch::PlatformSpecific, hardware::HardwareHandler, klog::KernelLogNativeProgram,\n    pci::native::PciNativeProgram, random::native::RandomNativeProgram, time::TimeHandler,\n};\n\nuse alloc::{format, string::String, sync::Arc, vec::Vec};\nuse core::{pin::Pin, sync::atomic::Ordering};\nuse futures::prelude::*;\nuse redshirt_core::{\n    build_wasm_module,\n    extrinsics::wasi::WasiExtrinsics,\n    system::{KernelDebugMetricsRequest, SystemRunOutcome},\n    System,\n};\n\n/// Main struct of this crate. Runs everything.\npub struct Kernel {\n    /// Contains the list of all processes, threads, interfaces, messages, and so on.\n    system: System<WasiExtrinsics>,\n    /// Has one entry for each CPU. Never resized.\n    cpu_counters: Vec<CpuCounter>,\n    /// Platform-specific getters. Passed at initialization.\n    platform_specific: Pin<Arc<PlatformSpecific>>,\n    time: TimeHandler,\n    randomness: RandomNativeProgram,\n    hardware: HardwareHandler,\n    pci: PciNativeProgram,\n    klog: KernelLogNativeProgram,\n}\n\n#[derive(Debug)]\nstruct CpuCounter {\n    /// True if the CPU has been started at all.\n    started: atomic::Atomic<bool>,\n    /// Total number of nanoseconds spent working since [`Kernel::run`] has been called.\n    busy_ticks: atomic::Atomic<u128>,\n    /// Total number of nanoseconds spent idle since [`Kernel::run`] has been called.\n    idle_ticks: atomic::Atomic<u128>,\n}\n\nimpl Kernel {\n    /// Initializes a new `Kernel`.\n    pub fn init(platform_specific: Pin<Arc<PlatformSpecific>>) -> Self {\n        // TODO: don't do this on platforms that don't have PCI?\n        let pci_devices = unsafe { crate::pci::pci::init_cam_pci() };\n\n        let randomness = RandomNativeProgram::new(platform_specific.clone());\n\n        let mut rng_seed = [0; 64];\n        randomness.fill_bytes(&mut rng_seed);\n\n        let system_builder = redshirt_core::system::SystemBuilder::<WasiExtrinsics>::new(rng_seed)\n            .with_native_interface_handler(redshirt_hardware_interface::ffi::INTERFACE)\n            .with_native_interface_handler(redshirt_time_interface::ffi::INTERFACE)\n            .with_native_interface_handler(redshirt_random_interface::ffi::INTERFACE)\n            .with_native_interface_handler(redshirt_pci_interface::ffi::INTERFACE)\n            .with_native_interface_handler(redshirt_kernel_log_interface::ffi::INTERFACE)\n            .with_startup_process(build_wasm_module!(\"../../../programs/compositor\"))\n            .with_startup_process(build_wasm_module!(\"../../../programs/pci-printer\"))\n            // TODO: actually implement system-time and remove this dummy; https://github.com/tomaka/redshirt/issues/542\n            .with_startup_process(build_wasm_module!(\"../../../programs/dummy-system-time\"))\n            .with_startup_process(build_wasm_module!(\"../../../programs/log-to-kernel\"))\n            .with_startup_process(build_wasm_module!(\"../../../programs/vga-vbe\"))\n            .with_startup_process(build_wasm_module!(\n                \"../../../programs/diagnostics-http-server\"\n            ))\n            .with_startup_process(build_wasm_module!(\"../../../programs/hello-world\"))\n            .with_startup_process(build_wasm_module!(\"../../../programs/network-manager\"))\n            .with_startup_process(build_wasm_module!(\"../../../programs/e1000\"));\n\n        // TODO: remove the cfg guards once rpi-framebuffer is capable of auto-detecting whether\n        // it should enable itself\n        #[cfg(any(target_arch = \"arm\", target_arch = \"aarch64\"))]\n        let system_builder = system_builder\n            .with_startup_process(build_wasm_module!(\"../../../programs/rpi-framebuffer\"));\n\n        // TODO: temporary; uncomment to test\n        /*system_builder = system_builder.with_main_program(\n            ModuleHash::from_base58(\"FWMwRMQCKdWVDdKyx6ogQ8sXuoeDLNzZxniRMyD5S71\").unwrap(),\n        );*/\n\n        let cpu_counters = (0..platform_specific.as_ref().num_cpus().get())\n            .map(|_| CpuCounter {\n                started: atomic::Atomic::new(false),\n                busy_ticks: atomic::Atomic::new(0),\n                idle_ticks: atomic::Atomic::new(0),\n            })\n            .collect();\n\n        Kernel {\n            system: system_builder.build().expect(\"failed to start kernel\"),\n            cpu_counters,\n            platform_specific: platform_specific.clone(),\n            time: TimeHandler::new(platform_specific.clone()),\n            randomness,\n            hardware: HardwareHandler::new(platform_specific.clone()),\n            pci: PciNativeProgram::new(pci_devices, platform_specific.clone()),\n            klog: KernelLogNativeProgram::new(platform_specific.clone()),\n        }\n    }\n\n    /// Run the kernel. Must be called once per CPU.\n    pub async fn run(&self, cpu_index: usize) -> ! {\n        // Check that the `cpu_index` is correct.\n        {\n            let was_started = self.cpu_counters[cpu_index]\n                .started\n                .swap(true, Ordering::Relaxed);\n            assert!(!was_started);\n        }\n\n        // In order for the idle/busy counters to report accurate information, we keep here the\n        // last time we have updated one of the counters.\n        let mut now = self.platform_specific.as_ref().monotonic_clock();\n\n        loop {\n            // Prepare `interface_handlers`, the future that polls the external interface handlers\n            // for new message answers.\n            let next_time_response = self.time.next_response();\n            let next_pci_response = self.pci.next_response();\n            futures::pin_mut!(next_time_response, next_pci_response);\n            let mut interface_handlers =\n                future::select(next_time_response, next_pci_response).map(|e| e.factor_first().0);\n\n            // Poll the interface handlers first in order to guarantee that messages are answered\n            // in between two program executions in the core.\n            if let Some((message_id, response)) = (&mut interface_handlers).now_or_never() {\n                self.system.answer_message(message_id, Ok(response));\n                continue;\n            }\n\n            // Ask the core for the next event, or the next process execution to perform.\n            let core_work = self.system.run();\n            futures::pin_mut!(core_work);\n            let core_event = match future::select(interface_handlers, core_work).await {\n                future::Either::Right((event, _)) => event,\n                future::Either::Left(((message_id, response), _)) => {\n                    self.system.answer_message(message_id, Ok(response));\n                    continue;\n                }\n            };\n\n            // Grabbing the value of the monotonic clock is a \"semi-expensive\" operation. It is\n            // grabbed here because it is potentially needed below.\n            let new_now = self.platform_specific.as_ref().monotonic_clock();\n\n            let ready_to_run = match core_event {\n                redshirt_core::ExecuteOut::Direct(ev) => {\n                    self.handle_event(ev, new_now);\n                    continue;\n                }\n                redshirt_core::ExecuteOut::ReadyToRun(ready_to_run) => ready_to_run,\n            };\n\n            // The code below has the objective of calling `ready_to_run.run()`. We need to\n            // update the CPU counters in order to report the CPU as busy during the execution.\n\n            // TODO: because of the way it is implemented, the idle counter is only updated when the\n            // CPU has some work to do; in other words, if a CPU is asleep for a long time then its\n            // counters will not be updated\n            let elapsed_idle = new_now.checked_sub(now).unwrap();\n            now = new_now;\n            self.cpu_counters[cpu_index]\n                .idle_ticks\n                .fetch_add(elapsed_idle, Ordering::Relaxed);\n\n            let run_outcome = ready_to_run.run();\n\n            let new_now = self.platform_specific.as_ref().monotonic_clock();\n            let elapsed_budy = new_now.checked_sub(now).unwrap();\n            now = new_now;\n            self.cpu_counters[cpu_index]\n                .busy_ticks\n                .fetch_add(elapsed_budy, Ordering::Relaxed);\n\n            if let Some(event) = run_outcome {\n                self.handle_event(event, now);\n            }\n        }\n    }\n\n    fn handle_event(\n        &self,\n        core_event: SystemRunOutcome<WasiExtrinsics>,\n        monotonic_clock_value: u128,\n    ) {\n        match core_event {\n            SystemRunOutcome::ProgramFinished { pid, .. } => {\n                self.hardware.process_destroyed(pid);\n            }\n            SystemRunOutcome::KernelDebugMetricsRequest(report) => {\n                self.report_kernel_metrics(report, monotonic_clock_value);\n            }\n\n            // Time handling.\n            SystemRunOutcome::NativeInterfaceMessage {\n                interface,\n                message_id: Some(message_id),\n                message,\n                ..\n            } if interface == redshirt_time_interface::ffi::INTERFACE => {\n                if let Some(response) = self.time.interface_message(message_id, message) {\n                    self.system.answer_message(message_id, response);\n                }\n            }\n            SystemRunOutcome::NativeInterfaceMessage {\n                interface,\n                message_id: None,\n                ..\n            } if interface == redshirt_time_interface::ffi::INTERFACE => {}\n\n            // Randomness queries handling.\n            SystemRunOutcome::NativeInterfaceMessage {\n                interface,\n                message_id: Some(message_id),\n                message,\n                ..\n            } if interface == redshirt_random_interface::ffi::INTERFACE => {\n                let response = self.randomness.interface_message(message);\n                self.system.answer_message(message_id, response);\n            }\n            SystemRunOutcome::NativeInterfaceMessage {\n                interface,\n                message_id: None,\n                ..\n            } if interface == redshirt_random_interface::ffi::INTERFACE => {}\n\n            // Hardware handling.\n            SystemRunOutcome::NativeInterfaceMessage {\n                interface,\n                message_id: Some(message_id),\n                message,\n                emitter_pid,\n                ..\n            } if interface == redshirt_hardware_interface::ffi::INTERFACE => {\n                if let Some(response) = self.hardware.interface_message(emitter_pid, message) {\n                    self.system.answer_message(message_id, response);\n                }\n            }\n            SystemRunOutcome::NativeInterfaceMessage {\n                interface,\n                message_id: None,\n                emitter_pid,\n                message,\n                ..\n            } if interface == redshirt_hardware_interface::ffi::INTERFACE => {\n                self.hardware.interface_message(emitter_pid, message);\n            }\n\n            // PCI handling.\n            SystemRunOutcome::NativeInterfaceMessage {\n                interface,\n                message_id: Some(message_id),\n                message,\n                emitter_pid,\n                ..\n            } if interface == redshirt_pci_interface::ffi::INTERFACE => {\n                if let Some(response) =\n                    self.pci\n                        .interface_message(Some(message_id), emitter_pid, message)\n                {\n                    self.system.answer_message(message_id, response);\n                }\n            }\n            SystemRunOutcome::NativeInterfaceMessage {\n                interface,\n                message_id: None,\n                emitter_pid,\n                message,\n            } if interface == redshirt_pci_interface::ffi::INTERFACE => {\n                self.pci.interface_message(None, emitter_pid, message);\n            }\n\n            // Kernel logs handling.\n            SystemRunOutcome::NativeInterfaceMessage {\n                interface, message, ..\n            } if interface == redshirt_kernel_log_interface::ffi::INTERFACE => {\n                self.klog.interface_message(message);\n            }\n\n            SystemRunOutcome::NativeInterfaceMessage { .. } => {\n                unreachable!()\n            }\n        }\n    }\n\n    fn report_kernel_metrics(\n        &self,\n        report: KernelDebugMetricsRequest<WasiExtrinsics>,\n        monotonic_clock_value: u128,\n    ) {\n        let mut out = String::new();\n\n        // cpu_idle_seconds_total\n        out.push_str(\"# HELP redshirt_cpu_idle_seconds_total Total number of seconds during which each CPU has been idle.\\n\");\n        out.push_str(\"# TYPE redshirt_cpu_idle_seconds_total counter\\n\");\n        for (cpu_n, cpu) in self.cpu_counters.iter().enumerate() {\n            let as_secs = cpu.idle_ticks.load(Ordering::Relaxed) as f64 / 1_000_000_000.0;\n            out.push_str(&format!(\n                \"redshirt_cpu_idle_seconds_total{{cpu=\\\"{}\\\"}} {}\\n\",\n                cpu_n, as_secs\n            ));\n        }\n        out.push_str(\"\\n\");\n\n        // cpu_busy_seconds_total\n        out.push_str(\"# HELP redshirt_cpu_busy_seconds_total Total number of seconds during which each CPU has been busy.\\n\");\n        out.push_str(\"# TYPE redshirt_cpu_busy_seconds_total counter\\n\");\n        for (cpu_n, cpu) in self.cpu_counters.iter().enumerate() {\n            let as_secs = cpu.busy_ticks.load(Ordering::Relaxed) as f64 / 1_000_000_000.0;\n            out.push_str(&format!(\n                \"redshirt_cpu_busy_seconds_total{{cpu=\\\"{}\\\"}} {}\\n\",\n                cpu_n, as_secs\n            ));\n        }\n        out.push_str(\"\\n\");\n\n        // monotonic_clock\n        out.push_str(\"# HELP redshirt_monotonic_clock Value of the monotonic clock.\\n\");\n        out.push_str(\"# TYPE redshirt_monotonic_clock counter\\n\");\n        out.push_str(&format!(\n            \"redshirt_monotonic_clock {}\\n\",\n            monotonic_clock_value\n        ));\n        out.push_str(\"\\n\");\n\n        // started_cpus\n        out.push_str(\"# HELP redshirt_started_cpus Number of CPUs started on the machine.\\n\");\n        out.push_str(\"# TYPE redshirt_started_cpus counter\\n\");\n        out.push_str(&format!(\n            \"redshirt_started_cpus {}\\n\",\n            self.cpu_counters\n                .iter()\n                .filter(|c| c.started.load(Ordering::Relaxed))\n                .count()\n        ));\n        out.push_str(\"\\n\");\n\n        report.respond(&out);\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/klog/logger.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::klog::video;\n\nuse core::{convert::TryFrom as _, fmt, hint};\nuse redshirt_kernel_log_interface::ffi::{KernelLogMethod, UartAccess, UartInfo};\nuse spinning_top::{guard::SpinlockGuard, Spinlock};\n#[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nuse x86_64::structures::port::{PortRead as _, PortWrite as _};\n\npub struct KLogger {\n    inner: Spinlock<Inner>,\n}\n\nenum Inner {\n    Disabled(KernelLogMethod),\n    Enabled {\n        terminal: Option<video::Terminal>,\n        uart: Option<UartInfo>,\n    },\n}\n\nimpl KLogger {\n    /// Initializes a disabled [`KLogger`].\n    pub const fn disabled() -> KLogger {\n        KLogger {\n            inner: Spinlock::new(Inner::Disabled(KernelLogMethod {\n                enabled: false,\n                framebuffer: None,\n                uart: None,\n            })),\n        }\n    }\n\n    /// Returns an object that implements `core::fmt::Write` for writing logs.\n    ///\n    /// The returned object holds a lock to some important information. Please call this method\n    /// and destroy the object as soon as possible.\n    pub fn log_printer<'a>(&'a self) -> impl fmt::Write + 'a {\n        Printer {\n            inner: self.inner.lock(),\n            color: [0xdd, 0xdd, 0xdd],\n        }\n    }\n\n    /// Returns an object that implements `core::fmt::Write` designed for printing a panic\n    /// message.\n    ///\n    /// The returned object holds a lock to some important information. Please call this method\n    /// and destroy the object as soon as possible.\n    pub fn panic_printer<'a>(&'a self) -> impl fmt::Write + 'a {\n        Printer {\n            inner: self.inner.lock(),\n            color: [0xff, 0x0, 0x0],\n        }\n    }\n\n    /// Modifies the way logs should be printed.\n    pub fn set_method(&self, method: KernelLogMethod) {\n        // TODO: this isn't properly implemented ; on new terminal, which should re-print older logs\n        unsafe {\n            if method.enabled {\n                *self.inner.lock() = Inner::Enabled {\n                    terminal: match method.framebuffer {\n                        Some(fb) => Some(video::Terminal::new(fb)),\n                        None => None,\n                    },\n                    uart: method.uart,\n                };\n            } else {\n                *self.inner.lock() = Inner::Disabled(method);\n            }\n        }\n    }\n}\n\nstruct Printer<'a> {\n    inner: SpinlockGuard<'a, Inner>,\n    color: [u8; 3],\n}\n\nimpl<'a> fmt::Write for Printer<'a> {\n    fn write_str(&mut self, message: &str) -> fmt::Result {\n        match &mut *self.inner {\n            Inner::Disabled(_) => {} // TODO: push to some buffer\n            Inner::Enabled { terminal, uart } => {\n                if let Some(terminal) = terminal {\n                    // TODO: red for panics\n                    terminal.printer(self.color).write_str(message)?;\n                }\n\n                if let Some(uart) = uart {\n                    unsafe {\n                        for byte in message.as_bytes() {\n                            loop {\n                                let v = match uart.wait_address {\n                                    UartAccess::MemoryMappedU32(r_addr) => {\n                                        if let Ok(r_addr) = usize::try_from(r_addr) {\n                                            (r_addr as *const u32).read_volatile()\n                                        } else {\n                                            0\n                                        }\n                                    }\n                                    #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n                                    UartAccess::IoPortU8(r_port) => {\n                                        u32::from(u8::read_from_port(r_port))\n                                    }\n                                    #[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n                                    UartAccess::IoPortU8(r_port) => 0,\n                                };\n\n                                if (v & uart.wait_mask) == uart.wait_compare_equal_if_ready {\n                                    break;\n                                }\n\n                                hint::spin_loop();\n                            }\n\n                            match uart.write_address {\n                                UartAccess::MemoryMappedU32(w_addr) => {\n                                    if let Ok(w_addr) = usize::try_from(w_addr) {\n                                        (w_addr as *mut u32).write_volatile(u32::from(*byte))\n                                    }\n                                }\n                                #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n                                UartAccess::IoPortU8(r_port) => {\n                                    u8::write_to_port(r_port, *byte);\n                                }\n                                #[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n                                UartAccess::IoPortU8(r_port) => {}\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/klog/native.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Native program that handles the `kernel_log` interface.\n\nuse crate::arch::PlatformSpecific;\n\nuse alloc::sync::Arc;\nuse core::{pin::Pin, str};\nuse redshirt_core::{extrinsics::Extrinsics, system::NativeInterfaceMessage};\n\n/// State machine for `kernel_log` interface messages handling.\npub struct KernelLogNativeProgram {\n    /// Platform-specific hooks.\n    platform_specific: Pin<Arc<PlatformSpecific>>,\n    /// Lock used to ensure ordering of logs messages.\n    lock: spinning_top::Spinlock<()>,\n}\n\nimpl KernelLogNativeProgram {\n    /// Initializes the native program.\n    pub fn new(platform_specific: Pin<Arc<PlatformSpecific>>) -> Self {\n        KernelLogNativeProgram {\n            platform_specific,\n            lock: spinning_top::Spinlock::new(()),\n        }\n    }\n\n    pub fn interface_message<TExtr: Extrinsics>(&self, message: NativeInterfaceMessage<TExtr>) {\n        let _lock = self.lock.lock();\n        let message = message.extract();\n        match message.0.get(0) {\n            Some(0) => {\n                // Log message.\n                let message = &message.0[1..];\n                if message.is_ascii() {\n                    self.platform_specific\n                        .write_log(str::from_utf8(message).unwrap());\n                }\n            }\n            Some(1) => {\n                // New log method.\n                unimplemented!(); // TODO:\n                                  /*if let Ok(method) = KernelLogMethod::decode(&message.0[1..]) {\n                                      self.klogger.set_method(method);\n                                      if let Some(message_id) = notification.message_id {\n                                          self.pending_messages_tx.unbounded_send((message_id, Ok(().encode())))\n                                      }\n                                  } else {\n                                      if let Some(message_id) = notification.message_id {\n                                          self.pending_messages_tx.unbounded_send((message_id, Err(())))\n                                      }\n                                  }*/\n            }\n            _ => {}\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/klog/video.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse core::{convert::TryFrom as _, fmt, ptr};\nuse redshirt_kernel_log_interface::ffi::{FramebufferFormat, FramebufferInfo};\n\npub struct Terminal {\n    framebuffer: FramebufferInfo,\n    cursor_x: u32,\n    cursor_y: u32,\n    character_width: u32,\n    character_height: u32,\n    /// If this is false, we need to clear the screen before doing anything more.\n    /// This is not done immediately at initialization in order to have `new` be a `const`\n    /// function.\n    screen_cleared: bool,\n}\n\nimpl Terminal {\n    /// Clears the given framebuffer and returns a terminal.\n    pub const unsafe fn new(framebuffer: FramebufferInfo) -> Terminal {\n        // TODO: proper calculation based on screen dimensions\n        let character_dims = match framebuffer.format {\n            FramebufferFormat::Text => 1,\n            FramebufferFormat::Rgb { .. } => 8,\n        };\n\n        Terminal {\n            framebuffer,\n            cursor_x: 0,\n            cursor_y: 0,\n            character_width: character_dims,\n            character_height: character_dims,\n            screen_cleared: false,\n        }\n    }\n\n    /// Returns an object that implements `core::fmt::Write` designed for printing a message.\n    pub fn printer<'a>(&'a mut self, color: [u8; 3]) -> impl fmt::Write + 'a {\n        if !self.screen_cleared {\n            // Safety is covered by `Terminal::new`.\n            unsafe {\n                clear_screen(&self.framebuffer);\n                self.screen_cleared = true;\n            }\n        }\n\n        struct Printer<'a> {\n            klog: &'a mut Terminal,\n            color: [u8; 3],\n        }\n        impl<'a> fmt::Write for Printer<'a> {\n            fn write_str(&mut self, message: &str) -> fmt::Result {\n                self.klog.print(message, self.color);\n                Ok(())\n            }\n        }\n        Printer { klog: self, color }\n    }\n\n    /// Adds a message to the terminal.\n    fn print(&mut self, message: &str, color: [u8; 3]) {\n        for chr in message.chars() {\n            if !chr.is_ascii() {\n                continue;\n            }\n            // TODO: better way to convert to ASCII?\n            let chr = chr as u8;\n\n            if chr == b'\\n' {\n                self.carriage_return();\n                continue;\n            }\n\n            self.print_at_cursor(chr, color);\n\n            debug_assert!(self.cursor_x < self.framebuffer.width);\n            self.cursor_x = self.cursor_x.saturating_add(self.character_width);\n            if self.cursor_x > self.framebuffer.width.saturating_sub(self.character_width) {\n                self.carriage_return();\n            }\n        }\n    }\n\n    /// Returns the memory address where the cursor is currently located.\n    fn cursor_mem_address(&self) -> *mut u8 {\n        unsafe {\n            let y_offset = usize::try_from(\n                self.framebuffer\n                    .pitch\n                    .saturating_mul(u64::from(self.cursor_y)),\n            )\n            .unwrap_or(usize::max_value());\n            let x_offset = usize::try_from(self.cursor_x)\n                .unwrap_or(usize::max_value())\n                .saturating_mul(usize::from(self.framebuffer.bytes_per_character));\n            (self.framebuffer.address as *mut u8).add(x_offset.saturating_add(y_offset))\n        }\n    }\n\n    fn print_at_cursor(&mut self, chr: u8, color: [u8; 3]) {\n        unsafe {\n            let addr = self.cursor_mem_address();\n\n            match self.framebuffer.format {\n                FramebufferFormat::Text => {\n                    let attrs = u16::from(term_color(color)) << 8;\n                    (addr as *mut u16).write_volatile(u16::from(chr) | attrs);\n                }\n                FramebufferFormat::Rgb { .. } => {\n                    let src_data = {\n                        let idx = usize::from(chr) * 64;\n                        if (idx + 64) > FONT_DATA.len() {\n                            return;\n                        }\n                        &FONT_DATA[idx..idx + 64]\n                    };\n\n                    let bpp = usize::from(self.framebuffer.bytes_per_character);\n                    let chr_width = match usize::try_from(self.character_width) {\n                        Ok(w) => w,\n                        _ => return,\n                    };\n                    let chr_height = match usize::try_from(self.character_height) {\n                        Ok(h) => h,\n                        _ => return,\n                    };\n                    let pitch = match usize::try_from(self.framebuffer.pitch) {\n                        Ok(p) => p,\n                        _ => return,\n                    };\n\n                    for y in 0..chr_height {\n                        let addr = addr.add(y.saturating_mul(pitch));\n\n                        for x in 0..chr_width {\n                            // FIXME: only works because we hard-code 8 as character width/height\n                            // should be properly sampled\n                            let src_px = src_data[y * 8 + x];\n                            let r = mix(src_px, color[0]);\n                            let g = mix(src_px, color[1]);\n                            let b = mix(src_px, color[2]);\n\n                            let addr = addr.add(x.saturating_mul(bpp));\n                            write_rgb_color(addr, &self.framebuffer, [r, g, b]);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /// Moves the cursor and the content of the screen one line up.\n    fn line_down(&mut self) {\n        // Safety is covered by `Terminal::new`.\n        unsafe {\n            // Note that we read from the framebuffer here, which is extremely slow, but is also the\n            // only way we can avoid memory allocations.\n            copy_row_up(&self.framebuffer, self.character_height);\n            self.cursor_y = self.cursor_y.saturating_sub(self.character_height);\n        }\n    }\n\n    fn carriage_return(&mut self) {\n        self.cursor_x = 0;\n        self.cursor_y = self.cursor_y.saturating_add(self.character_height);\n        while self.cursor_y >= self.framebuffer.height {\n            self.line_down();\n        }\n    }\n}\n\n/// Font data generated by a build script.\n///\n/// Contains the 128 ASCII characters. Each character is 8x8 bytes. Each byte contains the\n/// opacity of the corresponding pixel, where `0x0` means transparent and `0xff` means opaque.\nconst FONT_DATA: &[u8] = include_bytes!(concat!(env!(\"OUT_DIR\"), \"/font.bin\"));\n\nfn mix(v1: u8, v2: u8) -> u8 {\n    ((u16::from(v1) * u16::from(v2)) / 255) as u8\n}\n\n/// Copies all the rows of the framebuffer `n` rows up and clears the last `n` rows.\nunsafe fn copy_row_up(info: &FramebufferInfo, rows_up: u32) {\n    let ptr = match usize::try_from(info.address) {\n        Ok(p) => p as *mut u8,\n        _ => return,\n    };\n\n    let width = match usize::try_from(info.width) {\n        Ok(w) => w,\n        _ => return,\n    };\n\n    let height = match usize::try_from(info.height) {\n        Ok(h) => h,\n        _ => return,\n    };\n\n    let rows_up = match usize::try_from(rows_up) {\n        Ok(0) => return,\n        Ok(r) => r,\n        _ => return,\n    };\n\n    let pitch = match usize::try_from(info.pitch) {\n        Ok(p) => p,\n        _ => return,\n    };\n\n    let bpp = usize::from(info.bytes_per_character);\n\n    for y in 0..(height - rows_up) {\n        let src = ptr.add(pitch.saturating_mul(y + rows_up));\n        let dst = ptr.add(pitch.saturating_mul(y));\n        // Note: we don't use `copy_non_overlapping` as we don't actually know if that's true.\n        ptr::copy(src, dst, bpp.saturating_mul(width));\n    }\n\n    for y in (height - rows_up)..height {\n        let dst = ptr.add(pitch.saturating_mul(y));\n        ptr::write_bytes(dst, 0x0, bpp.saturating_mul(width));\n    }\n}\n\n/// Writes `0x0` on the entire framebuffer.\nunsafe fn clear_screen(info: &FramebufferInfo) {\n    let ptr = match usize::try_from(info.address) {\n        Ok(p) => p as *mut u8,\n        _ => return,\n    };\n\n    let width = match usize::try_from(info.width) {\n        Ok(w) => w,\n        _ => return,\n    };\n\n    let height = match usize::try_from(info.height) {\n        Ok(h) => h,\n        _ => return,\n    };\n\n    let pitch = match usize::try_from(info.pitch) {\n        Ok(p) => p,\n        _ => return,\n    };\n\n    let bpp = usize::from(info.bytes_per_character);\n\n    for y in 0..height {\n        let ptr = ptr.add(pitch.saturating_mul(y));\n        ptr::write_bytes(ptr, 0x0, bpp.saturating_mul(width));\n    }\n}\n\nunsafe fn write_rgb_color(dst: *mut u8, info: &FramebufferInfo, color: [u8; 3]) {\n    if info.bytes_per_character > 4 {\n        // TODO: not supported\n        return;\n    }\n\n    let mut pixel_to_write = 0u32;\n\n    if let FramebufferFormat::Rgb {\n        red_size,\n        red_position,\n        green_size,\n        green_position,\n        blue_size,\n        blue_position,\n    } = info.format\n    {\n        let red = if red_size >= 8 {\n            u32::from(color[0]).wrapping_shl(u32::from(red_size) - 8)\n        } else {\n            u32::from(color[0]).wrapping_shr(8 - u32::from(red_size))\n        };\n\n        let green = if green_size >= 8 {\n            u32::from(color[1]).wrapping_shl(u32::from(green_size) - 8)\n        } else {\n            u32::from(color[1]).wrapping_shr(8 - u32::from(green_size))\n        };\n\n        let blue = if blue_size >= 8 {\n            u32::from(color[2]).wrapping_shl(u32::from(blue_size) - 8)\n        } else {\n            u32::from(color[2]).wrapping_shr(8 - u32::from(blue_size))\n        };\n\n        pixel_to_write = red.wrapping_shl(u32::from(red_position))\n            | green.wrapping_shl(u32::from(green_position))\n            | blue.wrapping_shl(u32::from(blue_position));\n    } // TODO: else?\n\n    let pixel_to_write = pixel_to_write.to_le_bytes(); // TODO: LE bytes? lol, this one is hard\n    ptr::copy_nonoverlapping(\n        pixel_to_write.as_ptr(),\n        dst,\n        usize::from(info.bytes_per_character),\n    );\n}\n\n/// Returns the most appropriate \"text mode characteristics\" byte from an RGB color.\nfn term_color(color: [u8; 3]) -> u8 {\n    const AVAILABLE: [[u8; 4]; 16] = [\n        [0x00, 0x00, 0x00, 0x0],\n        [0x00, 0x00, 0xaa, 0x1],\n        [0x00, 0xaa, 0x00, 0x2],\n        [0x00, 0xaa, 0xaa, 0x3],\n        [0xaa, 0x00, 0x00, 0x4],\n        [0xaa, 0x00, 0xaa, 0x5],\n        [0xaa, 0xaa, 0x00, 0x6],\n        [0xaa, 0xaa, 0xaa, 0x7],\n        [0x55, 0x55, 0x55, 0x8],\n        [0x55, 0x55, 0xff, 0x9],\n        [0x55, 0xff, 0x55, 0xa],\n        [0x55, 0xff, 0xff, 0xb],\n        [0xff, 0x55, 0x55, 0xc],\n        [0xff, 0x55, 0xff, 0xd],\n        [0xff, 0xff, 0x55, 0xe],\n        [0xff, 0xff, 0xff, 0xf],\n    ];\n\n    // We find the closest color from the ones available.\n    AVAILABLE\n        .iter()\n        .map(|val| {\n            let distance = (i16::from(color[0]) - i16::from(val[0])).abs()\n                + (i16::from(color[1]) - i16::from(val[1])).abs()\n                + (i16::from(color[2]) - i16::from(val[2])).abs();\n            (distance, val[3])\n        })\n        .min_by_key(|v| v.0)\n        .unwrap()\n        .1\n}\n"
  },
  {
    "path": "kernel/standalone/src/klog.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Kernel logs handling.\n//!\n//! This module handles the way the kernel prints logs. It provides the [`KLogger`] structure\n//! that needs to be configured with a certain logging output method, and is then capable of\n//! outputting logs.\n//!\n//! # Panic-free code\n//!\n//! The code within this module is designed to be as panic-free as possible. In other words, you\n//! can assume that a [`KLogger`] will be capable of printing a panic message without itself\n//! triggering a nested panic. In particular, none of the code within this module does any heap\n//! allocation.\n\npub use logger::KLogger;\npub use native::KernelLogNativeProgram;\n\nmod logger;\nmod native;\nmod video;\n"
  },
  {
    "path": "kernel/standalone/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Standalone redshirt kernel building tookit.\n//!\n//! This library provides a toolkit that lets one create a stand-alone redshirt kernel. Two things\n//! are provided:\n//!\n//! - A `__gen_boot!` macro that gets passed a bunch of information about the target platform, and\n//! generates a function exported under the symbol `_start`.\n//! - A `run` function, suitable to be passed to the `gen_boot!` macro, that runs the kernel after\n//! an environment has been setup.\n//!\n//! It is intended that in the future this crate allows more customizations, and a more\n//! fine-grained split of components.\n//!\n//! # Kernel environment\n//!\n//! When the `_gen_boot!` macro is used, a symbol named `_start` is generated. The user is\n//! responsible for ensuring that execution jumps to this symbol, after which the code of the\n//! macro is in total control of the hardware.\n//!\n//! No assumption is made about the state of the registers, memory, or hardware when `_start` is\n//! executed.\n//!\n//! The only exception concerns the x86 and x86_64 platform, where `_start` is expected to be\n//! loaded from a multiboot2-compatible loader.\n//! See <https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html> for more information.\n//!\n//! Additionally, this crate defines [a panic handler](https://doc.rust-lang.org/reference/runtime.html#the-panic_handler-attribute)\n//! and a [global allocator](https://doc.rust-lang.org/reference/runtime.html#the-global_allocator-attribute).\n//! It is not possible to set your own panic handler or global allocator when having this crate\n//! as a dependency.\n\n#![no_std]\n#![feature(allocator_api)] // TODO: https://github.com/rust-lang/rust/issues/32838\n#![feature(naked_functions)] // TODO: https://github.com/rust-lang/rust/issues/32408\n#![cfg_attr(target_arch = \"x86_64\", feature(abi_x86_interrupt))] // TODO: https://github.com/rust-lang/rust/issues/40180\n\nextern crate alloc;\nextern crate rlibc; // TODO: necessary as a work-around for some linking issue; needs to be investigated\n\nuse alloc::sync::Arc;\nuse core::{pin::Pin, sync::atomic};\n\n#[macro_use]\npub mod arch;\n\nmod hardware;\nmod pci;\nmod random;\nmod time;\n\n// TODO: don't make public\n#[doc(hidden)]\npub mod klog;\n#[doc(hidden)]\npub mod mem_alloc;\n\n// Re-exports necessary to make the `__gen_boot!` macro work.\n// TODO: don't make public\n#[doc(hidden)]\npub extern crate futures;\n#[doc(hidden)]\npub extern crate redshirt_kernel_log_interface;\n\n// TODO: instead of having a public `kernel` module, this library should instead expose the various components, and the user builds the kernel themselves\npub mod kernel;\n\npub async fn run(platform_specific: Pin<Arc<arch::PlatformSpecific>>) -> ! {\n    // Initialize the kernel once for all cores.\n    static KERNEL: spinning_top::Spinlock<Option<Arc<kernel::Kernel>>> =\n        spinning_top::Spinlock::new(None);\n\n    // Initialize the kernel.\n    // TODO: do this better than spinlocking, as initialization might be expensive\n    let kernel = {\n        let mut lock = KERNEL.lock();\n        if let Some(existing_kernel) = lock.as_ref() {\n            existing_kernel.clone()\n        } else {\n            let new_kernel = Arc::new(kernel::Kernel::init(platform_specific));\n            *lock = Some(new_kernel.clone());\n            new_kernel\n        }\n    };\n\n    // Assign an index to each CPU.\n    static CPU_INDEX: atomic::AtomicUsize = atomic::AtomicUsize::new(0);\n    let cpu_index = CPU_INDEX.fetch_add(1, atomic::Ordering::Relaxed);\n\n    // Run the kernel. This call never returns.\n    kernel.run(cpu_index).await\n}\n"
  },
  {
    "path": "kernel/standalone/src/mem_alloc.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse core::ops::Range;\n\n/// Initialize the memory allocator.\n///\n/// Pass to this function a list of memory ranges that are available for use.\n///\n/// After this function returns, you can use heap allocations.\n///\n/// > **Note**: It is \"safe\" to try to perform memory allocations before this function has been\n/// >           called, but doing so will result in a panic.\n///\n/// # Panics\n///\n/// Panics if `range.end` is inferior to `range.start` for any of the elements.\n///\n/// # Safety\n///\n/// The memory ranges have to be RAM or behave like RAM (i.e. both readable and writable,\n/// consistent, and so on). The memory ranges must not be touched by anything (other than the\n/// allocator) afterwards.\n///\npub unsafe fn initialize(ranges: impl Iterator<Item = Range<usize>>) {\n    // We choose the largest range.\n    let range = ranges.max_by_key(|r| {\n        assert!(r.end >= r.start);\n        r.end - r.start\n    });\n\n    let range = match range {\n        Some(r) => r,\n        // If the iterator was empty, return with initializing the allocator.\n        None => return,\n    };\n\n    // Don't initialize the allocator if all the ranges were 0.\n    if range.start == range.end {\n        return;\n    }\n\n    assert!(range.end >= range.start);\n    ALLOCATOR.lock().init(range.start, range.end - range.start);\n}\n\n#[global_allocator]\nstatic ALLOCATOR: linked_list_allocator::LockedHeap = linked_list_allocator::LockedHeap::empty();\n"
  },
  {
    "path": "kernel/standalone/src/pci/native.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Native program that handles the `pci` interface.\n\nuse crate::{arch::PlatformSpecific, pci::pci};\n\nuse alloc::{boxed::Box, collections::VecDeque, sync::Arc, vec::Vec};\nuse core::{convert::TryFrom as _, pin::Pin, task::Poll};\nuse crossbeam_queue::SegQueue;\nuse futures::prelude::*;\nuse redshirt_core::{\n    extrinsics::Extrinsics, system::NativeInterfaceMessage, Decode as _, Encode as _,\n    EncodedMessage, MessageId, Pid,\n};\nuse redshirt_pci_interface::ffi;\nuse spinning_top::Spinlock;\n\n/// State machine for `pci` interface messages handling.\npub struct PciNativeProgram {\n    /// Platform-specific hooks.\n    platform_specific: Pin<Arc<PlatformSpecific>>,\n    /// Future triggered the next time a PCI device generates an interrupt.\n    // TODO: at the moment we don't differentiate between devices\n    next_irq: Spinlock<Pin<Box<dyn Future<Output = ()> + Send>>>,\n\n    pending_answers: SegQueue<(MessageId, EncodedMessage)>,\n\n    /// Devices manager. Does the actual work.\n    devices: pci::PciDevices,\n    /// List of devices locked by processes.\n    locked_devices: Spinlock<Vec<LockedDevice>>,\n}\n\n#[derive(Debug)]\nstruct LockedDevice {\n    owner: Pid,\n    bdf: ffi::PciDeviceBdf,\n\n    /// List of `MessageId`s sent and requesting to be answered when the next interrupt happens.\n    next_interrupt_messages: VecDeque<MessageId>,\n}\n\nimpl PciNativeProgram {\n    /// Initializes the new state machine for PCI messages handling.\n    pub fn new(devices: pci::PciDevices, platform_specific: Pin<Arc<PlatformSpecific>>) -> Self {\n        let next_irq = Spinlock::new(Box::pin(PlatformSpecific::next_irq(\n            platform_specific.as_ref(),\n        )) as Pin<Box<_>>);\n\n        PciNativeProgram {\n            platform_specific,\n            next_irq,\n            pending_answers: crossbeam_queue::SegQueue::new(),\n            devices,\n            locked_devices: Spinlock::new(Vec::new()),\n        }\n    }\n\n    pub async fn next_response(&self) -> (MessageId, EncodedMessage) {\n        loop {\n            if let Some(answer) = self.pending_answers.pop() {\n                return answer;\n            }\n\n            future::poll_fn(move |cx| {\n                let mut next_irq = self.next_irq.lock();\n                match next_irq.poll_unpin(cx) {\n                    Poll::Ready(()) => {}\n                    Poll::Pending => return Poll::Pending,\n                };\n\n                // We grab the next IRQ future now, in order to not miss any IRQ happening\n                // while `locked_devices` is processed below.\n                *next_irq = Box::pin(PlatformSpecific::next_irq(self.platform_specific.as_ref()))\n                    as Pin<Box<_>>;\n                drop(next_irq);\n\n                // Wake up all the devices.\n                let mut locked_devices = self.locked_devices.lock();\n                for device in locked_devices.iter_mut() {\n                    for msg in device.next_interrupt_messages.drain(..) {\n                        let answer =\n                            redshirt_pci_interface::ffi::NextInterruptResponse::Interrupt.encode();\n                        self.pending_answers.push((msg, answer));\n                    }\n                }\n\n                Poll::Ready(())\n            })\n            .await\n        }\n    }\n\n    pub fn interface_message<TExtr: Extrinsics>(\n        &self,\n        message_id: Option<MessageId>,\n        emitter_pid: Pid,\n        message: NativeInterfaceMessage<TExtr>,\n    ) -> Option<Result<EncodedMessage, ()>> {\n        // Locking `locked_devices` ahead of time to avoid messages being processed in the\n        // wrong order in case `interface_message` is called multiple times from different\n        // threads.\n        let mut locked_devices = self.locked_devices.lock();\n\n        match ffi::PciMessage::decode(message.extract()) {\n            Ok(ffi::PciMessage::LockDevice(bdf)) => {\n                if locked_devices.iter().any(|dev| dev.bdf == bdf) {\n                    Some(Ok(Result::<(), _>::Err(()).encode()))\n                } else {\n                    // TODO: check device validity\n                    locked_devices.push(LockedDevice {\n                        owner: emitter_pid,\n                        bdf,\n                        next_interrupt_messages: VecDeque::new(),\n                    });\n\n                    Some(Ok(Result::<_, ()>::Ok(()).encode()))\n                }\n            }\n\n            Ok(ffi::PciMessage::UnlockDevice(bdf)) => {\n                if let Some(pos) = locked_devices\n                    .iter_mut()\n                    .position(|dev| dev.owner == emitter_pid && dev.bdf == bdf)\n                {\n                    let locked_device = locked_devices.remove(pos);\n                    for m in locked_device.next_interrupt_messages {\n                        self.pending_answers\n                            .push((m, ffi::NextInterruptResponse::Unlocked.encode()));\n                    }\n                }\n                None\n            }\n\n            Ok(ffi::PciMessage::SetCommand {\n                location,\n                io_space,\n                memory_space,\n                bus_master,\n            }) => {\n                if locked_devices\n                    .iter()\n                    .any(|dev| dev.owner == emitter_pid && dev.bdf == location)\n                {\n                    self.devices\n                        .devices()\n                        .find(|d| {\n                            d.bus() == location.bus\n                                && d.device() == location.device\n                                && d.function() == location.function\n                        })\n                        .unwrap()\n                        .set_command(bus_master, memory_space, io_space);\n                }\n                None\n            }\n\n            Ok(ffi::PciMessage::NextInterrupt(bdf)) => {\n                // TODO: actually make these interrupts work\n                if let Some(message_id) = message_id {\n                    if let Some(dev) = locked_devices\n                        .iter_mut()\n                        .find(|dev| dev.owner == emitter_pid && dev.bdf == bdf)\n                    {\n                        dev.next_interrupt_messages.push_back(message_id);\n                        None\n                    } else {\n                        Some(Ok(ffi::NextInterruptResponse::BadDevice.encode()))\n                    }\n                } else {\n                    None\n                }\n            }\n\n            Ok(ffi::PciMessage::GetDevicesList) => {\n                if let Some(message_id) = message_id {\n                    let response = ffi::GetDevicesListResponse {\n                        devices: self\n                            .devices\n                            .devices()\n                            .map(|device| ffi::PciDeviceInfo {\n                                location: ffi::PciDeviceBdf {\n                                    bus: device.bus(),\n                                    device: device.device(),\n                                    function: device.function(),\n                                },\n                                vendor_id: device.vendor_id(),\n                                device_id: device.device_id(),\n                                class_code: device.class_code(),\n                                subclass: device.subclass(),\n                                prog_if: device.prog_if(),\n                                revision_id: device.revision_id(),\n                                base_address_registers: device\n                                    .base_address_registers()\n                                    .map(|bar| match bar {\n                                        pci::BaseAddressRegister::Memory {\n                                            base_address, ..\n                                        } => ffi::PciBaseAddressRegister::Memory {\n                                            base_address: u64::try_from(base_address).unwrap(),\n                                        },\n                                        pci::BaseAddressRegister::Io { base_address } => {\n                                            ffi::PciBaseAddressRegister::Io {\n                                                base_address: u32::from(base_address),\n                                            }\n                                        }\n                                    })\n                                    .collect(),\n                            })\n                            .collect(),\n                    };\n\n                    Some(Ok(response.encode()))\n                } else {\n                    None\n                }\n            }\n\n            Ok(_) => unimplemented!(), // TODO:\n\n            Err(_) => Some(Err(())),\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/pci/pci.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Manages the PCI devices of the system.\n//!\n//! See https://en.wikipedia.org/wiki/PCI_configuration_space\n\nuse alloc::{collections::VecDeque, vec::Vec};\nuse core::{convert::TryFrom as _, iter};\n\n#[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nuse x86_64::structures::port::{PortRead as _, PortWrite as _};\n\n/// Initializes PCI the \"legacy\" way, by reading and writing CPU I/O ports.\n///\n/// # Safety\n///\n/// The PCI space must only be enabled once.\n// TODO: support Enhanced Configuration Access Mechanism (ECAM)\npub unsafe fn init_cam_pci() -> PciDevices {\n    PciDevices {\n        known_devices: scan_all_buses(),\n    }\n}\n\n/// Manages PCI devices.\npub struct PciDevices {\n    /// Result of the devices scan.\n    /// Never modified.\n    known_devices: Vec<DeviceInfo>,\n}\n\n#[derive(Debug, Copy, Clone)]\nstruct DeviceBdf {\n    bus: u8,\n    device: u8,\n    function: u8,\n}\n\n#[derive(Debug)]\nstruct DeviceInfo {\n    bdf: DeviceBdf,\n    vendor_id: u16,\n    device_id: u16,\n    header_ty: u8,\n    class_code: u8,\n    subclass: u8,\n    prog_if: u8,\n    revision_id: u8,\n    base_address_registers: Vec<BaseAddressRegister>,\n}\n\nimpl PciDevices {\n    // TODO:\n    pub fn devices(&self) -> impl Iterator<Item = Device> {\n        (0..self.known_devices.len()).map(move |index| Device {\n            parent: self,\n            index,\n        })\n    }\n}\n\n/// Access to a single device within the list.\npub struct Device<'a> {\n    parent: &'a PciDevices,\n    index: usize,\n}\n\nimpl<'a> Device<'a> {\n    #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n    pub fn set_command(&mut self, bus_master: bool, memory_space: bool, io_space: bool) {\n        let command: u16 = if bus_master { 1 << 2 } else { 0 }\n            | if memory_space { 1 << 1 } else { 0 }\n            | if io_space { 1 << 0 } else { 0 };\n\n        // TODO: that overwrites status, is that ok?\n        pci_cfg_write_u32(\n            &self.parent.known_devices[self.index].bdf,\n            0x4,\n            u32::from(command),\n        );\n    }\n\n    #[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n    pub fn set_command(&mut self, _: bool, _: bool, _: bool) {\n        unreachable!()\n    }\n\n    pub fn bus(&self) -> u8 {\n        self.parent.known_devices[self.index].bdf.bus\n    }\n\n    pub fn device(&self) -> u8 {\n        self.parent.known_devices[self.index].bdf.device\n    }\n\n    pub fn function(&self) -> u8 {\n        self.parent.known_devices[self.index].bdf.function\n    }\n\n    pub fn vendor_id(&self) -> u16 {\n        self.parent.known_devices[self.index].vendor_id\n    }\n\n    pub fn device_id(&self) -> u16 {\n        self.parent.known_devices[self.index].device_id\n    }\n\n    pub fn class_code(&self) -> u8 {\n        self.parent.known_devices[self.index].class_code\n    }\n\n    pub fn subclass(&self) -> u8 {\n        self.parent.known_devices[self.index].subclass\n    }\n\n    pub fn prog_if(&self) -> u8 {\n        self.parent.known_devices[self.index].prog_if\n    }\n\n    pub fn revision_id(&self) -> u8 {\n        self.parent.known_devices[self.index].revision_id\n    }\n\n    pub fn base_address_registers(&self) -> impl Iterator<Item = BaseAddressRegister> + 'a {\n        self.parent.known_devices[self.index]\n            .base_address_registers\n            .iter()\n            .cloned()\n    }\n}\n\n#[derive(Debug, Copy, Clone)]\npub enum BaseAddressRegister {\n    Memory {\n        base_address: usize,\n        prefetchable: bool,\n    },\n    Io {\n        base_address: u16,\n    },\n}\n\n/// Scans all the PCI devices.\n#[cfg(not(any(target_arch = \"x86\", target_arch = \"x86_64\")))]\nfn scan_all_buses() -> Vec<DeviceInfo> {\n    Vec::new()\n}\n\n/// Scans all the PCI devices.\n#[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nfn scan_all_buses() -> Vec<DeviceInfo> {\n    // TODO: apparently it's possible to have multiple PCI controllers\n    //       see https://wiki.osdev.org/PCI#Recursive_Scan\n\n    let mut checked = Vec::with_capacity(32);\n    let mut to_check = VecDeque::with_capacity(32);\n    to_check.push_back(0);\n    let mut out = Vec::with_capacity(64);\n\n    loop {\n        let next_bus = match to_check.pop_front() {\n            Some(b) => b,\n            None => return out,\n        };\n\n        debug_assert!(!checked.iter().any(|b| *b == next_bus));\n        checked.push(next_bus);\n\n        for scan_result in scan_bus(next_bus) {\n            match scan_result {\n                ScanResult::Device(dev) => out.push(dev),\n                ScanResult::Bridge { target_bus, .. } => {\n                    if !checked.iter().any(|b| *b == next_bus) {\n                        to_check.push_back(target_bus);\n                    }\n                }\n            }\n        }\n    }\n}\n\n/// Scans all the devices on a certain PCI bus.\n#[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nfn scan_bus(bus: u8) -> impl Iterator<Item = ScanResult> {\n    (0..32).flat_map(move |device_idx| scan_device(bus, device_idx))\n}\n\n/// Reads the information about a single PCI device. Returns the list of devices that have been found.\n///\n/// # Panic\n///\n/// Panics if the device is out of range.\n#[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nfn scan_device(bus: u8, device: u8) -> impl Iterator<Item = ScanResult> {\n    assert!(device < 32);\n\n    let f0 = match scan_function(&DeviceBdf {\n        bus,\n        device,\n        function: 0,\n    }) {\n        Some(f) => f,\n        None => return either::Right(iter::empty()),\n    };\n\n    match f0 {\n        // If the MSB of `header_ty` is 1, then this is a \"multi-function\" device and we need to\n        // scan all the other functions.\n        ScanResult::Device(info) if (info.header_ty & 0x80) != 0 => {\n            let iter = (1..=7).flat_map(move |func_idx| {\n                scan_function(&DeviceBdf {\n                    bus,\n                    device,\n                    function: func_idx,\n                })\n                .into_iter()\n            });\n\n            either::Left(either::Right(iter))\n        }\n        f0 => either::Left(either::Left(iter::once(f0))),\n    }\n}\n\n/// Output of [`scan_function`].\n#[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n#[derive(Debug)]\nenum ScanResult {\n    /// Function is a device description.\n    Device(DeviceInfo),\n    /// Function is a bridge to a different bus.\n    Bridge {\n        /// Location of the function that we have scanned.\n        bdf: DeviceBdf,\n        /// Bus in question.\n        target_bus: u8,\n    },\n}\n\n/// Reads the information about a single PCI slot, or `None` if it is empty.\n///\n/// # Panic\n///\n/// Panics if the device is out of range.\n#[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nfn scan_function(bdf: &DeviceBdf) -> Option<ScanResult> {\n    let (vendor_id, device_id) = {\n        let vendor_device = pci_cfg_read_u32(bdf, 0);\n        let vendor_id = u16::try_from(vendor_device & 0xffff).unwrap();\n        let device_id = u16::try_from(vendor_device >> 16).unwrap();\n        (vendor_id, device_id)\n    };\n\n    if vendor_id == 0xffff {\n        return None;\n    }\n\n    let (class_code, subclass, prog_if, revision_id) = {\n        let val = pci_cfg_read_u32(bdf, 0x8);\n        let bytes = val.to_be_bytes();\n        (bytes[0], bytes[1], bytes[2], bytes[3])\n    };\n\n    let (_bist, header_ty, _latency, _cache_line) = {\n        let val = pci_cfg_read_u32(bdf, 0xc);\n        let bytes = val.to_be_bytes();\n        (bytes[0], bytes[1], bytes[2], bytes[3])\n    };\n\n    // This class/subclass combination indicates a PCI-to-PCI bridge, for which we return\n    // something different.\n    if class_code == 0x7 && subclass == 0x4 {\n        let (_sec_latency_timer, _sub_bus_num, sec_bus_num, _prim_bus_num) = {\n            let val = pci_cfg_read_u32(bdf, 0x18);\n            let bytes = val.to_be_bytes();\n            (bytes[0], bytes[1], bytes[2], bytes[3])\n        };\n\n        return Some(ScanResult::Bridge {\n            bdf: *bdf,\n            target_bus: sec_bus_num,\n        });\n    }\n\n    Some(ScanResult::Device(DeviceInfo {\n        bdf: *bdf,\n        vendor_id,\n        device_id,\n        header_ty,\n        class_code,\n        subclass,\n        prog_if,\n        revision_id,\n        base_address_registers: {\n            let mut list = Vec::with_capacity(6);\n\n            let mut bar_n = 0;\n            loop {\n                if bar_n >= 6 {\n                    break;\n                }\n\n                let bar = pci_cfg_read_u32(bdf, 0x10 + bar_n * 0x4);\n                if (bar & 0x1) == 0 {\n                    let ty = (bar >> 1) & 0b11;\n                    let prefetchable = (bar & (1 << 3)) != 0;\n                    let base_address = bar & !0b1111;\n\n                    if ty == 0 {\n                        // 32 bits memory BAR\n                        list.push(BaseAddressRegister::Memory {\n                            base_address: usize::try_from(base_address).unwrap(),\n                            prefetchable,\n                        });\n                        bar_n += 1;\n                    } else if ty == 2 {\n                        // 64 bits memory BAR. The higher 32 bits are located in the next BAR.\n                        let addr_hi = pci_cfg_read_u32(bdf, 0x10 + (bar_n + 1) * 0x4);\n                        let address = (u64::from(addr_hi) << 32) | u64::from(base_address);\n                        if let Ok(address) = usize::try_from(address) {\n                            list.push(BaseAddressRegister::Memory {\n                                base_address: address,\n                                prefetchable,\n                            });\n                        }\n                        bar_n += 2;\n                    }\n                } else {\n                    // TODO: this ` & 0xffff` is normally not needed, but it seems like on real\n                    // hardware the value is higher than 0xffff\n                    let base_address = u16::try_from((bar & !0b11) & 0xffff).unwrap();\n                    list.push(BaseAddressRegister::Io { base_address });\n                    bar_n += 1;\n                }\n            }\n\n            list\n        },\n    }))\n}\n\n/// Reads the configuration space of the given device.\n///\n/// Automatically swaps bytes on big-endian platforms.\n///\n/// # Panic\n///\n/// Panics if the device or function are out of range.\n/// Panics if `offset` is not 4-bytes aligned.\n///\n#[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nfn pci_cfg_read_u32(bdf: &DeviceBdf, offset: u8) -> u32 {\n    pci_cfg_prepare_port(bdf, offset);\n\n    unsafe {\n        if cfg!(target_endian = \"little\") {\n            u32::read_from_port(0xcfc)\n        } else {\n            u32::read_from_port(0xcfc).swap_bytes()\n        }\n    }\n}\n\n/// Writes the configuration space of the given device.\n///\n/// Automatically swaps bytes on big-endian platforms.\n///\n/// # Panic\n///\n/// Panics if the device or function are out of range.\n/// Panics if `offset` is not 4-bytes aligned.\n///\n#[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nfn pci_cfg_write_u32(bdf: &DeviceBdf, offset: u8, data: u32) {\n    pci_cfg_prepare_port(bdf, offset);\n\n    unsafe {\n        if cfg!(target_endian = \"little\") {\n            u32::write_to_port(0xcfc, data)\n        } else {\n            u32::write_to_port(0xcfc, data.swap_bytes())\n        }\n    }\n}\n\n#[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nfn pci_cfg_prepare_port(bdf: &DeviceBdf, offset: u8) {\n    assert!(bdf.device < 32);\n    assert!(bdf.function < 8);\n    assert_eq!(offset % 4, 0);\n\n    let addr: u32 = 0x80000000\n        | (u32::from(bdf.bus) << 16)\n        | (u32::from(bdf.device) << 11)\n        | (u32::from(bdf.function) << 8)\n        | u32::from(offset);\n\n    unsafe {\n        u32::write_to_port(0xcf8, addr);\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/pci.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\npub mod native;\npub mod pci;\n"
  },
  {
    "path": "kernel/standalone/src/random/native.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Native program that handles the `random` interface.\n\nuse crate::{arch::PlatformSpecific, random::rng::KernelRng};\n\nuse alloc::{sync::Arc, vec};\nuse core::pin::Pin;\nuse crossbeam_queue::SegQueue;\nuse rand_core::RngCore as _;\nuse redshirt_core::{\n    extrinsics::Extrinsics, system::NativeInterfaceMessage, Decode as _, Encode as _,\n    EncodedMessage,\n};\nuse redshirt_random_interface::ffi::{GenerateResponse, RandomMessage};\n\n/// State machine for `random` interface messages handling.\npub struct RandomNativeProgram {\n    /// Queue of random number generators. If it is empty, we generate a new one.\n    rngs: SegQueue<KernelRng>,\n    /// Platform-specific hooks.\n    platform_specific: Pin<Arc<PlatformSpecific>>,\n}\n\nimpl RandomNativeProgram {\n    /// Initializes the new state machine for random messages handling.\n    pub fn new(platform_specific: Pin<Arc<PlatformSpecific>>) -> Self {\n        RandomNativeProgram {\n            rngs: SegQueue::new(),\n            platform_specific,\n        }\n    }\n\n    /// Fills the given buffer with random bytes.\n    pub fn fill_bytes(&self, out: &mut [u8]) {\n        let mut rng = if let Some(rng) = self.rngs.pop() {\n            rng\n        } else {\n            KernelRng::new(self.platform_specific.clone())\n        };\n\n        rng.fill_bytes(out);\n        self.rngs.push(rng);\n    }\n\n    pub fn interface_message<TExtr: Extrinsics>(\n        &self,\n        message: NativeInterfaceMessage<TExtr>,\n    ) -> Result<EncodedMessage, ()> {\n        match RandomMessage::decode(message.extract()) {\n            Ok(RandomMessage::Generate { len }) => {\n                let mut out = vec![0; usize::from(len)];\n                self.fill_bytes(&mut out);\n                Ok(GenerateResponse { result: out }.encode())\n            }\n            Err(_) => Err(()),\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/standalone/src/random/rng.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Random number generation.\n//!\n//! This module aims to provide cryptographically-secure random number generation.\n//!\n//! Since computers are deterministic, it is surprisingly difficult to generate entropy. This is\n//! typically not a concern for most developers in the world, because most of the time when\n//! a program needs random data, it simply asks the kernel for some (e.g. by reading\n//! `/dev/urandom` on Unix). Here, however, we *are* the kernel.\n//!\n//! In order to generate entropy, we can rely on:\n//!\n//! - Hardware random number generators, such as `rdseed`/`rdrand` on x86/x64. This is however\n//! generally widely untrusted.\n//! - Unpredictable events coming from the hardware, such as time between keyboard presses or\n//! network packets.\n//! - CPU execution time jitter. The time it takes for a CPU to execute instructions is very hard\n//! to predict because of caches, memory bus speed, power management, and so on.\n//!\n//! # Implementation in redshirt\n//!\n//! The current implementation relies on ChaCha20 seeded by a JitterRng and RdSeed/RdRand if they\n//! are available.\n//!\n\nuse crate::arch::PlatformSpecific;\n\nuse alloc::sync::Arc;\nuse core::{convert::TryFrom as _, pin::Pin};\nuse rand_chacha::{ChaCha20Core, ChaCha20Rng};\nuse rand_core::{RngCore, SeedableRng as _};\nuse rand_jitter::JitterRng;\n\n/// Kernel random number generator.\npub struct KernelRng {\n    /// Inner PRNG.\n    rng: ChaCha20Rng,\n}\n\nimpl KernelRng {\n    /// Initializes a new [`KernelRng`].\n    pub fn new(platform_specific: Pin<Arc<PlatformSpecific>>) -> KernelRng {\n        // Initialize the `JitterRng`.\n        let mut jitter = {\n            let mut rng = JitterRng::new_with_timer(move || {\n                u64::try_from(platform_specific.as_ref().monotonic_clock() & 0xffffffffffffffff)\n                    .unwrap()\n            });\n\n            // This makes sure that the `JitterRng` is good enough. A panic here indicates that\n            // our entropy would be too low.\n            let rounds = match rng.test_timer() {\n                Ok(r) => r,\n                Err(err) => panic!(\"{:?}\", err),\n            };\n            rng.set_rounds(rounds);\n            // According to the documentation, we have to discard the first `u64`.\n            let _ = rng.next_u64();\n            rng\n        };\n\n        // We now build the seed for the main ChaCha PRNG.\n        let chacha_seed = {\n            let mut hasher = blake3::Hasher::new();\n            let mut jitter_bytes = [0; 64];\n            jitter.fill_bytes(&mut jitter_bytes);\n            hasher.update(&jitter_bytes[..]);\n            add_hardware_entropy(&mut hasher);\n            <[u8; 32]>::from(hasher.finalize())\n        };\n\n        KernelRng {\n            rng: From::from(ChaCha20Core::from_seed(chacha_seed)),\n        }\n    }\n}\n\nimpl RngCore for KernelRng {\n    fn next_u32(&mut self) -> u32 {\n        self.rng.next_u32()\n    }\n\n    fn next_u64(&mut self) -> u64 {\n        self.rng.next_u64()\n    }\n\n    fn fill_bytes(&mut self, dest: &mut [u8]) {\n        self.rng.fill_bytes(dest)\n    }\n\n    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {\n        self.rng.try_fill_bytes(dest)\n    }\n}\n\n// TODO: move add_hardware_entropy to the PlatformSpecific trait?\n\n#[cfg(target_arch = \"x86_64\")]\nfn add_hardware_entropy(hasher: &mut blake3::Hasher) {\n    if let Ok(mut rdseed) = rdrand::RdSeed::new() {\n        let mut buf = [0; 64];\n        if rdseed.try_fill_bytes(&mut buf).is_ok() {\n            hasher.update(&buf);\n            return;\n        }\n    }\n\n    if let Ok(mut rdrand) = rdrand::RdRand::new() {\n        let mut buf = [0; 64];\n        if rdrand.try_fill_bytes(&mut buf).is_ok() {\n            hasher.update(&buf);\n            return;\n        }\n    }\n}\n\n#[cfg(not(target_arch = \"x86_64\"))]\nfn add_hardware_entropy(_: &mut blake3::Hasher) {}\n"
  },
  {
    "path": "kernel/standalone/src/random.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\npub mod native;\npub mod rng;\n"
  },
  {
    "path": "kernel/standalone/src/time.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Implements the `time` interface.\n\nuse crate::arch::PlatformSpecific;\n\nuse alloc::{boxed::Box, sync::Arc};\nuse core::pin::Pin;\nuse futures::{prelude::*, stream::FuturesUnordered, task::Poll};\nuse redshirt_core::{\n    extrinsics::Extrinsics, system::NativeInterfaceMessage, Decode as _, Encode as _,\n    EncodedMessage, MessageId,\n};\nuse redshirt_time_interface::ffi::TimeMessage;\nuse spinning_top::Spinlock;\n\n/// State machine for `time` interface messages handling.\npub struct TimeHandler {\n    /// Platform-specific hooks.\n    platform_specific: Pin<Arc<PlatformSpecific>>,\n    /// List of active timers.\n    timers: Spinlock<FuturesUnordered<Pin<Box<dyn Future<Output = MessageId> + Send>>>>,\n}\n\nimpl TimeHandler {\n    /// Initializes the new state machine for time accesses.\n    pub fn new(platform_specific: Pin<Arc<PlatformSpecific>>) -> Self {\n        TimeHandler {\n            platform_specific,\n            timers: Spinlock::new(FuturesUnordered::new()),\n        }\n    }\n\n    pub fn interface_message<TExtr: Extrinsics>(\n        &self,\n        message_id: MessageId,\n        message: NativeInterfaceMessage<TExtr>,\n    ) -> Option<Result<EncodedMessage, ()>> {\n        match TimeMessage::decode(message.extract()) {\n            Ok(TimeMessage::GetMonotonic) => {\n                let now = self.platform_specific.as_ref().monotonic_clock();\n                Some(Ok(now.encode()))\n            }\n            Ok(TimeMessage::WaitMonotonic(value)) => {\n                let timers = self.timers.lock();\n                timers.push(\n                    self.platform_specific\n                        .as_ref()\n                        .timer(value)\n                        .map(move |_| message_id)\n                        .boxed(),\n                );\n                None\n            }\n            Err(_) => Some(Err(())),\n        }\n    }\n\n    pub async fn next_response(&self) -> (MessageId, EncodedMessage) {\n        future::poll_fn(move |cx| {\n            let mut timers = self.timers.lock();\n            if timers.is_empty() {\n                return Poll::Pending;\n            }\n\n            let message_id = match timers.poll_next_unpin(cx) {\n                Poll::Ready(Some(id)) => id,\n                Poll::Ready(None) => unreachable!(),\n                Poll::Pending => return Poll::Pending,\n            };\n\n            Poll::Ready((message_id, ().encode()))\n        })\n        .await\n    }\n}\n"
  },
  {
    "path": "kernel-standalone-builder/Cargo.toml",
    "content": "[package]\nname = \"redshirt-standalone-builder\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\nbuild = \"build.rs\"\n\n[workspace]\n\n[dependencies]\nfatfs = \"0.3.5\"\nfscommon = \"0.1.1\"\nfutures = \"0.3.21\"\nfutures-timer = \"3.0.2\"\ncargo_metadata = \"0.12\"\nmbrman = \"0.4.0\"\nserde_json = \"1.0.79\"\nstructopt = \"0.3.26\"\ntempdir = \"0.3.7\"\nthiserror = \"1.0\"\ntoml = \"0.5.8\"\nwalkdir = \"2.3.2\"\n\n[build-dependencies]\ncc = \"1.2.16\"\n\n[profile.dev]\nopt-level = 1\n\n[profile.dev.package.\"*\"]\nopt-level = 3\n\n[profile.test.package.\"*\"]\nopt-level = 3\n"
  },
  {
    "path": "kernel-standalone-builder/build.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nfn main() {\n    println!(\"cargo::rerun-if-changed=simpleboot\");\n    cc::Build::new()\n        .file(\"simpleboot/wrapper.c\")\n        .compile(\"simpleboot\");\n}\n"
  },
  {
    "path": "kernel-standalone-builder/res/rpi-firmware/boot/COPYING.linux",
    "content": "\n   NOTE! This copyright does *not* cover user programs that use kernel\n services by normal system calls - this is merely considered normal use\n of the kernel, and does *not* fall under the heading of \"derived work\".\n Also note that the GPL below is copyrighted by the Free Software\n Foundation, but the instance of code that it refers to (the Linux\n kernel) is copyrighted by me and others who actually wrote it.\n\n Also note that the only valid version of the GPL as far as the kernel\n is concerned is _this_ particular version of the license (ie v2, not\n v2.2 or v3.x or whatever), unless explicitly otherwise stated.\n\n\t\t\tLinus Torvalds\n\n----------------------------------------\n\n\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Library General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\f\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\f\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\f\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\f\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\f\n\t    How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program; if not, write to the Free Software\n    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Library General\nPublic License instead of this License.\n"
  },
  {
    "path": "kernel-standalone-builder/res/rpi-firmware/boot/LICENCE.broadcom",
    "content": "Copyright (c) 2006, Broadcom Corporation.\nCopyright (c) 2015, Raspberry Pi (Trading) Ltd\nAll rights reserved.\n\nRedistribution.  Redistribution and use in binary form, without\nmodification, are permitted provided that the following conditions are\nmet:\n\n* This software may only be used for the purposes of developing for, \n  running or using a Raspberry Pi device, or authorised derivative\n  device manufactured via the element14 Raspberry Pi Customization Service\n* Redistributions must reproduce the above copyright notice and the\n  following disclaimer in the documentation and/or other materials\n  provided with the distribution.\n* Neither the name of Broadcom Corporation nor the names of its suppliers\n  may be used to endorse or promote products derived from this software\n  without specific prior written permission.\n\nDISCLAIMER.  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\nCONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\nBUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\nCOPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\nBUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS\nOF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR\nTORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE\nUSE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGE.\n\n"
  },
  {
    "path": "kernel-standalone-builder/res/specs/aarch64-freestanding.json",
    "content": "{\n    \"arch\": \"aarch64\",\n    \"data-layout\": \"e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128\",\n    \"disable-redzone\": true,\n    \"env\": \"\",\n    \"executables\": true,\n    \"features\": \"+strict-align,+neon,+fp-armv8\",\n    \"linker\": \"rust-lld\",\n    \"linker-flavor\": \"ld.lld\",\n    \"linker-is-gnu\": true,\n    \"llvm-target\": \"aarch64-unknown-none\",\n    \"max-atomic-width\": 128,\n    \"os\": \"none\",\n    \"panic-strategy\": \"abort\",\n    \"relocation-model\": \"static\",\n    \"target-c-int-width\": \"32\",\n    \"target-endian\": \"little\",\n    \"target-pointer-width\": \"64\",\n    \"unsupported-abis\": [\n      \"stdcall\",\n      \"fastcall\",\n      \"vectorcall\",\n      \"thiscall\",\n      \"win64\",\n      \"sysv64\"\n    ]\n}\n"
  },
  {
    "path": "kernel-standalone-builder/res/specs/aarch64-freestanding.ld",
    "content": "ENTRY(_entry_point)\n\nSECTIONS {\n    . = 0x80000;\n    .text : AT(ADDR(.text)) {\n        _entry_point = .;\n        /* Same as above, jump to the address of `_start` */\n        /* TODO: this always fails, no clue why: ASSERT(((_start - 0x80000) >> 2) == ((_start >> 2) & 0x1FFFFFF), \"_start too far away\") */\n        LONG(0x14000000 | (((_start - 0x80000) >> 2) & 0x1FFFFFF))\n\n        *(.text*)\n        *(.rodata*)\n    }\n\n    /* Garbage that the compiler seems to introduce for stack unwinding purposes */\n    .ARM.exidx : AT(ADDR(.ARM.exidx)) {\n        *(.ARM.exidx*)\n        *(.gnu.linkonce.armexidx.*)\n    }\n\n    .data : AT(ADDR(.data)) {\n        *(.data*)\n    }\n\n    .bss : AT(ADDR(.bss)) ALIGN(8) {\n        __bss_start = .;\n        *(.bss*)\n        *(COMMON*)\n        __bss_end = .;\n    }\n}\n"
  },
  {
    "path": "kernel-standalone-builder/res/specs/arm-freestanding.json",
    "content": "{\n    \"arch\": \"arm\",\n    \"data-layout\": \"e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64\",\n    \"emit-debug-gdb-scripts\": false,\n    \"env\": \"\",\n    \"executables\": true,\n    \"features\": \"+armv7-a,-slowfpvmlx,-vfp2,-vfp3,-vfp4,+soft-float\",\n    \"linker\": \"ld.lld\",\n    \"linker-flavor\": \"ld\",\n    \"lld-flavor\": \"link\",\n    \"llvm-target\": \"armv7a-unknown-none-eabi\",\n    \"max-atomic-width\": 32,\n    \"os\": \"none\",\n    \"panic-strategy\": \"abort\",\n    \"relocation-model\": \"static\",\n    \"target-c-int-width\": \"32\",\n    \"target-endian\": \"little\",\n    \"target-pointer-width\": \"32\",\n    \"unsupported-abis\": [\n        \"stdcall\",\n        \"fastcall\",\n        \"vectorcall\",\n        \"thiscall\",\n        \"win64\",\n        \"sysv64\"\n    ]\n}\n"
  },
  {
    "path": "kernel-standalone-builder/res/specs/arm-freestanding.ld",
    "content": "ENTRY(_entry_point)\n\nSECTIONS {\n    . = 0x8000;\n    .text : AT(ADDR(.text)) {\n        _entry_point = .;\n        /* Same as above, jump to the address of `_start` */\n        /* TODO: this always fails, no clue why: ASSERT((((_start - 0x8000) >> 2) - 2) == (((_start >> 2) - 2) & 0x1FFFFFF), \"_start too far away\") */\n        LONG(0xea000000 | ((((_start - 0x8000) >> 2) - 2) & 0x1FFFFFF))\n\n        *(.text*)\n        *(.rodata*)\n    }\n\n    /* Garbage that the compiler seems to introduce for stack unwinding purposes */\n    .ARM.exidx : AT(ADDR(.ARM.exidx)) {\n        *(.ARM.exidx*)\n        *(.gnu.linkonce.armexidx.*)\n    }\n\n    .data : AT(ADDR(.data)) {\n        *(.data*)\n    }\n\n    .bss : AT(ADDR(.bss)) ALIGN(8) {\n        __bss_start = .;\n        *(.bss*)\n        *(COMMON*)\n        __bss_end = .;\n    }\n}\n"
  },
  {
    "path": "kernel-standalone-builder/res/specs/riscv-hifive.json",
    "content": "{\n    \"arch\": \"riscv32\",\n    \"cpu\": \"generic-rv32\",\n    \"data-layout\": \"e-m:e-p:32:32-i64:64-n32-S128\",\n    \"eliminate-frame-pointer\": false,\n    \"emit-debug-gdb-scripts\": false,\n    \"env\": \"\",\n    \"executables\": true,\n    \"features\": \"+m,+a,+c\",\n    \"is-builtin\": true,\n    \"linker\": \"rust-lld\",\n    \"linker-flavor\": \"ld.lld\",\n    \"llvm-target\": \"riscv32\",\n    \"max-atomic-width\": 32,\n    \"os\": \"none\",\n    \"panic-strategy\": \"abort\",\n    \"relocation-model\": \"static\",\n    \"target-c-int-width\": \"32\",\n    \"target-endian\": \"little\",\n    \"target-pointer-width\": \"32\",\n    \"unsupported-abis\": [\n        \"cdecl\",\n        \"stdcall\",\n        \"fastcall\",\n        \"vectorcall\",\n        \"thiscall\",\n        \"aapcs\",\n        \"win64\",\n        \"sysv64\",\n        \"ptx-kernel\",\n        \"msp430-interrupt\",\n        \"x86-interrupt\",\n        \"amdgpu-kernel\"\n    ]\n}\n"
  },
  {
    "path": "kernel-standalone-builder/res/specs/riscv-hifive.ld",
    "content": "OUTPUT_ARCH(\"riscv\")\nENTRY(_entry_point)\n\nMEMORY {\n  RAM : ORIGIN = 0x80000000, LENGTH = 16K\n  FLASH : ORIGIN = 0x20400000, LENGTH = 512M\n}\n\nSECTIONS {\n  .text : {\n    . = 0x20400000;\n    _entry_point = .;\n\n    /* Jump to the address of `_start` */\n    ASSERT((_start - 0x20400000) < (1 << 21), \"_start too far away\")\n    LONG(\n      0x6f |\n      ((((_start - 0x20400000) >> 12) & 0xff) << 12) |\n      ((((_start - 0x20400000) >> 11) & 0x1) << 20) |\n      ((((_start - 0x20400000) >> 1) & 0x3ff) << 21) |\n      ((((_start - 0x20400000) >> 20) & 0x1) << 31)\n    )\n\n    *(.text)\n    *(.text.*)\n    *(.rodata)\n    *(.rodata.*)\n    *(.sdata)\n    *(.sdata.*)\n  } > FLASH\n\n  .data : {\n    *(.data)\n    *(.data.*)\n  } > RAM AT > FLASH\n\n  .bss : {\n    __bss_start = .;\n    *(.bss)\n    *(.bss.*)\n    *(COMMON)\n    __bss_end = .;\n  } > RAM\n\n  /DISCARD/ : {\n    *(.eh_frame);\n    *(.eh_frame_hdr);\n    *(.comment);\n  }\n}\n"
  },
  {
    "path": "kernel-standalone-builder/res/specs/x86_64-multiboot2.json",
    "content": "{\n    \"arch\": \"x86_64\",\n    \"code-model\": \"kernel\",\n    \"cpu\": \"x86-64\",\n    \"crt-objects-fallback\": \"false\",\n    \"data-layout\": \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128\",\n    \"disable-redzone\": true,\n    \"eliminate-frame-pointer\": true,\n    \"executables\": true,\n    \"features\": \"+mmx,+sse,+sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,-soft-float\",\n    \"linker\": \"rust-lld\",\n    \"linker-flavor\": \"gnu-lld\",\n    \"lld-flavor\": \"link\",\n    \"llvm-target\": \"x86_64-unknown-none-elf\",\n    \"max-atomic-width\": 64,\n    \"os\": \"none\",\n    \"panic-strategy\": \"abort\",\n    \"plt-by-default\": false,\n    \"position-independent-executables\": true,\n    \"relocation-model\": \"static\",\n    \"singlethread\": false,\n    \"stack-probes\": {\n        \"kind\": \"inline\"\n    },\n    \"target-c-int-width\": \"32\",\n    \"target-endian\": \"little\",\n    \"target-pointer-width\": \"64\"\n}\n"
  },
  {
    "path": "kernel-standalone-builder/res/specs/x86_64-multiboot2.ld",
    "content": "OUTPUT_FORMAT(\"elf64-x86-64\")\nOUTPUT_ARCH(\"i386:x86-64\")\nENTRY(_start)\n\nMULTIBOOT2_MAGIC = 0xe85250d6;\nMULTIBOOT2_ARCH = 0;\nMULTIBOOT2_HEADER_LEN = mboot_end - mboot_start;\nMULTIBOOT2_CHECKSUM = -(MULTIBOOT2_MAGIC + MULTIBOOT2_ARCH + MULTIBOOT2_HEADER_LEN);\n\nSECTIONS {\n  . = 4M;\n\n  .mboot ALIGN(4) : AT(ADDR(.mboot)) {\n    mboot_start = .;\n\n    LONG(MULTIBOOT2_MAGIC)\n    LONG(MULTIBOOT2_ARCH)\n    LONG(MULTIBOOT2_HEADER_LEN)\n    LONG(MULTIBOOT2_CHECKSUM)\n\n    /* Flags tag, indicating that we support graphics */\n    . = ALIGN(8);\n    SHORT(4)\n    SHORT(1)    /* flags = 1 means this tag can be ignored if not supported */\n    LONG(12)\n    LONG(1)     /* 0 = text, 1 = graphics\n\n    /* Framebuffer tag, indicating the preferred graphics mode */\n    . = ALIGN(8);\n    SHORT(5)\n    SHORT(1)    /* flags = 1 means this tag can be ignored if not supported */\n    LONG(20)\n    LONG(1024)  /* width */\n    LONG(768)   /* height */\n    LONG(32)    /* depth */\n\n    /* end of tags */\n    . = ALIGN(8);\n    SHORT(0)\n    SHORT(0)\n    LONG(8)\n\n    mboot_end = .;\n  }\n\n  .text ALIGN(4096) : AT(ADDR(.text)) {\n    *(.text)\n    *(.text.*)\n  }\n\n  .rodata ALIGN(4096) : AT(ADDR(.rodata)) {\n    *(.rodata)\n    *(.rodata.*)\n  }\n\n  .data ALIGN(4096) : AT(ADDR(.data)) {\n    *(.data)\n    *(.data.*)\n  }\n\n  .bss ALIGN(4096) : AT(ADDR(.bss)) {\n    __bss_start = .;\n    *(.bss)\n    *(.bss.*)\n    *(COMMON)\n    __bss_end = .;\n  }\n\n  /DISCARD/ : {\n    *(.eh_frame)\n    *(.debug_*)\n  }\n}\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/README.md",
    "content": "The `simpleboot` directory contains a copy of <https://gitlab.com/bztsrc/simpleboot>,\nexcept that the `main` function has been renamed to `simpleboot_main` in order to\nmake it usable as a library.\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/.gitignore",
    "content": "*.o\n*.img\n*.bin\n*.rom\n*.efi\n*.elf\nexample/boot\nexample/mnt\nsrc/simpleboot\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/Kconfig",
    "content": "if PAYLOAD_SIMPLEBOOT\n\nconfig PAYLOAD_FILE\n\tdefault \"payloads/external/simpleboot/src/loader_cb.elf\"\n\nendif\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/Kconfig.name",
    "content": "config PAYLOAD_SIMPLEBOOT\n\tbool \"Simpleboot\"\n\tdepends on ARCH_X86 || ARCH_ARM64\n\tselect WANT_LINEAR_FRAMEBUFFER\n\tselect COMPRESSED_PAYLOAD_NONE\n\tselect DEFAULT_CONSOLE_LOGLEVEL_3\n\thelp\n\t  Select this option if you want to build a coreboot image\n\t  with Simpleboot (simplified Multiboot2 Protocol) payload.\n\n\t  See https://gitlab.com/bztsrc/simpleboot for more information.\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/LICENSE",
    "content": "    Copyright (C) 2023 bzt (bztsrc@gitlab)\n\n    Permission is hereby granted, free of charge, to any person\n    obtaining a copy of this software and associated documentation\n    files (the \"Software\"), to deal in the Software without\n    restriction, including without limitation the rights to use, copy,\n    modify, merge, publish, distribute, sublicense, and/or sell copies\n    of the Software, and to permit persons to whom the Software is\n    furnished to do so, subject to the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n    DEALINGS IN THE SOFTWARE.\n\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/Makefile",
    "content": "# for coreboot integration only\n# normally you'll need src/Makefile and that's it.\n\nifeq ($(CONFIG_COREBOOT_BUILD),)\ninclude ../../../.config\nendif\nlibpayload_dir=../../libpayload\n\nunexport KCONFIG_AUTOHEADER\nunexport KCONFIG_AUTOCONFIG\nunexport KCONFIG_DEPENDENCIES\nunexport KCONFIG_SPLITCONFIG\nunexport KCONFIG_TRISTATE\nunexport KCONFIG_NEGATIVES\n\nall: simpleboot\n\npayloads/external/simpleboot/src/loader_cb.elf: simpleboot\n\nsimpleboot: $(libpayload_dir)/build/libpayload.a\n\t@echo \"    MAKE       src/loader_cb.elf\"\n\t@$(MAKE) -C src LIBPAYLOAD_PATH=../$(libpayload_dir) loader_cb.elf\n\n$(libpayload_dir)/build/libpayload.a:\n\t@$(MAKE) -C $(libpayload_dir) defconfig\n\t@sed -i \"s|.*CONFIG_LP_BASE_ADDRESS=.*|CONFIG_LP_BASE_ADDRESS=0x03000000|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*CONFIG_LP_MULTIBOOT=y.*|# CONFIG_LP_MULTIBOOT is not set|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*CONFIG_LP_CURSES=y.*|# CONFIG_LP_CURSES is not set|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*CONFIG_LP_TINYCURSES=y.*|# CONFIG_LP_TINYCURSES is not set|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*CONFIG_LP_PDCURSES=y.*|# CONFIG_LP_PDCURSES is not set|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*# CONFIG_LP_CBFS is not set.*|CONFIG_LP_CBFS=y|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*CONFIG_LP_DEBUG_CBFS=y.*|# CONFIG_LP_DEBUG_CBFS is not set|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*CONFIG_LP_ENABLE_CBFS_FALLBACK=y.*|# CONFIG_LP_ENABLE_CBFS_FALLBACK is not set|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*CONFIG_LP_LZMA=y.*|# CONFIG_LP_LZMA is not set|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*CONFIG_LP_LZ4=y.*|# CONFIG_LP_LZ4 is not set|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*CONFIG_LP_VBOOT_LIB=y.*|# CONFIG_LP_VBOOT_LIB is not set|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*CONFIG_LP_CBMEM_CONSOLE=y.*|# CONFIG_LP_CBMEM_CONSOLE is not set|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*# CONFIG_LP_SERIAL_CONSOLE is not set.*|CONFIG_LP_SERIAL_CONSOLE=y|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*# CONFIG_LP_VIDEO_CONSOLE is not set.*|CONFIG_LP_VIDEO_CONSOLE=y|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*CONFIG_LP_VGA_VIDEO_CONSOLE=y.*|# CONFIG_LP_VGA_VIDEO_CONSOLE is not set|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*# CONFIG_LP_COREBOOT_VIDEO_CONSOLE is not set.*|CONFIG_LP_COREBOOT_VIDEO_CONSOLE=y|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*CONFIG_LP_MOUSE_CURSOR=y.*|# CONFIG_LP_MOUSE_CURSOR is not set|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*# CONFIG_LP_STORAGE is not set.*|CONFIG_LP_STORAGE=y|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*# CONFIG_LP_IGNORE_UNKNOWN_INTERRUPTS is not set.*|CONFIG_LP_IGNORE_UNKNOWN_INTERRUPTS=y|\" $(libpayload_dir)/.config\n\t@sed -i \"s|.*CONFIG_LP_DIE_ON_UNKNOWN_INTERRUPT=y.*|# CONFIG_LP_DIE_ON_UNKNOWN_INTERRUPT is not set|\" $(libpayload_dir)/.config\n\t@# patch that extremely annoying cbfs (we can't use an empty macro either...)\n\t@sed -i \"s|.*LOG.*;|{}|\" $(libpayload_dir)/libcbfs/cbfs.c\n\t$(MAKE) -C $(libpayload_dir)\n\nclean:\n\t$(MAKE) -C src clean\n\ndistclean: clean\n\t$(MAKE) -C $(libpayload_dir) clean\n\nprint-repo-info:\n\techo \"https://gitlab.com/bztsrc/simpleboot.git Simpleboot\"\n\n.PHONY: simpleboot libpayload clean distclean print-repo-info\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/README.md",
    "content": "Simpleboot\n==========\n\n[Simpleboot](https://gitlab.com/bztsrc/simpleboot) is an all-in-one OS loader and bootable disk image creator that can load Linux\nkernels and Multiboot2 compliant kernels in ELF and PE formats.\n\nNOTE: This is a boot *loader*, its job is to load a single kernel. If you're looking for a boot *manager*, which is capable to\nboot multiple kernels and has an interactive menu as well, then take a look at **Simpleboot**'s big brother,\n[Easyboot](https://gitlab.com/bztsrc/easyboot).\n\n *\"Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.\"*\n\n *Antoine de Saint-Exupéry*\n\nThis loader is a single file, as small as 58k, and yet it supports multiple firmware (like BIOS, UEFI), multiple file formats (ELF,\nPE), multiple ABIs (SysV, fastcall, CDECL), multiple architectures (i386, x86_64; there's also an AArch64 variant for Raspberry Pi),\nmultiple boot protocols (Linux boot, Multiboot2, capable to fallback to FreeBSD or BIOS boot partitions), even transparently\nuncompresses your payloads and generates ACPI tables on platforms that do not support it natively. It also supports SMP and able to\nrun the kernel on all CPU cores at once. It's probably the winner by far in \"the most features per byte in a boot loader\" category.\nAnd yes, you can relax, it can also display a custom boot logo for you.\n\nRationale\n---------\n\nI was wondering what could be the bare minimum and simplest usable implementation of booting a kernel, because let's face it, GRUB\nand the others sucks big time. They're very overcomplicated, bloated, hard to install and very easy to fuck up their config syntax.\nAnd all the helpers (like grub-mkrescue or syslinux) have an outrageous number of dependencies, each with its own unnecessary\nhazard of version incompatibility or possibly missing commands. To be honest, I never understood why creating a disk image file has\nto be more complicated than creating a zip or tar archive for example.\n\nThere's definitely a need for a much simpler, much easier to use and much more user friendlier solution than GRUB. The typical\nusecase is OS installer image creation, 99% of end-user computers with just one OS, and especially hobby OS development. In all\nthese cases there's absolutely no need for a complicated and interactive boot manager, because there's only one kernel to boot, and\nwith the last case it is very important that you should be able to rapidly and quickly create and test run new images without a\nfuzz. So just because I can, I've created such a [suckless](https://suckless.org) tool, here's my solution:\n\n1. create a directory and put your files in it, among other things your kernel binary\n2. execute the dependency-free `simpleboot (source directory) (output image file)` command\n3. and... that's about it... nothing else left to do! The image *Just Works (TM)*, it will get your kernel booted!\n\nYou can install the loader and make an existing device or image bootable; or you can create a bootable image anew. You can boot\nthat image in a VM, or you can write it with `dd` or [USBImager](https://bztsrc.gitlab.io/usbimager/) to a storage and boot that\non a real machine too.\n\nSimplicity is the ultimate sophistication! The name **Simpleboot** is a pun on Multiboot because it uses a saner, simpler (yet\ncompatible) subset of the boot protocol and has a much simpler tool usage.\n\nNOTE: The Multiboot2 protocol is just too dumb, so we violate the protocol a bit to support higher-half kernels, SMP (multicore)\nand clean 64-bit long mode entry point if the kernel's format is 64-bit.\n\nInstallation\n------------\n\nJust download the binary for your OS. These are portable executables, they don't require installation and they don't need any\nshared libraries / DLLs.\n\n- [simpleboot](https://gitlab.com/bztsrc/simpleboot/-/raw/main/distrib/simpleboot) Linux, \\*BSD (167k)\n- [simpleboot.exe](https://gitlab.com/bztsrc/simpleboot/-/raw/main/distrib/simpleboot.exe) Windows (169k)\n\nFurthermore you can find various packaging solutions in the [distrib](distrib) directory (for Debian, Ubuntu, RaspiOS, Gentoo,\nArch, qemu coreboot BIOS ROM).\n\nDocumentation\n-------------\n\nThe detailed [documentation](docs) on how to use the bootable disk creator and how a kernel is booted can be found in the docs\ndirectory. It includes all the relevant parts of the Multiboot2 specification too (a fixed version that matches what's actually\nin GRUB's multiboot2.h header, plus Simpleboot's additions).\n\nExample Kernels\n---------------\n\nIn the [example](example) directory, you can find very simple \"kernels\", these just dump the received boot parameters to the serial\nconsole. The [kernel.c](example/kernel.c) is more or less the same as the example kernel in the Multiboot2 specification (just uses\nthe `simpleboot.h` header with typedefs and has serial output instead of VGA text mode). Note that *NO ASSEMBLY* prologue nor any\nspecial embedded data required with **Simpleboot**. The [linux.c](example/linux.c) is just a Linux kernel mock up for testing the\nboot parameters passing.\n\nCompilation\n-----------\n\nGNU/make needed for orchestration (although it's literally just `cc simpleboot.c -o simpleboot`). The toolchain doesn't matter,\nany ANSI C compiler will do, works on POSIX and WIN32 MINGW too. Just go to the [src](src) directory and run `make`. That's all.\nDespite of it's small size, it is self-contained and has exactly zero library dependencies. It's not called **Simpleboot** for\nnothing :-)\n\nTo recompile the \"boot_x86.bin\" sector, you'll need the [flatassembler](https://flatassembler.net), and for the \"loader_x86.efi\"\nand \"loader_rpi.bin\" you'll have to install LLVM Clang and lld (gcc and GNU ld won't work I'm afraid). But don't worry, I've\nadded all three to `src/data.h` as a byte array, so you don't have to compile these unless you really really want to (for that,\njust delete data.h before you run make).\n\nYou can also compile **Simpleboot** as a [coreboot](https://coreboot.org/) payload. See the comments at the beginning of\n[src/loader_cb.c](src/loader_cb.c) for build instructions and the [documentation](docs/coreboot.md) for more information.\n\nLicense\n-------\n\nLicensed under the permissive terms of the MIT license, see [LICENSE](LICENSE) file for details. Do as you please. Not required,\nbut attribution appreciated.\n\nContributors\n------------\n\nI'd like to say thanks to Zahy for valuable feedback on FreeBSD. Special thanks to dzsolt for providing the ebuild.\n\nSocial\n------\n\n* [Hungarian UNIX Portal](https://hup.hu/node/182370) (original announcement)\n* [Flatassembler forum](https://board.flatassembler.net/topic.php?t=22876) (about the legacy boot sector)\n* [Raspberry Pi forum](https://forums.raspberrypi.com/viewtopic.php?p=2122434) (about the RPi port)\n* [OSDEV forum](https://forum.osdev.org/viewtopic.php?f=2&t=56905) (about writing kernels)\n\nSorry, I don't use facepalm, twitees, masturbadon, vector, discoss and alike. I don't use anything that forces shady JS on users\n(and that's why this repo isn't stored on github, btw).\n\nCheers,\n\nbzt\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/distrib/PKGBUILD",
    "content": "# Maintainer: bzt <https://gitlab.com/bztsrc/simpleboot/issues>\n# Contributor: Ramadan Ali (alicavus) <rot13: ezqa@ezqa.ny>\npkgname=simpleboot\npkgver=1.0.0\npkgrel=1\npkgdesc=\"Dependency-free, all-in-one boot loader and bootable disk image creator.\"\narch=(\"x86_64\" \"aarch64\")\nurl=\"https://gitlab.com/bztsrc/simpleboot\"\nlicense=(\"MIT\")\nmakedepends=(\"clang\")\nsource=(\"${url}/-/archive/main/${pkgname}-main.tar.gz\")\nb2sums=(\"SKIP\")\n\npkgver() {\n\tcd \"${pkgname}-main/src\"\n\tprintf \"%s\" `grep -m 1 sbver simpleboot.c | cut -d '\"' -f 2`\n}\n\nbuild() {\n\tcd \"${pkgname}-main/src\"\n\tmake clean all\n}\n\npackage() {\n\tcd \"${pkgname}-main/src\"\n\tDESTDIR=$pkgdir/ make install\n}\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/distrib/simpleboot-1.0.0.ebuild",
    "content": "# Copyright (C) 2023 dzsolt\n# Distributed under the terms of the GNU General Public License v2\n\nEAPI=7\n\nDESCRIPTION=\"Dependency-free, all-in-one boot loader and bootable disk image creator.\"\nHOMEPAGE=\"https://gitlab.com/bztsrc/simpleboot\"\n\nLICENSE=\"MIT\"\nSLOT=\"0\"\nIUSE=\"rebuild\"\n\n# If PV starts with 9999, use git-r3 for version control\nif [[ ${PV} == 9999* ]]; then\n    inherit git-r3\n    EGIT_REPO_URI='https://gitlab.com/bztsrc/simpleboot.git'\nelse\n    SRC_URI=\"https://gitlab.com/bztsrc/simpleboot/-/archive/${PV}/simpleboot-${PV}.tar.gz -> ${P}.tar.gz\"\n    KEYWORDS=\"~amd64 ~x86 ~arm64 ~arm\"\nfi\n\nBDEPEND=\"\n    rebuild? (\n        dev-lang/fasm\n        sys-devel/llvm\n        sys-devel/lld\n    )\n\"\n\nsrc_prepare() {\n    default\n    # Nothing specific to prepare\n}\n\nsrc_compile() {\n    if use rebuild; then\n        emake -C src distclean || die \"Failed to execute 'make -C src distclean'\"\n    fi\n    emake -C src -j1 || die \"Failed to build simpleboot\"\n}\n\nsrc_install() {\n    dobin src/simpleboot || die \"Failed to install simpleboot\"\n    doman src/misc/simpleboot.1.gz\n    doheader simpleboot.h\n}\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/distrib/simpleboot-9999.ebuild",
    "content": "# Copyright (C) 2023 dzsolt\n# Distributed under the terms of the GNU General Public License v2\n\nEAPI=7\n\nDESCRIPTION=\"Dependency-free, all-in-one boot loader and bootable disk image creator.\"\nHOMEPAGE=\"https://gitlab.com/bztsrc/simpleboot\"\n\nLICENSE=\"MIT\"\nSLOT=\"0\"\nIUSE=\"rebuild\"\n\n# If PV starts with 9999, use git-r3 for version control\nif [[ ${PV} == 9999* ]]; then\n    inherit git-r3\n    EGIT_REPO_URI='https://gitlab.com/bztsrc/simpleboot.git'\nelse\n    SRC_URI=\"https://gitlab.com/bztsrc/simpleboot/-/archive/${PV}/simpleboot-${PV}.tar.gz -> ${P}.tar.gz\"\n    KEYWORDS=\"~amd64 ~x86 ~arm64 ~arm\"\nfi\n\nBDEPEND=\"\n    rebuild? (\n        dev-lang/fasm\n        sys-devel/llvm\n        sys-devel/lld\n    )\n\"\n\nsrc_prepare() {\n    default\n    # Nothing specific to prepare\n}\n\nsrc_compile() {\n    if use rebuild; then\n        emake -C src distclean || die \"Failed to execute 'make -C src distclean'\"\n    fi\n    emake -C src -j1 || die \"Failed to build simpleboot\"\n}\n\nsrc_install() {\n    dobin src/simpleboot || die \"Failed to install simpleboot\"\n    doman src/misc/simpleboot.1.gz\n    doheader simpleboot.h\n}\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/docs/ABI.md",
    "content": "Writing Simpleboot compatible kernels\n=====================================\n\n[Simpleboot](https://gitlab.com/bztsrc/simpleboot) is an all-in-one boot loader and bootable disk image creator that can load Linux\nkernels and Multiboot2 compliant kernels in ELF and PE formats.\n\nThis is the very same protocol that [Easyboot](https://gitlab.com/bztsrc/easyboot) uses, all of the example kernels in this\nrepo must work with **Easyboot** too.\n\nYou can use the original Multiboot2 header in GRUB's repo, or the [simpleboot.h](../simpleboot.h) C/C++ header file to get easier to\nuse typedefs. The low-level binary format is the same, you can also use any existing Multiboot2 libraries, even with non-C\nlanguages, like this [Rust](https://github.com/rust-osdev/multiboot2/tree/main/multiboot2/src) library for example (note: I'm not\naffiliated with those devs in any way, I just searched for \"Rust Multiboot2\" and that was the first result).\n\nVarious kernel protocols only supported on x86, while 64-bit Multiboot2 kernel is supported on all platforms.\n\n[[_TOC_]]\n\nBoot Sequence\n-------------\n\n### Bootstrapping the loader\n\nOn *BIOS* machines, the very first sector of the disk is loaded to 0:0x7C00, and control passed to it. In this sector\n**Simpleboot** has [boot_x86.asm](../src/boot_x86.asm), which is smart enough to locate and load the 2nd stage loader, and also\nto set up long mode for it.\n\nOn *UEFI* machines the very same 2nd stage file, called `EFI/BOOT/BOOTX64.EFI` is loaded directly by the firmware. The source for\nthis loader can be found in [loader_x86.c](../src/loader_x86.c). That's it, **Simpleboot** isn't GRUB nor syslinux, both of which\nrequiring dozens and dozens of system files on the disk. Here no more files needed, just this one.\n\nOn *Raspberry Pi* the loader is called `KERNEL8.IMG`, compiled from [loader_rpi.c](../src/loader_rpi.c). This will work in qemu,\nbut to boot on a real machine, you'll need further firmware files `bootcode.bin`, `fixup.dat` and `start.elf` too, which can be\ndownloaded from the [official repository](https://github.com/raspberrypi/firmware/tree/master/boot). Place these files in the\ndirectory that you use to generate the boot partition.\n\nOn *coreboot* machines, there's no loader file, it is part of the ROM and flashed with the rest of firmware to the motherboard.\nThis version is compiled from [loader_cb.c](../src/loader_cb.c) which is built on top of coreboot's libpayload library.\n\n### The loader\n\nThis loader is very carefully written to work on multiple platforms and configurations. It loads the GUID Partitioning Table from\nthe disk, and looks for an \"EFI System Partition\". When found, it looks for the `simpleboot.cfg` configuration file on that boot\npartition. If not found, then it defaults to what was given during disk image creation. Now that your kernel's filename is known,\nthe loader locates and loads the first 4096 bytes of it.\n\nUsing that buffer it autodetects the kernel's format, and it is smart enough to interpret the section and segment information about\nwhere to load what (it does on-demand memory mapping whenever necessary). Then it sets up a proper environment depending on the\ndetected boot protocol (Multiboot2 / Linux / etc. protected or long mode, ABI arguments etc.). After the machine state is solid and\nwell-defined, as a very last act, the loader jumps to your kernel's entry point.\n\nMachine State\n-------------\n\nEverything what's written in the [Multiboot2 specification](https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html)\nabout the machine state stands, except for the general purpose registers. **Simpleboot** passes two arguments to your kernel's\nentry point according to the SysV ABI and Microsoft fastcall ABI as well. First parameter is the magic, the second one is a\nphysical memory address, pointing to a Multiboot Information taglist (abbreviated as MBI hereafter, see below).\n\nWe also violate the Multiboot2 protocol a bit to handle higher-half kernels. Multiboot2 mandates that memory must be identity\nmapped. Well, under **Simpleboot** this is just partially true: we only guarantee that all of the physical RAM is surely identity\nmapped as expected; however some regions above that (depending on the kernel's program headers) might be yet available. This does\nnot break normal Multiboot2 compliant kernels, which are not supposed to access memory outside of the available physical RAM.\n\nYour kernel is loaded exactly the same way on both BIOS and UEFI systems as well as on RPi, firmware differences are just \"Somebody\nElse's Problem\". The only thing your kernel will see is whether the MBI contains the EFI system table tag or not. To simplify your\nlife, **Simpleboot** does not generate EFI memory map (type 17) tag either, it provides only the [Memory map](#memory_map) (type 6)\ntag indiscriminatly on all platforms (on UEFI systems too, there the memory map is simply converted for you, so your kernel has to\ndeal with only one kind of tags). Old, obsolete tags are also ommited and never generated by this boot loader.\n\nThe kernel is running at supervisor level (ring 0 on x86, EL1 on ARM), possibly on all CPU cores in parallel.\n\nGDT unspecified, but valid. Stack is set up in the first 640k, and growing downwards (but you should change this as soon as\npossible to whatever stack you deem worthy). When SMP is enabled, all cores have their own stacks, and the core id is on the\ntop of the stack (but you can also get the core id the usual platform specific way, using cpuid / mpidr / etc.).\n\nYou should consider IDT as unspecified; IRQs, NMI and software interrupts disabled. Dummy exception handlers are set up to display\nsome minimal dump and halt the machine. These should only be relied on to report if your kernel goes havoc before you were able\nto set up your own IDT and handlers, preferably as soon as possible. On ARM vbar_el1 is set up to call the same dummy exception\nhandlers (although they dump different registers of course).\n\nFramebuffer is also set by default. You can alter the resolution in config, but if not given, framebuffer is still configured.\n\nIt is important to never return from your kernel. You're free to overwrite any part of the loader in memory (as soon as you've\nfinished with the MBI tags), so there's simply nowhere to return to. \"Der Mohr hat seine Schuldigkeit getan, der Mohr kann gehen.\"\n\n### ELF32 / PE32\n\nIf your kernel is a 32-bit binary (or 64-bit but `-g` force GRUB compatiblity mode flag was used), then the kernel will run in\nprotected mode, without any paging and with flat segmentation (meaning segments will have the base of 0 and limit of 0xFFFFFFFF).\nThese 32-bit kernels are loaded with a 100% GRUB-compatible Multiboot2 protocol.\n\nNote that 32-bit is *just for kernel* backward compatibility, you'll still have to have a 64-bit machine (EFI32 and legacy\ncomputers without long mode not supported).\n\n### ELF64 / PE32+\n\nOtherwise if your kernel is a 64-bit binary, then it will run in long mode, with identity mapping (meaning virtual addresses are\nthe same as physical addresses). No 64-bit trampoline code needed and kernel could be higher-half mapped, so this is *not*\nGRUB-compatible (which mandates 32-bit protected mode entry point). On ARM only 64-bit mode supported.\n\nThese 64-bit kernels might be booted on all CPU cores at once too using the `multicore` directive (or the `-m` flag, SMP).\n\n### Linux kernels\n\nLinux (if kernel has 0xAA55 at offset 0x1FE and `HdrS` at offset 0x202) is a special case, with such kernels *Multiboot2 not used*\nat all, instead the [The Linux/x86 Boot Protocol](https://www.kernel.org/doc/html/latest/arch/x86/boot.html) applies. The minimum\nboot protocol version supported is v2.12 (the value at offset 0x206 must be larger or equal to 0x20C). Has no program headers, so a\nblock starting at file offset `((byte at offset 0x1F1 + 1) * 512)` and `(uint32_t at offset 0x260)` bytes long is loaded to address\n`(uint32_t at offset 0x258)`. The control is then transferred to address `(uint32_t at offset 0x258) + 512` in pure 64-bit long\nmode. No MBI tags passed, instead `rsi` points to a [zero page](https://www.kernel.org/doc/html/latest/arch/x86/zero-page.html),\nwhich is a [struct boot_params](https://github.com/torvalds/linux/blob/master/arch/x86/include/uapi/asm/bootparam.h#L185)\nstructure, with very similar information.\n\nOn ARM, the Linux kernel has the magic `ARM` plus a byte 64 at offset 0x38. This image is loaded at 0x80000, which is also the\ntop of the stack and the entry point. The FDT (Flattened Device Tree, .dtb) pointer is passed in the `x0` register.\n\nBoot information passed to your kernel\n--------------------------------------\n\nIt's not obvious at first, but Multiboot2 actually specifies two, totally independent set of tags:\n\n- The first set supposed to be inlined in a Multiboot2 compliant kernel, called OS image's Multiboot2 header (section 3.1.2), hence\n  *provided by the kernel*. **Simpleboot** does not care about these tags, and it does not parse your kernel for these either.\n  You simply don't need any special magical data embedded in your kernel file with **Simpleboot**, ELF and PE headers suffice.\n\n- The second set is *passed to the kernel* dynamically on boot, **Simpleboot** uses only these tags. However it does not generate\n  all that Multiboot2 specifies (it simply omits the old, obsoleted or legacy ones). These tags are called the MBI tags, see\n  [Boot information](https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Boot-information-format) (section 3.6).\n\nNOTE: the Multiboot2 specification on MBI tags is buggy as hell. You can find a fixed up version below, which aligns with the\nmultiboot2.h header file that you can find in GRUB's source repository. This spec also contains the **Simpleboot** additions.\n\nThe first parameter to your kernel is the magic 0x36d76289 (in `rax`, `rcx` and `rdi`). You can locate the MBI tags using the\nsecond parameter (in `rbx`, `rdx` and `rsi`). On ARM platform magic is in `x0` and address is in `x1`. On RISC-V and MIPS `a0` and\n`a1` used, respectively. If and when this loader is ported to another architecture, then always the registers specified by SysV ABI\nfor function arguments must be used. If there are other common ABIs on the platform which do not interfere with SysV ABI, then the\nvalues should be duplicated in those ABI's registers (or on the top of the stack) too.\n\n### Headers\n\nThe passed address is always 8-bytes aligned, and starts with an MBI header:\n\n```\n        +-------------------+\nu32     | total_size        |\nu32     | reserved          |\n        +-------------------+\n```\n\nThis is followed by a series of also 8-bytes aligned tags. Every tag begins with the following tag header fields:\n\n```\n        +-------------------+\nu32     | type              |\nu32     | size              |\n        +-------------------+\n```\n\n`type` contains an identifier of contents of the rest of the tag. `size` contains the size of tag including header fields but not\nincluding padding. Tags follow one another padded when necessary in order for each tag to start at 8-bytes aligned address. Tags\nare terminated by a tag of type `0` and size `8`.\n\n### Boot command line\n\n```\n        +-------------------+\nu32     | type = 1          |\nu32     | size              |\nu8[n]   | string            |\n        +-------------------+\n```\n\n`string` contains the command line specified in *simpleboot.cfg*'s `kernel` line (without the kernel's path and filename). The\ncommand line is a normal C-style zero-terminated UTF-8 string.\n\n### Boot loader name\n\n```\n        +----------------------+\nu32     | type = 2             |\nu32     | size = 19            |\nu8[n]   | string \"Simpleboot\"  |\n        +----------------------+\n```\n\n`string` contains the name of a boot loader booting the kernel. The name is a normal C-style UTF-8 zero-terminated string. If\nyou're booting an emergency backup, then the string will be `Simpleboot (backup)`.\n\n### Modules\n\n```\n        +-------------------+\nu32     | type = 3          |\nu32     | size              |\nu32     | mod_start         |\nu32     | mod_end           |\nu8[n]   | string            |\n        +-------------------+\n```\n\nThis tag indicates to the kernel what boot module was loaded along with the kernel image, and where it can be found. The\n`mod_start` and `mod_end` contain the start and end physical addresses of the boot module itself. You'll never get a gzip\ncompressed buffer, because **Simpleboot** transparently uncompresses those for you. The `string` field provides an arbitrary\nstring to be associated with that particular boot module; it is a normal C-style zero-terminated UTF-8 string. Specified in\n*simpleboot.cfg*'s `module` line and its exact use is specific to the operating system. Unlike the boot command line tag, the\nmodule tags *also include* the module's path and filename.\n\nOne tag appears per module. This tag type may appear multiple times. If an initial ramdisk was loaded along with your kernel,\nthen that will appear as the first module.\n\nThere's a special case, if the file is a DSDT ACPI table, an FDT (dtb) or GUDT blob, then it won't appear as a module, rather\nACPI old RSDP (type 14) or ACPI new RSDP (type 15) will be patched and their DSDT replaced with the contents of this file.\n\n### Memory map\n\nThis tag provides memory map.\n\n```\n        +-------------------+\nu32     | type = 6          |\nu32     | size              |\nu32     | entry_size = 24   |\nu32     | entry_version = 0 |\nvaries  | entries           |\n        +-------------------+\n```\n\n`size` contains the size of all the entries including this field itself. `entry_size` is always 24. `entry_version` is set at `0`.\nEach entry has the following structure:\n\n```\n        +-------------------+\nu64     | base_addr         |\nu64     | length            |\nu32     | type              |\nu32     | reserved          |\n        +-------------------+\n```\n\n`base_addr` is the starting physical address. `length` is the size of the memory region in bytes. `type` is the variety of address\nrange represented, where a value of `1` indicates available RAM, value of `3` indicates usable memory holding ACPI information,\nvalue of `4` indicates reserved memory which needs to be preserved on hibernation, value of `5` indicates a memory which is\noccupied by defective RAM modules and all other values currently indicated a reserved area. `reserved` is set to `0` on BIOS boots.\n\nWhen the MBI generated on a UEFI machine, then various EFI Memory Map entries are stored as type `1` (available RAM) or `2`\n(reserved RAM), and should you need it, the original EFI Memory Type is placed in the `reserved` field.\n\nThe map provided is guaranteed to list all standard RAM that should be available for normal use, and it is always ordered by\nascending `base_addr`. This available RAM type however includes the regions occupied by kernel, mbi, segments and modules. Kernel\nmust take care not to overwrite these regions (**Simpleboot** could easily exclude those regions, but that would break Multiboot2\ncompatibility).\n\n### Framebuffer info\n\n```\n        +----------------------------------+\nu32     | type = 8                         |\nu32     | size = 38                        |\nu64     | framebuffer_addr                 |\nu32     | framebuffer_pitch                |\nu32     | framebuffer_width                |\nu32     | framebuffer_height               |\nu8      | framebuffer_bpp                  |\nu8      | framebuffer_type = 1             |\nu16     | reserved                         |\nu8      | framebuffer_red_field_position   |\nu8      | framebuffer_red_mask_size        |\nu8      | framebuffer_green_field_position |\nu8      | framebuffer_green_mask_size      |\nu8      | framebuffer_blue_field_position  |\nu8      | framebuffer_blue_mask_size       |\n        +----------------------------------+\n```\n\nThe field `framebuffer_addr` contains framebuffer physical address. The field `framebuffer_pitch` contains the length of one row in\nbytes. The fields `framebuffer_width`, `framebuffer_height` contain framebuffer dimensions in pixels. The field `framebuffer_bpp`\ncontains number of bits per pixel. `framebuffer_type` is always set to 1, and `reserved` always contains 0 in current version of\nspecification and must be ignored by OS image. The remaining field describe a packed pixel format, the channels' position and size\nin bits. You can use the expression `((~(0xffffffff << size)) << position) & 0xffffffff` to get an UEFI GOP like channel mask.\n\n### EFI 64-bit system table pointer\n\nThis tag only exists if **Simpleboot** is running on a UEFI machine. On a BIOS machine this tag never generated.\n\n```\n        +-------------------+\nu32     | type = 12         |\nu32     | size = 16         |\nu64     | pointer           |\n        +-------------------+\n```\n\nThis tag contains pointer to EFI system table.\n\n### EFI 64-bit image handle pointer\n\nThis tag only exists if **Simpleboot** is running on a UEFI machine. On a BIOS machine this tag never generated.\n\n```\n        +-------------------+\nu32     | type = 20         |\nu32     | size = 16         |\nu64     | pointer           |\n        +-------------------+\n```\n\nThis tag contains pointer to EFI image handle. Usually it is boot loader image handle.\n\n### SMBIOS tables\n\n```\n        +-------------------+\nu32     | type = 13         |\nu32     | size              |\nu8      | major             |\nu8      | minor             |\nu8[6]   | reserved          |\n        | smbios tables     |\n        +-------------------+\n```\n\nThis tag contains a copy of SMBIOS tables as well as their version.\n\n### ACPI old RSDP\n\n```\n        +-------------------+\nu32     | type = 14         |\nu32     | size              |\n        | copy of RSDPv1    |\n        +-------------------+\n```\n\nThis tag contains a copy of RSDP as defined per ACPI 1.0 specification. (With a 32-bit address.)\n\n### ACPI new RSDP\n\n```\n        +-------------------+\nu32     | type = 15         |\nu32     | size              |\n        | copy of RSDPv2    |\n        +-------------------+\n```\n\nThis tag contains a copy of RSDP as defined per ACPI 2.0 or later specification. (With a 64-bit address probably.)\n\nThese (type 14 and 15) point to an `RSDT` or `XSDT` table with a pointer to a `FACP` table, which in turn contains two pointers to\na `DSDT` table, which describes the machine. **Simpleboot** fakes these tables on machines that do not support ACPI otherwise. Also\nif you provide a DSDT table, an FDT (dtb) or GUDT blob as a module, then **Simpleboot** will patch the pointers to point to that\nuser provided table. To parse these tables, you can use my dependency-free, single header [hwdet](https://gitlab.com/bztsrc/hwdet)\nlibrary (or the bloated [apcica](https://github.com/acpica/acpica) and [libfdt](https://github.com/dgibson/dtc)).\n\n### EDID\n\nTags with `type` greater than or equal to 256 are not part of the Multiboot2 specification, nonetheless provided by **Simpleboot**.\n\n```\n        +-------------------+\nu32     | type = 256        |\nu32     | size              |\n        | copy of EDID      |\n        +-------------------+\n```\n\nThis tag contains a copy of the supported monitor resolution list according to the EDID specification.\n\n### SMP\n\nSymmetric MultiProcessing is only supported for 64-bit Multiboot2 kernels.\n\n```\n        +-------------------+\nu32     | type = 257        |\nu32     | size              |\nu32     | numcores          |\nu32     | running           |\nu32     | bspid             |\n        +-------------------+\n```\n\nThis tag exists if `multicore` directive was given. `numcores` contains the number of CPU cores in the system, `running` is\nthe number of cores that have successfully initialized and running the same kernel in parallel. The `bspid` contains the BSP\ncore's identifier (on x86 lAPIC id), so that kernels can distinguish APs and run a different code on those. All APs have their\nown stack, and on top of the stack there'll be the id of the current core (but you can also get that using cpuid / mpidr / etc.).\n\n### Boot Partition\n\n```\n        +-------------------+\nu32     | type = 258        |\nu32     | size = 24         |\nu128    | bootuuid          |\nu128    | rootuuid          |\n        +-------------------+\n```\n\nThis tag contains the unique identifier field in the GPT of the boot partition. If the booting does not use a GUID Partitioning\nTable, then generated as `54524150-(device code)-(partition number)-616F6F7400000000`. The root partition's unique identifier\nis only stored if `size` is 40 (Easyboot only, **Simpleboot** always generates 24 bytes long tag with just the boot partition).\n\nMemory Layout\n-------------\n\n### BIOS machines\n\n| Start    | End     | Description                                                  |\n|---------:|--------:|--------------------------------------------------------------|\n|      0x0 |   0x400 | Interrupt Vector Table (usable, real mode IDT)               |\n|    0x400 |   0x4FF | BIOS Data Area (usable)                                      |\n|    0x4FF |   0x500 | BIOS boot drive code (most likely 0x80, usable)              |\n|    0x500 |   0x5A0 | syncronization data for SMP (usable)                         |\n|    0x5A0 |  0x1000 | exception handler stack (usable after you set up your IDT)   |\n|   0x1000 |  0x8000 | paging tables (usable after you set up your paging tables)   |\n|   0x8000 | 0x20000 | loader code and data (usable after you set up your IDT)      |\n|  0x20000 | 0x90000 | config + logo + tags; from the top to bottom: kernel's stack |\n|  0x90000 | 0x9A000 | Linux kernel only: zero page + cmdline                       |\n|  0x9A000 | 0xA0000 | Extended BIOS Data Area (better not to touch)                |\n|  0xA0000 | 0xFFFFF | VRAM and BIOS ROM (not usable)                               |\n| 0x100000 |       x | kernel segments, followed by the modules, each page aligned  |\n\n### UEFI machines\n\nNobody knows. UEFI allocates memory as it pleases. Expect anything and everything, but most likely placed below 256M. All area\nwill be surely listed in the memory map as type = 1 (`MULTIBOOT_MEMORY_AVAILABLE`) and reserved = 2 (`EfiLoaderData`), however\nthis isn't exclusive, other kinds of memory too might be listed like that (boot loader's bss section for example).\n\n### Raspberry Pi\n\n| Start    | End     | Description                                                  |\n|---------:|--------:|--------------------------------------------------------------|\n|      0x0 |   0x500 | reserved by firmware (better not to touch)                   |\n|    0x500 |   0x5A0 | syncronization data for SMP (usable)                         |\n|    0x5A0 |  0x1000 | exception handler stack (usable after you set up your VBAR)  |\n|   0x1000 | 0x20000 | paging tables (usable after you set up your paging tables)   |\n|  0x20000 | 0x80000 | config + logo + tags; from the top to bottom: kernel's stack |\n|  0x80000 | 0x8F000 | loader code and data (usable after you set up your VBAR)     |\n|  0x8F000 |       x | kernel segments, followed by the modules, each page aligned  |\n\nThe first few bytes are reserved for [armstub](https://github.com/raspberrypi/tools/blob/master/armstubs/armstub8.S). It only\nstarts core 0, so to start Application Processors, write a function's address to 0xE0 (core 1), 0xE8 (core 2), 0xF0 (core 3),\nwhich addresses are located in this area. This is irrelevant when the `multicore` directive is used, then all cores will\nexecute the kernel.\n\nAlthough natively not supported on the RPi, you still get an ACPI old RSDP (type 14) tag, with fake tables. The `APIC` table\nis used to communicate the number of available CPU cores to the kernel. The startup function address is stored in the RSD PTR\n-> RSDT -> APIC -> cpu\\[x].apic_id field (and core id in cpu\\[x].acpi_id, where BSP is always cpu\\[0].acpi_id = 0 and\ncpu\\[0].apic_id = 0xD8. Watch out, \"acpi\" and \"apic\" looks pretty similar).\n\nIf a valid FDT blob is passed by the firmware, or if one of the modules is a .dtb, .aml or .gudt file, then a FADT (with magic\n`FACP`) table is also added. In this table, the DSDT pointer (32-bit, at offset 40) is pointing to the provided flattened device\ntree blob. For Linux kernels this pointer is passed to the entry point in `x0`.\n\nAlthough no memory map feature provided by the firmware, you'll still get a Memory Map (type 6) tag too, listing detected RAM\nand the MMIO region. You can use this to detect the MMIO's base address, which is different on RPi3 and RPi4.\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/docs/README.md",
    "content": "Booting a kernel with Simpleboot\n================================\n\n[Simpleboot](https://gitlab.com/bztsrc/simpleboot) is an all-in-one boot loader and bootable disk image creator that can load Linux\nkernels and Multiboot2 compliant kernels in ELF and PE formats.\n\n[[_TOC_]]\n\nConfiguration\n-------------\n\n```\n simpleboot [-v|-vv] [-k <name>] [-i <name>] [-m|-g] [-s <mb>] [-b <mb>] [-u <guid>] [-p <t> <u> <i>]\n   [-r|-e] [-c] <indir> <outfile|device>\n\n  -v, -vv         increase verbosity / validation\n  -k <name>       set the default kernel filename (defaults to 'kernel')\n  -i <name>       set the default initrd filename (by default none)\n  -m              set multicore to enabled (by default disabled)\n  -g              set 32-bit GRUB compatibility mode (by default disabled)\n  -s <mb>         set the disk image size in Megabytes (defaults to 35M)\n  -b <mb>         set the boot partition size in Megabytes (defaults to 33M)\n  -u <guid>       set the boot partition's unique identifier (defaults to random)\n  -p <t> <u> <i>  add a root partition (type guid, unique guid, imagefile)\n  -r              place loaders in ROM (by default save them into the image)\n  -e              add El Torito Boot Catalog (BIOS / EFI CDROM boot support)\n  -c              always create a new image file even if it exists\n  indir           use the contents of this directory for the boot partition\n  outfile         output image file or device name\n```\n\nThe **Simpleboot** tool creates a bootable disk image named `(outfile)` using GUID Partitioning Table with a single partition\nformatted as FAT32 and named as \"EFI System Partition\". The contents of that partition are taken from the `(indir)` you provide.\nUnless specified otherwise, by default the file named `kernel` in the root of that partition will be booted. If you place a file\nnamed `simpleboot.cfg` in the same root directory, then it will be parsed during boot, and will overrule the defaults. Instead of\nthat overcomplicated and brain-dead OS image Multiboot2 header, **Simpleboot** uses a simple plain text file for configuration.\nWith either NL or CRLF line endings, you can easily edit it with any text editor. No need for re-compilation or messing with a\nhexeditor just to change the screen resolution for example.\n\nThe `-k (name)` and `-i (name)` arguments change the default kernel filename and default initrd filename, respectively. Note that\nspecifying these do absolutely nothing with any files, they just set the default names in the loader. Likewise `-m` turns multicore\n(Symmetric MultiProcessing) on by default. These are just defaults, all of these can be overridden from the config file during boot.\n\nNormally 32-bit kernels started in protected mode (just like with GRUB), and 64-bit kernels in long mode (GRUB does not support\nthese). With `-g` you can enforce a 32-bit GRUB compatible protected mode entry point even on 64-bit kernels. Mutually exclusive\nwith the `-m` flag (GRUB does not support SMP at all).\n\nThe tool also has some optional command line flags: `-s (mb)` sets the overall size of the generated disk image in Megabytes, while\n`-b (mb)` sets the size of the boot partition in Megabytes. Obviously the former must be bigger than the latter. If not specified,\nthen partition size is calculated from the size of the given directory (33 Mb at a minimum, the smallest FAT32 there can be) and\ndisk size defaults to 2 Mb bigger than the partition (due to alignment and space needed for the partitioning table). If there's a\nmore than 2 Mb gap between these two size values, then you can use 3rd party tools like `fdisk` to add more partitions to the\nimage to your liking (or see `-p` below). If you want a predictable layout, you can also specify the boot partition's unique\nidentifier (UniquePartitionGUID) with the `-u <guid>` flag.\n\nOptionally you can also add extra partition(s) with the `-p` flag. This requires 3 arguments: (PartitionTypeGUID),\n(UniquePartitionGUID) and the name of the image file that contains the contents of the partition. This flag can be repeated\nmultiple times.\n\nThe `-r` flag does not save the loader into the image or on the disk, it rather creates `sb_bios.rom` (a legacy BIOS Expansion\nROM) and `sb_uefi.rom` (an UEFI PCI Option ROM) files next to the output file, which you can flash to a motherboard's ROM. For\nbackward compatibility only, if you really want ROM booting, then you should use the more advanced [coreboot](coreboot.md) loader\ninstead. Mutually exclusive with the `-e` flag.\n\nThe `-e` flag adds El Torito Boot Catalog to the generated image, so that it can be booted not just as an USB stick but as a\nBIOS / EFI CDROM too. Mutually exclusive with the `-r` flag.\n\nIf `(outfile)` is a device file (eg. `/dev/sda` on Linux, `/dev/disk0` on BSDs, and `\\\\.\\PhysicalDrive0` on Windows), then it does\nnot create GPT nor ESP, instead it locates the already existing ones on the device. It still copies all files in `(indir)` to the\nboot partition, and installs loaders. This also works if `(outfile)` is an image file that already exists (in this case use `-c` to\nalways create a new, empty image file first).\n\nThe `simpleboot.cfg` file may contain the following lines (very similar to grub.cfg's syntax, you can find an example configuration\nfile [here](../example/simpleboot.cfg)):\n\n### Comments\n\nAll lines starting with a `#` are considered comments and skipped till the end of the line.\n\n### Verbosity level\n\nYou can set the verbosity level using a line starting with `verbose`.\n\n```\nverbose (0-3)\n```\n\nThis tells the loader how much information to print to the boot console. Verbose 0 means totally quiet (default) and verbose 3\nwill dump the loaded kernel segments and the machine code at the entry point.\n\n### Framebuffer\n\nYou can request a specific screen resolution with the line starting with `framebuffer`. The format is as follows:\n\n```\nframebuffer (width) (height) (bits per pixel)\n```\n\n**Simpleboot** will set up a framebuffer for you, even if this line doesn't exists (800 x 600 x 32bpp by default). But if this\nline does exist, then it will try to set the specified resolution. You should check the [Framebuffer info](ABI.md#framebuffer-info)\n(type 8) tag to see what resolution you actually have. Paletted modes not supported, so bits per pixel has to be 15 at least.\n\n### Boot splash logo\n\nYou can also display a logo at the center of the screen using a line starting with `bootsplash`.\n\n```\nbootsplash [#(bgcolor)] (path to a tga file)\n```\n\nThe background color is optional, and has to be in HTML notation starting with a hashmark followed by 6 hexadecimal digits, RRGGBB.\nFor example `#ff0000` is full bright red and `#007f7f` is a darker cyan. If the first argument does not start with `#`, then a path\nargument is assumed.\n\nThe path must point to an existing file, and it has to be an absolute path on the boot partition. The image must be in a run length\nencoded, color-mapped [Targa format](https://www.gamers.org/dEngine/quake3/TGA.txt), because that's the most compressed variant\n(first three bytes of the file must be `0`, `1` and `9` in this order, see Data Type 9 in the specification).\n\nTo save in this format from GIMP, first select \"Image > Mode > Indexed...\", in the pop-up window set \"Maximum number of colors\"\nto 256. Then select \"File > Export As...\", enter a filename which ends in `.tga`, and in the pop-up window check \"RLE compression\".\nFor a command line conversion tool, you can use ImageMagick, `convert (any image file) -colors 256 -compress RLE bootsplash.tga`.\n(Note: I was first considering [qoi](https://qoiformat.org/), but in all my test cases tga compressed much better. That website\nis cheating big time, it presents only special, carefully hand-picked test images. No boot logos among them.)\n\n### Loading a kernel\n\nThe line starting with `kernel` tells what file should be booted, and with what parameters. If this line is missing, then the\nfilename given with `-k` on the **Simpleboot** command line will be used, and if even that's missing then simply the name `kernel`.\n\n```\nkernel (path to your kernel file) (optional boot command line arguments)\n```\n\nThe path must point to an existing file, a kernel binary, and it has to be an absolute path on the boot partition. If the kernel\nisn't in the root directory of the partition, then the directory separator is always `/`, even on UEFI systems. If the name contains\na space, then that must be escaped with `\\`. The path might be followed by command line arguments, separated by a space. These\ncommand line arguments will be passed to your kernel in the [Boot command line](ABI.md#boot-command-line) (type 1) tag.\n\nNOTE: unlike GRUB, where you have to use special commands like \"linux\" or \"multiboot\" to select the boot protocol, here there's\njust one command and the protocol is autodetected from your kernel in run-time.\n\nNOTE: normally the Multiboot2 protocol does not allow higher-half kernels, but **Simpleboot** violates the protocol a little bit\nfor those kernels in a way that does not break normal, non-higher-half Multiboot2 compatible kernels.\n\n### Loading further modules\n\nYou can load arbitrary files (initial ramdisks, kernel drivers, etc.) along with the kernel using lines starting with `module`.\nNote that this line can be repeated multiple times. If initrd was given on the **Simpleboot** command line, then that counts as\nthe first module, therefore the very first `module` line in the configuration file will override it.\n\n```\nmodule (path to a file) (optional module command line arguments)\n```\n\nThe path must point to an existing file, and it has to be an absolute path on the boot partition. It might be followed by command\nline arguments, separated by a space. If the file is gzip compressed, then it will be transparently uncompressed. Information\nabout these loaded (and uncompressed) modules will be passed to your kernel in [Modules](ABI.md#modules) (type 3) tags.\n\nThe special case is if the module starts with the bytes `DSDT`, `GUDT` or `0xD00DFEED`. In these case the file won't be added to\nthe Modules tags, rather the ACPI table will be patched so that its DSDT pointers will point to the contents of this file. With\nthis you can easily replace a buggy BIOS' ACPI table with a user provided one.\n\nTo parse these tables, you can use my dependency-free, single header [hwdet](https://gitlab.com/bztsrc/hwdet) library.\n\n### Multicore Support\n\nTo start the kernel on all processor cores at once, specify the `multicore` directive (64-bit Multiboot2 kernels only). This will\nadd [SMP](ABI.md#smp) (type 257) tag to the MBI.\n\n```\nmulticore\n```\n\nEmergency Backup\n----------------\n\nIf during loading you press <kbd>any</kbd> key, then the boot process will restart, only this time `simpleboot.cfg` will be\nparsed for commands prefixed by `backup`, for example `backupkernel`, `backupmodule`, etc.\n\nWith his feature you can quickly revert to a known to work configuration should you experience any issues with your latest kernel\nor modules.\n\nTroubleshooting\n---------------\n\nIf you encounter any problems, just run with `simpleboot -vv` flag. This will perform validation and will output the results\nverbosely at image creation time. Otherwise add `verbose 3` to `simpleboot.cfg` to get detailed boot time messages.\n\nIf you see `PMBR-ERR` string on the top left corner with red background, then that means your CPU is very old and does not\nsupport 64-bit long mode or the boot sector was unable to bootstrap the loader. Might occur only on BIOS machines, this can\nnever happen with UEFI or on RaspberryPi.\n\nOtherwise please feel free to open an [issue](https://gitlab.com/bztsrc/simpleboot/-/issues) on gitlab.\n\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/docs/coreboot.md",
    "content": "Simpleboot in ROM\n=================\n\nFor backward compatiblity, you can create the disk image with the `-r` flag. This will also save `sb_bios.rom` (legacy BIOS\nExpansion ROM) and `sb_uefi.rom` (legacy UEFI PCI Option ROM). You can test these in qemu with `-option-rom`, for example:\n\n```\nqemu-system-x86_64 -option-rom /path/to/your/sb_bios.rom -drive file=/path/to/your/disk.img,format=raw -serial stdio\n```\n\nBut the real deal is that you can use **Simpleboot** in a Free and Open Source ROM. That is, neither BIOS nor UEFI (not a\nproprietary blob that some company created and may or may not contain backdoors and telemetry). For maximum security and\nprivacy, you can compile this loader as a payload for the Free and Open Source [coreboot](https://coreboot.org/) firmware.\nAnother advantage, this boots blazing fast, about 50 times faster than with UEFI, truely within a blink of an eye. See\nthe comments at the beginning of [src/loader_cb.c](../src/loader_cb.c) for build instructions. Once compiled, you can\n[flash that ROM](https://doc.coreboot.org/tutorial/flashing_firmware/index.html) to a real motherboard, or you can try it\nout in a virtual machine, eg. in qemu (replace `/path/to/your/disk.img` with your actual disk image file):\n\n```\nqemu-system-x86_64 -bios build/coreboot.rom -drive file=/path/to/your/disk.img,format=raw -serial stdio\n```\n\nNote that the disk is specified as usual, but there's also a `-bios` parameter which replaces the factory default firmware ROM.\n\nConfiguration\n-------------\n\nThis firmware ROM now contains the loader, but you still need a disk with an operating system to boot. On that disk, you must have\na *GUID Partitioning Table*, with an *EFI System Partition* formatted as FAT32 (no UEFI files needed, it's just the partition's\ntype is the same as with UEFI for inter-operability). More partitions might co-exists on the disk; you just need a well-recognizable\none (with a well-supported file system) to serve as a boot partition.\n\nThere's no boot menu, always the *first internal disk* will be booted, unless you plug in an USB storage before you power on the\nmachine (for this, you must compile coreboot with USB support). Other removable media (like eg. CDROM) and other obsolete tech not\nsupported. If by any chance needed, you can still use them with an USB adapter.\n\n### Defaults\n\nBy default you should have only two files on the boot partition, a kernel and an initial ramdisk by these names:\n\n- `vmlinuz-linux`\n- `initramfs-linux.img`\n\nThese are what most (but sadly not all) distributions use and most likely work out-of-the-box. If you press any key (probably\n<kbd>Space</kbd>) during boot, then **Simpleboot** will fallback to a backup operating system configuration, which is:\n\n- `vmlinuz-fallback`\n- `initramfs-linux-fallback.img`\n\nIf these are not found, then the **Simpleboot** default `kernel` is also tried. You cannot change the default kernel name in\ncoreboot with `-k` when you generate the disk because it's in a separate read-only ROM image file, but see below.\n\n### Variable configuration on disk\n\nTo have more control over the boot process and what files to load, you can create [simpleboot.cfg](README.md) on the boot\npartition. This works exactly like with the non-ROM loader, except the `framebuffer` directive does nothing. The coreboot\nfirmware has no means to change the resolution in run-time, that's configured at compile-time using coreboot's `make menuconfig`.\n\nWith a configuration file you can use whatever operating system files you'd like, and you can also load any non-Linux, custom\n[Multiboot2](ABI.md) compliant kernel with as many modules as you'd like. The same applies to the backup configuration too.\n\n### Permanent configuration in ROM\n\nTo make filenames fixed that users can't alter (just the files themselves), you can add the configuration file to the firmware\nbefore you flash it to the ROM.\n\n```\n./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/simpleboot.cfg -n simpleboot.cfg\n```\n\n**Simpleboot** will only look for the on disk configuration file if not found in the ROM. Likewise you can add a bootsplash logo:\n\n```\n./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/logo.tga -n logo.tga\n```\n\nThere's no need for a `bootsplash` directive in the configuration, it will be displayed automatically. However if `bootsplash` or\n`backupbootsplash` is given, then the specified file will be loaded from disk and that logo will be displayed instead of the\nembedded one (add the configuration file to the ROM to prevent this).\n\nIf you wish, you can add a [device tree blob](https://gitlab.com/bztsrc/gudt) to the ROM too (in GUDT, DSDT (ACPI .aml) or\nFDT (.dtb) formats; depending which format your kernel understands):\n\n```\n./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/devices.gud -n devices\n./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/devices.dtb -n devices\n./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/DSDT.aml -n devices\n```\n\nJust like the logo, this will only serve as a reasonable default, which you can override in the configuration by loading a device\ntree from disk with the `module` or `backupmodule` directive.\n\nFinally, you can also add a default kernel and default initrd too (not just set their default filenames with `-k` and `-i`, but\ntheir actual file content can be embedded in the ROM):\n\n```\n./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/kernel -n kernel\n./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/initrd -n initrd\n```\n\nIf exists, these are only used as a very last resort fallback option when absolutely all the other methods have failed.\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/example/Makefile",
    "content": "SIMPLEBOOT=../src/simpleboot\nKERNEL?=mykernel\nOVMF?=/usr/share/qemu/bios-TianoCoreEFI.bin\n# compile a \"Linux\" kernel\n#LINUX=1\n# compile a Multiboot COFF/PE kernel (otherwise ELF)\n#PE=1\n# compile a Multiboot 32-bit kernel\n#MB32=1\n# compile a Multiboot 64-bit kernel for Raspberry Pi\n#RPI=1\n# test Symmetric MultiProcessor support\n#SMP=1\n# create El Torito hybrid disk image\n#CDROM=1\n\nCFLAGS?=-Wall -ffreestanding -fno-stack-protector -nostdlib -static -I..\nifeq ($(MB32),)\nGCCFLG=-m64\nCLANGFLG=--target=x86_64-pc-win32-coff\nelse\nGCCFLG=-m32\nCLANGFLG=--target=i386-pc-win32-coff\nendif\nifneq ($(RPI),)\nSBFLAGS=-s 64\nendif\nifeq ($(HI),)\nBASE=0x10\nelse\nBASE=0xffffffffffe0\nendif\nifneq ($(ROM),)\nSBFLAGS+=-r\nQEMUFLG=-option-rom sb_bios.rom\nendif\nifneq ($(CDROM),)\nSBFLAGS+=-e\nendif\n\nall: disk.img\n\n# compile the kernel\nboot/$(KERNEL): kernel.c linux.c ../simpleboot.h\n\t@mkdir -p boot\nifneq ($(RPI),)\nifeq ($(PE),)\n\tclang --target=aarch64-elf -fno-strict-aliasing $(CFLAGS) -Wl,-Ttext=$(BASE)0000 -Wl,--omagic kernel.c -o boot/$(KERNEL)\nelse\n\tclang --target=aarch64-win32-coff -fno-strict-aliasing $(CFLAGS) -c kernel.c -o kernel.o\n\tlld -flavor link -subsystem:console -nodefaultlib -base:$(BASE)0000 -entry:_start kernel.o -out:boot/$(KERNEL)\n\t@rm kernel.o\nendif\nelse\nifeq ($(LINUX),)\nifeq ($(PE),)\n\tgcc $(GCCFLG) $(CFLAGS) -Wl,-Ttext=$(BASE)1000 kernel.c -o boot/$(KERNEL)\nelse\n\tclang $(CLANGFLG) -fno-strict-aliasing $(CFLAGS) -c kernel.c -o kernel.o\n\tlld -flavor link -subsystem:console -nodefaultlib -base:$(BASE)0000 -entry:_start kernel.o -out:boot/$(KERNEL)\n\t@rm kernel.o\nendif\nelse\n\tgcc $(CFLAGS) -Wl,-Ttext=$(BASE)0000 linux.c -o kernel.o\n\tstrip --remove-section=.note.gnu.property --remove-section=.note.gnu.build-id --remove-section=.comment kernel.o\n\tobjcopy -O binary kernel.o boot/$(KERNEL)\n\t@rm kernel.o\nendif\nendif\n\n# compile the simpleboot image generator\n$(SIMPLEBOOT):\n\t@make --no-print-directory -C ../src simpleboot\n\n# generate a bootable disk image with our kernel in it\ndisk.img: boot/$(KERNEL) $(SIMPLEBOOT)\nifneq ($(SMP),)\n\t@echo \"multicore\" > boot/simpleboot.cfg\nendif\n\t$(SIMPLEBOOT) $(SBFLAGS) -vv -k \"$(KERNEL)\" boot disk.img\n\n# mount the generated disk (requires root priviledge)\nmnt: disk.img\n\t@mkdir -p mnt || true\n\tsudo mount -o loop,offset=1048576,user,umask=000 disk.img mnt\n\n# test in a UEFI machine (as EFI CDROM)\neficdrom: disk.img\n\tqemu-system-x86_64 -bios $(OVMF) -m 256 -cdrom disk.img -serial stdio\n\t@printf '\\033[0m'\n\n# test in a UEFI machine\nefi: disk.img\n\tqemu-system-x86_64 -bios $(OVMF) -m 256 -drive file=disk.img,format=raw -serial stdio -smp cpus=2\n\t@printf '\\033[0m'\n\n# test in a BIOS machine (as BIOS CDROM)\ncdrom: disk.img\n\tqemu-system-x86_64 -m 256 -cdrom disk.img -serial stdio\n\n# test in a BIOS machine\nqemu: disk.img\nifeq ($(RPI),)\n\tqemu-system-x86_64 $(QEMUFLG) -m 256 -drive file=disk.img,format=raw -serial stdio -smp cpus=2\nelse\n\t@make --no-print-directory rpi\nendif\n\n# test with another, non-qemu VM too\nbochs: disk.img\n\tbochs -f bochs.rc -q\n\n# test in a Raspberry Pi 3B\nrpi: disk.img\n\t@mkdir mnt && sudo mount -o loop,offset=1048576,user,umask=000 disk.img mnt\n\tqemu-system-aarch64 -M raspi3b -kernel mnt/KERNEL8.IMG -drive file=disk.img,if=sd,format=raw -serial stdio || true\n\t@sudo umount mnt && rmdir mnt\n\n# test with coreboot\ncb: disk.img\n\tqemu-system-x86_64 -bios ../distrib/coreboot.rom -drive file=disk.img,format=raw -serial stdio -smp cpus=2\n\n# debug in a UEFI machine (stop before executing)\nefidbg: disk.img\n\tqemu-system-x86_64 -s -S -d int -bios $(OVMF) -m 256 -drive file=disk.img,format=raw -serial stdio -smp cpus=2 || true\n\t@printf '\\033[0m'\n\n# debug in a BIOS machine (stop before executing)\nqemudbg: disk.img\n\tqemu-system-x86_64 -s -S -d int -m 256 -drive file=disk.img,format=raw -serial stdio -smp cpus=2\n\n# start the debugger and attach it to the stopped VM\ngdb:\n\tgdb -w -x gdb.rc || true\n\tpkill qemu\n\nclean:\n\t@(test -d mnt && (sudo umount mnt || true) && rmdir mnt) || true\n\trm -rf boot disk.img kernel.o *.rom 2>/dev/null || true\n\ndistclean: clean\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/example/README.md",
    "content": "Simpleboot Example Kernels\n==========================\n\nThis directory contains the source for very minimal kernels, that can be booted with Simpleboot (and\n[Easyboot](https://gitlab.com/bztsrc/easyboot) as well). All they do is dumping the received boot parameters to the serial console.\n\nCompilation\n-----------\n\n`make all`\n\nWill compile the example 64-bit [Multiboot2](https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html)-compatible ELF\nkernel and create the bootable disk image `disk.img`.\n\n`LINUX=1 make all`\n\nCreates a disk image with an example kernel that speaks the\n[Linux/x86 Boot Protocol](https://www.kernel.org/doc/html/latest/arch/x86/boot.html) v2.12+ (needs objcopy).\n\n`MB32=1 make all`\n\nCreates a disk image with a 32-bit Multiboot2-compatible ELF kernel.\n\n`PE=1 make clean all`\n\nCreates a disk image with a 64-bit Multiboot2-compatible COFF/PE kernel (requires Clang + lld).\n\n`MB32=1 PE=1 make all`\n\nCreates a disk image with a 32-bit Multiboot2-compatible COFF/PE kernel (requires Clang + lld).\n\n`RPI=1 make clean all`\n\nCreates a disk image with a 64-bit Multiboot2-compatible kernel for the Raspberry Pi (requires Clang + lld).\n\n`RPI=1 PE=1 make clean all`\n\nCreates a disk image with a 64-bit Multiboot2-compatible COFF/PE kernel for the Raspberry Pi (requires Clang + lld).\n\n`make clean`\n\nCleans the repo from the compiled binaries.\n\nPlus all cases can be prefixed by `HI=1` which will compile a higher half kernel, and `SMP=1` will test Symmetric\nMultiProcessing (latter only with 64-bit Multiboot2-compatible ELF/COFF kernels, no Linux and no 32-bit).\n\nTesting\n-------\n\n`make mnt`\n\nMounts the boot partition inside the disk image so that you can examine its contents.\n\n`make qemu`\n\nBoots the disk image in qemu using BIOS (or Raspberry Pi if `RPI` set).\n\n`make efi`\n\nBoots the disk image in qemu using UEFI (you have to provide your own OVMF).\n\n`make cdrom`\n\nBoots the disk image in qemu using BIOS and El Torito \"no emulation\" mode.\nUse `CDROM=1 make disk.img` to generate a hybrid disk / cdrom image.\n\n`make eficdrom`\n\nBoots the disk image in qemu using UEFI and El Torito \"no emulation\" mode (you have to provide your own OVMF).\nUse `CDROM=1 make disk.img` to generate a hybrid disk / cdrom image.\n\n`make bochs`\n\nBoots the disk image in bochs using BIOS.\n\n`make rpi`\n\nBoots the disk image in qemu on Raspberry Pi.\n\n`make cb`\n\nBoots the disk image using coreboot. Note: this toolchain generates `boot/mykernel`, and coreboot will complain about not finding\nthe kernel. To fix, either add `boot/simpleboot.cfg` too or use `mv boot/mykernel boot/kernel; make cb` (unlike with the other\nloaders, you cannot change the default name with `-k` because coreboot is a read-only ROM image, so only config file works).\n\nDebugging\n---------\n\n`make qemudbg`\n\nBoots the disk image in qemu using BIOS, but does not start the VM.\n\n`make efidbg`\n\nBoots the disk image in qemu using UEFI, but does not start the VM.\n\n`make gdb`\n\nRun this in another terminal. It runs gdb, connects it to the stopped VM and starts execution.\nBecause there's no symbol file, it's a bit tricky to use. Place `1:jmp 1b` anywhere in the code, and press <kbd>Ctrl</kbd>+\n<kbd>C</kbd> in the gdb's window. You'll see that the VM is running that jump. Use `set $pc += 2` to step over the jump\ninstruction, and after that you can do step by step execution with `si`, or continue with `c`.\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/example/bochs.rc",
    "content": "# configuration file generated by Bochs\nplugin_ctrl: unmapped=1, biosdev=1, speaker=0, extfpuirq=1, parallel=0, serial=1, iodebug=0\nconfig_interface: textconfig\ndisplay_library: x\nmemory: host=128, guest=128\nromimage: file=\"/usr/share/bochs/BIOS-bochs-latest\"\nvgaromimage: file=\"/usr/share/bochs/VGABIOS-lgpl-latest\"\n#boot: cdrom\nboot: disk\nata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14\nata0-master: type=disk, path=\"disk.img\", mode=flat, cylinders=2, heads=16, spt=63, model=\"Generic 1234\", biosdetect=auto, translation=auto\n#ata0-slave: type=cdrom, path=\"disk.img\", status=inserted\nata0-slave: type=none\nata1: enabled=0\nata2: enabled=0\nata3: enabled=0\npci: enabled=1, chipset=i440fx\nvga: extension=vbe, update_freq=10, realtime=1\ncpu: count=2, ips=4000000, model=corei7_ivy_bridge_3770k, reset_on_triple_fault=0, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0\ncpuid: level=6, apic=x2apic, simd=avx, aes=1\nprint_timestamps: enabled=0\ndebugger_log: -\nmagic_break: enabled=1\nport_e9_hack: enabled=1\nprivate_colormap: enabled=0\nclock: sync=realtime, time0=local, rtc_sync=1\nlog: -\nlogprefix: %t%e%d\ndebug: action=ignore\ninfo: action=report\nerror: action=report\npanic: action=ask\nkeyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none\nmouse: type=imps2, enabled=0, toggle=ctrl+mbutton\ncom1: enabled=1, mode=file, dev=/dev/stdout\n#optromimage1: file=\"sb_bios.rom\", address=0xCA000\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/example/gdb.rc",
    "content": "target remote localhost:1234\nset architecture i386:x86-64\nset style enabled off\ndisplay/4i $pc\nc\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/example/kernel.c",
    "content": "/*\n * example/kernel.c\n * https://gitlab.com/bztsrc/simpleboot\n *\n * Copyright (C) 2023 bzt (bztsrc@gitlab), MIT license\n * Copyright (C) 1999,2003,2007,2008,2009,2010  Free Software Foundation, Inc.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * @brief An example Multiboot2 compliant kernel for the Simpleboot loader\n * https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html\n *\n * This is a very minimal \"kernel\" that just dumps the MBI to the serial console.\n * The main function is 99.9% identical to the one in the Multiboot2 spec (that's\n * why the identation is so ugly).\n */\n\n#include <simpleboot.h>\n\nvoid printf(char *fmt, ...);\nvoid dumpacpi(uint64_t addr);\nvoid dumpuuid(uint8_t *uuid);\n\n/*****************************************\n *          kernel entry point           *\n *****************************************/\nvoid _start(uint32_t magic, uintptr_t addr)\n{\n    multiboot_tag_t *tag, *last;\n    multiboot_mmap_entry_t *mmap;\n    multiboot_tag_framebuffer_t *tagfb;\n    unsigned int size;\n\n    /* if everything else fails, this always works */\n/*\n    __asm__ __volatile__(\"\":\"=a\"(magic),\"=b\"(addr)::);\n*/\n\n    /* since this might run on multiple cores, do some locking to avoid messing up each other's output */\n    while(*((volatile uint8_t*)0x558)) {}; *((volatile uint8_t*)0x558) = 1;\n\n    /*  Am I booted by a Multiboot-compliant boot loader? */\n    if (magic != MULTIBOOT2_BOOTLOADER_MAGIC) {\n      printf (\"Invalid magic number: 0x%x\\n\", (unsigned) magic);\n      goto halt;\n    }\n\n    if (addr & 7) {\n      printf (\"Unaligned MBI: 0x%x\\n\", addr);\n      goto halt;\n    }\n\n    /*  Dump the MBI tags that we've received */\n    size = ((multiboot_info_t*)addr)->total_size;\n    printf (\"\\nAnnounced MBI size 0x%x\\n\", size);\n    for (tag = (multiboot_tag_t *) (addr + 8), last = (multiboot_tag_t *) (addr + size);\n         tag < last && tag->type != MULTIBOOT_TAG_TYPE_END;\n         tag = (multiboot_tag_t *) ((uint8_t *) tag + ((tag->size + 7) & ~7)))\n    {\n      printf (\"Tag 0x%x, Size 0x%x\\n\", tag->type, tag->size);\n      switch (tag->type) {\n        case MULTIBOOT_TAG_TYPE_CMDLINE:\n          printf (\"Command line = %s\\n\",\n                  ((multiboot_tag_cmdline_t *) tag)->string);\n          break;\n        case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:\n          printf (\"Boot loader name = %s\\n\",\n                  ((multiboot_tag_loader_t *) tag)->string);\n          break;\n        case MULTIBOOT_TAG_TYPE_MODULE:\n          printf (\"Module at 0x%x-0x%x. Command line %s\\n\",\n                  ((multiboot_tag_module_t *) tag)->mod_start,\n                  ((multiboot_tag_module_t *) tag)->mod_end,\n                  ((multiboot_tag_module_t *) tag)->string);\n          break;\n        case MULTIBOOT_TAG_TYPE_MMAP:\n          {\n            printf (\"mmap\\n\");\n            for (mmap = ((multiboot_tag_mmap_t *) tag)->entries;\n                 (uint8_t *) mmap < (uint8_t *) tag + tag->size;\n                 mmap = (multiboot_mmap_entry_t *) ((uintptr_t) mmap\n                    + ((multiboot_tag_mmap_t *) tag)->entry_size))\n              printf (\" base_addr = 0x%8x%8x,\"\n                      \" length = 0x%8x%8x, type = 0x%x %s, res = 0x%x\\n\",\n                      (unsigned) (mmap->base_addr >> 32),\n                      (unsigned) (mmap->base_addr & 0xffffffff),\n                      (unsigned) (mmap->length >> 32),\n                      (unsigned) (mmap->length & 0xffffffff),\n                      (unsigned) mmap->type,\n                      mmap->type == MULTIBOOT_MEMORY_AVAILABLE ? \"free\" : (\n                      mmap->type == MULTIBOOT_MEMORY_ACPI_RECLAIMABLE ? \"ACPI\" : (\n                      mmap->type == MULTIBOOT_MEMORY_NVS ? \"ACPI NVS\" : \"used\")),\n                      (unsigned) mmap->reserved);\n          }\n          break;\n        case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:\n          {\n            tagfb = (multiboot_tag_framebuffer_t *) tag;\n            printf (\"framebuffer\\n\");\n            printf (\" address 0x%8x%8x pitch %d\\n\",\n                (unsigned) (tagfb->framebuffer_addr >> 32),\n                (unsigned) (tagfb->framebuffer_addr & 0xffffffff),\n                tagfb->framebuffer_pitch);\n            printf (\" width %d height %d depth %d bpp\\n\",\n                tagfb->framebuffer_width,\n                tagfb->framebuffer_height,\n                tagfb->framebuffer_bpp);\n            printf (\" red channel:   at %d, %d bits\\n\",\n                tagfb->framebuffer_red_field_position,\n                tagfb->framebuffer_red_mask_size);\n            printf (\" green channel: at %d, %d bits\\n\",\n                tagfb->framebuffer_green_field_position,\n                tagfb->framebuffer_green_mask_size);\n            printf (\" blue channel:  at %d, %d bits\\n\",\n                tagfb->framebuffer_blue_field_position,\n                tagfb->framebuffer_blue_mask_size);\n            break;\n          }\n        case MULTIBOOT_TAG_TYPE_EFI64:\n          printf (\"EFI system table 0x%x\\n\",\n                  ((multiboot_tag_efi64_t *) tag)->pointer);\n          break;\n        case MULTIBOOT_TAG_TYPE_EFI64_IH:\n          printf (\"EFI image handle 0x%x\\n\",\n                  ((multiboot_tag_efi64_t *) tag)->pointer);\n          break;\n        case MULTIBOOT_TAG_TYPE_SMBIOS:\n          printf (\"SMBIOS table major %d minor %d\\n\",\n                  ((multiboot_tag_smbios_t *) tag)->major,\n                  ((multiboot_tag_smbios_t *) tag)->minor);\n          break;\n        case MULTIBOOT_TAG_TYPE_ACPI_OLD:\n          printf (\"ACPI table (1.0, old RSDP)\");\n          dumpacpi ((uint64_t)*((uint32_t*)&((multiboot_tag_old_acpi_t *) tag)->rsdp[16]));\n          break;\n        case MULTIBOOT_TAG_TYPE_ACPI_NEW:\n          printf (\"ACPI table (2.0, new RSDP)\");\n          dumpacpi (*((uint64_t*)&((multiboot_tag_new_acpi_t *) tag)->rsdp[24]));\n          break;\n        /* additional, not in the original Multiboot2 spec */\n        case MULTIBOOT_TAG_TYPE_EDID:\n          printf (\"EDID info\\n\");\n          printf (\" manufacturer ID %02x%02x\\n\",\n            ((multiboot_tag_edid_t *) tag)->edid[8], ((multiboot_tag_edid_t *) tag)->edid[9]);\n          printf (\" EDID ID %02x%02x Version %d Rev %d\\n\",\n            ((multiboot_tag_edid_t *) tag)->edid[10], ((multiboot_tag_edid_t *) tag)->edid[11],\n            ((multiboot_tag_edid_t *) tag)->edid[18], ((multiboot_tag_edid_t *) tag)->edid[19]);\n          printf (\" monitor type %02x size %d cm x %d cm\\n\",\n            ((multiboot_tag_edid_t *) tag)->edid[20], ((multiboot_tag_edid_t *) tag)->edid[21],\n            ((multiboot_tag_edid_t *) tag)->edid[22]);\n          break;\n        case MULTIBOOT_TAG_TYPE_SMP:\n          printf (\"SMP supported\\n\");\n          printf (\" %d core(s)\\n\", ((multiboot_tag_smp_t*) tag)->numcores);\n          printf (\" %d running\\n\", ((multiboot_tag_smp_t*) tag)->running);\n          printf (\" %02x bsp id\\n\", ((multiboot_tag_smp_t*) tag)->bspid);\n          break;\n        case MULTIBOOT_TAG_TYPE_PARTUUID:\n          printf (\"Partition UUIDs\\n\");\n          printf (\" boot \"); dumpuuid(((multiboot_tag_partuuid_t*) tag)->bootuuid);\n          if(tag->size >= 40) {\n            printf (\" root \"); dumpuuid(((multiboot_tag_partuuid_t*) tag)->rootuuid);\n          }\n          break;\n        default:\n          printf (\"---unknown MBI tag, this shouldn't happen with Simpleboot/Easyboot!---\\n\");\n          goto halt;\n        }\n    }\n    tag = (multiboot_tag_t *) ((uint8_t *) tag + ((tag->size + 7) & ~7));\n    printf (\"Total MBI size 0x%x %s\\n\", (uintptr_t)tag - addr, ((uintptr_t)tag - addr) == size ? \"OK\" : \"ERR\");\n\n    /* there's nowhere to return to, halt machine */\nhalt:\n    *((volatile uint8_t*)0x558) = 0;\n#ifdef __aarch64__\n    __asm__ __volatile__(\"1: wfe; b 1b\");\n#else\n    __asm__ __volatile__(\"1: cli; hlt; jmp 1b\");\n#endif\n}\n\n/**\n * Display (extremely minimal) formated message on serial\n */\nvoid printf(char *fmt, ...)\n{\n    __builtin_va_list args;\n    int arg, len, sign, i;\n    unsigned int uarg;\n    char *p, tmpstr[19], n;\n    /* macro to put a character on serial console */\n#ifdef __aarch64__\n#define mmio_base   0x3F000000\n#define UART0_DR    ((volatile uint32_t*)(mmio_base+0x00201000))\n#define UART0_FR    ((volatile uint32_t*)(mmio_base+0x00201018))\n#define PUTC(c)     do{do{ __asm__ __volatile__(\"nop\");} while(*UART0_FR&0x20); *UART0_DR=c;}while(0)\n#else\n#define PUTC(c)     __asm__ __volatile__( \\\n                    \"xorl %%ebx, %%ebx; movb %0, %%bl;\" \\\n                    \"movl $10000,%%ecx;\" \\\n                    \"1:inb %%dx, %%al;pause;\" \\\n                    \"cmpb $0xff,%%al;je 2f;\" \\\n                    \"dec %%ecx;jz 2f;\" \\\n                    \"andb $0x20,%%al;jz 1b;\" \\\n                    \"subb $5,%%dl;movb %%bl, %%al;outb %%al, %%dx;2:\" \\\n                    ::\"a\"(c),\"d\"(0x3fd): \"rbx\", \"rcx\");\n#endif\n    /* parse format and print */\n    __builtin_va_start(args, fmt);\n    arg = 0;\n    while(*fmt) {\n        if(*fmt == '%') {\n            fmt++;\n            if(*fmt == '%') goto put;\n            len=0; while(*fmt >= '0' && *fmt <= '9') { len *= 10; len += *fmt - '0'; fmt++; }\n            if(*fmt == 'c') { arg = __builtin_va_arg(args, int); PUTC((uint8_t)arg); fmt++; continue; } else\n            if(*fmt == 'd') {\n                arg = __builtin_va_arg(args, int);\n                sign = 0; if((int)arg < 0) { arg = -arg; sign++; }\n                i = 18; tmpstr[i] = 0;\n                do { tmpstr[--i] = '0' + (arg % 10); arg /= 10; } while(arg != 0 && i > 0);\n                if(sign) tmpstr[--i] = '-';\n                if(len > 0 && len < 18) { while(i > 18 - len) tmpstr[--i] = ' '; }\n                p = &tmpstr[i];\n                goto putstring;\n            } else\n            if(*fmt == 'x') {\n                uarg = __builtin_va_arg(args, unsigned int);\n                i = 16; tmpstr[i] = 0;\n                do { n = uarg & 0xf; tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); uarg >>= 4; } while(uarg != 0 && i > 0);\n                if(len > 0 && len <= 16) { while(i > 16 - len) tmpstr[--i] = '0'; }\n                p = &tmpstr[i];\n                goto putstring;\n            } else\n            if(*fmt == 's') {\n                p = __builtin_va_arg(args, char*);\nputstring:      if(p == (void*)0) p = \"(null)\";\n                while(*p) PUTC(*p++);\n            }\n        } else {\nput:        PUTC(*fmt);\n        }\n        fmt++;\n    }\n    __builtin_va_end(args);\n}\n\n/**\n * Print a binary UUID in human readable form\n */\nvoid dumpuuid(uint8_t *uuid)\n{\n    printf(\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x\\n\",\n        uuid[3], uuid[2], uuid[1], uuid[0],\n        uuid[5], uuid[4],\n        uuid[7], uuid[6],\n        uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);\n}\n\ntypedef struct {\n    char magic[4];\n    uint32_t size;\n    uint8_t rev;\n    uint8_t chksum;\n    char OEM[6];\n    char OEMtableid[8];\n    uint32_t OEMrev;\n    uint32_t creatid;\n    uint32_t creatrev;\n} __attribute__((packed)) sdt_hdr_t;\n\ntypedef struct {\n    char magic[4];\n    uint32_t size;\n    uint8_t rev;\n    uint8_t chksum;\n    uint8_t res0[30];\n    uint32_t dsdt;\n    uint8_t  reserved[96];\n    uint64_t x_dsdt;\n} __attribute__((packed)) fadt_t;\n\n/**\n * Dump ACPI tables\n */\nvoid dumpacpi(uint64_t addr)\n{\n    uint8_t *ptr, *end, *p;\n    sdt_hdr_t *hdr = (sdt_hdr_t*)addr, *tbl = 0;\n\n    /* print root table, either RSDT or XSDT */\n    printf(\" 0x%08x%08x %c%c%c%c size %d\\n\",\n        addr >> 32, addr & 0xffffffff,\n        hdr->magic[0], hdr->magic[1], hdr->magic[2], hdr->magic[3],\n        hdr->size);\n    /* iterate on tables */\n    if(hdr->magic[1] == 'S' && hdr->magic[2] == 'D' && hdr->magic[3] == 'T')\n        for(ptr = (uint8_t*)(addr + sizeof(sdt_hdr_t)), end = (uint8_t*)(addr + hdr->size);\n          ptr < end; ptr += hdr->magic[0] == 'X' ? 8 : 4) {\n            /* with RSDT we have 32-bit addresses, but with XSDT 64-bit */\n            tbl = (hdr->magic[0] == 'X' ?\n                (sdt_hdr_t*)((uintptr_t)*((uint64_t*)ptr)) :\n                (sdt_hdr_t*)((uintptr_t)*((uint32_t*)ptr)));\n            printf(\"  0x%08x%08x %c%c%c%c size %d\",\n                (uint64_t)tbl >> 32, (uint64_t)tbl & 0xffffffff,\n                tbl->magic[0], tbl->magic[1], tbl->magic[2], tbl->magic[3],\n                tbl->size);\n            /* if it's FADT, print the DSDT in it too. There's a 32-bit address and a 64-bit address for it as well */\n            if(tbl->magic[0] == 'F' && tbl->magic[1] == 'A' && tbl->magic[2] == 'C' && tbl->magic[3] == 'P') {\n                p = tbl->rev >= 2 && tbl->size > 148 ? (uint8_t*)(uintptr_t)((fadt_t*)tbl)->x_dsdt :\n                    (uint8_t*)(uintptr_t)((fadt_t*)tbl)->dsdt;\n                /* it is possible that the DSDT data is actually GUDT or DTB encoded (loader's feature, not in ACPI) */\n                if(p[0] == 0xD0 && p[1] == 0x0D && p[2] == 0xFE && p[3] == 0xED)\n                    printf(\" (DTB \");\n                else\n                    printf(\" (%c%c%c%c \", p[0], p[1], p[2], p[3]);\n                /* print out address */\n                if(tbl->rev >= 2 && tbl->size > 148)\n                    printf(\"0x%08x%08x)\", ((fadt_t*)tbl)->x_dsdt >> 32, ((fadt_t*)tbl)->x_dsdt & 0xffffffff);\n                else\n                    printf(\"0x%08x)\", p);\n            }\n            printf(\"\\n\");\n        }\n}\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/example/linux.c",
    "content": "/*\n * example/linux.c\n * https://gitlab.com/bztsrc/simpleboot\n *\n * Copyright (C) 2023 bzt (bztsrc@gitlab), MIT license\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * @brief An example Linux/x86 Boot Protocol compliant kernel for the Simpleboot loader\n * https://www.kernel.org/doc/html/latest/arch/x86/boot.html\n *\n * This is a very minimal \"kernel\" that just dumps the boot_params to the serial console.\n */\n\n#include <simpleboot.h>\n/* get the Linux structs */\n#include \"../src/loader.h\"\n\nvoid printf(char *fmt, ...);\n\n/***************************************************************************\n * Linux has no concept of a header with an entry point field, so we must  *\n * keep fixed positions: setup_header must be at 0x1f1 and _start at 0x600 *\n ***************************************************************************/\nuint8_t __attribute__((section(\".text\"))) __attribute__ ((aligned (1)))\n    padding1[0x1f1] = { 0 };\nlinux_boot_t __attribute__((section(\".text\"))) __attribute__ ((aligned (1))) setup_header = {\n.setup_sects = 1,\n.boot_flag = 0xAA55,\n.jump = 0x6AEB,\n.header = 0x53726448, /* \"HdrS\" */\n.version = 0x20c,\n.pref_address = 0x100000,\n.init_size = 4900-1024\n};\nuint8_t __attribute__((section(\".text\"))) __attribute__ ((aligned (1)))\n    padding2[0x600 - 0x1f1 - sizeof(setup_header)] = { 0 };\n\n/*****************************************\n *          kernel entry point           *\n *****************************************/\nvoid _start(uint32_t dummy, linux_boot_params_t *bp)\n{\n    uint32_t i;\n\n    printf(\"\\r\\nstruct boot_params at %x\\r\\n{\\r\\n\", bp);\n    printf(\".screen_info.lfb_width %d\\r\\n\", bp->lfb_width);\n    printf(\".screen_info.lfb_height %d\\r\\n\", bp->lfb_height);\n    printf(\".screen_info.lfb_depth %d\\r\\n\", bp->lfb_depth);\n    printf(\".screen_info.lfb_base %x\\r\\n\", bp->lfb_base);\n    printf(\".screen_info.lfb_size %d\\r\\n\", bp->lfb_size);\n    printf(\".screen_info.lfb_linelength %d\\r\\n\", bp->lfb_linelength);\n    printf(\".screen_info.red_size %d\\r\\n\", bp->red_size);\n    printf(\".screen_info.red_pos %d\\r\\n\", bp->red_pos);\n    printf(\".screen_info.green_size %d\\r\\n\", bp->green_size);\n    printf(\".screen_info.green_pos %d\\r\\n\", bp->green_pos);\n    printf(\".screen_info.blue_size %d\\r\\n\", bp->blue_size);\n    printf(\".screen_info.blue_pos %d\\r\\n\", bp->blue_pos);\n    printf(\".acpi_rsdp_addr %x\\r\\n\", bp->acpi_rsdp_addr);\n    printf(\".e820_entries %d\\r\\n\", bp->e820_entries);\n    for(i = 0; i < bp->e820_entries && i < E820_MAX_ENTRIES_ZEROPAGE; i++)\n        printf(\".e820_table[%d] = { .base %012x .size %d .type %x }\\r\\n\", i,\n            bp->e820_table[i].addr, bp->e820_table[i].size, bp->e820_table[i].type);\n    printf(\".hdr.setup_sects %d\\r\\n\", bp->hdr.setup_sects);\n    printf(\".hdr.version %04x\\r\\n\", bp->hdr.version);\n    printf(\".hdr.type_of_loader %d\\r\\n\", bp->hdr.type_of_loader);\n    printf(\".hdr.loadflags %x\\r\\n\", bp->hdr.loadflags);\n    printf(\".hdr.code32_start %x\\r\\n\", bp->hdr.code32_start);\n    printf(\".hdr.ramdisk_image %x\\r\\n\", bp->hdr.ramdisk_image);\n    printf(\".hdr.ramdisk_size %d\\r\\n\", bp->hdr.ramdisk_size);\n    printf(\".hdr.cmd_line_ptr %x '%s'\\r\\n\", bp->hdr.cmd_line_ptr, (char*)(uintptr_t)bp->hdr.cmd_line_ptr);\n    printf(\".hdr.pref_address %x\\r\\n\", (uint32_t)bp->hdr.pref_address);\n    printf(\".hdr.init_size %d\\r\\n\", bp->hdr.init_size);\n    printf(\"}\\r\\n\\r\\n\");\n\n    /* there's nowhere to return to, halt machine */\n    __asm__ __volatile__(\"1: cli; hlt; jmp 1b\");\n}\n\n/**\n * Display (extremely minimal) formated message on serial\n */\nvoid printf(char *fmt, ...)\n{\n    __builtin_va_list args;\n    int64_t arg;\n    int len, sign, i;\n    char *p, tmpstr[19], n;\n    /* macro to put a character on serial console */\n#define PUTC(c) __asm__ __volatile__( \\\n                \"xorl %%ebx, %%ebx; movb %0, %%bl;\" \\\n                \"movl $10000,%%ecx;\" \\\n                \"1:inb %%dx, %%al;pause;\" \\\n                \"cmpb $0xff,%%al;je 2f;\" \\\n                \"dec %%ecx;jz 2f;\" \\\n                \"andb $0x20,%%al;jz 1b;\" \\\n                \"subb $5,%%dl;movb %%bl, %%al;outb %%al, %%dx;2:\" \\\n                ::\"a\"(c),\"d\"(0x3fd): \"rbx\", \"rcx\");\n    /* parse format and print */\n    __builtin_va_start(args, fmt);\n    arg = 0;\n    while(*fmt) {\n        if(*fmt == '%') {\n            fmt++;\n            if(*fmt == '%') goto put;\n            len=0; while(*fmt >= '0' && *fmt <= '9') { len *= 10; len += *fmt - '0'; fmt++; }\n            if(*fmt == 'd') {\n                arg = __builtin_va_arg(args, int64_t);\n                sign = 0; if((int)arg < 0) { arg = -arg; sign++; }\n                i = 18; tmpstr[i] = 0;\n                do { tmpstr[--i] = '0' + (arg % 10); arg /= 10; } while(arg != 0 && i > 0);\n                if(sign) tmpstr[--i] = '-';\n                if(len > 0 && len < 18) { while(i > 18 - len) tmpstr[--i] = ' '; }\n                p = &tmpstr[i];\n                goto putstring;\n            } else\n            if(*fmt == 'x') {\n                arg = __builtin_va_arg(args, int64_t);\n                i = 16; tmpstr[i] = 0;\n                do { n = arg & 0xf; tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); arg >>= 4; } while(arg != 0 && i > 0);\n                if(len > 0 && len <= 16) { while(i > 16 - len) tmpstr[--i] = '0'; }\n                p = &tmpstr[i];\n                goto putstring;\n            } else\n            if(*fmt == 's') {\n                p = __builtin_va_arg(args, char*);\nputstring:      if(p == (void*)0) p = \"(null)\";\n                while(*p) PUTC(*p++);\n            }\n        } else {\nput:        PUTC(*fmt);\n        }\n        fmt++;\n    }\n    __builtin_va_end(args);\n}\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/example/simpleboot.cfg",
    "content": "#\n#  example/simpleboot.cfg\n#  https://gitlab.com/bztsrc/simpleboot\n#\n#  Copyright (C) 2023 bzt (bztsrc@gitlab), MIT license\n#\n#  Permission is hereby granted, free of charge, to any person obtaining a copy\n#  of this software and associated documentation files (the \"Software\"), to\n#  deal in the Software without restriction, including without limitation the\n#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n#  sell copies of the Software, and to permit persons to whom the Software is\n#  furnished to do so, subject to the following conditions:\n#\n#  The above copyright notice and this permission notice shall be included in\n#  all copies or substantial portions of the Software.\n#\n#  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n#  DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n#  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n#  IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n#\n#  @brief Example configuration file for Simpleboot\n#\n#  HINT: running `simpleboot -vv` (with at least 2 'v's) will validate the\n#  input, which includes a boot configuration file syntax check too.\n#\n\n# ------------------------------------------------------------------------------\n# With the `kernel` you can tell what file to load, and what arguments to pass.\n# The path must be an absolute one (no `.` nor `..`), and its root is relative\n# to the boot partition. If directories used, then the separator is `/` (on UEFI\n# too). A space separates the path from the command line, so if you need a space\n# in the path, you must escape it with a backslash, like `my\\ kernel`. The name\n# match is upper-case lower-case INsensitive.\n\nkernel vmlinuz-linux console=ttyS0,115200 console=tty0\n#kernel mykernel\n#kernel core.exe\n#kernel boot/bzImage quiet\n#kernel EFI/boot/3rd\\ Party.elf\n\n# ------------------------------------------------------------------------------\n# You can load further files with the module directive. Same syntax as with\n# `kernel`, first argument is a path, the rest optional parameters for you.\n\nmodule initrd\n#module boot/rootfs.tgz arch=any some other arguments\n\n# ------------------------------------------------------------------------------\n# The framebuffer is always set up, by default at 800 x 600 x 32bpp. You can\n# change this with the following line.\n\nframebuffer 1024 768 16\n#framebuffer 1920 1080 32\n\n# ------------------------------------------------------------------------------\n# Of course you can display a boot splash logo. It has to be in RLE compressed\n# indexed (color-mapped) TGA format. If the first argument isn't starting with\n# a `#` hashmark, then there's only one argument, then that's the logo file.\n# If the first argument starts with a `#`, then a HTML color notation follows,\n# which sets the background color. In this case the second argument is the path.\n\nbootsplash #1177FF logo.tga\n#bootsplash logo.tga\n#bootsplash #00FF00 boot/images/my\\ splash\\ screen.tga\n\n# ------------------------------------------------------------------------------\n# By default the boot messages are surpressed, \"quiet\" mode. You can increase\n# the verbosity level to see more and more details.\n\nverbose 1\n#verbose 3\n\n# ------------------------------------------------------------------------------\n# By default all kernels started on the boot-strap processor only. However with\n# this directive you can turn on SMP and run the kernel on all CPU cores in\n# parallel (only for 64-bit Multiboot2 kernels).\n\n#multicore\n\n# ------------------------------------------------------------------------------\n# All commands have a variant prefixed by `backup`. If you press any key during\n# boot, then the boot process will restart, only this time the prefixed commands\n# will be used, and unprefixed ones skipped. Normally it's the other way around,\n# prefixed versions are skipped.\n\nbackupkernel oldkernel\nbackupmodule oldinitrd\nbackupframebuffer 640 480 32\n# use red background color when loading backup\nbackupbootsplash #FF7711 logo_backup.tga\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/simpleboot.h",
    "content": "/*\n * simpleboot.h - Multiboot2 compatible Boot header file.\n * https://codeberg.org/bzt/simpleboot\n *\n * Copyright (C) 2023 bzt, MIT license\n * Copyright (C) 1999,2003,2007,2008,2009,2010  Free Software Foundation, Inc.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * @brief Simpleboot / Easyboot header file for kernels\n */\n\n#if !defined(SIMPLEBOOT_H) && !defined(EASYBOOT_H)\n#define SIMPLEBOOT_H 1\n\n#include <stdint.h>\n\n#ifdef  __cplusplus\nextern \"C\" {\n#endif\n\n#define SIMPLEBOOT_MAGIC  \"Simpleboot\"      /* minimalistic boot loader */\n#define EASYBOOT_MAGIC    \"Easyboot\"        /* fully featured boot manager */\n\n/*** Multiboot2 ***/\n\n/* This should be in the first kernel parameter as well as in %eax. */\n#define MULTIBOOT2_BOOTLOADER_MAGIC         0x36d76289\n\n/*  Alignment of multiboot modules. */\n#define MULTIBOOT_MOD_ALIGN                 0x00001000\n\n/*  Alignment of the multiboot info structure. */\n#define MULTIBOOT_INFO_ALIGN                0x00000008\n\n/*  Flags set in the ’flags’ member of the multiboot header. */\n#define MULTIBOOT_TAG_ALIGN                 8\n#define MULTIBOOT_TAG_TYPE_END              0\n#define MULTIBOOT_TAG_TYPE_CMDLINE          1\n#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2\n#define MULTIBOOT_TAG_TYPE_MODULE           3\n#define MULTIBOOT_TAG_TYPE_MMAP             6\n#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER      8\n#define MULTIBOOT_TAG_TYPE_EFI64            12\n#define MULTIBOOT_TAG_TYPE_SMBIOS           13\n#define MULTIBOOT_TAG_TYPE_ACPI_OLD         14\n#define MULTIBOOT_TAG_TYPE_ACPI_NEW         15\n#define MULTIBOOT_TAG_TYPE_EFI64_IH         20\n/*  Additional, not in the original Multiboot2 spec. */\n#define MULTIBOOT_TAG_TYPE_EDID             256\n#define MULTIBOOT_TAG_TYPE_SMP              257\n#define MULTIBOOT_TAG_TYPE_PARTUUID         258\n\n/* Multiboot2 information header */\ntypedef struct {\n  uint32_t  total_size;\n  uint32_t  reserved;\n} multiboot_info_t;\n\n/* common tag header */\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n} multiboot_tag_t;\n\n/* Boot command line (type 1) */\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n  char      string[0];\n} multiboot_tag_cmdline_t;\n\n/* Boot loader name (type 2) */\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n  char      string[0];\n} multiboot_tag_loader_t;\n\n/* Modules (type 3) */\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n  uint32_t  mod_start;\n  uint32_t  mod_end;\n  char      string[0];\n} multiboot_tag_module_t;\n\n/* Memory Map (type 6) */\n#define MULTIBOOT_MEMORY_AVAILABLE          1\n#define MULTIBOOT_MEMORY_RESERVED           2\n/* original EFI type stored in \"reserved\" field */\n#define MULTIBOOT_MEMORY_UEFI               MULTIBOOT_MEMORY_RESERVED\n#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE   3\n#define MULTIBOOT_MEMORY_NVS                4\n#define MULTIBOOT_MEMORY_BADRAM             5\ntypedef struct {\n  uint64_t  base_addr;\n  uint64_t  length;\n  uint32_t  type;\n  uint32_t  reserved;       /* original EFI Memory Type */\n} multiboot_mmap_entry_t;\n\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n  uint32_t  entry_size;\n  uint32_t  entry_version;\n  multiboot_mmap_entry_t entries[0];\n} multiboot_tag_mmap_t;\n\n/* Framebuffer info (type 8) */\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n  uint64_t  framebuffer_addr;\n  uint32_t  framebuffer_pitch;\n  uint32_t  framebuffer_width;\n  uint32_t  framebuffer_height;\n  uint8_t   framebuffer_bpp;\n  uint8_t   framebuffer_type; /* must be 1 */\n  uint16_t  reserved;\n  uint8_t   framebuffer_red_field_position;\n  uint8_t   framebuffer_red_mask_size;\n  uint8_t   framebuffer_green_field_position;\n  uint8_t   framebuffer_green_mask_size;\n  uint8_t   framebuffer_blue_field_position;\n  uint8_t   framebuffer_blue_mask_size;\n} multiboot_tag_framebuffer_t;\n\n/* EFI 64-bit image handle pointer (type 12) */\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n  uint64_t  pointer;\n} multiboot_tag_efi64_t;\n\n/* SMBIOS tables (type 13) */\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n  uint8_t   major;\n  uint8_t   minor;\n  uint8_t   reserved[6];\n  uint8_t   tables[0];\n} multiboot_tag_smbios_t;\n\n/* ACPI old RSDP (type 14) */\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n  uint8_t   rsdp[0];\n} multiboot_tag_old_acpi_t;\n\n/* ACPI new RSDP (type 15) */\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n  uint8_t   rsdp[0];\n} multiboot_tag_new_acpi_t;\n\n/* EFI 64-bit image handle pointer (type 20) */\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n  uint64_t  pointer;\n} multiboot_tag_efi64_ih_t;\n\n/* EDID supported monitor resolutions (type 256) */\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n  uint8_t   edid[0];\n} multiboot_tag_edid_t;\n\n/* SMP supported (type 257) */\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n  uint32_t  numcores;\n  uint32_t  running;\n  uint32_t  bspid;\n} multiboot_tag_smp_t;\n\n/* Partition UUIDs (type 258) */\ntypedef struct {\n  uint32_t  type;\n  uint32_t  size;\n  uint8_t   bootuuid[16];\n  uint8_t   rootuuid[16];\n} multiboot_tag_partuuid_t;\n\n#ifdef  __cplusplus\n}\n#endif\n\n#endif /* SIMPLEBOOT_H */\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/Makefile",
    "content": "ifneq ($(LIBPAYLOAD_PATH),)\ninclude $(LIBPAYLOAD_PATH)/build/xcompile\nifneq ($(CONFIG_LP_ARCH_ARM64),)\nSTRIP=$(STRIP_arm64)\nelse\nSTRIP=$(STRIP_x86_32)\nendif\nifneq ($(DEBUG),)\nCFLAGS+=-DDEBUG=1\nendif\nCFLAGS+=-fshort-wchar -fno-strict-aliasing -fno-stack-protector -fno-stack-check -mno-red-zone -Wall -Wextra -Werror\nelse\nPREFIX?=usr/\nINSTDIR?=$(DESTDIR:/=)/$(PREFIX:/=)\nARCH=$(shell uname -m)\nTMP=$(ARCH:x86_64=amd64)\nTMP2=$(TMP:armv7l=armhf)\nDEBARCH=$(TMP2:aarch64=arm64)\nVERSION=$(shell grep -m 1 sbver simpleboot.c|cut -d '\"' -f 2)\nCFLAGS=-fshort-wchar -fno-strict-aliasing -ffreestanding -fno-stack-protector -fno-stack-check -mno-red-zone \\\n  -nostdlib -Wall -Wextra -Werror -Wno-long-long\nendif\n\nall: simpleboot\n\nromfoss_x86.bin: romfoss_x86.asm\n\tfasm romfoss_x86.asm romfoss_x86.bin\n\nrombios_x86.bin: rombios_x86.asm\n\tfasm rombios_x86.asm rombios_x86.bin\n\ncdemu_x86.bin: cdemu_x86.asm\n\tfasm cdemu_x86.asm cdemu_x86.bin\n\nboot_x86.bin: boot_x86.asm\n\tfasm boot_x86.asm boot_x86.bin\n\nloader_x86.efi: loader_x86.c loader.h ../simpleboot.h\n\tclang --target=x86_64-pc-win32-coff $(CFLAGS) -Wframe-larger-than=512 -c loader_x86.c -o loader_x86.o\n\tlld -flavor link -subsystem:efi_application -Brepro -nodefaultlib -dll -dynamicbase -base:0x7000 -entry:_start loader_x86.o -out:loader_x86.efi\n\t@rm loader_x86.o loader_x86.lib 2>/dev/null\n\nloader_rpi.bin: loader_rpi.c loader.h ../simpleboot.h\n\tclang --target=aarch64-elf $(CFLAGS) -Wl,-Ttext=0x80000 -Wl,--omagic loader_rpi.c -o loader_rpi.o\n\nloader_cb.elf: loader_cb.c loader.h ../simpleboot.h\n\t$(LIBPAYLOAD_PATH)/bin/lpgcc $(CFLAGS) -o loader_cb.elf loader_cb.c\nifeq ($(DEBUG),)\n\t@$(STRIP) loader_cb.elf\nendif\n\ndata.h: romfoss_x86.bin rombios_x86.bin cdemu_x86.bin boot_x86.bin loader_x86.efi loader_rpi.bin\n\t@$(CC) misc/bin2h.c -o bin2h\n\t@./bin2h romfoss_x86.bin rombios_x86.bin cdemu_x86.bin boot_x86.bin loader_x86.efi loader_rpi.o\n\t@rm bin2h\n\t@touch data.h\n\nsimpleboot: loader.h simpleboot.c\n\t@test -f data.h || make --no-print-directory data.h\n\t$(CC) -ansi -Wall -Wextra simpleboot.c -o simpleboot\n\t@strip simpleboot 2>/dev/null || true\n\t@strip simpleboot.exe 2>/dev/null || true\n\ninstall: simpleboot\nifneq (\"$(INSTDIR)\",\"\")\n\tinstall -D -m 755 -o root -g root simpleboot -t $(INSTDIR)/bin\n\t@mkdir -p $(INSTDIR)/share/man/man1 2>/dev/null || true\n\tcp misc/simpleboot.1.gz $(INSTDIR)/share/man/man1\n\tcp ../simpleboot.h $(INSTDIR)/include\nelse\n\t@echo \"INSTDIR variable not set, not installing.\"\n\t@false\nendif\n\ndeb:\n\t@rm -rf DEBIAN usr 2>/dev/null || true\n\t@mkdir -p DEBIAN usr/bin usr/include usr/share/man/man1\n\t@cp simpleboot usr/bin\n\t@cp ../simpleboot.h usr/include\n\t@cp misc/simpleboot.1.gz usr/share/man/man1\n\t@cat misc/deb_control | sed s/ARCH/$(DEBARCH)/g | sed s/VERSION/$(VERSION)/g | sed s/SIZE/`du -s usr|cut -f 1`/g >DEBIAN/control\n\t@md5sum `find usr -type f` >DEBIAN/md5sums\n\t@cp ../LICENSE DEBIAN/copyright\n\t@echo \"2.0\" >debian-binary\n\t@tar -czvf data.tar.gz usr\n\t@tar -C DEBIAN -czvf control.tar.gz control copyright md5sums\n\tar r ../distrib/simpleboot_$(VERSION)-$(DEBARCH).deb debian-binary control.tar.gz data.tar.gz\n\t@rm -rf debian-binary control.tar.gz data.tar.gz DEBIAN usr\n\nclean:\n\trm *.bin loader_*.o loader_*.lib loader_*.efi loader_*.elf simpleboot 2>/dev/null || true\n\ndistclean: clean\n\trm data.h 2>/dev/null || true\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/boot_x86.asm",
    "content": ";\n;  src/boot_x86.asm\n;  https://codeberg.org/bzt/simpleboot\n;\n;  Copyright (C) 2023 bzt, MIT license\n;\n;  Permission is hereby granted, free of charge, to any person obtaining a copy\n;  of this software and associated documentation files (the \"Software\"), to\n;  deal in the Software without restriction, including without limitation the\n;  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n;  sell copies of the Software, and to permit persons to whom the Software is\n;  furnished to do so, subject to the following conditions:\n;\n;  The above copyright notice and this permission notice shall be included in\n;  all copies or substantial portions of the Software.\n;\n;  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n;  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n;  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n;  DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n;  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n;  IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n;\n;  @brief Legacy mode Protective Master Boot Record for Simpleboot, written with\n;      flatassembler: https://flatassembler.net It's job is to load loader_x86.efi,\n;      extract its sections, set up long mode and pass control to it\n;\n;  Memory layout on handover:\n;        0h -   400h    IVT (must be preserved)\n;      400h -   4FFh    BDA (must be preserved)\n;      4FFh -   500h    BIOS boot drive code\n;      500h -   510h    BIOS LBA packet\n;      510h -   550h    GDT\n;      550h -  1000h    stack (2k+)\n;     1000h -  8000h    paging tables\n;     8000h - 60000h    loader_x86.efi's sections\n;    9A000h - A0000h    EBDA (must be preserved)\n\nsimpleboot_addr equ     08000h\n\n            ORG         07C00h\n            USE16\n\n;*********************************************************************\n;*                             code                                  *\n;*********************************************************************\n            jmp         short @f                ; mandatory jump (magic)\n            nop\n            db          \"Simpleboot\", 0\n            ;---- set up environment ----\n@@:         cli\n            cld\n            mov         al, 0FFh                ; disable PIC\n            out         021h, al\n            out         0A1h, al\n            in          al, 70h                 ; disable NMI\n            or          al, 80h\n            out         70h, al\n            xor         ax, ax\n            mov         ss, ax\n            mov         ds, ax\n            mov         es, ax\n            mov         sp, simpleboot_addr\n            ;---- read in loader_x86.efi ----\n            mov         bx, 500h\n            mov         di, bx\n            mov         byte [di - 1], dl\n            mov         si, loader_lba\n            xor         ah, ah\n            mov         al, 16                  ; size\n            stosw\n            mov         al, 120                 ; count\n            stosw\n            xor         ax, ax                  ; addr0, load to 60000h\n            stosw\n            mov         ah, 60h                 ; addr1\n            stosw\n            movsw                               ; sect0\n            movsw                               ; sect1\n            xor         ax, ax\n            stosw                               ; sect2\n            stosw                               ; sect3\n            mov         si, GDT_value\n            mov         cx, word[si]\n            repnz       movsb\n            mov         ah, 42h\n            mov         si, bx\n            push        si\n            int         13h\n            pop         si\n            add         byte [si + 7], 15\n            add         dword [si + 8], 120\n            mov         ah, 42h\n            int         13h\n            ;---- enable protmode ----\n            mov         ax, 2401h               ; enable A20\n            int         15h\n            lgdt        [510h]\n            mov         eax, cr0\n            or          al, 1\n            mov         cr0, eax\n            jmp         16:@f\n            USE32\n@@:         mov         ax, 24\n            mov         ds, ax\n            mov         es, ax\n            ; look for long mode supported flag\n            xor         edx, edx\n            mov         eax, 80000001h\n            cpuid\n            bt          edx, 29\n            jnc         .die\n            ;---- enable longmode ----\n            xor         eax, eax\n            mov         ah, 010h\n            mov         cr3, eax\n            ; we only map 2M here, loader will finish up the rest overwriting us in the process\n            mov         edx, eax                ; PML4\n            mov         ebx, eax\n            xor         eax, eax\n            mov         dword [ebx], 02003h     ; pointer to 2M PDPE\n            mov         dword [ebx + 4], eax\n            add         ebx, edx                ; 2M PDPE\n            mov         dword [ebx], 03003h\n            mov         dword [ebx + 4], eax\n            add         ebx, edx                ; 2M PDE\n            mov         dword [ebx], 00083h\n            mov         dword [ebx + 4], eax\n            mov         al, 0E0h                ; set PAE, MCE, PGE; clear everything else\n            mov         cr4, eax\n            mov         ecx, 0C0000080h         ; EFER MSR\n            rdmsr\n            bts         eax, 8                  ; enable long mode page tables\n            wrmsr\n            mov         eax, cr0\n            xor         cl, cl\n            or          eax, ecx\n            btc         eax, 16                 ; clear WP\n            mov         cr0, eax                ; enable paging with cache disabled (set PE, CD)\n            lgdt        [510h]                  ; read 80 bit address (16+64)\n            jmp         32:@f\n            USE64\n@@:         xor         rax, rax                ; load long mode segments\n            mov         al, 40\n            mov         ds, ax\n            mov         es, ax\n            mov         ss, ax\n            mov         ax, simpleboot_addr\n            ;---- parse loader_x86.efi (PE / COFF format) ----\n            mov         ebx, 60000h             ; load buffer address\n            cmp         word [ebx], 5A4Dh       ; check MZ\n            jne         .die\n            mov         r8d, ebx\n            add         ebx, dword [ebx + 0x3c] ; get COFF header\n            cmp         word [ebx], 4550h       ; check PE\n            jne         .die\n            mov         dl, byte [ebx + 6]      ; number of sections\n            mov         r9d, dword [ebx + 0x28] ; entry point\n            mov         ebp, dword [ebx + 0x2c] ; code base\n            add         r9d, eax\n            sub         r9d, ebp\n            add         bx, word [ebx + 0x14]   ; add header size\n            add         bx, 24                  ; ebx now points to section table\n@@:         mov         edi, dword [ebx + 12]   ; copy sections from PE into VA\n            add         edi, eax\n            sub         edi, ebp                ; dest: virtual address + reloc offset - code base\n            mov         ecx, dword [ebx + 16]   ; size of raw data\n            mov         esi, dword [ebx + 20]\n            add         esi, r8d                ; source: pointer to raw data + load offset\n            repnz       movsb\n            add         ebx, 40                 ; go to next section\n            dec         dl\n            jnz         @b\n            xor         rsp, rsp\n            mov         sp, 1000h               ; set stack\n            xor         rcx, rcx                ; image handle\n            xor         rdx, rdx                ; system table pointer\n            jmp         r9                      ; jump to relocated entry point\n            ;---- die function ----\n            ; written in a way that it's decodeable as prot mode as well as long mode instructions\n.die:       mov         esi, .err\n            mov         edi, 0B8000h\n            mov         ah, 04fh\n@@:         lodsb\n            or          al, al\n            jz          @f\n            stosw\n            jmp         @b\n@@:         hlt\n\n;*********************************************************************\n;*                          data area                                *\n;*********************************************************************\n.err:       db          \"PMBR-ERR\", 0\nGDT_value:  dw          GDT_value.end-GDT_value ; value / null descriptor\n            dd          510h\n            dw          0\n            dd          0000FFFFh,00009800h     ;  8 - legacy real cs\n            dd          0000FFFFh,00CF9A00h     ; 16 - prot mode cs\n            dd          0000FFFFh,008F9200h     ; 24 - prot mode ds\n            dd          0000FFFFh,00AF9A00h     ; 32 - long mode cs\n            dd          0000FFFFh,00CF9200h     ; 40 - long mode ds\n.end:       db          01B0h-($-$$) dup 0\nloader_lba: dd          0h                      ; the image generator sets this\n            ;---- space for legacy partitioning table ----\n            db          01FEh-($-$$) dup 0\n            db          55h, 0AAh               ; mandatory magic bytes\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/cdemu_x86.asm",
    "content": ";\n;  src/cdemu_x86.asm\n;  https://codeberg.org/bzt/simpleboot\n;\n;  Copyright (C) 2023 bzt, MIT license\n;\n;  Permission is hereby granted, free of charge, to any person obtaining a copy\n;  of this software and associated documentation files (the \"Software\"), to\n;  deal in the Software without restriction, including without limitation the\n;  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n;  sell copies of the Software, and to permit persons to whom the Software is\n;  furnished to do so, subject to the following conditions:\n;\n;  The above copyright notice and this permission notice shall be included in\n;  all copies or substantial portions of the Software.\n;\n;  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n;  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n;  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n;  DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n;  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n;  IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n;\n;  @brief Legacy mode BIOS CDROM boot for Simpleboot, written with\n;      flatassembler: https://flatassembler.net It's job is to hook on INT 13h,\n;      then load and execute the original MBR boot code as usual\n;\n;  Memory layout on handover:\n;        0h -   400h    IVT (must be preserved)\n;      400h -  7C00h    stack\n;     7C00h -  7E00h    we're loaded here, also original MBR loaded here\n;    9A000h - 9A200h    our relocated TSR code\n;    9A200h - 9AA00h    CDROM sector cache\n\nSEG         equ         09A00h\n            ORG         0h\n            USE16\n\nvirtual at 0\nlbapacket.size: dw      ?\nlbapacket.count:dw      ?\nlbapacket.addr0:dw      ?\nlbapacket.addr1:dw      ?\nlbapacket.sect0:dw      ?\nlbapacket.sect1:dw      ?\nlbapacket.sect2:dw      ?\nlbapacket.sect3:dw      ?\nend virtual\n\n;*********************************************************************\n;*                          data area                                *\n;*********************************************************************\n            ;could be 0:7C00 or 07C0:0 as well depending on BIOS\nlbapacket:  jmp         short @f                ; mandatory jump (magic)\n            nop\n            db          13 dup 0\norigip:     dw          0\norigcs:     dw          0\nsave:       dd          0\ndrive:      dw          0\n            db          060h-($-$$) dup 0       ; skip over FAT32 BPB\n\n;*********************************************************************\n;*                             code                                  *\n;*********************************************************************\n@@:         cli\n            cld\n            xor         ax, ax\n            mov         ss, ax\n            mov         sp, 07C00h\n            ;find our position in memory.\n            push        cs\n            pop         ds\n            call        @f\n@@:         pop         si\n            sub         si, @b-lbapacket\n            ;---- relocate ourself to 09A00:0000 ----\n            mov         ax, SEG\n            mov         es, ax\n            xor         di, di\n            mov         cx, 200h\n            repnz       movsw\n            push        es\n            pop         ds\n            jmp         SEG:.start\n            ;clear and reuse BPB data area\n.start:     xor         di, di\n            xor         ax, ax\n            mov         cx, 30h\n            repnz       stosw\n            mov         byte [drive], dl        ; save CDROM's drive code\n            xor         di, di\n            mov         al, 16                  ; .size\n            stosw\n            mov         al, 1                   ; .count\n            stosw\n            mov         ax, cache               ; .addr0\n            push        ax\n            stosw\n            mov         ax, es                  ; .addr1\n            stosw\n            ;load the original MBR (plus 3 more sectors) into cache\n            mov         ah, byte 42h\n            xor         si, si\n            int         13h\n            ;copy the first 512 bytes of cache to 0:7C00h\n            pop         si\n            mov         di, sp\n            push        es\n            xor         ax, ax\n            mov         es, ax\n            mov         cx, 100h\n            repnz       movsw\n            pop         es\n            ;---- install TSR, hook INT 13h ----\n            mov         di, origip\n            xor         ax, ax\n            mov         ds, ax\n            mov         si, 13h * 4\n            mov         ax, word[si]\n            stosw\n            mov         word[si], tsr\n            add         si, 2\n            mov         ax, word[si]\n            stosw\n            mov         ax, es\n            mov         word[si], ax\n            ;---- arrange environment and jump to MBR code ----\n            xor         ax, ax\n            mov         es, ax\n            mov         bx, ax\n            mov         cx, ax\n            mov         dx, ax\n            mov         si, ax\n            mov         di, ax\n            mov         dl, 81h                 ; secondary BIOS HDD\n            mov         ax, 0AA55h\n            jmp         0:7C00h\n\n            ;---- emulate 2048 bytes CDROM sectors as 512 bytes HDD sectors ----\ntsr:        ;pass through all non \"extended read on secondary HDD\" calls\n            cmp         ah, 42h\n            jne         @f\n            cmp         dl, 81h\n            je          .emulate\n@@:         jmp         dword[cs:origip]\n.emulate:   push        es\n            push        ds\n            push        cx\n            push        dx\n            push        si\n            ;read the lba packet we're servicing into registers\n            mov         di, word [si + lbapacket.addr0]\n            mov         ax, word [si + lbapacket.addr1]\n            mov         es, ax\n            xor         bh, bh\n            mov         bl, byte [si + lbapacket.count]\n            mov         edx, dword [si + lbapacket.sect0]\n            push        cs\n            pop         ds\n            or          bl, bl\n            jz          .none\n            ;---- for each sector ----\n.next:      ;do we have the relevant 2048 bytes sector cached?\n            mov         eax, edx\n            shr         eax, 2\n            cmp         eax, dword[lbapacket.sect0]\n            je          @f\n            ;no, read it in from CDROM\n            push        es\n            push        ds\n            push        di\n            push        bx\n            mov         dword[save], edx\n            ;call original ISR\n            mov         dword[lbapacket.sect0], eax\n            mov         dl, byte[drive]\n            mov         ax, 4200h\n            xor         si, si\n            clc\n            pushf\n            call        dword[origip]\n            mov         edx, dword[save]\n            pop         bx\n            pop         di\n            pop         ds\n            pop         es\n            jc          .end\n            or          ah, ah\n            jnz         .end\n            ;copy 512 bytes from cache to caller's buffer\n@@:         mov         si, dx\n            and         si, 3\n            shl         si, 9\n            add         si, cache\n            mov         cx, 100h\n            repnz       movsw\n            ;adjust to next sector\n            inc         edx\n            inc         bh\n            dec         bl\n            or          bl, bl\n            jnz         .next\n            ;---- finished ----\n.none:      xor         ax, ax\n            clc\n.end:       pop         si\n            pop         dx\n            pop         cx\n            pop         ds\n            pop         es\n            ;update the sector count in caller's lba packet\n            mov         byte[si + lbapacket.count], bh\n            mov         bx, 0AA55h\n            iret\n\n            ;padding (check if our code fits into 510 bytes)\n            db          01FEh-($-$$) dup 0\n            db          55h, 0AAh               ; mandatory magic bytes\n\n;*********************************************************************\n;*                           bss area                                *\n;*********************************************************************\ncache:      db          2048 dup ?              ; CDROM sector cache\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/data.h",
    "content": "/*\n * src/data.h\n * https://codeberg.org/bzt/simpleboot\n *\n * Copyright (C) 2023 bzt, MIT license\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * @brief Embedded loader binary data, used by the image creator\n */\n\n/* generated by bin2h, do not edit */\n\nunsigned char romfoss_x86_bin[132] = { 232,0,0,0,0,88,72,131,192,20,72,139,127,24,72,137,71,16,72,49,192,72,49,210,195,73,137,250,72,49,228,102,188,0,16,232,0,0,0,0,91,72,131,195,92,72,49,192,102,184,0,128,73,137,216,77,49,201,72,49,255,72,3,91,60,138,83,6,68,139,75,40,139,107,44,65,1,193,65,41,233,102,3,91,20,102,131,195,24,139,123,12,1,199,41,239,139,75,16,139,115,20,76,1,198,242,164,72,131,195,40,254,202,117,230,72,49,210,76,137,214,72,49,255,191,5,177,85,240,65,255,225 };\nunsigned char rombios_x86_bin[432] = { 85,170,0,235,2,144,0,250,252,176,255,230,33,230,161,228,112,12,128,230,112,49,192,142,192,142,208,188,0,124,14,31,102,49,246,232,0,0,94,131,238,38,102,49,192,102,49,237,137,245,129,197,176,1,140,200,102,193,224,4,102,1,197,137,231,185,0,1,242,165,234,75,124,0,0,49,192,142,216,198,6,255,4,128,184,1,36,205,21,190,128,125,191,16,5,139,12,242,164,15,1,22,16,5,15,32,192,12,1,15,34,192,234,117,124,16,0,102,184,24,0,142,216,142,192,49,210,184,1,0,0,128,15,162,15,186,226,29,15,131,207,0,0,0,49,192,180,16,15,34,216,137,194,137,195,49,192,199,3,3,32,0,0,137,67,4,1,211,199,3,3,48,0,0,137,67,4,1,211,199,3,131,0,0,0,137,67,4,176,224,15,34,224,185,128,0,0,192,15,50,15,186,232,8,15,48,15,32,192,48,201,9,200,15,186,248,16,15,34,192,15,1,21,16,5,0,0,234,234,124,0,0,32,0,72,49,192,102,184,40,0,142,216,142,192,142,208,102,184,0,128,137,235,103,102,129,59,77,90,117,90,65,137,216,77,49,201,103,3,91,60,103,102,129,59,80,69,117,72,103,138,83,6,103,68,139,75,40,103,139,107,44,65,1,193,65,41,233,103,102,3,91,20,102,131,195,24,103,139,123,12,1,199,41,239,103,139,75,16,103,139,115,20,68,1,198,242,164,131,195,40,254,202,117,228,72,49,228,102,188,0,16,72,49,201,72,49,210,65,255,225,190,120,125,0,0,191,0,128,11,0,180,79,172,8,192,116,4,102,171,235,247,244,144,144,144,82,79,77,45,69,82,82,0,48,0,16,5,0,0,0,0,255,255,0,0,0,152,0,0,255,255,0,0,0,154,207,0,255,255,0,0,0,146,143,0,255,255,0,0,0,154,175,0,255,255,0,0,0,146,207,0 };\nunsigned char cdemu_x86_bin[512] = { 235,94,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,250,252,49,192,142,208,188,0,124,14,31,232,0,0,94,131,238,110,184,0,154,142,192,49,255,185,0,2,242,165,6,31,234,133,0,0,154,49,255,49,192,185,48,0,242,171,136,22,24,0,49,255,176,16,171,176,1,171,184,0,2,80,171,140,192,171,180,66,49,246,205,19,94,137,231,6,49,192,142,192,185,0,1,242,165,7,191,16,0,49,192,142,216,190,76,0,139,4,171,199,4,233,0,131,198,2,139,4,171,140,192,137,4,49,192,142,192,137,195,137,193,137,194,137,198,137,199,178,129,184,85,170,234,0,124,0,0,128,252,66,117,5,128,250,129,116,5,46,255,46,16,0,6,30,81,82,86,139,124,4,139,68,6,142,192,48,255,138,92,2,102,139,84,8,14,31,8,219,116,84,102,137,208,102,193,232,2,102,59,6,8,0,116,43,6,30,87,83,102,137,22,20,0,102,163,8,0,138,22,24,0,184,0,66,49,246,248,156,255,30,16,0,102,139,22,20,0,91,95,31,7,114,34,8,228,117,30,137,214,131,230,3,193,230,9,129,198,0,2,185,0,1,242,165,102,66,254,199,254,203,8,219,117,172,49,192,248,94,90,89,31,7,136,124,2,187,85,170,207,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,170 };\nunsigned char boot_x86_bin[512] = { 235,12,144,83,105,109,112,108,101,98,111,111,116,0,250,252,176,255,230,33,230,161,228,112,12,128,230,112,49,192,142,208,142,216,142,192,188,0,128,187,0,5,137,223,136,85,255,190,176,125,48,228,176,16,171,176,120,171,49,192,171,180,96,171,165,165,49,192,171,171,190,128,125,139,12,242,164,180,66,137,222,86,205,19,94,128,68,7,15,102,131,68,8,120,180,66,205,19,184,1,36,205,21,15,1,22,16,5,15,32,192,12,1,15,34,192,234,121,124,16,0,102,184,24,0,142,216,142,192,49,210,184,1,0,0,128,15,162,15,186,226,29,15,131,205,0,0,0,49,192,180,16,15,34,216,137,194,137,195,49,192,199,3,3,32,0,0,137,67,4,1,211,199,3,3,48,0,0,137,67,4,1,211,199,3,131,0,0,0,137,67,4,176,224,15,34,224,185,128,0,0,192,15,50,15,186,232,8,15,48,15,32,192,48,201,9,200,15,186,248,16,15,34,192,15,1,21,16,5,0,0,234,238,124,0,0,32,0,72,49,192,176,40,142,216,142,192,142,208,102,184,0,128,187,0,0,6,0,103,102,129,59,77,90,117,87,65,137,216,103,3,91,60,103,102,129,59,80,69,117,72,103,138,83,6,103,68,139,75,40,103,139,107,44,65,1,193,65,41,233,103,102,3,91,20,102,131,195,24,103,139,123,12,1,199,41,239,103,139,75,16,103,139,115,20,68,1,198,242,164,131,195,40,254,202,117,228,72,49,228,102,188,0,16,72,49,201,72,49,210,65,255,225,190,119,125,0,0,191,0,128,11,0,180,79,172,8,192,116,4,102,171,235,247,244,80,77,66,82,45,69,82,82,0,48,0,16,5,0,0,0,0,255,255,0,0,0,152,0,0,255,255,0,0,0,154,207,0,255,255,0,0,0,146,143,0,255,255,0,0,0,154,175,0,255,255,0,0,0,146,207,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,170 };\nunsigned char loader_x86_efi[54784] = { 77,90,120,0,1,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,120,0,0,0,83,105,109,112,108,101,98,111,111,116,32,104,116,116,112,115,58,47,47,99,111,100,101,98,101,114,103,46,111,114,103,47,98,122,116,47,115,105,109,112,108,101,98,111,111,116,0,120,56,54,95,54,52,0,0,0,80,69,0,0,100,134,4,0,47,219,42,52,0,0,0,0,0,0,0,0,240,0,34,32,11,2,14,0,0,188,0,0,0,22,0,0,0,0,0,0,64,196,0,0,0,16,0,0,0,112,0,0,0,0,0,0,0,16,0,0,0,2,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,64,1,0,0,4,0,0,0,0,0,0,10,0,96,1,0,0,16,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,1,0,56,0,0,0,108,217,0,0,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,46,116,101,120,116,0,0,0,64,186,0,0,0,16,0,0,0,188,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,96,46,114,100,97,116,97,0,0,136,9,0,0,0,208,0,0,0,10,0,0,0,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,64,46,100,97,116,97,0,0,0,16,69,0,0,0,224,0,0,0,10,0,0,0,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,192,46,114,101,108,111,99,0,0,56,0,0,0,0,48,1,0,0,2,0,0,0,212,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,131,236,24,72,137,84,36,16,72,137,76,36,8,199,68,36,4,2,0,0,0,72,139,68,36,16,199,0,0,0,0,0,139,68,36,4,137,193,131,193,255,137,76,36,4,131,248,0,15,132,216,0,0,0,72,139,68,36,8,15,190,0,131,248,48,124,50,72,139,68,36,8,15,190,0,131,248,57,127,37,72,139,68,36,16,139,8,193,225,4,137,8,72,139,68,36,8,15,190,8,131,233,48,72,139,68,36,16,3,8,137,8,233,132,0,0,0,72,139,68,36,8,15,190,0,131,248,97,124,50,72,139,68,36,8,15,190,0,131,248,102,127,37,72,139,68,36,16,139,8,193,225,4,137,8,72,139,68,36,8,15,190,8,131,233,97,131,193,10,72,139,68,36,16,3,8,137,8,235,67,72,139,68,36,8,15,190,0,131,248,65,124,50,72,139,68,36,8,15,190,0,131,248,70,127,37,72,139,68,36,16,139,8,193,225,4,137,8,72,139,68,36,8,15,190,8,131,233,65,131,193,10,72,139,68,36,16,3,8,137,8,235,2,235,25,235,0,235,0,235,0,72,139,68,36,8,72,131,192,1,72,137,68,36,8,233,18,255,255,255,72,139,68,36,8,72,131,196,24,195,15,31,128,0,0,0,0,72,131,236,24,72,137,84,36,16,72,137,76,36,8,72,139,68,36,16,199,0,0,0,0,0,72,139,68,36,8,15,190,8,49,192,131,249,48,136,68,36,7,124,18,72,139,68,36,8,15,190,0,131,248,57,15,158,192,136,68,36,7,138,68,36,7,168,1,117,2,235,46,72,139,68,36,16,107,8,10,137,8,72,139,68,36,8,15,190,8,131,233,48,72,139,68,36,16,3,8,137,8,72,139,68,36,8,72,131,192,1,72,137,68,36,8,235,163,72,139,68,36,8,72,131,196,24,195,86,87,72,131,236,24,68,137,68,36,20,72,137,84,36,8,72,137,12,36,72,139,60,36,72,139,116,36,8,139,76,36,20,242,164,72,131,196,24,95,94,195,102,15,31,68,0,0,87,72,131,236,16,68,137,68,36,12,136,84,36,11,72,137,12,36,72,139,60,36,138,68,36,11,139,76,36,12,242,170,72,131,196,16,95,195,102,46,15,31,132,0,0,0,0,0,86,87,72,131,236,32,68,137,68,36,28,72,137,84,36,16,72,137,76,36,8,72,139,124,36,8,72,139,116,36,16,139,76,36,28,252,243,166,49,192,138,71,255,42,70,255,137,68,36,4,139,68,36,4,72,131,196,32,95,94,195,15,31,0,72,131,236,40,72,131,61,212,213,0,0,0,116,55,72,139,5,203,213,0,0,72,131,120,56,0,116,41,72,139,5,189,213,0,0,72,139,64,56,69,49,201,186,0,194,1,0,65,184,8,0,0,0,68,137,201,199,68,36,32,1,0,0,0,255,80,40,235,46,184,249,3,0,0,137,194,48,192,238,176,128,128,194,2,238,176,1,128,234,3,238,48,192,254,194,238,254,194,238,176,67,254,194,238,176,8,254,194,238,48,192,128,234,4,236,199,5,107,213,0,0,4,0,0,0,199,5,101,213,0,0,4,0,0,0,102,199,5,96,213,0,0,0,0,102,199,5,89,213,0,0,0,0,72,131,61,95,213,0,0,0,117,28,72,131,61,117,213,0,0,0,117,18,185,0,128,11,0,49,210,65,184,160,15,0,0,232,209,254,255,255,72,131,196,40,195,102,102,102,46,15,31,132,0,0,0,0,0,83,72,129,236,144,0,0,0,136,140,36,143,0,0,0,72,141,5,218,204,0,0,72,137,132,36,128,0,0,0,72,139,132,36,128,0,0,0,139,64,28,131,192,7,193,232,3,137,68,36,104,72,139,5,246,212,0,0,72,137,68,36,88,72,131,61,201,212,0,0,0,116,42,72,139,5,192,212,0,0,72,131,120,56,0,116,28,72,139,5,178,212,0,0,72,139,64,56,72,139,64,16,138,148,36,143,0,0,0,49,201,255,208,235,42,138,132,36,143,0,0,0,186,253,3,0,0,49,219,136,195,185,16,39,0,0,236,243,144,60,255,116,14,255,201,116,10,36,32,116,241,128,234,5,136,216,238,72,131,124,36,88,0,15,132,73,4,0,0,15,182,132,36,143,0,0,0,137,68,36,84,131,232,10,116,28,235,0,139,68,36,84,131,232,13,117,55,235,0,199,5,75,212,0,0,4,0,0,0,233,26,4,0,0,199,5,60,212,0,0,4,0,0,0,72,139,132,36,128,0,0,0,139,64,24,3,5,39,212,0,0,137,5,33,212,0,0,233,244,3,0,0,139,5,26,212,0,0,72,139,140,36,128,0,0,0,3,65,28,131,192,5,59,5,38,212,0,0,114,33,199,5,250,211,0,0,4,0,0,0,72,139,132,36,128,0,0,0,139,64,24,3,5,229,211,0,0,137,5,223,211,0,0,139,5,217,211,0,0,72,139,140,36,128,0,0,0,3,65,24,131,192,5,59,5,237,211,0,0,15,134,10,1,0,0,139,5,185,211,0,0,137,68,36,124,139,5,215,211,0,0,72,139,140,36,128,0,0,0,43,65,24,131,232,5,137,5,155,211,0,0,139,13,149,211,0,0,139,68,36,124,41,200,137,68,36,124,199,68,36,108,0,0,0,0,139,68,36,124,15,175,5,152,211,0,0,137,68,36,116,139,68,36,124,137,68,36,120,139,68,36,120,59,5,138,211,0,0,115,77,68,139,5,121,211,0,0,72,139,84,36,88,139,68,36,116,72,1,194,72,139,76,36,88,139,68,36,108,72,1,193,232,180,252,255,255,139,68,36,120,131,192,1,137,68,36,120,139,5,75,211,0,0,3,68,36,108,137,68,36,108,139,5,61,211,0,0,3,68,36,116,137,68,36,116,235,167,139,5,13,211,0,0,137,68,36,120,139,5,3,211,0,0,15,175,5,28,211,0,0,137,68,36,108,139,68,36,120,59,5,22,211,0,0,115,53,68,139,5,5,211,0,0,72,139,76,36,88,139,68,36,108,72,1,193,49,210,232,122,252,255,255,139,68,36,120,131,192,1,137,68,36,120,139,5,225,210,0,0,3,68,36,108,137,68,36,108,235,191,235,0,72,139,132,36,128,0,0,0,139,64,8,137,193,72,141,5,121,202,0,0,72,1,200,72,137,68,36,72,15,182,132,36,143,0,0,0,131,248,0,126,35,15,182,132,36,143,0,0,0,72,139,140,36,128,0,0,0,59,65,16,115,14,15,182,132,36,143,0,0,0,137,68,36,68,235,8,49,192,137,68,36,68,235,0,72,139,68,36,72,139,76,36,68,72,139,148,36,128,0,0,0,15,175,74,20,137,201,72,1,200,72,137,68,36,96,139,5,60,210,0,0,15,175,5,85,210,0,0,139,13,51,210,0,0,15,182,21,84,210,0,0,131,194,7,193,250,3,15,175,202,1,200,137,68,36,108,72,139,132,36,128,0,0,0,139,64,28,131,192,1,3,5,9,210,0,0,137,5,3,210,0,0,199,68,36,120,0,0,0,0,139,68,36,120,72,139,140,36,128,0,0,0,59,65,24,15,131,184,1,0,0,139,68,36,108,137,68,36,116,72,139,132,36,128,0,0,0,139,72,28,131,233,1,184,1,0,0,0,211,224,137,68,36,112,199,68,36,124,0,0,0,0,139,76,36,124,72,139,148,36,128,0,0,0,49,192,59,74,28,136,68,36,67,115,12,131,124,36,112,0,15,149,192,136,68,36,67,138,68,36,67,168,1,117,5,233,28,1,0,0,15,182,5,174,209,0,0,137,68,36,60,131,192,241,131,232,2,114,31,235,0,139,68,36,60,131,232,24,116,94,235,0,139,68,36,60,131,232,32,15,132,146,0,0,0,233,206,0,0,0,72,139,68,36,96,15,182,0,35,68,36,112,131,248,0,116,11,184,255,255,0,0,137,68,36,56,235,10,139,5,117,209,0,0,137,68,36,56,139,68,36,56,102,137,194,72,139,68,36,88,139,76,36,116,102,137,20,8,139,68,36,116,131,192,2,137,68,36,116,233,132,0,0,0,72,139,68,36,96,15,182,0,35,68,36,112,131,248,0,116,11,184,255,255,255,0,137,68,36,52,235,10,139,5,43,209,0,0,137,68,36,52,139,84,36,52,72,139,68,36,88,139,76,36,116,137,20,8,139,68,36,116,131,192,3,137,68,36,116,235,65,72,139,68,36,96,15,182,0,35,68,36,112,131,248,0,116,11,184,255,255,255,255,137,68,36,48,235,10,139,5,232,208,0,0,137,68,36,48,139,84,36,48,72,139,68,36,88,139,76,36,116,137,20,8,139,68,36,116,131,192,4,137,68,36,116,235,0,139,68,36,124,131,192,1,137,68,36,124,139,68,36,112,209,232,137,68,36,112,233,180,254,255,255,139,21,167,208,0,0,72,139,68,36,88,139,76,36,116,137,20,8,139,68,36,120,131,192,1,137,68,36,120,139,76,36,104,72,139,68,36,96,137,201,72,1,200,72,137,68,36,96,139,5,87,208,0,0,3,68,36,108,137,68,36,108,233,51,254,255,255,235,0,235,0,72,131,124,36,88,0,15,133,253,0,0,0,72,131,61,74,208,0,0,0,15,133,239,0,0,0,15,182,132,36,143,0,0,0,137,68,36,44,131,232,10,116,27,235,0,139,68,36,44,131,232,13,117,48,235,0,102,199,5,239,207,0,0,0,0,233,193,0,0,0,102,199,5,225,207,0,0,0,0,102,139,5,216,207,0,0,102,131,192,1,102,137,5,205,207,0,0,233,161,0,0,0,15,183,5,193,207,0,0,131,248,25,124,69,185,0,128,11,0,72,137,202,72,129,194,160,0,0,0,65,184,0,15,0,0,232,18,249,255,255,102,199,5,155,207,0,0,0,0,102,199,5,144,207,0,0,24,0,185,0,128,11,0,72,129,193,0,15,0,0,49,210,65,184,160,0,0,0,232,23,249,255,255,15,182,132,36,143,0,0,0,37,255,0,0,0,13,0,15,0,0,102,137,193,15,183,5,91,207,0,0,105,192,160,0,0,0,72,152,72,5,0,128,11,0,102,139,21,72,207,0,0,102,65,137,208,102,65,131,192,1,102,68,137,5,55,207,0,0,15,183,210,209,226,72,99,210,72,1,208,102,137,8,235,0,72,129,196,144,0,0,0,91,195,102,102,102,46,15,31,132,0,0,0,0,0,72,129,236,136,0,0,0,76,137,140,36,168,0,0,0,76,137,132,36,160,0,0,0,72,137,148,36,152,0,0,0,72,137,140,36,128,0,0,0,72,141,132,36,152,0,0,0,72,137,68,36,120,72,199,68,36,104,0,0,0,0,72,139,132,36,128,0,0,0,128,56,0,15,132,231,6,0,0,72,139,132,36,128,0,0,0,15,190,0,131,248,37,15,133,169,6,0,0,72,139,132,36,128,0,0,0,72,131,192,1,72,137,132,36,128,0,0,0,72,139,132,36,128,0,0,0,15,190,0,131,248,37,117,5,233,130,6,0,0,199,68,36,80,0,0,0,0,199,68,36,92,0,0,0,0,72,139,132,36,128,0,0,0,15,190,8,49,192,131,249,48,136,68,36,46,124,21,72,139,132,36,128,0,0,0,15,190,0,131,248,57,15,158,192,136,68,36,46,138,68,36,46,168,1,117,2,235,53,107,68,36,92,10,137,68,36,92,72,139,132,36,128,0,0,0,15,190,0,131,232,48,3,68,36,92,137,68,36,92,72,139,132,36,128,0,0,0,72,131,192,1,72,137,132,36,128,0,0,0,235,150,72,139,132,36,128,0,0,0,15,190,0,131,248,108,117,31,139,68,36,80,131,192,1,137,68,36,80,72,139,132,36,128,0,0,0,72,131,192,1,72,137,132,36,128,0,0,0,72,139,132,36,128,0,0,0,15,190,0,131,248,99,117,62,72,139,68,36,120,72,137,193,72,131,193,8,72,137,76,36,120,72,99,0,72,137,68,36,104,72,139,68,36,104,136,193,232,135,248,255,255,72,139,132,36,128,0,0,0,72,131,192,1,72,137,132,36,128,0,0,0,233,187,254,255,255,72,139,132,36,128,0,0,0,15,190,0,131,248,100,15,133,57,1,0,0,131,124,36,80,0,117,27,72,139,68,36,120,72,137,193,72,131,193,8,72,137,76,36,120,72,99,0,72,137,68,36,104,235,25,72,139,68,36,120,72,137,193,72,131,193,8,72,137,76,36,120,72,139,0,72,137,68,36,104,199,68,36,88,0,0,0,0,72,139,68,36,104,131,248,0,125,23,49,192,72,43,68,36,104,72,137,68,36,104,139,68,36,88,131,192,1,137,68,36,88,199,68,36,84,18,0,0,0,72,99,68,36,84,198,68,4,48,0,72,139,68,36,104,185,10,0,0,0,72,153,72,247,249,72,131,194,48,136,209,139,68,36,84,131,192,255,137,68,36,84,72,152,136,76,4,48,72,139,68,36,104,185,10,0,0,0,72,153,72,247,249,72,137,68,36,104,49,192,72,131,124,36,104,0,136,68,36,45,116,12,131,124,36,84,0,15,159,192,136,68,36,45,138,68,36,45,168,1,117,164,131,124,36,88,0,116,18,139,68,36,84,131,192,255,137,68,36,84,72,152,198,68,4,48,45,131,124,36,92,0,126,48,131,124,36,92,18,125,41,235,0,139,68,36,84,185,18,0,0,0,43,76,36,92,57,200,126,20,139,68,36,84,131,192,255,137,68,36,84,72,152,198,68,4,48,32,235,219,235,0,72,99,76,36,84,72,141,68,36,48,72,1,200,72,137,68,36,72,233,125,1,0,0,72,139,132,36,128,0,0,0,15,190,0,131,248,120,116,20,72,139,132,36,128,0,0,0,15,190,0,131,248,112,15,133,48,1,0,0,72,139,132,36,128,0,0,0,15,190,0,131,248,120,117,34,131,124,36,80,0,117,27,72,139,68,36,120,72,137,193,72,131,193,8,72,137,76,36,120,72,99,0,72,137,68,36,104,235,25,72,139,68,36,120,72,137,193,72,131,193,8,72,137,76,36,120,72,139,0,72,137,68,36,104,199,68,36,84,16,0,0,0,72,99,68,36,84,198,68,4,48,0,72,139,132,36,128,0,0,0,15,190,0,131,248,112,117,8,199,68,36,92,16,0,0,0,235,0,72,139,68,36,104,72,131,224,15,136,68,36,47,15,190,68,36,47,68,15,190,68,36,47,185,48,0,0,0,186,55,0,0,0,65,131,248,9,15,79,202,1,200,136,193,139,68,36,84,131,192,255,137,68,36,84,72,152,136,76,4,48,72,139,68,36,104,72,193,248,4,72,137,68,36,104,49,192,72,131,124,36,104,0,136,68,36,44,116,12,131,124,36,84,0,15,159,192,136,68,36,44,138,68,36,44,168,1,117,146,131,124,36,92,0,126,48,131,124,36,92,16,127,41,235,0,139,68,36,84,185,16,0,0,0,43,76,36,92,57,200,126,20,139,68,36,84,131,192,255,137,68,36,84,72,152,198,68,4,48,48,235,219,235,0,72,99,76,36,84,72,141,68,36,48,72,1,200,72,137,68,36,72,235,41,72,139,132,36,128,0,0,0,15,190,0,131,248,115,117,85,72,139,68,36,120,72,137,193,72,131,193,8,72,137,76,36,120,72,139,0,72,137,68,36,72,72,131,124,36,72,0,117,12,72,141,5,36,182,0,0,72,137,68,36,72,235,0,72,139,68,36,72,128,56,0,116,26,72,139,68,36,72,72,137,193,72,131,193,1,72,137,76,36,72,138,8,232,108,245,255,255,235,220,235,0,235,0,235,0,235,0,72,139,132,36,128,0,0,0,15,190,0,131,248,83,117,92,72,139,68,36,120,72,137,193,72,131,193,8,72,137,76,36,120,72,139,0,72,137,68,36,96,72,131,124,36,96,0,117,12,72,141,5,120,187,0,0,72,137,68,36,96,235,0,72,139,68,36,96,102,131,56,0,116,29,72,139,68,36,96,72,137,193,72,131,193,2,72,137,76,36,96,102,139,0,136,193,232,253,244,255,255,235,216,233,15,2,0,0,72,139,132,36,128,0,0,0,15,190,0,131,248,68,15,133,249,1,0,0,72,139,68,36,120,72,137,193,72,131,193,8,72,137,76,36,120,72,139,0,72,137,68,36,104,131,124,36,92,1,125,8,199,68,36,92,1,0,0,0,235,0,199,68,36,84,28,0,0,0,131,124,36,84,0,124,74,72,139,68,36,104,139,76,36,84,72,211,248,72,131,224,15,136,68,36,47,15,190,84,36,47,185,48,0,0,0,184,55,0,0,0,131,250,9,15,79,200,15,190,68,36,47,1,200,136,68,36,47,138,76,36,47,232,108,244,255,255,139,68,36,84,131,232,4,137,68,36,84,235,175,185,58,0,0,0,232,85,244,255,255,185,32,0,0,0,232,75,244,255,255,72,139,68,36,104,72,137,68,36,112,199,68,36,84,0,0,0,0,131,124,36,84,16,15,141,153,0,0,0,72,139,68,36,112,72,99,76,36,84,15,182,4,8,193,248,4,131,224,15,136,68,36,47,15,190,84,36,47,185,48,0,0,0,184,55,0,0,0,131,250,9,15,79,200,15,190,68,36,47,1,200,136,68,36,47,138,76,36,47,232,237,243,255,255,72,139,68,36,112,72,99,76,36,84,15,182,4,8,131,224,15,136,68,36,47,15,190,84,36,47,185,48,0,0,0,184,55,0,0,0,131,250,9,15,79,200,15,190,68,36,47,1,200,136,68,36,47,138,76,36,47,232,175,243,255,255,185,32,0,0,0,232,165,243,255,255,139,68,36,84,131,192,1,137,68,36,84,233,92,255,255,255,185,32,0,0,0,232,139,243,255,255,199,68,36,84,0,0,0,0,131,124,36,84,16,125,91,72,139,68,36,112,72,99,76,36,84,15,182,4,8,131,248,32,124,19,72,139,68,36,112,72,99,76,36,84,15,182,4,8,131,248,127,124,11,184,46,0,0,0,137,68,36,40,235,18,72,139,68,36,112,72,99,76,36,84,15,182,4,8,137,68,36,40,139,68,36,40,136,193,232,46,243,255,255,139,68,36,84,131,192,1,137,68,36,84,235,158,185,13,0,0,0,232,23,243,255,255,185,10,0,0,0,232,13,243,255,255,72,139,68,36,104,72,131,192,16,72,137,68,36,104,139,68,36,92,131,192,255,137,68,36,92,131,248,0,15,133,51,254,255,255,235,0,235,0,235,17,235,0,72,139,132,36,128,0,0,0,138,8,232,212,242,255,255,72,139,132,36,128,0,0,0,72,131,192,1,72,137,132,36,128,0,0,0,233,8,249,255,255,72,129,196,136,0,0,0,195,15,31,0,72,131,236,56,72,137,76,36,40,72,199,5,252,199,0,0,0,0,0,0,72,139,68,36,40,72,193,232,9,72,131,192,1,137,5,241,199,0,0,199,5,235,199,0,0,0,0,0,0,72,131,61,167,199,0,0,0,116,27,72,131,124,36,40,0,116,19,139,5,207,199,0,0,139,13,157,199,0,0,131,233,4,57,200,115,14,72,199,68,36,48,0,0,0,0,233,29,2,0,0,15,182,5,137,199,0,0,131,192,7,193,248,3,137,5,169,199,0,0,72,139,5,98,199,0,0,139,13,108,199,0,0,131,233,4,15,175,13,90,199,0,0,137,201,72,1,200,139,13,135,199,0,0,209,225,137,201,72,1,200,72,137,5,105,199,0,0,15,182,5,75,199,0,0,131,248,8,126,23,15,182,13,63,199,0,0,131,233,8,184,32,0,0,0,211,224,137,68,36,24,235,25,15,182,5,40,199,0,0,185,8,0,0,0,41,193,184,32,0,0,0,211,248,137,68,36,24,139,68,36,24,15,182,13,10,199,0,0,211,224,137,68,36,20,15,182,5,0,199,0,0,131,248,8,126,23,15,182,13,244,198,0,0,131,233,8,184,32,0,0,0,211,224,137,68,36,16,235,25,15,182,5,221,198,0,0,185,8,0,0,0,41,193,184,32,0,0,0,211,248,137,68,36,16,139,68,36,20,139,84,36,16,15,182,13,187,198,0,0,211,226,137,209,9,200,137,68,36,12,15,182,5,173,198,0,0,131,248,8,126,23,15,182,13,161,198,0,0,131,233,8,184,32,0,0,0,211,224,137,68,36,8,235,25,15,182,5,138,198,0,0,185,8,0,0,0,41,193,184,32,0,0,0,211,248,137,68,36,8,139,68,36,12,139,84,36,8,15,182,13,104,198,0,0,211,226,137,209,9,200,137,68,36,36,199,68,36,28,0,0,0,0,199,68,36,32,0,0,0,0,139,68,36,28,139,13,52,198,0,0,131,233,4,57,200,15,131,164,0,0,0,15,182,5,42,198,0,0,137,68,36,4,131,192,241,131,232,2,114,24,235,0,139,68,36,4,131,232,24,116,61,235,0,139,68,36,4,131,232,32,116,50,235,89,139,68,36,36,102,137,194,72,139,5,20,198,0,0,139,13,230,197,0,0,72,1,200,139,76,36,32,102,137,20,8,72,139,5,252,197,0,0,139,76,36,32,102,137,20,8,235,41,139,84,36,36,72,139,5,231,197,0,0,139,13,185,197,0,0,72,1,200,139,76,36,32,137,20,8,72,139,5,208,197,0,0,139,76,36,32,137,20,8,235,0,139,68,36,28,131,192,1,137,68,36,28,139,5,198,197,0,0,3,68,36,32,137,68,36,32,233,71,255,255,255,72,139,68,36,40,139,13,122,197,0,0,131,233,4,137,201,49,210,72,247,241,72,137,68,36,48,72,139,68,36,48,72,131,196,56,195,15,31,68,0,0,72,131,236,16,72,137,76,36,8,72,131,61,111,197,0,0,0,15,132,227,0,0,0,139,5,111,197,0,0,137,68,36,4,72,139,68,36,8,72,193,232,9,139,13,44,197,0,0,131,233,4,137,201,72,15,175,193,139,13,73,197,0,0,49,210,72,247,241,139,13,70,197,0,0,72,15,175,193,137,5,56,197,0,0,139,68,36,4,59,5,46,197,0,0,15,131,148,0,0,0,15,182,5,249,196,0,0,137,4,36,131,192,241,131,232,2,114,22,235,0,139,4,36,131,232,24,116,57,235,0,139,4,36,131,232,32,116,47,235,90,72,139,5,237,196,0,0,139,13,191,196,0,0,72,1,200,139,76,36,4,102,199,4,8,255,255,72,139,5,211,196,0,0,139,76,36,4,102,199,4,8,255,255,235,45,72,139,5,192,196,0,0,139,13,146,196,0,0,72,1,200,139,76,36,4,199,4,8,255,255,255,0,72,139,5,165,196,0,0,139,76,36,4,199,4,8,255,255,255,0,235,0,139,68,36,4,131,192,1,137,68,36,4,233,92,255,255,255,235,0,72,131,196,16,195,144,72,131,236,16,72,131,61,116,196,0,0,0,15,132,207,0,0,0,199,68,36,8,0,0,0,0,199,68,36,12,0,0,0,0,139,68,36,8,139,13,48,196,0,0,131,233,2,57,200,15,131,168,0,0,0,15,182,5,38,196,0,0,137,68,36,4,131,192,241,131,232,2,114,24,235,0,139,68,36,4,131,232,24,116,63,235,0,139,68,36,4,131,232,32,116,52,235,93,139,5,16,196,0,0,102,137,194,72,139,5,14,196,0,0,139,13,224,195,0,0,72,1,200,139,76,36,12,102,137,20,8,72,139,5,246,195,0,0,139,76,36,12,102,137,20,8,235,43,139,21,222,195,0,0,72,139,5,223,195,0,0,139,13,177,195,0,0,72,1,200,139,76,36,12,137,20,8,72,139,5,200,195,0,0,139,76,36,12,137,20,8,235,0,139,68,36,8,131,192,1,137,68,36,8,139,5,190,195,0,0,3,68,36,12,137,68,36,12,233,67,255,255,255,235,0,72,199,5,148,195,0,0,0,0,0,0,72,131,196,16,195,102,102,102,102,102,102,46,15,31,132,0,0,0,0,0,86,87,83,72,131,236,16,72,137,84,36,8,72,137,12,36,72,131,61,88,195,0,0,0,117,8,72,131,124,36,8,0,117,5,233,102,1,0,0,184,2,5,0,0,102,199,0,1,0,184,4,5,0,0,199,0,0,6,0,0,72,139,12,36,184,8,5,0,0,72,137,8,72,139,28,36,72,139,124,36,8,128,60,37,255,4,0,0,128,15,133,149,0,0,0,102,186,247,1,236,60,0,15,132,136,0,0,0,60,255,15,132,128,0,0,0,236,36,192,60,64,117,249,176,10,102,186,246,3,238,176,64,102,186,246,1,238,48,192,102,186,242,1,238,72,137,216,72,193,232,24,102,186,243,1,238,72,193,232,8,102,186,244,1,238,72,193,232,8,102,186,245,1,238,176,1,102,186,242,1,238,72,137,216,102,186,243,1,238,72,193,232,8,102,186,244,1,238,72,193,232,8,102,186,245,1,238,176,36,102,186,247,1,238,236,36,193,60,1,116,23,60,64,117,245,72,199,193,128,0,0,0,102,186,240,1,252,243,109,233,153,0,0,0,87,72,199,199,0,6,0,0,72,199,193,64,0,0,0,72,49,192,242,72,171,72,199,192,16,0,0,0,80,72,199,192,11,150,0,0,80,72,203,15,32,192,15,186,248,31,15,34,192,234,28,150,0,0,8,0,15,32,192,36,254,15,34,192,234,43,150,0,0,0,0,49,192,142,216,142,192,142,208,180,66,190,0,5,138,84,255,248,205,19,15,32,192,12,1,15,34,192,234,77,150,16,0,16,0,15,32,192,15,186,232,31,15,34,192,234,94,150,0,0,32,0,102,184,40,0,142,216,142,192,142,208,72,49,201,72,49,246,177,64,102,190,0,6,95,72,57,247,116,3,242,72,165,72,131,196,16,91,95,94,195,102,102,46,15,31,132,0,0,0,0,0,86,87,83,72,131,236,48,68,137,68,36,44,137,84,36,40,137,76,36,36,72,131,61,180,193,0,0,0,117,27,129,124,36,36,64,1,0,0,114,17,129,124,36,40,200,0,0,0,114,7,131,124,36,44,15,115,5,233,41,2,0,0,185,128,5,0,0,49,210,65,184,128,0,0,0,232,240,234,255,255,139,68,36,36,139,92,36,40,139,76,36,44,72,141,61,69,193,0,0,72,193,225,32,72,193,227,16,72,1,217,72,1,193,72,49,192,80,87,81,72,199,192,16,0,0,0,80,72,199,192,25,151,0,0,80,72,203,15,32,192,15,186,248,31,15,34,192,234,42,151,0,0,8,0,15,32,192,36,254,15,34,192,234,57,151,0,0,0,0,49,192,142,216,142,192,142,208,184,21,79,187,1,0,49,201,49,210,191,128,5,205,16,191,0,6,102,199,5,86,66,69,50,184,0,79,30,6,205,16,7,31,131,248,79,15,133,51,1,102,49,246,102,49,255,139,54,14,6,161,16,6,142,216,191,0,10,185,0,1,173,131,248,255,116,9,131,248,0,116,4,171,73,117,241,49,192,171,142,216,103,199,68,36,20,255,255,190,0,10,199,6,0,6,0,0,173,9,192,116,98,137,193,191,0,6,184,1,79,81,86,30,6,205,16,7,31,94,89,131,248,79,117,222,161,0,6,37,155,0,61,155,0,117,211,103,138,68,36,4,58,6,25,6,117,200,161,20,6,103,59,68,36,2,119,190,103,59,68,36,18,114,183,161,18,6,103,59,4,36,119,174,103,59,68,36,16,114,167,103,137,68,36,16,161,20,6,103,137,68,36,18,103,137,76,36,20,235,147,103,131,124,36,20,255,15,132,137,0,103,139,92,36,20,129,203,0,96,184,2,79,81,86,30,6,205,16,7,31,94,89,131,248,79,117,110,103,139,76,36,20,191,0,6,184,1,79,81,86,30,6,205,16,7,31,94,89,131,248,79,117,84,103,102,139,124,36,8,102,161,40,6,103,102,137,71,8,102,161,44,6,103,102,137,71,12,161,16,6,103,137,71,16,161,18,6,103,137,71,20,161,20,6,103,137,71,24,160,25,6,103,136,71,28,103,198,71,29,1,161,31,6,134,224,103,137,71,32,161,33,6,134,224,103,137,71,34,161,35,6,134,224,103,137,71,36,15,32,192,12,1,15,34,192,234,172,152,16,0,16,0,15,32,192,15,186,232,31,15,34,192,234,189,152,0,0,32,0,102,184,40,0,142,216,142,192,142,208,72,131,196,24,72,131,61,109,191,0,0,0,117,14,72,141,13,184,171,0,0,232,63,240,255,255,235,20,199,5,59,191,0,0,4,0,0,0,199,5,53,191,0,0,4,0,0,0,72,131,196,48,91,95,94,195,144,86,87,83,72,131,236,64,72,137,76,36,48,199,68,36,44,0,0,0,0,72,131,61,68,191,0,0,0,117,8,72,131,124,36,48,0,117,13,199,68,36,60,0,0,0,0,233,226,0,0,0,72,139,124,36,48,87,72,49,255,106,0,72,199,192,16,0,0,0,80,72,199,192,80,153,0,0,80,72,203,15,32,192,15,186,248,31,15,34,192,234,97,153,0,0,8,0,15,32,192,36,254,15,34,192,234,112,153,0,0,0,0,49,192,142,216,142,192,142,208,248,102,49,219,102,191,0,6,0,0,102,184,32,232,0,0,102,186,80,65,77,83,102,49,201,177,20,205,21,114,19,102,131,199,20,102,49,192,102,171,103,102,255,4,36,102,9,219,117,216,15,32,192,12,1,15,34,192,234,185,153,16,0,16,0,15,32,192,15,186,232,31,15,34,192,234,202,153,0,0,32,0,102,184,40,0,142,216,142,192,142,208,72,137,249,72,199,198,0,6,0,0,72,41,241,91,95,242,164,72,137,216,137,68,36,44,139,84,36,44,72,139,76,36,48,232,54,0,0,0,131,124,36,44,1,125,12,72,141,13,231,170,0,0,232,19,239,255,255,139,68,36,44,137,68,36,60,139,68,36,60,72,131,196,64,91,95,94,195,102,102,102,102,102,102,46,15,31,132,0,0,0,0,0,72,131,236,104,137,84,36,100,72,137,76,36,88,199,68,36,84,1,0,0,0,139,68,36,84,59,68,36,100,15,141,78,1,0,0,139,68,36,84,137,68,36,80,49,192,131,124,36,80,0,136,68,36,47,126,52,72,139,68,36,88,72,99,76,36,80,72,107,201,24,72,1,200,72,139,0,72,139,76,36,88,139,84,36,80,131,234,1,72,99,210,72,107,210,24,72,1,209,72,59,1,15,146,192,136,68,36,47,138,68,36,47,168,1,117,5,233,135,0,0,0,72,139,84,36,88,139,68,36,80,131,232,1,72,152,72,107,192,24,72,1,194,72,141,76,36,48,65,184,24,0,0,0,232,210,230,255,255,72,139,84,36,88,72,99,68,36,80,72,107,192,24,72,1,194,72,139,76,36,88,139,68,36,80,131,232,1,72,152,72,107,192,24,72,1,193,65,184,24,0,0,0,232,161,230,255,255,72,139,76,36,88,72,99,68,36,80,72,107,192,24,72,1,193,72,141,84,36,48,65,184,24,0,0,0,232,128,230,255,255,139,68,36,80,131,192,255,137,68,36,80,233,43,255,255,255,72,139,68,36,88,72,99,76,36,84,72,107,201,24,72,1,200,72,139,0,72,139,76,36,88,72,99,84,36,84,72,107,210,24,72,1,209,72,3,65,8,72,137,68,36,72,72,139,68,36,88,72,99,76,36,84,72,107,201,24,72,1,200,131,120,16,1,117,26,72,139,68,36,72,72,59,5,31,205,0,0,118,12,72,139,68,36,72,72,137,5,17,205,0,0,235,0,139,68,36,84,131,192,1,137,68,36,84,233,164,254,255,255,72,131,196,104,195,102,46,15,31,132,0,0,0,0,0,232,0,0,0,0,94,72,131,198,88,72,199,199,0,6,0,0,72,199,193,41,0,0,0,242,164,72,199,192,16,0,0,0,80,72,199,192,230,155,0,0,80,72,203,255,3,0,0,0,0,0,0,0,0,15,1,29,220,155,0,0,15,32,192,15,186,248,31,15,34,192,234,254,155,0,0,8,0,15,32,192,36,254,15,34,192,234,0,6,0,0,0,0,49,192,142,216,142,192,142,208,187,0,124,137,220,198,7,244,180,66,190,0,5,138,84,255,248,82,205,19,184,3,0,205,16,90,252,250,234,0,124,0,0,195,102,15,31,132,0,0,0,0,0,72,131,236,40,137,76,36,36,72,139,13,57,188,0,0,72,131,193,8,49,210,65,184,248,15,0,0,232,112,229,255,255,72,139,13,33,188,0,0,72,129,193,8,16,0,0,49,210,65,184,248,15,0,0,232,85,229,255,255,72,139,13,6,188,0,0,72,129,193,8,32,0,0,49,210,65,184,248,79,0,0,232,58,229,255,255,72,139,13,235,187,0,0,72,129,193,0,16,0,0,72,131,193,3,72,139,5,217,187,0,0,72,137,8,199,68,36,32,0,0,0,0,139,68,36,32,59,68,36,36,125,63,72,139,21,189,187,0,0,139,68,36,32,131,192,2,193,224,12,72,152,72,1,194,72,131,194,3,72,139,5,163,187,0,0,139,76,36,32,129,193,0,2,0,0,72,99,201,72,137,20,200,139,68,36,32,131,192,1,137,68,36,32,235,183,199,68,36,32,0,0,0,0,139,68,36,32,139,76,36,36,193,225,9,57,200,125,60,72,99,84,36,32,72,209,226,72,193,226,10,72,193,226,10,72,129,194,131,0,0,0,72,139,5,80,187,0,0,139,76,36,32,129,193,0,4,0,0,72,99,201,72,137,20,200,139,68,36,32,131,192,1,137,68,36,32,235,181,72,131,196,40,195,15,31,68,0,0,72,129,236,168,0,0,0,68,137,132,36,164,0,0,0,137,148,36,160,0,0,0,137,140,36,156,0,0,0,72,139,5,124,163,0,0,72,137,132,36,140,0,0,0,72,139,5,117,163,0,0,72,137,132,36,148,0,0,0,72,199,132,36,128,0,0,0,0,0,0,0,72,199,68,36,120,0,0,0,0,72,199,68,36,104,36,0,0,0,199,68,36,88,0,0,0,0,199,68,36,84,0,0,0,0,199,68,36,80,0,0,0,0,199,68,36,76,255,255,255,255,72,131,61,127,186,0,0,0,116,46,72,131,61,165,186,0,0,0,116,36,129,188,36,156,0,0,0,64,1,0,0,114,23,129,188,36,160,0,0,0,200,0,0,0,114,10,131,188,36,164,0,0,0,15,115,5,233,239,5,0,0,72,139,5,115,186,0,0,72,141,140,36,140,0,0,0,49,210,76,141,132,36,128,0,0,0,255,144,64,1,0,0,72,137,68,36,112,72,131,124,36,112,0,15,140,191,5,0,0,72,131,188,36,128,0,0,0,0,15,132,176,5,0,0,72,139,132,36,128,0,0,0,72,139,0,72,137,68,36,64,72,139,132,36,128,0,0,0,72,131,120,24,0,116,21,72,139,132,36,128,0,0,0,72,139,64,24,139,64,4,137,68,36,60,235,8,49,192,137,68,36,60,235,0,72,139,68,36,64,139,84,36,60,72,139,140,36,128,0,0,0,76,141,68,36,104,76,141,76,36,120,255,208,72,137,68,36,112,72,131,124,36,112,0,124,15,72,139,132,36,128,0,0,0,72,131,120,24,0,117,29,72,139,132,36,128,0,0,0,72,139,64,8,72,139,140,36,128,0,0,0,49,210,255,208,72,137,68,36,112,72,131,124,36,112,0,15,140,114,1,0,0,72,199,68,36,96,0,0,0,0,72,139,68,36,96,72,139,140,36,128,0,0,0,72,139,73,24,139,9,72,57,200,15,131,75,1,0,0,72,139,132,36,128,0,0,0,72,139,0,72,139,76,36,96,137,202,72,139,140,36,128,0,0,0,76,141,68,36,104,76,141,76,36,120,255,208,72,137,68,36,112,72,131,124,36,112,0,124,11,72,139,68,36,120,131,120,12,2,126,5,233,245,0,0,0,72,139,68,36,120,139,64,12,131,232,1,119,12,235,0,199,68,36,88,32,0,0,0,235,110,72,139,68,36,120,139,64,16,72,139,76,36,120,11,65,20,72,139,76,36,120,11,65,24,137,68,36,92,199,68,36,88,32,0,0,0,49,192,131,124,36,88,0,136,68,36,59,118,34,139,68,36,92,139,76,36,88,131,233,1,186,1,0,0,0,211,226,137,209,33,200,131,248,0,15,149,192,52,255,136,68,36,59,138,68,36,59,168,1,117,2,235,15,235,0,139,68,36,88,131,192,255,137,68,36,88,235,184,235,0,139,132,36,164,0,0,0,59,68,36,88,117,95,72,139,68,36,120,139,64,4,59,132,36,156,0,0,0,119,78,72,139,68,36,120,139,64,8,59,132,36,160,0,0,0,119,61,72,139,68,36,120,139,64,4,59,68,36,84,118,47,72,139,68,36,120,139,64,8,59,68,36,80,118,33,72,139,68,36,96,137,68,36,76,72,139,68,36,120,139,64,4,137,68,36,84,72,139,68,36,120,139,64,8,137,68,36,80,235,0,72,139,68,36,96,72,131,192,1,72,137,68,36,96,233,153,254,255,255,235,0,131,124,36,76,255,15,132,125,3,0,0,72,139,132,36,128,0,0,0,72,139,64,8,139,84,36,76,72,139,140,36,128,0,0,0,255,208,72,137,68,36,112,72,131,124,36,112,0,15,140,80,3,0,0,199,5,131,183,0,0,4,0,0,0,199,5,125,183,0,0,4,0,0,0,72,139,132,36,128,0,0,0,72,139,0,72,137,68,36,48,72,139,132,36,128,0,0,0,72,131,120,24,0,116,21,72,139,132,36,128,0,0,0,72,139,64,24,139,64,4,137,68,36,44,235,8,49,192,137,68,36,44,235,0,72,139,68,36,48,139,84,36,44,72,139,140,36,128,0,0,0,76,141,68,36,104,76,141,76,36,120,255,208,72,137,68,36,112,72,139,68,36,120,139,64,12,137,68,36,40,133,192,116,13,235,0,139,68,36,40,131,232,1,116,57,235,110,198,5,39,183,0,0,0,198,5,33,183,0,0,8,198,5,27,183,0,0,8,198,5,21,183,0,0,8,198,5,15,183,0,0,16,198,5,9,183,0,0,8,199,68,36,88,32,0,0,0,233,43,2,0,0,198,5,240,182,0,0,16,198,5,234,182,0,0,8,198,5,228,182,0,0,8,198,5,222,182,0,0,8,198,5,216,182,0,0,0,198,5,210,182,0,0,8,199,68,36,88,32,0,0,0,233,244,1,0,0,72,139,68,36,120,139,64,16,72,139,76,36,120,11,65,20,72,139,76,36,120,11,65,24,137,68,36,92,199,68,36,88,32,0,0,0,49,192,131,124,36,88,0,136,68,36,39,118,34,139,68,36,92,139,76,36,88,131,233,1,186,1,0,0,0,211,226,137,209,33,200,131,248,0,15,149,192,52,255,136,68,36,39,138,68,36,39,168,1,117,2,235,15,235,0,139,68,36,88,131,192,255,137,68,36,88,235,184,198,5,77,182,0,0,0,72,139,68,36,120,139,64,16,15,182,13,62,182,0,0,186,1,0,0,0,211,226,137,209,33,200,131,248,0,15,149,192,52,255,168,1,117,2,235,18,235,0,138,5,29,182,0,0,4,1,136,5,21,182,0,0,235,198,198,5,13,182,0,0,0,72,139,68,36,120,139,64,16,15,182,13,253,181,0,0,15,182,21,247,181,0,0,1,209,186,1,0,0,0,211,226,137,209,33,200,131,248,0,116,18,235,0,138,5,221,181,0,0,4,1,136,5,213,181,0,0,235,198,198,5,205,181,0,0,0,72,139,68,36,120,139,64,20,15,182,13,190,181,0,0,186,1,0,0,0,211,226,137,209,33,200,131,248,0,15,149,192,52,255,168,1,117,2,235,18,235,0,138,5,157,181,0,0,4,1,136,5,149,181,0,0,235,198,198,5,141,181,0,0,0,72,139,68,36,120,139,64,20,15,182,13,125,181,0,0,15,182,21,119,181,0,0,1,209,186,1,0,0,0,211,226,137,209,33,200,131,248,0,116,18,235,0,138,5,93,181,0,0,4,1,136,5,85,181,0,0,235,198,198,5,77,181,0,0,0,72,139,68,36,120,139,64,24,15,182,13,62,181,0,0,186,1,0,0,0,211,226,137,209,33,200,131,248,0,15,149,192,52,255,168,1,117,2,235,18,235,0,138,5,29,181,0,0,4,1,136,5,21,181,0,0,235,198,198,5,13,181,0,0,0,72,139,68,36,120,139,64,24,15,182,13,253,180,0,0,15,182,21,247,180,0,0,1,209,186,1,0,0,0,211,226,137,209,33,200,131,248,0,116,18,235,0,138,5,221,180,0,0,4,1,136,5,213,180,0,0,235,198,235,0,72,139,132,36,128,0,0,0,72,139,64,24,72,139,64,24,72,137,5,157,180,0,0,72,139,68,36,120,139,64,32,139,76,36,88,131,193,7,193,233,3,15,175,193,137,5,138,180,0,0,72,139,68,36,120,139,64,4,137,5,128,180,0,0,72,139,68,36,120,139,64,8,137,5,118,180,0,0,139,68,36,88,136,5,112,180,0,0,198,5,106,180,0,0,1,235,0,72,131,61,75,180,0,0,0,117,12,72,141,13,104,160,0,0,232,29,229,255,255,235,0,72,129,196,168,0,0,0,195,15,31,0,72,129,236,136,0,0,0,72,137,148,36,128,0,0,0,72,137,76,36,120,72,139,5,229,156,0,0,72,137,68,36,104,72,139,5,225,156,0,0,72,137,68,36,112,72,139,5,221,156,0,0,72,137,68,36,88,72,139,5,217,156,0,0,72,137,68,36,96,72,139,5,213,156,0,0,72,137,68,36,72,72,139,5,209,156,0,0,72,137,68,36,80,72,199,68,36,64,0,0,0,0,72,141,5,36,180,0,0,72,137,68,36,56,72,199,68,36,48,0,16,0,0,72,139,132,36,128,0,0,0,199,0,0,0,0,0,72,139,68,36,120,72,199,0,0,0,0,0,72,139,68,36,48,65,137,192,72,139,76,36,56,49,210,232,24,221,255,255,72,139,5,209,179,0,0,72,139,128,176,0,0,0,76,139,84,36,56,185,2,0,0,0,72,141,84,36,104,69,49,192,76,141,76,36,48,76,137,84,36,32,255,208,72,131,248,0,15,140,174,0,0,0,72,139,5,155,179,0,0,72,139,128,152,0,0,0,72,139,76,36,56,72,139,9,72,141,84,36,88,76,141,68,36,64,255,208,72,131,248,0,124,30,72,131,124,36,64,0,116,22,72,139,68,36,64,131,56,0,116,12,72,139,68,36,64,72,131,120,8,0,117,70,72,139,5,85,179,0,0,72,139,128,152,0,0,0,72,139,76,36,56,72,139,9,72,141,84,36,72,76,141,68,36,64,255,208,72,131,248,0,124,64,72,131,124,36,64,0,116,56,72,139,68,36,64,131,56,0,116,46,72,139,68,36,64,72,131,120,8,0,116,34,72,139,68,36,64,139,8,72,139,132,36,128,0,0,0,137,8,72,139,68,36,64,72,139,72,8,72,139,68,36,120,72,137,8,72,129,196,136,0,0,0,195,102,102,102,46,15,31,132,0,0,0,0,0,72,129,236,136,0,0,0,72,137,76,36,120,199,68,36,116,0,0,0,0,72,199,68,36,88,0,0,0,0,72,199,68,36,72,0,0,0,0,72,199,68,36,64,0,0,0,0,72,199,68,36,56,0,0,0,0,72,131,61,112,178,0,0,0,116,10,72,131,61,150,178,0,0,0,117,16,199,132,36,132,0,0,0,0,0,0,0,233,229,2,0,0,72,139,5,125,178,0,0,72,141,76,36,72,49,210,76,141,68,36,64,76,141,76,36,56,72,199,68,36,32,0,0,0,0,255,80,56,72,137,68,36,96,72,184,5,0,0,0,0,0,0,128,72,57,68,36,96,117,8,72,131,124,36,72,0,117,5,233,120,2,0,0,72,139,68,36,56,72,193,224,2,72,3,68,36,72,72,137,68,36,72,72,139,5,35,178,0,0,72,139,64,64,72,139,84,36,72,185,2,0,0,0,76,141,68,36,88,255,208,72,137,68,36,96,72,131,124,36,96,0,124,8,72,131,124,36,88,0,117,5,233,47,2,0,0,72,139,5,237,177,0,0,72,139,64,56,72,139,84,36,88,72,141,76,36,72,76,141,68,36,64,76,141,76,36,56,69,49,210,72,199,68,36,32,0,0,0,0,255,208,72,137,68,36,96,72,131,124,36,96,0,125,28,72,139,5,179,177,0,0,72,139,64,72,72,139,76,36,88,255,208,72,137,68,36,96,233,217,1,0,0,72,131,124,36,120,0,15,132,65,1,0,0,72,139,68,36,88,72,137,68,36,80,72,139,68,36,80,72,139,76,36,88,72,3,76,36,72,72,57,200,15,131,15,1,0,0,72,139,68,36,80,72,139,72,8,72,139,68,36,120,72,99,84,36,116,72,107,210,24,72,1,208,72,137,8,72,139,68,36,80,72,139,72,24,72,193,225,12,72,139,68,36,120,72,99,84,36,116,72,107,210,24,72,1,208,72,137,72,8,72,139,68,36,80,139,8,72,139,68,36,120,72,99,84,36,116,72,107,210,24,72,1,208,137,72,20,72,139,68,36,80,131,56,0,118,10,72,139,68,36,80,131,56,5,114,10,72,139,68,36,80,131,56,7,117,11,184,1,0,0,0,137,68,36,52,235,85,72,139,68,36,80,131,56,8,117,11,184,5,0,0,0,137,68,36,48,235,56,72,139,68,36,80,131,56,9,117,11,184,3,0,0,0,137,68,36,44,235,27,72,139,68,36,80,139,16,184,2,0,0,0,185,4,0,0,0,131,250,10,15,68,193,137,68,36,44,139,68,36,44,137,68,36,48,139,68,36,48,137,68,36,52,139,76,36,52,72,139,68,36,120,72,99,84,36,116,72,107,210,24,72,1,208,137,72,16,72,139,68,36,80,72,3,68,36,56,72,137,68,36,80,139,68,36,116,131,192,1,137,68,36,116,233,217,254,255,255,139,84,36,116,72,139,76,36,120,232,243,241,255,255,235,117,72,139,68,36,88,72,137,68,36,80,72,139,68,36,80,72,139,76,36,88,72,3,76,36,72,72,57,200,115,85,72,139,68,36,80,72,139,64,8,72,139,76,36,80,72,139,73,24,72,193,225,12,72,1,200,72,137,68,36,104,72,139,68,36,80,131,56,7,117,26,72,139,68,36,104,72,59,5,15,192,0,0,118,12,72,139,68,36,104,72,137,5,1,192,0,0,235,0,72,139,68,36,80,72,3,68,36,56,72,137,68,36,80,235,151,235,0,72,139,5,213,175,0,0,72,139,64,72,72,139,76,36,88,255,208,72,137,68,36,96,72,131,124,36,120,0,116,19,131,124,36,116,1,125,12,72,141,13,236,155,0,0,232,58,224,255,255,139,68,36,116,137,132,36,132,0,0,0,139,132,36,132,0,0,0,72,129,196,136,0,0,0,195,72,131,236,56,72,199,68,36,40,0,0,0,0,72,139,5,124,175,0,0,49,201,186,2,0,0,0,65,184,1,0,0,0,76,141,76,36,40,255,80,40,72,137,68,36,48,72,131,124,36,48,0,125,11,72,199,68,36,40,0,0,0,0,235,18,72,139,76,36,40,49,210,65,184,0,16,0,0,232,125,216,255,255,72,139,68,36,40,72,131,196,56,195,15,31,0,72,131,236,72,76,137,68,36,56,72,137,84,36,48,137,76,36,44,72,131,61,230,174,0,0,0,116,10,72,131,61,12,175,0,0,0,117,14,72,199,68,36,64,0,0,0,0,233,142,0,0,0,72,139,5,245,174,0,0,72,139,64,40,76,139,68,36,48,139,76,36,44,186,2,0,0,0,76,141,76,36,56,255,208,72,137,68,36,32,72,131,124,36,32,0,125,11,72,199,68,36,56,0,0,0,0,235,76,72,139,76,36,56,139,5,217,194,0,0,137,194,72,141,5,208,190,0,0,72,193,226,4,72,1,208,72,137,8,72,139,76,36,48,139,5,187,194,0,0,137,194,72,141,5,178,190,0,0,72,193,226,4,72,1,208,72,137,72,8,139,5,161,194,0,0,131,192,1,137,5,152,194,0,0,72,139,68,36,56,72,137,68,36,64,72,139,68,36,64,72,131,196,72,195,15,31,64,0,72,131,236,40,72,131,61,36,174,0,0,0,15,132,247,0,0,0,72,131,61,110,194,0,0,0,116,36,72,139,5,61,174,0,0,72,139,64,48,72,139,13,90,194,0,0,186,0,4,0,0,255,208,72,199,5,72,194,0,0,0,0,0,0,131,61,57,194,0,0,0,15,132,186,0,0,0,199,68,36,36,0,0,0,0,139,68,36,36,59,5,33,194,0,0,15,131,132,0,0,0,139,68,36,36,137,193,72,141,5,14,190,0,0,72,193,225,4,72,1,200,72,131,56,0,116,88,139,68,36,36,137,193,72,141,5,244,189,0,0,72,193,225,4,72,1,200,72,131,120,8,0,116,61,72,139,5,191,173,0,0,72,139,64,48,139,76,36,36,137,202,72,141,13,206,189,0,0,72,193,226,4,72,1,209,72,139,81,8,139,76,36,36,65,137,200,72,141,13,181,189,0,0,73,193,224,4,76,1,193,72,139,9,255,208,235,0,139,68,36,36,131,192,1,137,68,36,36,233,108,255,255,255,199,5,141,193,0,0,0,0,0,0,72,141,13,134,189,0,0,49,210,65,184,0,4,0,0,232,153,214,255,255,235,0,72,131,196,40,195,102,144,72,131,236,104,72,137,76,36,88,72,139,5,240,149,0,0,72,137,68,36,64,72,139,5,236,149,0,0,72,137,68,36,72,72,199,68,36,56,96,2,0,0,72,131,61,238,172,0,0,0,116,29,72,131,61,68,193,0,0,0,116,19,72,131,124,36,88,0,116,11,72,139,68,36,88,102,131,56,0,117,13,199,68,36,100,0,0,0,0,233,5,1,0,0,199,68,36,52,0,0,0,0,72,139,68,36,88,72,99,76,36,52,102,131,60,72,0,116,50,72,139,68,36,88,72,99,76,36,52,15,183,4,72,131,248,47,117,16,72,139,68,36,88,72,99,76,36,52,102,199,4,72,92,0,235,0,139,68,36,52,131,192,1,137,68,36,52,235,189,72,139,5,208,192,0,0,72,139,64,8,76,139,68,36,88,72,139,13,192,192,0,0,72,141,21,193,192,0,0,65,185,1,0,0,0,69,49,210,72,199,68,36,32,0,0,0,0,255,208,72,137,68,36,80,72,131,124,36,80,0,125,32,72,199,5,149,192,0,0,0,0,0,0,72,199,5,146,192,0,0,0,0,0,0,199,68,36,100,0,0,0,0,235,91,72,139,5,121,192,0,0,72,139,64,64,72,139,13,110,192,0,0,72,141,84,36,64,76,141,68,36,56,76,141,13,109,192,0,0,255,208,72,137,68,36,80,72,131,124,36,80,0,125,9,49,192,72,137,68,36,40,235,12,72,139,5,86,192,0,0,72,137,68,36,40,72,139,68,36,40,72,137,5,53,192,0,0,199,68,36,100,1,0,0,0,139,68,36,100,72,131,196,104,195,15,31,64,0,72,131,236,120,76,137,68,36,104,72,137,84,36,96,72,137,76,36,88,72,141,76,36,76,49,210,65,184,4,0,0,0,232,251,212,255,255,72,131,61,131,171,0,0,0,116,40,72,131,61,225,191,0,0,0,116,30,72,139,68,36,88,72,59,5,219,191,0,0,115,16,72,131,124,36,96,0,116,8,72,131,124,36,104,0,117,14,72,199,68,36,112,0,0,0,0,233,2,2,0,0,72,139,68,36,88,72,3,68,36,96,72,59,5,170,191,0,0,118,17,72,139,5,161,191,0,0,72,43,68,36,88,72,137,68,36,96,72,139,5,136,191,0,0,72,139,64,56,72,139,84,36,88,72,139,13,120,191,0,0,255,208,72,137,68,36,80,72,131,124,36,80,0,125,14,72,199,68,36,112,0,0,0,0,233,170,1,0,0,72,139,76,36,96,232,233,226,255,255,72,137,68,36,64,72,131,248,0,15,132,243,0,0,0,72,199,68,36,56,0,0,0,0,49,192,72,131,124,36,80,0,136,68,36,55,124,17,72,139,68,36,56,72,59,68,36,96,15,146,192,136,68,36,55,138,68,36,55,168,1,117,5,233,188,0,0,0,131,61,118,193,0,0,0,117,77,131,61,113,193,0,0,0,117,68,72,139,5,140,170,0,0,72,139,64,48,72,139,64,8,72,139,13,125,170,0,0,72,139,73,48,72,141,84,36,76,255,208,72,137,68,36,80,72,131,124,36,80,0,124,20,15,183,68,36,78,131,248,0,116,10,199,5,45,193,0,0,1,0,0,0,235,0,72,139,68,36,96,72,43,68,36,56,72,59,68,36,64,115,15,72,139,68,36,96,72,43,68,36,56,72,137,68,36,64,72,139,5,144,190,0,0,72,139,64,32,76,139,68,36,104,76,3,68,36,56,72,139,13,123,190,0,0,72,141,84,36,64,255,208,72,137,68,36,80,72,139,76,36,56,232,141,228,255,255,72,139,68,36,64,72,3,68,36,56,72,137,68,36,56,233,24,255,255,255,235,121,131,61,184,192,0,0,0,117,77,131,61,179,192,0,0,0,117,68,72,139,5,206,169,0,0,72,139,64,48,72,139,64,8,72,139,13,191,169,0,0,72,139,73,48,72,141,84,36,76,255,208,72,137,68,36,80,72,131,124,36,80,0,124,20,15,183,68,36,78,131,248,0,116,10,199,5,111,192,0,0,1,0,0,0,235,0,72,139,5,242,189,0,0,72,139,64,32,76,139,68,36,104,72,139,13,226,189,0,0,72,141,84,36,96,255,208,72,137,68,36,80,72,131,124,36,80,0,125,9,49,192,72,137,68,36,40,235,10,72,139,68,36,96,72,137,68,36,40,72,139,68,36,40,72,137,68,36,112,72,139,68,36,112,72,131,196,120,195,102,102,102,102,102,102,46,15,31,132,0,0,0,0,0,72,131,236,40,72,131,61,36,169,0,0,0,116,30,72,131,61,130,189,0,0,0,116,20,72,139,5,121,189,0,0,72,139,64,16,72,139,13,110,189,0,0,255,208,72,199,5,97,189,0,0,0,0,0,0,72,199,5,94,189,0,0,0,0,0,0,72,131,196,40,195,102,15,31,132,0,0,0,0,0,72,131,236,120,72,139,5,197,145,0,0,72,137,68,36,104,72,139,5,193,145,0,0,72,137,68,36,112,72,139,5,189,145,0,0,72,137,68,36,88,72,139,5,185,145,0,0,72,137,68,36,96,72,139,5,181,145,0,0,72,137,68,36,72,72,139,5,177,145,0,0,72,137,68,36,80,72,131,61,140,168,0,0,0,116,10,72,131,61,98,191,0,0,0,117,5,233,171,2,0,0,199,68,36,60,0,0,0,0,72,139,5,108,168,0,0,72,139,64,112,72,137,68,36,64,139,68,36,60,72,139,13,88,168,0,0,72,59,65,104,15,131,130,1,0,0,72,139,76,36,64,72,141,84,36,104,65,184,16,0,0,0,232,217,209,255,255,131,248,0,15,133,181,0,0,0,72,139,68,36,64,72,139,64,16,72,137,68,36,48,72,139,13,251,190,0,0,49,210,65,184,16,0,0,0,232,126,209,255,255,72,139,5,231,190,0,0,199,0,13,0,0,0,72,139,68,36,48,15,182,64,5,137,192,72,131,192,16,137,193,72,139,5,201,190,0,0,137,72,4,72,139,68,36,48,138,72,7,72,139,5,183,190,0,0,136,72,8,72,139,68,36,48,138,72,8,72,139,5,165,190,0,0,136,72,9,72,139,68,36,48,68,15,182,64,5,72,139,84,36,48,72,139,13,140,190,0,0,72,131,193,16,232,227,208,255,255,72,139,5,124,190,0,0,139,72,4,131,193,7,131,225,248,72,139,5,108,190,0,0,137,201,72,1,200,72,137,5,96,190,0,0,233,143,0,0,0,72,139,76,36,64,72,141,84,36,72,65,184,16,0,0,0,232,6,209,255,255,131,248,0,117,115,72,139,68,36,64,72,139,64,16,72,137,68,36,48,72,139,5,44,190,0,0,199,0,15,0,0,0,72,139,5,31,190,0,0,199,64,4,44,0,0,0,72,139,84,36,48,72,139,13,12,190,0,0,72,131,193,8,65,184,36,0,0,0,232,93,208,255,255,72,139,5,246,189,0,0,139,72,4,131,193,7,131,225,248,72,139,5,230,189,0,0,137,201,72,1,200,72,137,5,218,189,0,0,72,139,68,36,48,72,137,5,214,189,0,0,235,0,235,0,139,68,36,60,131,192,1,137,68,36,60,72,139,68,36,64,72,131,192,24,72,137,68,36,64,233,105,254,255,255,199,68,36,60,0,0,0,0,72,139,5,189,166,0,0,72,139,64,112,72,137,68,36,64,139,68,36,60,137,193,72,139,21,167,166,0,0,49,192,72,59,74,104,136,68,36,47,115,17,72,131,61,123,189,0,0,0,15,149,192,52,255,136,68,36,47,138,68,36,47,168,1,117,5,233,173,0,0,0,72,139,76,36,64,72,141,84,36,88,65,184,16,0,0,0,232,8,208,255,255,131,248,0,117,115,72,139,68,36,64,72,139,64,16,72,137,68,36,48,72,139,5,46,189,0,0,199,0,14,0,0,0,72,139,5,33,189,0,0,199,64,4,32,0,0,0,72,139,84,36,48,72,139,13,14,189,0,0,72,131,193,8,65,184,24,0,0,0,232,95,207,255,255,72,139,5,248,188,0,0,139,72,4,131,193,7,131,225,248,72,139,5,232,188,0,0,137,201,72,1,200,72,137,5,220,188,0,0,72,139,68,36,48,72,137,5,216,188,0,0,235,0,139,68,36,60,131,192,1,137,68,36,60,72,139,68,36,64,72,131,192,24,72,137,68,36,64,233,28,255,255,255,72,131,196,120,195,102,102,46,15,31,132,0,0,0,0,0,72,129,236,136,0,0,0,72,199,132,36,128,0,0,0,0,0,0,0,72,199,68,36,120,0,0,0,0,72,139,5,189,142,0,0,72,137,68,36,104,72,139,5,185,142,0,0,72,137,68,36,112,72,139,5,181,142,0,0,72,137,68,36,88,72,139,5,177,142,0,0,72,137,68,36,96,72,139,5,173,142,0,0,72,137,68,36,72,72,139,5,169,142,0,0,72,137,68,36,80,72,199,68,36,64,0,0,0,0,72,139,5,76,165,0,0,72,139,64,96,72,137,5,113,165,0,0,72,139,5,42,188,0,0,72,137,5,139,185,0,0,72,139,5,92,165,0,0,186,2,0,0,0,65,184,0,4,0,0,76,141,13,114,185,0,0,137,209,255,80,40,72,131,248,0,125,11,72,199,5,92,185,0,0,0,0,0,0,68,139,5,245,187,0,0,139,21,243,187,0,0,139,13,241,187,0,0,232,236,233,255,255,72,131,61,196,164,0,0,0,117,44,199,5,216,187,0,0,128,2,0,0,199,5,202,187,0,0,224,1,0,0,68,139,5,191,187,0,0,139,21,189,187,0,0,139,13,187,187,0,0,232,182,233,255,255,72,131,61,182,187,0,0,0,15,132,186,1,0,0,72,131,61,208,164,0,0,0,15,132,172,1,0,0,72,139,5,195,164,0,0,72,131,184,152,0,0,0,0,15,132,151,1,0,0,72,139,5,174,164,0,0,72,139,128,152,0,0,0,72,139,13,120,187,0,0,72,141,84,36,88,76,141,132,36,128,0,0,0,255,208,72,139,5,138,164,0,0,72,139,128,152,0,0,0,72,139,140,36,128,0,0,0,72,139,73,24,72,141,84,36,72,76,141,68,36,120,255,208,72,131,248,0,124,42,72,139,68,36,120,72,139,64,8,72,139,76,36,120,72,141,21,128,184,0,0,255,208,72,131,248,0,125,11,72,199,5,109,184,0,0,0,0,0,0,235,0,72,139,5,52,164,0,0,72,139,128,152,0,0,0,72,139,140,36,128,0,0,0,72,139,73,24,72,141,84,36,104,76,141,68,36,64,255,208,72,131,248,0,15,140,235,0,0,0,72,131,124,36,64,0,15,132,223,0,0,0,72,139,68,36,64,72,137,68,36,56,72,139,68,36,64,72,5,0,128,0,0,72,137,68,36,48,72,139,76,36,56,49,192,72,59,76,36,48,136,68,36,47,115,65,72,139,68,36,56,15,182,8,49,192,131,249,127,136,68,36,47,116,46,72,139,68,36,56,15,182,8,176,1,131,249,4,136,68,36,46,117,19,72,139,68,36,56,15,182,64,1,131,248,1,15,149,192,136,68,36,46,138,68,36,46,136,68,36,47,138,68,36,47,168,1,117,2,235,46,235,0,72,139,68,36,56,15,182,72,3,193,225,8,72,139,68,36,56,15,182,64,2,9,193,72,139,68,36,56,72,99,201,72,1,200,72,137,68,36,56,233,117,255,255,255,72,139,68,36,56,15,182,0,131,248,4,117,27,72,139,84,36,56,72,131,194,24,72,141,13,29,186,0,0,65,184,16,0,0,0,232,66,204,255,255,72,139,5,43,163,0,0,72,139,64,72,72,139,76,36,64,255,208,235,0,72,199,5,11,163,0,0,0,0,0,0,72,139,5,12,163,0,0,49,201,186,2,0,0,0,65,184,68,0,0,0,76,141,13,240,162,0,0,255,80,40,72,131,248,0,125,13,72,199,5,220,162,0,0,0,0,0,0,235,10,185,64,0,0,0,232,136,230,255,255,72,129,196,136,0,0,0,195,72,131,236,40,72,131,61,148,162,0,0,0,116,10,72,131,61,186,162,0,0,0,117,5,233,128,0,0,0,72,131,61,155,185,0,0,0,116,31,72,139,5,162,162,0,0,72,139,64,72,72,139,13,135,185,0,0,255,208,72,199,5,122,185,0,0,0,0,0,0,72,131,61,122,185,0,0,0,116,31,72,139,5,121,162,0,0,72,139,64,72,72,139,13,102,185,0,0,255,208,72,199,5,89,185,0,0,0,0,0,0,72,131,61,129,182,0,0,0,116,36,72,139,5,80,162,0,0,72,139,64,48,72,139,13,109,182,0,0,186,0,4,0,0,255,208,72,199,5,91,182,0,0,0,0,0,0,72,131,196,40,195,102,102,102,102,102,46,15,31,132,0,0,0,0,0,80,72,137,12,36,72,139,12,36,72,139,1,72,137,194,72,131,194,1,72,137,17,138,0,89,195,102,15,31,68,0,0,72,131,236,72,68,137,68,36,64,72,137,84,36,56,72,137,76,36,48,72,131,124,36,48,0,116,8,72,131,124,36,56,0,117,13,199,68,36,68,253,255,255,255,233,22,3,0,0,72,141,13,201,184,0,0,49,210,65,184,240,4,0,0,232,252,202,255,255,72,139,68,36,48,15,182,0,131,248,31,15,133,12,1,0,0,72,139,68,36,48,72,131,192,3,72,137,68,36,48,72,139,68,36,48,72,137,193,72,131,193,1,72,137,76,36,48,138,0,136,68,36,47,72,139,68,36,48,72,131,192,6,72,137,68,36,48,15,182,68,36,47,131,224,4,131,248,0,116,75,72,139,68,36,48,72,137,193,72,131,193,1,72,137,76,36,48,15,182,0,137,68,36,40,72,139,68,36,48,72,137,193,72,131,193,1,72,137,76,36,48,15,182,0,193,224,8,3,68,36,40,137,68,36,40,139,76,36,40,72,139,68,36,48,72,99,201,72,1,200,72,137,68,36,48,15,182,68,36,47,131,224,8,131,248,0,116,31,235,0,72,139,68,36,48,72,137,193,72,131,193,1,72,137,76,36,48,15,182,0,131,248,0,116,2,235,229,235,0,15,182,68,36,47,131,224,16,131,248,0,116,31,235,0,72,139,68,36,48,72,137,193,72,131,193,1,72,137,76,36,48,15,182,0,131,248,0,116,2,235,229,235,0,15,182,68,36,47,131,224,2,131,248,0,116,14,72,139,68,36,48,72,131,192,2,72,137,68,36,48,72,139,68,36,48,72,137,5,161,183,0,0,235,93,72,139,68,36,48,15,182,64,8,131,248,120,117,64,72,139,84,36,48,72,139,76,36,56,65,184,8,0,0,0,232,140,201,255,255,72,139,68,36,56,72,131,192,8,72,137,68,36,56,139,68,36,64,131,232,8,137,68,36,64,72,139,68,36,48,72,131,192,10,72,137,5,83,183,0,0,235,13,199,68,36,68,253,255,255,255,233,138,1,0,0,235,0,199,5,88,183,0,0,255,255,255,255,72,139,68,36,56,72,137,5,68,183,0,0,139,68,36,64,137,5,50,183,0,0,139,68,36,64,137,193,232,231,215,255,255,235,0,131,61,46,183,0,0,255,117,125,235,0,72,141,13,3,183,0,0,232,78,1,0,0,137,5,28,183,0,0,72,141,13,241,182,0,0,186,2,0,0,0,69,49,192,232,164,1,0,0,137,5,254,182,0,0,131,61,247,182,0,0,1,117,28,72,141,21,206,182,0,0,72,137,209,72,131,193,48,72,129,194,144,2,0,0,232,251,1,0,0,235,40,131,61,210,182,0,0,2,117,29,72,141,13,169,182,0,0,72,137,202,72,131,194,48,73,137,200,73,129,192,144,2,0,0,232,147,3,0,0,235,0,235,0,139,5,169,182,0,0,137,68,36,36,133,192,116,15,235,0,139,68,36,36,255,200,131,232,2,114,20,235,53,72,141,13,107,182,0,0,232,22,6,0,0,137,68,36,40,235,50,72,141,13,89,182,0,0,72,137,202,72,131,194,48,73,137,200,73,129,192,144,2,0,0,232,3,7,0,0,137,68,36,40,235,15,232,152,218,255,255,199,68,36,68,253,255,255,255,235,116,139,68,36,64,43,5,52,182,0,0,137,192,137,193,232,123,217,255,255,131,124,36,40,1,117,14,131,61,49,182,0,0,0,117,5,233,252,254,255,255,131,124,36,40,0,116,15,232,90,218,255,255,139,68,36,40,137,68,36,68,235,54,235,0,139,5,248,181,0,0,131,192,255,137,5,239,181,0,0,131,248,0,15,133,193,254,255,255,235,0,131,124,36,40,0,15,149,192,52,255,168,1,15,133,171,254,255,255,199,68,36,68,0,0,0,0,139,68,36,68,72,131,196,72,195,144,72,131,236,56,72,137,76,36,48,72,139,76,36,48,139,65,12,137,194,131,194,255,137,81,12,131,248,0,117,33,72,139,76,36,48,232,104,252,255,255,15,182,200,72,139,68,36,48,137,72,8,72,139,68,36,48,199,64,12,7,0,0,0,72,139,68,36,48,139,64,8,131,224,1,137,68,36,44,72,139,68,36,48,139,72,8,209,233,137,72,8,139,68,36,44,72,131,196,56,195,102,102,102,46,15,31,132,0,0,0,0,0,72,131,236,72,68,137,68,36,68,137,84,36,64,72,137,76,36,56,199,68,36,52,0,0,0,0,131,124,36,64,0,116,76,139,76,36,64,184,1,0,0,0,211,224,137,68,36,48,199,68,36,44,1,0,0,0,139,68,36,44,59,68,36,48,115,41,72,139,76,36,56,232,68,255,255,255,131,248,0,116,12,139,68,36,44,3,68,36,52,137,68,36,52,235,0,139,68,36,44,209,224,137,68,36,44,235,205,235,0,139,68,36,52,3,68,36,68,72,131,196,72,195,102,15,31,68,0,0,72,131,236,24,72,137,84,36,16,72,137,76,36,8,199,68,36,4,0,0,0,0,131,124,36,4,7,125,29,72,139,68,36,8,72,99,76,36,4,102,199,4,72,0,0,139,68,36,4,131,192,1,137,68,36,4,235,220,72,139,68,36,8,102,199,64,14,24,0,72,139,68,36,8,102,199,64,16,152,0,72,139,68,36,8,102,199,64,18,112,0,199,68,36,4,0,0,0,0,131,124,36,4,24,125,40,139,68,36,4,5,0,1,0,0,102,137,194,72,139,68,36,8,72,99,76,36,4,102,137,84,72,32,139,68,36,4,131,192,1,137,68,36,4,235,209,199,68,36,4,0,0,0,0,129,124,36,4,144,0,0,0,125,40,139,68,36,4,102,137,194,72,139,68,36,8,139,76,36,4,131,193,24,72,99,201,102,137,84,72,32,139,68,36,4,131,192,1,137,68,36,4,235,206,199,68,36,4,0,0,0,0,131,124,36,4,8,125,48,139,68,36,4,5,24,1,0,0,102,137,194,72,139,68,36,8,139,76,36,4,129,193,168,0,0,0,72,99,201,102,137,84,72,32,139,68,36,4,131,192,1,137,68,36,4,235,201,199,68,36,4,0,0,0,0,131,124,36,4,112,125,48,139,68,36,4,5,144,0,0,0,102,137,194,72,139,68,36,8,139,76,36,4,129,193,176,0,0,0,72,99,201,102,137,84,72,32,139,68,36,4,131,192,1,137,68,36,4,235,201,199,68,36,4,0,0,0,0,131,124,36,4,5,125,29,72,139,68,36,16,72,99,76,36,4,102,199,4,72,0,0,139,68,36,4,131,192,1,137,68,36,4,235,220,72,139,68,36,16,102,199,64,10,32,0,199,68,36,4,0,0,0,0,131,124,36,4,32,125,35,139,68,36,4,102,137,194,72,139,68,36,16,72,99,76,36,4,102,137,84,72,32,139,68,36,4,131,192,1,137,68,36,4,235,214,72,131,196,24,195,15,31,132,0,0,0,0,0,72,129,236,168,1,0,0,76,137,132,36,160,1,0,0,72,137,148,36,152,1,0,0,72,137,140,36,144,1,0,0,72,139,140,36,144,1,0,0,186,5,0,0,0,65,184,1,1,0,0,232,137,253,255,255,137,68,36,76,72,139,140,36,144,1,0,0,186,5,0,0,0,65,184,1,0,0,0,232,109,253,255,255,137,68,36,72,72,139,140,36,144,1,0,0,65,184,4,0,0,0,68,137,194,232,83,253,255,255,137,68,36,68,199,68,36,64,0,0,0,0,131,124,36,64,19,115,22,139,68,36,64,198,68,4,80,0,139,68,36,64,131,192,1,137,68,36,64,235,227,199,68,36,64,0,0,0,0,139,68,36,64,59,68,36,68,115,65,72,139,140,36,144,1,0,0,186,3,0,0,0,69,49,192,232,3,253,255,255,137,68,36,52,139,68,36,52,136,193,139,68,36,64,137,194,72,141,5,12,133,0,0,15,182,4,16,136,76,4,80,139,68,36,64,131,192,1,137,68,36,64,235,181,72,141,84,36,80,72,139,140,36,152,1,0,0,65,184,19,0,0,0,232,207,122,0,0,199,68,36,60,0,0,0,0,139,68,36,60,139,76,36,76,3,76,36,72,57,200,15,131,74,1,0,0,72,139,148,36,152,1,0,0,72,139,140,36,144,1,0,0,232,222,123,0,0,137,68,36,48,139,68,36,48,137,68,36,40,131,232,16,116,31,235,0,139,68,36,40,131,232,17,116,113,235,0,139,68,36,40,131,232,18,15,132,166,0,0,0,233,231,0,0,0,139,68,36,60,131,232,1,137,192,138,68,4,80,136,68,36,47,72,139,140,36,144,1,0,0,186,2,0,0,0,65,184,3,0,0,0,232,53,252,255,255,137,68,36,56,131,124,36,56,0,116,36,138,76,36,47,139,68,36,60,137,194,131,194,1,137,84,36,60,137,192,136,76,4,80,139,68,36,56,131,192,255,137,68,36,56,235,213,233,163,0,0,0,72,139,140,36,144,1,0,0,65,184,3,0,0,0,68,137,194,232,235,251,255,255,137,68,36,56,131,124,36,56,0,116,33,139,68,36,60,137,193,131,193,1,137,76,36,60,137,192,198,68,4,80,0,139,68,36,56,131,192,255,137,68,36,56,235,216,235,95,72,139,140,36,144,1,0,0,186,7,0,0,0,65,184,11,0,0,0,232,165,251,255,255,137,68,36,56,131,124,36,56,0,116,33,139,68,36,60,137,193,131,193,1,137,76,36,60,137,192,198,68,4,80,0,139,68,36,56,131,192,255,137,68,36,56,235,216,235,25,139,68,36,48,136,193,139,68,36,60,137,194,131,194,1,137,84,36,60,137,192,136,76,4,80,233,162,254,255,255,68,139,68,36,76,72,141,84,36,80,72,139,140,36,152,1,0,0,232,82,121,0,0,68,139,68,36,72,72,141,84,36,80,139,68,36,76,72,1,194,72,139,140,36,160,1,0,0,232,52,121,0,0,72,129,196,168,1,0,0,195,102,102,102,46,15,31,132,0,0,0,0,0,72,131,236,72,72,137,76,36,56,72,139,68,36,56,131,120,40,0,15,133,148,0,0,0,72,139,76,36,56,232,14,247,255,255,15,182,192,137,68,36,36,72,139,76,36,56,232,253,246,255,255,136,193,139,68,36,36,15,182,201,193,225,8,1,200,137,68,36,52,72,139,76,36,56,232,225,246,255,255,15,182,192,137,68,36,40,72,139,76,36,56,232,208,246,255,255,136,193,139,68,36,40,15,182,201,193,225,8,1,200,137,68,36,48,139,68,36,52,139,76,36,48,131,241,255,129,225,255,255,0,0,57,200,116,10,199,68,36,68,253,255,255,255,235,104,139,76,36,52,131,193,1,72,139,68,36,56,137,72,40,72,139,68,36,56,199,64,12,0,0,0,0,72,139,76,36,56,139,65,40,131,192,255,137,65,40,131,248,0,117,10,199,68,36,68,1,0,0,0,235,48,72,139,76,36,56,232,93,246,255,255,136,68,36,47,138,76,36,47,72,139,84,36,56,72,139,66,24,73,137,192,73,131,192,1,76,137,66,24,136,8,199,68,36,68,0,0,0,0,139,68,36,68,72,131,196,72,195,102,102,102,102,102,46,15,31,132,0,0,0,0,0,72,131,236,88,76,137,68,36,72,72,137,84,36,64,72,137,76,36,56,72,139,68,36,56,131,120,40,0,15,133,239,0,0,0,72,139,84,36,64,72,139,76,36,56,232,31,121,0,0,137,68,36,44,129,124,36,44,0,1,0,0,125,41,139,68,36,44,136,193,72,139,84,36,56,72,139,66,24,73,137,192,73,131,192,1,76,137,66,24,136,8,199,68,36,84,0,0,0,0,233,240,0,0,0,129,124,36,44,0,1,0,0,117,13,199,68,36,84,1,0,0,0,233,217,0,0,0,139,68,36,44,45,1,1,0,0,137,68,36,44,72,99,76,36,44,72,141,5,232,128,0,0,68,15,183,4,72,72,99,76,36,44,72,141,5,183,128,0,0,15,182,20,8,72,139,76,36,56,232,73,249,255,255,137,193,72,139,68,36,56,137,72,40,72,139,84,36,72,72,139,76,36,56,232,128,120,0,0,137,68,36,48,72,99,76,36,48,72,141,5,0,129,0,0,68,15,183,4,72,72,99,76,36,48,72,141,5,207,128,0,0,15,182,20,8,72,139,76,36,56,232,1,249,255,255,137,68,36,52,49,201,43,76,36,52,72,139,68,36,56,137,72,44,72,139,68,36,56,72,139,64,24,72,139,76,36,56,72,99,73,44,138,12,8,72,139,68,36,56,72,139,64,24,136,8,72,139,68,36,56,72,139,72,24,72,131,193,1,72,137,72,24,72,139,68,36,56,139,72,40,131,193,255,137,72,40,199,68,36,84,0,0,0,0,139,68,36,84,72,131,196,88,195,102,102,102,102,102,102,46,15,31,132,0,0,0,0,0,72,131,236,56,72,131,61,148,150,0,0,0,117,10,72,131,61,74,150,0,0,0,117,5,233,33,2,0,0,72,139,5,92,173,0,0,199,0,14,0,0,0,72,139,5,79,173,0,0,199,64,4,28,0,0,0,72,139,5,65,173,0,0,72,131,192,8,72,137,68,36,48,72,139,76,36,48,49,210,65,184,20,0,0,0,232,182,191,255,255,72,139,76,36,48,72,141,21,128,129,0,0,65,184,8,0,0,0,232,111,191,255,255,72,139,68,36,48,198,64,15,1,72,139,68,36,48,72,141,13,58,178,0,0,137,72,16,199,68,36,40,0,0,0,0,199,68,36,44,0,0,0,0,131,124,36,44,20,125,35,72,139,68,36,48,72,99,76,36,44,15,182,4,8,3,68,36,40,137,68,36,40,139,68,36,44,131,192,1,137,68,36,44,235,214,184,0,1,0,0,43,68,36,40,136,193,72,139,68,36,48,136,72,8,72,141,13,227,177,0,0,49,210,65,184,44,0,0,0,232,38,191,255,255,72,141,13,207,177,0,0,72,141,21,167,128,0,0,65,184,4,0,0,0,232,221,190,255,255,198,5,190,177,0,0,1,199,5,176,177,0,0,40,0,0,0,72,141,5,213,177,0,0,137,5,195,177,0,0,72,141,13,200,177,0,0,49,210,65,184,148,0,0,0,232,219,190,255,255,72,141,13,180,177,0,0,72,141,21,107,128,0,0,65,184,4,0,0,0,232,146,190,255,255,198,5,163,177,0,0,2,199,5,149,177,0,0,148,0,0,0,72,139,5,250,148,0,0,72,139,64,16,137,5,168,177,0,0,72,139,5,233,148,0,0,72,139,64,16,72,137,5,250,177,0,0,199,68,36,40,0,0,0,0,199,68,36,44,0,0,0,0,129,124,36,44,148,0,0,0,125,37,72,99,76,36,44,72,141,5,72,177,0,0,15,182,4,8,3,68,36,40,137,68,36,40,139,68,36,44,131,192,1,137,68,36,44,235,209,184,0,1,0,0,43,68,36,40,136,5,41,177,0,0,199,68,36,40,0,0,0,0,199,68,36,44,0,0,0,0,131,124,36,44,44,125,37,72,99,76,36,44,72,141,5,205,176,0,0,15,182,4,8,3,68,36,40,137,68,36,40,139,68,36,44,131,192,1,137,68,36,44,235,212,184,0,1,0,0,43,68,36,40,136,5,174,176,0,0,72,139,5,94,171,0,0,139,72,4,131,193,7,131,225,248,72,139,5,78,171,0,0,137,201,72,1,200,72,137,5,66,171,0,0,72,131,196,56,195,102,102,102,102,46,15,31,132,0,0,0,0,0,72,131,236,120,72,137,76,36,104,72,131,61,63,148,0,0,0,117,18,72,131,61,245,147,0,0,0,116,8,72,131,124,36,104,0,117,13,199,68,36,116,0,0,0,0,233,216,2,0,0,72,139,5,215,147,0,0,72,139,64,24,139,64,4,137,68,36,100,72,139,5,197,147,0,0,72,139,64,24,72,139,64,8,72,137,68,36,48,199,68,36,96,0,0,0,0,139,68,36,96,59,68,36,100,15,141,29,1,0,0,72,139,68,36,48,72,99,76,36,96,72,137,202,72,193,226,4,72,139,20,16,72,139,68,36,104,72,141,12,73,72,137,20,200,72,139,68,36,48,72,99,76,36,96,72,137,202,72,193,226,4,72,139,84,16,8,72,131,226,248,72,139,68,36,104,72,141,12,73,72,137,84,200,8,72,139,68,36,48,72,99,76,36,96,72,137,202,72,193,226,4,139,84,16,8,131,226,7,72,139,68,36,104,72,141,12,73,137,84,200,20,72,139,68,36,104,72,99,76,36,96,72,141,12,73,139,68,200,20,137,68,36,44,131,232,3,114,27,235,0,139,68,36,44,131,192,253,131,232,2,114,39,235,0,139,68,36,44,131,232,5,116,54,235,78,72,139,68,36,104,72,99,76,36,96,72,107,201,24,72,1,200,199,64,16,1,0,0,0,235,76,72,139,68,36,104,72,99,76,36,96,72,107,201,24,72,1,200,199,64,16,2,0,0,0,235,50,72,139,68,36,104,72,99,76,36,96,72,107,201,24,72,1,200,199,64,16,4,0,0,0,235,24,72,139,68,36,104,72,99,76,36,96,72,107,201,24,72,1,200,199,64,16,5,0,0,0,235,0,139,68,36,96,131,192,1,137,68,36,96,233,213,254,255,255,199,68,36,96,1,0,0,0,139,68,36,96,59,68,36,100,15,141,78,1,0,0,139,68,36,96,137,68,36,92,49,192,131,124,36,92,0,136,68,36,43,126,52,72,139,68,36,104,72,99,76,36,92,72,107,201,24,72,1,200,72,139,0,72,139,76,36,104,139,84,36,92,131,234,1,72,99,210,72,107,210,24,72,1,209,72,59,1,15,146,192,136,68,36,43,138,68,36,43,168,1,117,5,233,135,0,0,0,72,139,84,36,104,139,68,36,92,131,232,1,72,152,72,107,192,24,72,1,194,72,141,76,36,56,65,184,24,0,0,0,232,116,187,255,255,72,139,84,36,104,72,99,68,36,92,72,107,192,24,72,1,194,72,139,76,36,104,139,68,36,92,131,232,1,72,152,72,107,192,24,72,1,193,65,184,24,0,0,0,232,67,187,255,255,72,139,76,36,104,72,99,68,36,92,72,107,192,24,72,1,193,72,141,84,36,56,65,184,24,0,0,0,232,34,187,255,255,139,68,36,92,131,192,255,137,68,36,92,233,43,255,255,255,72,139,68,36,104,72,99,76,36,96,72,107,201,24,72,1,200,72,139,0,72,139,76,36,104,72,99,84,36,96,72,107,210,24,72,1,209,72,3,65,8,72,137,68,36,80,72,139,68,36,104,72,99,76,36,96,72,107,201,24,72,1,200,131,120,16,1,117,26,72,139,68,36,80,72,59,5,193,161,0,0,118,12,72,139,68,36,80,72,137,5,179,161,0,0,235,0,139,68,36,96,131,192,1,137,68,36,96,233,164,254,255,255,131,124,36,100,1,125,12,72,141,13,159,125,0,0,232,14,194,255,255,139,68,36,100,137,68,36,116,139,68,36,116,72,131,196,120,195,102,102,102,102,46,15,31,132,0,0,0,0,0,72,131,236,88,68,137,68,36,84,137,84,36,80,137,76,36,76,199,68,36,56,0,0,0,0,199,68,36,52,0,0,0,0,199,68,36,48,255,255,255,255,72,131,61,255,144,0,0,0,117,51,72,131,61,181,144,0,0,0,116,41,72,139,5,172,144,0,0,72,131,120,40,0,116,27,129,124,36,76,64,1,0,0,114,17,129,124,36,80,200,0,0,0,114,7,131,124,36,84,15,115,5,233,15,2,0,0,72,139,5,126,144,0,0,72,139,64,40,72,139,64,16,72,137,68,36,64,199,68,36,60,0,0,0,0,139,68,36,60,72,139,13,94,144,0,0,72,139,73,40,15,183,73,4,57,200,15,131,134,0,0,0,139,68,36,84,72,139,76,36,64,15,182,73,12,57,200,117,85,72,139,68,36,64,139,0,59,68,36,76,119,72,72,139,68,36,64,139,64,4,59,68,36,80,119,58,72,139,68,36,64,139,0,59,68,36,56,118,45,72,139,68,36,64,139,64,4,59,68,36,52,118,31,139,68,36,60,137,68,36,48,72,139,68,36,64,139,0,137,68,36,56,72,139,68,36,64,139,64,4,137,68,36,52,235,0,139,68,36,60,131,192,1,137,68,36,60,72,139,68,36,64,72,131,192,32,72,137,68,36,64,233,95,255,255,255,131,124,36,48,255,15,132,49,1,0,0,72,139,5,182,143,0,0,72,139,64,40,72,139,64,40,139,76,36,48,255,208,131,248,0,15,132,19,1,0,0,199,5,157,143,0,0,4,0,0,0,199,5,151,143,0,0,4,0,0,0,72,139,5,132,143,0,0,72,139,64,40,72,139,64,16,139,76,36,48,72,193,225,5,72,1,200,72,137,68,36,64,72,139,68,36,64,15,182,64,12,137,68,36,44,131,232,15,116,13,235,0,139,68,36,44,131,232,16,116,25,235,46,198,5,131,143,0,0,5,198,5,122,143,0,0,5,198,5,113,143,0,0,5,235,44,198,5,108,143,0,0,5,198,5,97,143,0,0,5,198,5,92,143,0,0,6,235,21,198,5,85,143,0,0,8,198,5,76,143,0,0,8,198,5,67,143,0,0,8,72,139,68,36,64,138,64,13,136,5,52,143,0,0,72,139,68,36,64,138,64,14,136,5,40,143,0,0,72,139,68,36,64,138,64,15,136,5,28,143,0,0,72,139,5,217,142,0,0,72,139,64,40,72,139,64,32,72,137,5,234,142,0,0,72,139,68,36,64,139,64,8,137,5,228,142,0,0,72,139,68,36,64,139,0,137,5,219,142,0,0,72,139,68,36,64,139,64,4,137,5,209,142,0,0,72,139,68,36,64,138,64,12,136,5,199,142,0,0,198,5,193,142,0,0,1,72,131,61,164,142,0,0,0,117,12,72,141,13,216,122,0,0,232,118,191,255,255,72,131,196,88,195,144,72,131,236,56,68,137,68,36,52,137,84,36,48,137,76,36,44,72,131,61,87,142,0,0,0,116,20,68,139,68,36,52,139,84,36,48,139,76,36,44,232,83,253,255,255,235,18,68,139,68,36,52,139,84,36,48,139,76,36,44,232,159,204,255,255,72,131,196,56,195,102,46,15,31,132,0,0,0,0,0,72,131,236,56,72,137,84,36,48,72,137,76,36,40,72,131,61,10,142,0,0,0,116,116,131,61,25,165,0,0,0,117,52,131,61,20,165,0,0,0,117,43,72,139,5,239,141,0,0,72,131,120,64,0,116,29,72,139,5,225,141,0,0,72,139,64,64,255,80,16,131,248,0,116,10,199,5,231,164,0,0,1,0,0,0,72,139,5,196,141,0,0,72,131,120,48,0,116,39,72,139,5,182,141,0,0,72,139,64,48,72,139,64,16,76,139,76,36,48,76,139,68,36,40,102,139,13,193,170,0,0,186,0,2,0,0,255,208,235,76,131,61,165,164,0,0,0,117,52,131,61,160,164,0,0,0,117,43,228,100,136,68,36,39,15,182,68,36,39,61,255,0,0,0,116,23,15,182,68,36,39,131,224,1,131,248,0,116,10,199,5,117,164,0,0,1,0,0,0,235,0,72,139,84,36,48,72,139,76,36,40,232,24,202,255,255,72,131,196,56,195,15,31,0,83,102,185,169,4,48,192,230,67,228,64,136,195,228,64,136,199,48,192,230,67,228,64,136,196,228,64,134,224,144,243,144,102,41,195,102,41,217,102,137,195,115,230,91,195,15,31,0,72,131,236,40,72,139,5,53,164,0,0,72,137,68,36,32,72,139,5,41,164,0,0,72,5,0,16,0,0,72,137,5,28,164,0,0,72,139,76,36,32,49,210,65,184,0,16,0,0,232,138,182,255,255,72,139,68,36,32,72,131,196,40,195,72,131,236,56,137,76,36,48,72,131,61,0,141,0,0,0,117,17,131,124,36,48,2,114,10,129,124,36,48,248,255,255,15,114,13,199,68,36,52,0,0,0,0,233,205,0,0,0,139,68,36,48,59,5,190,169,0,0,114,20,139,68,36,48,139,13,178,169,0,0,129,193,255,3,0,0,57,200,118,104,139,68,36,48,37,0,252,255,255,137,5,153,169,0,0,72,199,68,36,40,0,0,0,0,72,131,124,36,40,8,115,70,72,139,68,36,40,72,193,224,7,72,141,21,128,169,0,0,72,193,224,2,72,1,194,72,139,13,114,185,0,0,139,5,100,169,0,0,193,232,7,137,192,72,1,193,72,3,76,36,40,232,10,254,255,255,72,139,68,36,40,72,131,192,1,72,137,68,36,40,235,178,235,0,139,68,36,48,43,5,54,169,0,0,137,192,137,193,72,141,5,51,169,0,0,139,4,136,137,68,36,48,131,124,36,48,2,114,10,129,124,36,48,248,255,255,15,114,8,49,192,137,68,36,36,235,8,139,68,36,48,137,68,36,36,139,68,36,36,137,68,36,52,139,68,36,52,72,131,196,56,195,102,46,15,31,132,0,0,0,0,0,72,131,236,120,72,137,76,36,104,72,139,5,232,184,0,0,139,64,44,137,68,36,92,199,68,36,84,0,0,0,0,199,68,36,80,0,0,0,0,198,68,36,79,0,72,141,5,205,184,0,0,72,5,0,2,0,0,72,137,68,36,64,72,139,68,36,104,72,137,68,36,48,72,131,61,176,139,0,0,0,117,29,72,131,61,6,160,0,0,0,116,19,72,131,124,36,104,0,116,11,72,139,68,36,104,102,131,56,0,117,13,199,68,36,116,0,0,0,0,233,5,7,0,0,199,5,122,186,0,0,0,0,0,0,72,199,5,223,159,0,0,0,0,0,0,72,141,13,120,186,0,0,49,210,65,184,10,2,0,0,232,203,180,255,255,72,141,5,84,184,0,0,72,5,0,2,0,0,72,57,68,36,64,15,130,155,0,0,0,128,124,36,79,0,116,26,138,68,36,79,4,255,136,68,36,79,72,139,68,36,96,72,131,192,1,72,137,68,36,96,235,93,131,124,36,92,2,114,10,129,124,36,92,248,255,255,15,114,13,199,68,36,116,0,0,0,0,233,133,6,0,0,72,139,5,245,183,0,0,15,182,64,13,131,232,1,136,68,36,79,139,68,36,92,72,139,13,223,183,0,0,15,182,73,13,15,175,193,137,192,72,3,5,247,187,0,0,72,137,68,36,96,139,76,36,92,232,185,253,255,255,137,68,36,92,72,139,76,36,96,72,141,21,185,183,0,0,232,84,252,255,255,72,141,5,173,183,0,0,72,137,68,36,64,72,139,68,36,64,128,56,0,117,13,199,68,36,116,0,0,0,0,233,18,6,0,0,72,139,68,36,64,15,182,0,131,248,5,15,132,230,5,0,0,72,139,68,36,64,15,182,0,61,229,0,0,0,15,132,211,5,0,0,72,139,68,36,64,15,182,0,131,248,46,117,36,72,139,68,36,64,15,182,64,1,131,248,46,15,132,180,5,0,0,72,139,68,36,64,15,182,64,1,131,248,32,15,132,162,5,0,0,72,139,68,36,64,15,182,64,11,131,248,15,15,133,216,1,0,0,131,124,36,84,0,116,16,72,139,68,36,64,15,182,0,131,224,64,131,248,0,116,115,72,141,13,28,185,0,0,49,210,65,184,10,2,0,0,232,111,179,255,255,72,139,68,36,64,15,182,0,131,224,31,137,68,36,84,131,124,36,84,1,124,7,131,124,36,84,20,126,35,199,68,36,80,0,0,0,0,199,68,36,84,0,0,0,0,72,139,68,36,64,72,131,192,32,72,137,68,36,64,233,100,254,255,255,139,68,36,84,131,232,1,107,192,13,72,99,200,72,141,5,187,184,0,0,72,209,225,72,1,200,72,137,68,36,56,199,68,36,88,0,0,0,0,131,124,36,88,5,125,77,72,139,68,36,64,139,76,36,88,209,225,131,193,2,72,99,201,15,182,4,8,193,224,8,72,139,76,36,64,139,84,36,88,209,226,131,194,1,72,99,210,15,182,12,17,9,200,102,137,194,72,139,68,36,56,72,99,76,36,88,102,137,20,72,139,68,36,88,131,192,1,137,68,36,88,235,172,199,68,36,88,0,0,0,0,131,124,36,88,6,125,82,72,139,68,36,64,139,76,36,88,209,225,131,193,15,72,99,201,15,182,4,8,193,224,8,72,139,76,36,64,139,84,36,88,209,226,131,194,14,72,99,210,15,182,12,17,9,200,102,137,194,72,139,68,36,56,139,76,36,88,131,193,5,72,99,201,102,137,20,72,139,68,36,88,131,192,1,137,68,36,88,235,167,72,139,68,36,64,15,182,64,29,193,224,8,72,139,76,36,64,15,182,73,28,9,200,102,137,193,72,139,68,36,56,102,137,72,22,72,139,68,36,64,15,182,64,31,193,224,8,72,139,76,36,64,15,182,73,30,9,200,102,137,193,72,139,68,36,56,102,137,72,24,72,139,68,36,56,72,131,192,230,72,137,68,36,56,139,68,36,84,131,192,255,137,68,36,84,49,192,131,124,36,84,0,136,68,36,43,117,19,72,141,5,128,183,0,0,72,57,68,36,56,15,146,192,136,68,36,43,138,68,36,43,36,1,15,182,192,137,68,36,80,233,182,3,0,0,72,139,68,36,64,15,182,64,11,131,224,8,131,248,0,15,133,159,3,0,0,131,124,36,80,0,15,133,90,1,0,0,199,68,36,88,0,0,0,0,131,124,36,88,8,125,46,72,139,68,36,64,72,99,76,36,88,15,182,4,8,102,137,194,72,99,76,36,88,72,141,5,22,183,0,0,102,137,20,72,139,68,36,88,131,192,1,137,68,36,88,235,203,235,0,49,192,131,124,36,88,0,136,68,36,42,116,31,139,68,36,88,131,232,1,72,99,200,72,141,5,229,182,0,0,15,183,4,72,131,248,32,15,148,192,136,68,36,42,138,68,36,42,168,1,117,2,235,13,139,68,36,88,131,192,255,137,68,36,88,235,189,72,139,68,36,64,15,182,64,8,131,248,32,15,132,178,0,0,0,139,68,36,88,137,193,131,193,1,137,76,36,88,72,99,200,72,141,5,151,182,0,0,102,199,4,72,46,0,72,139,68,36,64,15,182,64,8,102,137,194,139,68,36,88,137,193,131,193,1,137,76,36,88,72,99,200,72,141,5,110,182,0,0,102,137,20,72,72,139,68,36,64,15,182,64,9,131,248,32,116,94,72,139,68,36,64,15,182,64,9,102,137,194,139,68,36,88,137,193,131,193,1,137,76,36,88,72,99,200,72,141,5,57,182,0,0,102,137,20,72,72,139,68,36,64,15,182,64,10,131,248,32,116,39,72,139,68,36,64,15,182,64,10,102,137,194,139,68,36,88,137,193,131,193,1,137,76,36,88,72,99,200,72,141,5,4,182,0,0,102,137,20,72,235,0,235,0,72,99,76,36,88,72,141,5,240,181,0,0,102,199,4,72,0,0,235,8,199,68,36,80,0,0,0,0,72,139,68,36,48,15,183,0,131,248,47,117,14,72,139,68,36,48,72,131,192,2,72,137,68,36,48,199,68,36,88,0,0,0,0,72,99,76,36,88,72,141,5,177,181,0,0,15,183,12,72,49,192,131,249,0,136,68,36,41,116,49,72,139,68,36,48,72,99,76,36,88,15,183,12,72,49,192,131,249,0,136,68,36,41,116,24,72,139,68,36,48,72,99,76,36,88,15,183,4,72,131,248,47,15,149,192,136,68,36,41,138,68,36,41,168,1,117,5,233,140,0,0,0,72,99,76,36,88,72,141,5,88,181,0,0,102,139,4,72,102,137,68,36,46,15,183,68,36,46,131,248,65,124,23,15,183,68,36,46,131,248,90,127,13,15,183,68,36,46,131,192,32,102,137,68,36,46,72,139,68,36,48,72,99,76,36,88,102,139,4,72,102,137,68,36,44,15,183,68,36,44,131,248,65,124,23,15,183,68,36,44,131,248,90,127,13,15,183,68,36,44,131,192,32,102,137,68,36,44,15,183,68,36,46,15,183,76,36,44,57,200,116,2,235,18,235,0,139,68,36,88,131,192,1,137,68,36,88,233,27,255,255,255,72,99,76,36,88,72,141,5,204,180,0,0,102,131,60,72,0,15,133,17,1,0,0,72,139,68,36,64,15,182,64,21,193,224,24,72,139,76,36,64,15,182,73,20,193,225,16,9,200,72,139,76,36,64,15,182,73,27,193,225,8,9,200,72,139,76,36,64,15,182,73,26,9,200,137,68,36,92,72,139,68,36,64,15,182,64,11,131,224,16,131,248,0,116,102,72,139,68,36,48,72,99,76,36,88,15,183,4,72,131,248,47,116,13,199,68,36,116,0,0,0,0,233,202,0,0,0,139,76,36,88,131,193,1,72,139,68,36,48,72,99,201,72,209,225,72,1,200,72,137,68,36,48,198,68,36,79,0,199,68,36,80,0,0,0,0,199,68,36,84,0,0,0,0,72,141,5,19,178,0,0,72,5,0,2,0,0,72,137,68,36,64,233,168,249,255,255,131,124,36,92,2,114,10,129,124,36,92,248,255,255,15,114,10,199,68,36,116,0,0,0,0,235,105,139,68,36,92,137,5,222,179,0,0,72,139,68,36,64,15,182,64,31,193,224,24,72,139,76,36,64,15,182,73,30,193,225,16,9,200,72,139,76,36,64,15,182,73,29,193,225,8,9,200,72,139,76,36,64,15,182,73,28,9,200,72,152,72,137,5,18,153,0,0,235,25,235,0,235,0,235,0,72,139,68,36,64,72,131,192,32,72,137,68,36,64,233,44,249,255,255,199,68,36,116,1,0,0,0,139,68,36,116,72,131,196,120,195,102,15,31,68,0,0,72,131,236,120,76,137,68,36,104,72,137,84,36,96,72,137,76,36,88,72,199,68,36,80,0,0,0,0,139,5,78,179,0,0,137,68,36,60,199,68,36,52,0,0,0,0,199,68,36,48,0,0,0,0,199,68,36,44,0,2,0,0,198,68,36,43,0,72,131,61,37,132,0,0,0,117,39,131,61,28,179,0,0,2,114,30,72,139,68,36,88,72,59,5,126,152,0,0,115,16,72,131,124,36,96,0,116,8,72,131,124,36,104,0,117,14,72,199,68,36,112,0,0,0,0,233,198,2,0,0,72,139,68,36,88,72,3,68,36,96,72,59,5,77,152,0,0,118,17,72,139,5,68,152,0,0,72,43,68,36,88,72,137,68,36,96,72,139,68,36,96,72,137,68,36,72,72,139,76,36,96,232,182,187,255,255,72,131,124,36,88,0,15,132,2,1,0,0,72,139,68,36,88,72,139,13,150,176,0,0,15,182,73,13,193,225,9,72,99,201,49,210,72,247,241,137,68,36,56,72,139,68,36,88,72,139,13,119,176,0,0,15,182,73,13,193,225,9,72,99,201,49,210,72,247,241,72,137,84,36,64,72,139,68,36,64,72,193,232,9,137,68,36,52,72,139,68,36,64,72,37,255,1,0,0,137,68,36,48,184,0,2,0,0,43,68,36,48,137,68,36,44,131,124,36,56,0,116,86,235,0,139,76,36,56,137,200,131,192,255,137,68,36,56,49,192,131,249,0,136,68,36,42,116,12,131,124,36,60,0,15,149,192,136,68,36,42,138,68,36,42,168,1,117,2,235,15,139,76,36,60,232,242,245,255,255,137,68,36,60,235,195,131,124,36,60,0,117,14,72,199,68,36,112,0,0,0,0,233,191,1,0,0,235,0,72,139,5,214,175,0,0,15,182,64,13,43,68,36,52,131,232,1,136,68,36,43,139,68,36,60,72,139,13,188,175,0,0,15,182,73,13,15,175,193,3,68,36,52,131,232,1,137,192,72,3,5,205,179,0,0,72,137,68,36,80,235,0,49,192,72,131,124,36,72,0,136,68,36,41,116,16,131,61,109,153,0,0,0,15,149,192,52,255,136,68,36,41,138,68,36,41,168,1,117,5,233,63,1,0,0,128,124,36,43,0,116,26,138,68,36,43,4,255,136,68,36,43,72,139,68,36,80,72,131,192,1,72,137,68,36,80,235,75,131,124,36,60,0,117,5,233,18,1,0,0,72,139,5,63,175,0,0,15,182,64,13,131,232,1,136,68,36,43,139,68,36,60,72,139,13,41,175,0,0,15,182,73,13,15,175,193,137,192,72,3,5,65,179,0,0,72,137,68,36,80,139,76,36,60,232,3,245,255,255,137,68,36,60,139,68,36,44,72,59,68,36,72,118,9,72,139,68,36,72,137,68,36,44,129,124,36,44,0,2,0,0,115,56,72,139,76,36,80,72,141,21,229,174,0,0,232,128,243,255,255,68,139,68,36,44,139,68,36,48,72,141,21,208,174,0,0,72,1,194,72,139,76,36,104,232,3,171,255,255,199,68,36,48,0,0,0,0,235,59,72,139,84,36,104,72,139,76,36,80,232,74,243,255,255,131,124,36,48,0,116,35,68,139,68,36,44,72,139,84,36,104,139,68,36,48,72,1,194,72,139,76,36,104,232,200,170,255,255,199,68,36,48,0,0,0,0,235,0,139,76,36,44,72,139,68,36,104,137,201,72,1,200,72,137,68,36,104,139,68,36,44,137,193,72,139,68,36,72,72,41,200,72,137,68,36,72,199,68,36,44,0,2,0,0,72,139,76,36,96,72,43,76,36,72,232,209,187,255,255,233,150,254,255,255,232,199,188,255,255,72,139,68,36,96,72,43,68,36,72,72,137,68,36,112,72,139,68,36,112,72,131,196,120,195,102,102,102,102,102,46,15,31,132,0,0,0,0,0,72,199,5,117,149,0,0,0,0,0,0,199,5,251,175,0,0,0,0,0,0,195,102,46,15,31,132,0,0,0,0,0,72,131,236,72,199,68,36,68,0,0,0,0,199,68,36,64,0,0,0,0,184,0,160,9,0,72,137,68,36,48,49,192,185,0,0,16,0,72,57,76,36,48,136,68,36,46,115,20,139,68,36,68,35,68,36,64,131,248,0,15,149,192,52,255,136,68,36,46,138,68,36,46,168,1,117,5,233,43,2,0,0,72,139,76,36,48,72,141,21,132,107,0,0,65,184,4,0,0,0,232,40,170,255,255,131,248,0,15,133,254,0,0,0,198,68,36,47,0,199,68,36,60,0,0,0,0,139,68,36,60,72,139,76,36,48,15,182,73,5,57,200,115,38,72,139,68,36,48,72,99,76,36,60,15,182,12,8,15,182,68,36,47,1,200,136,68,36,47,139,68,36,60,131,192,1,137,68,36,60,235,201,128,124,36,47,0,15,133,162,0,0,0,72,139,13,9,151,0,0,49,210,65,184,16,0,0,0,232,140,169,255,255,72,139,5,245,150,0,0,199,0,13,0,0,0,72,139,68,36,48,15,182,64,5,137,192,72,131,192,16,137,193,72,139,5,215,150,0,0,137,72,4,72,139,68,36,48,138,72,7,72,139,5,197,150,0,0,136,72,8,72,139,68,36,48,138,72,8,72,139,5,179,150,0,0,136,72,9,72,139,68,36,48,68,15,182,64,5,72,139,84,36,48,72,139,13,154,150,0,0,72,131,193,16,232,241,168,255,255,72,139,5,138,150,0,0,139,72,4,131,193,7,131,225,248,72,139,5,122,150,0,0,137,201,72,1,200,72,137,5,110,150,0,0,199,68,36,68,1,0,0,0,233,248,0,0,0,72,139,76,36,48,72,141,21,187,106,0,0,65,184,8,0,0,0,232,10,169,255,255,131,248,0,15,133,214,0,0,0,72,139,68,36,48,15,182,64,15,131,248,2,125,91,72,139,5,44,150,0,0,199,0,14,0,0,0,72,139,5,31,150,0,0,199,64,4,32,0,0,0,72,139,84,36,48,72,139,13,12,150,0,0,72,131,193,8,65,184,24,0,0,0,232,93,168,255,255,72,139,5,246,149,0,0,139,72,4,131,193,7,131,225,248,72,139,5,230,149,0,0,137,201,72,1,200,72,137,5,218,149,0,0,235,89,72,139,5,209,149,0,0,199,0,15,0,0,0,72,139,5,196,149,0,0,199,64,4,44,0,0,0,72,139,84,36,48,72,139,13,177,149,0,0,72,131,193,8,65,184,36,0,0,0,232,2,168,255,255,72,139,5,155,149,0,0,139,72,4,131,193,7,131,225,248,72,139,5,139,149,0,0,137,201,72,1,200,72,137,5,127,149,0,0,72,139,68,36,48,72,137,5,123,149,0,0,199,68,36,64,1,0,0,0,235,0,235,0,72,139,68,36,48,72,131,192,16,72,137,68,36,48,233,162,253,255,255,72,131,196,72,195,102,102,102,102,102,102,46,15,31,132,0,0,0,0,0,72,129,236,136,0,0,0,72,139,5,118,104,0,0,72,137,68,36,120,72,139,5,114,104,0,0,72,137,132,36,128,0,0,0,72,139,5,107,104,0,0,72,137,68,36,104,72,139,5,103,104,0,0,72,137,68,36,112,72,139,5,99,104,0,0,72,137,68,36,88,72,139,5,95,104,0,0,72,137,68,36,96,184,0,16,0,0,72,137,5,42,126,0,0,185,5,0,0,0,232,216,193,255,255,184,0,16,0,0,15,34,216,68,139,5,225,148,0,0,139,21,223,148,0,0,139,13,221,148,0,0,232,40,239,255,255,72,131,61,176,125,0,0,0,117,100,199,5,196,148,0,0,32,3,0,0,199,5,182,148,0,0,88,2,0,0,68,139,5,171,148,0,0,139,21,169,148,0,0,139,13,167,148,0,0,232,242,238,255,255,72,131,61,122,125,0,0,0,117,44,199,5,142,148,0,0,128,2,0,0,199,5,128,148,0,0,224,1,0,0,68,139,5,117,148,0,0,139,21,115,148,0,0,139,13,113,148,0,0,232,188,238,255,255,235,0,185,1,0,0,0,72,141,21,142,174,0,0,232,249,238,255,255,72,141,13,130,174,0,0,72,141,21,65,104,0,0,65,184,8,0,0,0,232,224,166,255,255,131,248,0,15,133,29,2,0,0,139,5,181,174,0,0,72,137,68,36,72,72,139,5,157,174,0,0,72,137,68,36,56,139,5,154,174,0,0,72,137,68,36,48,72,199,68,36,64,0,0,0,0,49,192,72,131,124,36,64,8,136,68,36,47,115,13,72,131,124,36,48,0,15,149,192,136,68,36,47,138,68,36,47,168,1,117,5,233,197,1,0,0,72,139,76,36,56,72,3,76,36,64,72,141,21,3,174,0,0,232,110,238,255,255,72,199,68,36,80,0,0,0,0,72,139,68,36,80,72,3,68,36,72,72,61,0,2,0,0,15,135,123,1,0,0,72,131,61,7,145,0,0,0,117,96,72,141,13,206,173,0,0,72,3,76,36,80,72,141,84,36,120,65,184,16,0,0,0,232,41,166,255,255,131,248,0,117,63,72,139,76,36,80,72,141,5,168,173,0,0,72,139,68,8,32,72,137,5,204,144,0,0,72,141,21,149,173,0,0,72,3,84,36,80,72,131,194,16,72,141,13,101,147,0,0,65,184,16,0,0,0,232,138,165,255,255,233,237,0,0,0,72,131,61,109,175,0,0,0,15,133,137,0,0,0,72,141,13,96,173,0,0,72,3,76,36,80,72,141,84,36,104,65,184,16,0,0,0,232,187,165,255,255,131,248,0,116,33,72,141,13,63,173,0,0,72,3,76,36,80,72,141,84,36,88,65,184,16,0,0,0,232,154,165,255,255,131,248,0,117,71,72,139,76,36,80,72,141,5,25,173,0,0,72,139,68,8,32,72,137,5,13,175,0,0,72,139,76,36,80,72,141,5,1,173,0,0,72,139,68,8,40,72,139,84,36,80,72,141,13,240,172,0,0,72,43,68,17,32,72,131,192,1,72,137,5,232,174,0,0,235,84,72,139,76,36,80,72,141,5,210,172,0,0,72,139,68,8,48,72,131,224,4,72,131,248,0,116,55,72,139,76,36,80,72,141,5,183,172,0,0,72,131,124,8,32,2,118,35,72,139,76,36,80,72,141,5,163,172,0,0,72,139,68,8,32,72,137,5,151,174,0,0,72,199,5,148,174,0,0,1,0,0,0,235,0,235,0,235,0,72,139,68,36,72,72,3,68,36,80,72,137,68,36,80,72,139,68,36,48,72,131,192,255,72,137,68,36,48,233,111,254,255,255,235,0,72,139,68,36,64,72,131,192,1,72,137,68,36,64,233,19,254,255,255,233,36,1,0,0,49,192,137,193,72,141,21,63,172,0,0,232,170,236,255,255,15,182,5,49,174,0,0,131,248,85,15,133,2,1,0,0,15,182,5,34,174,0,0,61,170,0,0,0,15,133,240,0,0,0,72,199,68,36,80,192,1,0,0,72,129,124,36,80,254,1,0,0,15,131,214,0,0,0,72,139,76,36,80,72,131,233,2,72,141,5,240,171,0,0,15,182,4,8,61,128,0,0,0,15,133,162,0,0,0,72,139,76,36,80,72,141,5,213,171,0,0,15,182,68,8,2,131,248,12,116,24,72,139,76,36,80,72,141,5,191,171,0,0,15,182,68,8,2,61,239,0,0,0,117,116,72,139,76,36,80,72,141,5,167,171,0,0,139,68,8,6,72,137,5,204,142,0,0,72,141,13,117,145,0,0,72,141,21,88,101,0,0,65,184,4,0,0,0,232,147,163,255,255,72,141,13,92,145,0,0,72,131,193,8,72,141,21,165,100,0,0,65,184,4,0,0,0,232,118,163,255,255,184,255,4,0,0,15,182,0,102,137,5,59,145,0,0,72,139,68,36,80,72,45,192,1,0,0,72,193,232,4,102,137,5,39,145,0,0,235,21,235,0,72,139,68,36,80,72,131,192,16,72,137,68,36,80,233,27,255,255,255,235,0,235,0,72,131,61,78,142,0,0,0,15,132,63,1,0,0,72,139,13,65,142,0,0,72,141,21,10,171,0,0,232,117,235,255,255,72,141,5,254,170,0,0,72,137,5,191,166,0,0,15,182,5,238,172,0,0,131,248,85,117,74,15,182,5,227,172,0,0,61,170,0,0,0,117,60,72,139,5,158,166,0,0,15,183,64,11,61,0,2,0,0,117,42,72,139,5,140,166,0,0,128,120,13,0,116,29,72,139,5,127,166,0,0,15,183,64,22,131,248,0,117,13,72,139,5,111,166,0,0,131,120,36,0,117,16,72,199,5,198,141,0,0,0,0,0,0,233,182,0,0,0,72,139,5,82,166,0,0,15,183,64,14,72,139,13,175,141,0,0,72,1,200,72,137,5,53,166,0,0,72,139,5,54,166,0,0,139,64,36,72,139,13,44,166,0,0,15,182,73,16,15,175,193,72,139,13,30,166,0,0,15,183,73,14,1,200,72,139,13,17,166,0,0,15,182,73,13,209,225,41,200,137,192,72,139,13,104,141,0,0,72,1,200,72,137,5,30,170,0,0,72,199,68,36,80,0,0,0,0,72,131,124,36,80,8,115,56,72,139,68,36,80,72,193,224,7,72,141,21,205,149,0,0,72,193,224,2,72,1,194,72,139,13,191,165,0,0,72,3,76,36,80,232,101,234,255,255,72,139,68,36,80,72,131,192,1,72,137,68,36,80,235,192,199,5,147,149,0,0,0,0,0,0,235,0,72,129,196,136,0,0,0,195,144,72,131,236,72,102,68,137,68,36,70,72,137,84,36,56,72,137,76,36,48,15,32,192,36,241,15,34,192,15,32,224,102,13,0,6,15,34,224,199,5,112,143,0,0,32,3,0,0,199,5,98,143,0,0,88,2,0,0,199,5,84,143,0,0,32,0,0,0,72,199,5,89,143,0,0,0,0,0,0,72,199,5,70,120,0,0,0,0,0,0,72,199,5,251,119,0,0,0,0,0,0,102,199,5,22,149,0,0,0,0,72,139,68,36,48,61,5,177,85,240,117,90,72,139,68,36,56,72,137,5,218,119,0,0,15,183,68,36,70,137,68,36,44,72,139,5,202,119,0,0,72,131,120,48,0,116,21,72,139,5,188,119,0,0,72,139,64,48,15,183,64,4,137,68,36,40,235,8,49,192,137,68,36,40,235,0,139,68,36,44,139,76,36,40,57,200,125,12,102,139,68,36,70,102,137,5,178,148,0,0,235,24,72,139,68,36,56,72,137,5,192,119,0,0,72,139,68,36,48,72,137,5,188,142,0,0,72,199,5,9,140,0,0,0,0,0,0,72,199,5,206,119,0,0,0,0,0,0,72,199,5,139,164,0,0,0,0,0,0,72,199,5,240,139,0,0,0,0,0,0,72,199,5,189,170,0,0,0,0,0,0,72,199,5,186,170,0,0,0,0,0,0,199,5,184,170,0,0,0,0,0,0,199,5,174,139,0,0,0,0,0,0,199,5,48,142,0,0,0,0,0,0,199,5,34,142,0,0,0,0,0,0,199,5,148,170,0,0,0,0,0,0,199,5,142,170,0,0,0,0,0,0,72,199,5,139,170,0,0,0,0,0,0,72,141,13,116,135,0,0,49,210,65,184,0,4,0,0,232,135,160,255,255,72,199,5,116,170,0,0,0,0,0,0,72,199,5,113,170,0,0,0,0,0,0,72,199,5,22,142,0,0,0,0,0,0,72,199,5,203,141,0,0,0,0,0,0,72,199,5,8,142,0,0,0,0,0,0,72,199,5,77,170,0,0,0,0,0,0,198,5,78,170,0,0,4,72,199,5,27,139,0,0,0,0,0,0,72,199,5,240,169,0,0,0,0,0,0,72,199,5,221,169,0,0,0,0,0,0,72,199,5,226,134,0,0,0,0,0,0,72,199,5,31,170,0,0,0,0,0,0,72,199,5,28,170,0,0,0,0,0,0,72,199,5,105,141,0,0,0,0,0,0,198,5,18,170,0,0,0,72,141,13,131,141,0,0,49,210,65,184,16,0,0,0,232,214,159,255,255,72,141,13,55,118,0,0,49,210,65,184,40,0,0,0,232,194,159,255,255,199,5,80,118,0,0,0,0,0,0,72,199,5,77,118,0,0,0,0,0,0,184,0,0,2,0,72,137,5,209,169,0,0,72,199,5,22,141,0,0,0,0,16,0,72,131,61,30,118,0,0,0,116,7,232,87,208,255,255,235,5,232,176,247,255,255,72,131,61,232,117,0,0,0,117,27,198,5,243,117,0,0,0,199,5,229,117,0,0,0,0,0,0,199,5,215,117,0,0,0,0,0,0,232,198,159,255,255,72,131,196,72,195,144,72,131,236,104,72,139,5,181,117,0,0,72,137,68,36,88,15,182,5,189,117,0,0,131,192,7,193,248,3,137,68,36,32,72,131,124,36,88,0,117,5,233,155,5,0,0,199,68,36,64,0,0,0,0,199,68,36,80,0,0,0,0,139,68,36,64,59,5,136,117,0,0,15,141,138,0,0,0,139,68,36,80,137,68,36,84,199,68,36,68,0,0,0,0,139,68,36,68,59,5,100,117,0,0,125,78,131,124,36,32,2,117,25,139,5,113,117,0,0,102,137,194,72,139,68,36,88,72,99,76,36,84,102,137,20,8,235,19,139,21,88,117,0,0,72,139,68,36,88,72,99,76,36,84,137,20,8,235,0,139,68,36,68,131,192,1,137,68,36,68,139,68,36,32,3,68,36,84,137,68,36,84,235,166,235,0,139,68,36,64,131,192,1,137,68,36,64,139,5,253,116,0,0,3,68,36,80,137,68,36,80,233,102,255,255,255,199,5,198,116,0,0,4,0,0,0,199,5,192,116,0,0,4,0,0,0,72,131,61,20,140,0,0,0,116,111,72,139,5,11,140,0,0,15,182,0,131,248,0,117,96,72,139,5,252,139,0,0,15,182,64,1,131,248,1,117,80,72,139,5,236,139,0,0,15,182,64,2,131,248,9,117,64,72,139,5,220,139,0,0,15,182,64,3,131,248,0,117,48,72,139,5,204,139,0,0,15,182,64,4,131,248,0,117,32,72,139,5,188,139,0,0,15,182,64,7,131,248,24,116,21,72,139,5,172,139,0,0,15,182,64,7,131,248,32,116,5,233,95,4,0,0,72,139,5,151,139,0,0,15,182,64,17,131,224,32,137,68,36,52,72,139,5,133,139,0,0,15,182,64,13,193,224,8,72,139,13,119,139,0,0,15,182,73,12,1,200,137,68,36,60,72,139,5,102,139,0,0,15,182,64,15,193,224,8,72,139,13,88,139,0,0,15,182,73,14,1,200,137,68,36,56,131,124,36,60,1,124,7,131,124,36,56,1,125,5,233,252,3,0,0,139,5,249,115,0,0,43,68,36,60,185,2,0,0,0,153,247,249,137,68,36,40,139,5,231,115,0,0,43,68,36,56,185,2,0,0,0,153,247,249,137,68,36,36,72,139,5,8,139,0,0,15,182,64,7,193,248,3,72,139,13,250,138,0,0,15,182,73,6,193,225,8,72,139,21,236,138,0,0,15,182,82,5,9,209,15,175,193,131,192,18,137,68,36,48,199,68,36,84,0,0,0,0,199,68,36,64,0,0,0,0,199,68,36,72,0,0,0,0,139,68,36,60,137,68,36,68,199,68,36,64,255,255,255,255,139,76,36,72,139,84,36,60,15,175,84,36,56,49,192,57,209,136,68,36,31,125,17,139,68,36,48,59,5,19,167,0,0,15,146,192,136,68,36,31,138,68,36,31,168,1,117,5,233,64,3,0,0,72,139,5,120,138,0,0,139,76,36,48,137,202,131,194,1,137,84,36,48,72,99,201,15,182,4,8,137,68,36,76,131,124,36,76,127,126,72,199,68,36,44,0,0,0,0,139,68,36,76,131,232,127,137,68,36,76,72,139,5,63,138,0,0,139,76,36,48,137,202,131,194,1,137,84,36,48,72,99,201,15,182,4,8,72,139,13,36,138,0,0,15,182,73,7,193,249,3,15,175,193,131,192,18,137,68,36,80,235,19,199,68,36,44,1,0,0,0,139,68,36,76,131,192,1,137,68,36,76,139,68,36,76,3,68,36,72,137,68,36,72,139,68,36,76,137,193,131,193,255,137,76,36,76,131,248,0,15,132,152,2,0,0,131,124,36,44,0,116,51,72,139,5,206,137,0,0,139,76,36,48,137,202,131,194,1,137,84,36,48,72,99,201,15,182,4,8,72,139,13,179,137,0,0,15,182,73,7,193,249,3,15,175,193,131,192,18,137,68,36,80,139,68,36,68,59,68,36,60,117,95,199,68,36,68,0,0,0,0,139,68,36,36,137,68,36,24,131,124,36,52,0,117,17,139,68,36,56,43,68,36,64,131,232,1,137,68,36,20,235,8,139,68,36,64,137,68,36,20,139,68,36,24,139,76,36,20,1,200,15,175,5,23,114,0,0,139,76,36,40,3,76,36,68,15,175,76,36,32,1,200,137,68,36,84,139,68,36,64,131,192,1,137,68,36,64,139,68,36,36,3,68,36,64,131,248,0,15,142,212,1,0,0,139,68,36,36,3,68,36,64,139,13,226,113,0,0,131,233,1,57,200,15,141,187,1,0,0,139,68,36,40,3,68,36,68,131,248,0,15,142,158,1,0,0,139,68,36,40,3,68,36,68,139,13,180,113,0,0,131,233,1,57,200,15,141,133,1,0,0,15,182,5,175,113,0,0,131,248,8,126,39,72,139,5,210,136,0,0,139,76,36,80,131,193,2,72,99,201,15,182,4,8,15,182,13,142,113,0,0,131,233,8,211,224,137,68,36,16,235,41,72,139,5,171,136,0,0,139,76,36,80,131,193,2,72,99,201,15,182,4,8,15,182,21,103,113,0,0,185,8,0,0,0,41,209,211,248,137,68,36,16,139,68,36,16,15,182,13,78,113,0,0,211,224,137,68,36,12,15,182,5,68,113,0,0,131,248,8,126,39,72,139,5,101,136,0,0,139,76,36,80,131,193,1,72,99,201,15,182,4,8,15,182,13,35,113,0,0,131,233,8,211,224,137,68,36,8,235,41,72,139,5,62,136,0,0,139,76,36,80,131,193,1,72,99,201,15,182,4,8,15,182,21,252,112,0,0,185,8,0,0,0,41,209,211,248,137,68,36,8,139,68,36,12,139,84,36,8,15,182,13,223,112,0,0,211,226,137,209,9,200,137,68,36,4,15,182,5,209,112,0,0,131,248,8,126,38,72,139,5,240,135,0,0,139,76,36,80,131,193,0,72,99,201,15,182,4,8,15,182,13,176,112,0,0,131,233,8,211,224,137,4,36,235,40,72,139,5,202,135,0,0,139,76,36,80,131,193,0,72,99,201,15,182,4,8,15,182,21,138,112,0,0,185,8,0,0,0,41,209,211,248,137,4,36,139,68,36,4,139,20,36,15,182,13,111,112,0,0,211,226,137,209,9,200,137,68,36,100,131,124,36,32,2,117,23,139,68,36,100,102,137,194,72,139,68,36,88,72,99,76,36,84,102,137,20,8,235,17,139,84,36,100,72,139,68,36,88,72,99,76,36,84,137,20,8,235,0,139,68,36,32,3,68,36,84,137,68,36,84,139,68,36,68,131,192,1,137,68,36,68,233,82,253,255,255,233,139,252,255,255,72,131,196,104,195,102,144,72,131,236,88,72,137,76,36,72,72,131,61,95,132,0,0,0,116,18,72,131,124,36,72,0,116,10,72,139,68,36,72,128,56,0,117,13,199,68,36,84,0,0,0,0,233,72,2,0,0,72,139,68,36,72,72,137,68,36,48,72,141,5,125,163,0,0,72,137,68,36,64,72,139,68,36,48,15,190,8,49,192,131,249,0,136,68,36,47,116,82,72,139,68,36,48,15,190,8,49,192,131,249,32,136,68,36,47,116,63,72,139,68,36,48,15,190,8,49,192,131,249,13,136,68,36,47,116,44,72,139,68,36,48,15,190,8,49,192,131,249,10,136,68,36,47,116,25,72,141,5,37,163,0,0,72,5,252,7,0,0,72,57,68,36,64,15,146,192,136,68,36,47,138,68,36,47,168,1,117,5,233,130,1,0,0,72,139,68,36,48,15,190,0,37,128,0,0,0,131,248,0,15,132,5,1,0,0,72,139,68,36,48,15,190,0,131,224,32,131,248,0,117,52,72,139,68,36,48,15,190,0,131,224,31,193,224,6,72,139,76,36,48,15,190,73,1,131,225,63,9,200,102,137,68,36,62,72,139,68,36,48,72,131,192,1,72,137,68,36,48,233,191,0,0,0,72,139,68,36,48,15,190,0,131,224,16,131,248,0,117,66,72,139,68,36,48,15,190,0,131,224,15,193,224,12,72,139,76,36,48,15,190,73,1,131,225,63,193,225,6,9,200,72,139,76,36,48,15,190,73,2,131,225,63,9,200,102,137,68,36,62,72,139,68,36,48,72,131,192,2,72,137,68,36,48,235,107,72,139,68,36,48,15,190,0,131,224,8,131,248,0,117,82,72,139,68,36,48,15,190,0,131,224,7,193,224,18,72,139,76,36,48,15,190,73,1,131,225,63,193,225,12,9,200,72,139,76,36,48,15,190,73,2,131,225,63,193,225,6,9,200,72,139,76,36,48,15,190,73,3,131,225,63,9,200,102,137,68,36,62,72,139,68,36,48,15,190,8,131,193,3,136,8,235,7,102,199,68,36,62,0,0,235,0,235,0,235,13,72,139,68,36,48,15,190,0,102,137,68,36,62,72,139,68,36,48,72,131,192,1,72,137,68,36,48,15,183,68,36,62,131,248,92,117,34,72,139,68,36,48,15,190,0,131,248,32,117,21,102,199,68,36,62,32,0,72,139,68,36,48,72,131,192,1,72,137,68,36,48,102,139,76,36,62,72,139,68,36,64,102,137,8,72,139,68,36,64,72,131,192,2,72,137,68,36,64,233,12,254,255,255,72,139,68,36,64,102,199,0,0,0,72,131,61,194,109,0,0,0,116,18,72,141,13,105,161,0,0,232,148,192,255,255,137,68,36,40,235,16,72,141,13,87,161,0,0,232,162,225,255,255,137,68,36,40,139,68,36,40,137,68,36,84,139,68,36,84,72,131,196,88,195,102,102,102,102,46,15,31,132,0,0,0,0,0,72,131,236,72,76,137,68,36,56,72,137,84,36,48,72,137,76,36,40,72,131,61,197,129,0,0,0,116,30,72,139,68,36,40,72,59,5,199,129,0,0,115,16,72,131,124,36,48,0,116,8,72,131,124,36,56,0,117,11,72,199,68,36,64,0,0,0,0,235,72,72,131,61,50,109,0,0,0,116,27,76,139,68,36,56,72,139,84,36,48,72,139,76,36,40,232,108,193,255,255,72,137,68,36,32,235,25,76,139,68,36,56,72,139,84,36,48,72,139,76,36,40,232,145,232,255,255,72,137,68,36,32,72,139,68,36,32,72,137,68,36,64,72,139,68,36,64,72,131,196,72,195,15,31,132,0,0,0,0,0,72,131,236,40,72,131,61,212,108,0,0,0,116,7,232,157,195,255,255,235,5,232,182,235,255,255,72,131,196,40,195,144,72,131,236,120,199,68,36,68,0,0,0,0,131,61,133,131,0,0,0,116,17,232,198,246,255,255,72,141,13,33,91,0,0,232,90,157,255,255,72,199,5,255,159,0,0,0,0,0,0,184,0,0,2,0,72,137,5,35,160,0,0,72,141,13,45,87,0,0,232,103,252,255,255,131,248,0,117,34,131,61,67,131,0,0,0,15,133,94,9,0,0,72,141,13,253,86,0,0,232,73,252,255,255,131,248,0,15,132,73,9,0,0,72,131,61,72,108,0,0,0,116,83,72,131,61,94,131,0,0,0,117,71,72,139,5,101,108,0,0,72,139,64,64,72,139,21,154,128,0,0,72,131,194,1,185,2,0,0,0,76,141,5,58,131,0,0,255,208,72,137,68,36,112,72,131,124,36,112,0,124,10,72,131,61,35,131,0,0,0,117,10,232,28,255,255,255,233,242,8,0,0,235,0,235,43,72,139,5,140,159,0,0,72,137,5,5,131,0,0,72,139,5,78,128,0,0,72,131,192,7,72,131,224,248,72,3,5,111,159,0,0,72,137,5,104,159,0,0,76,139,5,225,130,0,0,72,139,21,42,128,0,0,49,192,137,193,232,49,254,255,255,72,139,5,202,130,0,0,72,139,13,19,128,0,0,198,4,8,0,232,186,254,255,255,139,5,128,107,0,0,137,5,142,130,0,0,139,5,120,107,0,0,137,5,126,130,0,0,15,182,5,111,107,0,0,137,5,109,130,0,0,199,5,115,107,0,0,0,0,0,0,199,5,177,158,0,0,0,0,0,0,72,139,5,122,130,0,0,72,137,68,36,104,72,139,68,36,104,128,56,0,15,132,62,8,0,0,235,0,72,139,68,36,104,15,190,8,49,192,131,249,0,136,68,36,67,116,83,72,139,68,36,104,15,190,8,176,1,131,249,13,136,68,36,66,116,56,72,139,68,36,104,15,190,8,176,1,131,249,10,136,68,36,66,116,37,72,139,68,36,104,15,190,8,176,1,131,249,32,136,68,36,66,116,18,72,139,68,36,104,15,190,0,131,248,9,15,148,192,136,68,36,66,138,68,36,66,136,68,36,67,138,68,36,67,168,1,117,2,235,16,72,139,68,36,104,72,131,192,1,72,137,68,36,104,235,128,72,139,68,36,104,72,137,68,36,88,72,139,68,36,88,15,190,8,49,192,131,249,0,136,68,36,65,116,56,72,139,68,36,88,15,190,8,49,192,131,249,32,136,68,36,65,116,37,72,139,68,36,88,15,190,8,49,192,131,249,13,136,68,36,65,116,18,72,139,68,36,88,15,190,0,131,248,10,15,149,192,136,68,36,65,138,68,36,65,168,1,117,2,235,18,235,0,72,139,68,36,88,72,131,192,1,72,137,68,36,88,235,153,72,139,68,36,88,72,137,68,36,96,72,139,68,36,96,15,190,8,49,192,131,249,0,136,68,36,64,116,37,72,139,68,36,96,15,190,8,49,192,131,249,13,136,68,36,64,116,18,72,139,68,36,96,15,190,0,131,248,10,15,149,192,136,68,36,64,138,68,36,64,168,1,117,2,235,18,235,0,72,139,68,36,96,72,131,192,1,72,137,68,36,96,235,172,235,0,72,139,76,36,88,49,192,72,59,76,36,96,136,68,36,63,115,18,72,139,68,36,88,15,190,0,131,248,32,15,148,192,136,68,36,63,138,68,36,63,168,1,117,2,235,18,235,0,72,139,68,36,88,72,131,192,1,72,137,68,36,88,235,192,72,139,76,36,104,72,141,21,29,84,0,0,65,184,6,0,0,0,232,61,147,255,255,131,248,0,15,149,192,52,255,36,1,15,182,192,137,68,36,72,139,5,94,128,0,0,51,68,36,72,131,248,0,116,15,72,139,68,36,96,72,137,68,36,104,233,25,254,255,255,139,5,64,128,0,0,35,68,36,72,131,248,0,116,14,72,139,68,36,104,72,131,192,6,72,137,68,36,104,235,0,72,139,76,36,104,72,141,21,11,84,0,0,65,184,9,0,0,0,232,216,146,255,255,131,248,0,117,10,199,5,121,156,0,0,1,0,0,0,72,139,68,36,88,72,59,68,36,96,114,15,72,139,68,36,96,72,137,68,36,104,233,185,253,255,255,72,139,76,36,104,72,141,21,86,83,0,0,65,184,9,0,0,0,232,151,146,255,255,131,248,0,117,26,139,68,36,68,131,192,1,137,68,36,68,131,248,1,126,5,233,212,5,0,0,233,192,5,0,0,72,139,76,36,104,72,141,21,140,83,0,0,65,184,7,0,0,0,232,97,146,255,255,131,248,0,117,27,72,139,76,36,88,72,141,21,4,156,0,0,232,107,145,255,255,72,137,68,36,88,233,135,5,0,0,72,139,76,36,104,72,141,21,254,82,0,0,65,184,11,0,0,0,232,42,146,255,255,131,248,0,15,133,42,1,0,0,72,139,76,36,88,72,141,21,117,127,0,0,232,48,145,255,255,72,137,68,36,88,72,139,76,36,88,49,192,72,59,76,36,96,136,68,36,62,115,18,72,139,68,36,88,15,190,0,131,248,32,15,148,192,136,68,36,62,138,68,36,62,168,1,117,2,235,16,72,139,68,36,88,72,131,192,1,72,137,68,36,88,235,194,72,139,76,36,88,72,141,21,29,127,0,0,232,220,144,255,255,72,137,68,36,88,72,139,76,36,88,49,192,72,59,76,36,96,136,68,36,61,115,18,72,139,68,36,88,15,190,0,131,248,32,15,148,192,136,68,36,61,138,68,36,61,168,1,117,2,235,16,72,139,68,36,88,72,131,192,1,72,137,68,36,88,235,194,72,139,76,36,88,72,141,21,197,126,0,0,232,136,144,255,255,72,137,68,36,88,129,61,185,126,0,0,64,1,0,0,114,54,129,61,173,126,0,0,0,0,1,0,119,42,129,61,157,126,0,0,200,0,0,0,114,30,129,61,145,126,0,0,0,0,1,0,119,18,131,61,132,126,0,0,15,114,9,131,61,123,126,0,0,32,118,37,139,5,103,103,0,0,137,5,117,126,0,0,139,5,95,103,0,0,137,5,101,126,0,0,15,182,5,86,103,0,0,137,5,84,126,0,0,233,59,4,0,0,72,139,76,36,104,72,141,21,223,81,0,0,65,184,10,0,0,0,232,224,144,255,255,131,248,0,15,133,193,2,0,0,72,139,68,36,88,15,190,0,131,248,35,15,133,125,1,0,0,72,139,68,36,88,72,131,192,1,72,137,68,36,88,72,139,76,36,88,72,141,84,36,84,232,169,142,255,255,72,137,68,36,88,72,139,76,36,88,72,141,84,36,80,232,149,142,255,255,72,137,68,36,88,72,139,76,36,88,72,141,84,36,76,232,129,142,255,255,72,137,68,36,88,15,182,5,206,102,0,0,131,248,8,126,22,139,68,36,84,15,182,13,190,102,0,0,131,233,8,211,224,137,68,36,56,235,24,139,68,36,84,15,182,21,168,102,0,0,185,8,0,0,0,41,209,211,232,137,68,36,56,139,68,36,56,15,182,13,143,102,0,0,211,224,137,68,36,52,15,182,5,133,102,0,0,131,248,8,126,22,139,68,36,80,15,182,13,117,102,0,0,131,233,8,211,224,137,68,36,48,235,24,139,68,36,80,15,182,21,95,102,0,0,185,8,0,0,0,41,209,211,232,137,68,36,48,139,68,36,52,139,84,36,48,15,182,13,66,102,0,0,211,226,137,209,9,200,137,68,36,44,15,182,5,52,102,0,0,131,248,8,126,22,139,68,36,76,15,182,13,36,102,0,0,131,233,8,211,224,137,68,36,40,235,24,139,68,36,76,15,182,21,14,102,0,0,185,8,0,0,0,41,209,211,232,137,68,36,40,139,68,36,44,139,84,36,40,15,182,13,241,101,0,0,211,226,137,209,9,200,137,5,241,101,0,0,72,139,76,36,88,49,192,72,59,76,36,96,136,68,36,39,115,18,72,139,68,36,88,15,190,0,131,248,32,15,148,192,136,68,36,39,138,68,36,39,168,1,117,2,235,16,72,139,68,36,88,72,131,192,1,72,137,68,36,88,235,194,235,0,72,139,68,36,88,72,59,68,36,96,15,131,25,1,0,0,72,139,76,36,88,232,127,245,255,255,131,248,0,15,132,230,0,0,0,72,131,61,126,101,0,0,0,116,99,72,131,61,156,124,0,0,0,116,31,72,139,5,155,101,0,0,72,139,64,72,72,139,13,136,124,0,0,255,208,72,199,5,123,124,0,0,0,0,0,0,72,139,5,124,101,0,0,72,139,64,64,72,139,21,177,121,0,0,185,2,0,0,0,76,141,5,93,124,0,0,255,208,72,137,68,36,112,72,131,124,36,112,0,125,11,72,199,5,67,124,0,0,0,0,0,0,235,43,72,139,5,178,152,0,0,72,137,5,51,124,0,0,72,139,5,116,121,0,0,72,131,192,7,72,131,224,248,72,3,5,149,152,0,0,72,137,5,142,152,0,0,131,61,59,152,0,0,0,116,26,76,139,5,78,121,0,0,72,141,13,150,83,0,0,72,141,21,128,152,0,0,232,139,149,255,255,72,139,5,52,121,0,0,137,5,102,152,0,0,76,139,5,223,123,0,0,72,139,21,32,121,0,0,49,192,137,193,232,39,247,255,255,232,194,247,255,255,235,30,131,61,237,151,0,0,0,116,19,72,141,13,46,85,0,0,72,141,21,57,152,0,0,232,68,149,255,255,235,0,235,0,232,155,238,255,255,233,88,1,0,0,72,139,68,36,88,72,59,68,36,96,15,131,70,1,0,0,72,139,76,36,104,72,141,21,214,78,0,0,65,184,6,0,0,0,232,239,141,255,255,131,248,0,15,133,38,1,0,0,72,139,68,36,88,72,137,5,170,151,0,0,72,139,76,36,88,49,192,72,59,76,36,96,136,68,36,38,115,75,72,139,68,36,88,15,190,8,49,192,131,249,0,136,68,36,38,116,56,72,139,68,36,88,15,190,8,49,192,131,249,32,136,68,36,38,116,37,72,139,68,36,88,15,190,8,49,192,131,249,13,136,68,36,38,116,18,72,139,68,36,88,15,190,0,131,248,10,15,149,192,136,68,36,38,138,68,36,38,168,1,117,2,235,62,72,139,68,36,88,15,190,0,131,248,92,117,28,72,139,68,36,88,15,190,64,1,131,248,32,117,14,72,139,68,36,88,72,131,192,1,72,137,68,36,88,235,0,72,139,68,36,88,72,131,192,1,72,137,68,36,88,233,91,255,255,255,235,0,72,139,76,36,88,49,192,72,59,76,36,96,136,68,36,37,115,18,72,139,68,36,88,15,190,0,131,248,32,15,148,192,136,68,36,37,138,68,36,37,168,1,117,2,235,16,72,139,68,36,88,72,131,192,1,72,137,68,36,88,235,194,72,139,68,36,88,15,190,0,131,248,0,116,38,72,139,68,36,88,15,190,0,131,248,13,116,25,72,139,68,36,88,15,190,0,131,248,10,116,12,72,139,68,36,88,72,137,5,138,150,0,0,235,0,235,0,235,0,235,0,235,0,72,139,68,36,96,72,137,68,36,104,233,180,247,255,255,235,0,235,0,72,131,61,109,150,0,0,0,117,14,72,141,5,180,74,0,0,72,137,5,93,150,0,0,131,61,190,121,0,0,0,117,22,15,190,5,28,75,0,0,131,248,1,117,10,199,5,30,150,0,0,1,0,0,0,72,131,196,120,195,102,15,31,132,0,0,0,0,0,72,131,236,72,72,131,61,180,98,0,0,0,117,22,72,199,5,55,150,0,0,0,0,0,0,72,199,5,140,121,0,0,0,0,16,0,131,61,109,121,0,0,0,117,77,72,131,61,139,98,0,0,0,116,67,72,199,5,30,150,0,0,0,0,0,0,72,139,5,167,98,0,0,49,201,186,2,0,0,0,65,184,30,0,0,0,76,141,13,3,150,0,0,255,80,40,72,137,68,36,64,72,131,124,36,64,0,125,11,72,199,5,232,149,0,0,0,0,0,0,235,0,72,139,5,223,149,0,0,72,137,5,24,121,0,0,72,131,61,16,121,0,0,0,15,132,220,2,0,0,72,139,5,195,149,0,0,199,64,4,0,0,0,0,72,139,5,181,149,0,0,199,0,0,0,0,0,72,139,5,232,120,0,0,72,131,192,8,72,137,5,221,120,0,0,72,139,5,214,120,0,0,72,137,68,36,56,72,139,68,36,56,199,0,2,0,0,0,139,21,184,120,0,0,185,19,0,0,0,184,28,0,0,0,131,250,0,15,69,200,72,139,68,36,56,137,72,4,72,139,76,36,56,72,131,193,8,72,141,21,22,76,0,0,65,184,11,0,0,0,232,237,138,255,255,131,61,126,120,0,0,0,116,31,72,139,76,36,56,72,131,193,8,72,131,193,10,72,141,21,197,76,0,0,65,184,10,0,0,0,232,197,138,255,255,72,139,68,36,56,139,72,4,131,193,7,131,225,248,72,139,5,80,120,0,0,137,201,72,1,200,72,137,5,68,120,0,0,72,131,61,196,148,0,0,0,15,132,5,1,0,0,72,139,5,183,148,0,0,72,137,68,36,40,72,139,68,36,40,15,190,8,49,192,131,249,0,136,68,36,39,116,37,72,139,68,36,40,15,190,8,49,192,131,249,13,136,68,36,39,116,18,72,139,68,36,40,15,190,0,131,248,10,15,149,192,136,68,36,39,138,68,36,39,168,1,117,2,235,18,235,0,72,139,68,36,40,72,131,192,1,72,137,68,36,40,235,172,72,139,5,207,119,0,0,72,137,68,36,56,72,139,68,36,56,199,0,1,0,0,0,72,139,68,36,40,72,131,192,9,72,139,13,55,148,0,0,72,41,200,137,193,72,139,68,36,56,137,72,4,72,139,68,36,40,72,139,13,30,148,0,0,72,41,200,65,137,192,72,139,21,17,148,0,0,72,139,76,36,56,72,131,193,8,232,219,137,255,255,72,139,68,36,56,72,139,76,36,40,72,139,21,242,147,0,0,72,41,209,198,68,8,8,0,72,139,68,36,56,139,72,4,131,193,7,131,225,248,72,139,5,77,119,0,0,137,201,72,1,200,72,137,5,65,119,0,0,72,139,68,36,56,72,131,192,8,72,137,5,185,147,0,0,72,131,61,73,96,0,0,0,15,133,211,0,0,0,72,131,61,251,95,0,0,0,116,7,232,148,201,255,255,235,5,232,61,223,255,255,72,139,5,6,119,0,0,72,137,68,36,48,72,139,68,36,48,199,0,6,0,0,0,72,139,68,36,48,199,64,8,24,0,0,0,72,139,68,36,48,199,64,12,0,0,0,0,72,131,61,182,95,0,0,0,116,20,72,139,76,36,48,72,131,193,16,232,150,203,255,255,137,68,36,32,235,18,72,139,76,36,48,72,131,193,16,232,114,160,255,255,137,68,36,32,139,68,36,32,137,5,28,147,0,0,131,61,21,147,0,0,0,118,73,72,139,68,36,48,72,131,192,16,72,137,5,235,146,0,0,139,5,253,146,0,0,72,107,192,24,72,131,192,16,137,193,72,139,68,36,48,137,72,4,72,139,68,36,48,139,72,4,131,193,7,131,225,248,72,139,5,94,118,0,0,137,201,72,1,200,72,137,5,82,118,0,0,235,14,232,139,182,255,255,49,192,137,193,232,178,172,255,255,72,139,5,155,111,0,0,72,37,0,0,224,255,72,137,5,142,111,0,0,72,131,196,72,195,102,15,31,132,0,0,0,0,0,72,129,236,152,0,0,0,199,68,36,108,0,0,0,0,199,68,36,104,0,0,0,0,72,131,61,65,118,0,0,0,15,132,8,8,0,0,72,139,5,52,118,0,0,72,137,68,36,80,49,192,131,61,226,117,0,0,0,136,68,36,63,117,31,49,192,131,124,36,104,0,136,68,36,63,117,18,72,139,68,36,80,15,190,0,131,248,0,15,149,192,136,68,36,63,138,68,36,63,168,1,117,5,233,191,7,0,0,235,0,72,139,68,36,80,15,190,8,49,192,131,249,0,136,68,36,62,116,83,72,139,68,36,80,15,190,8,176,1,131,249,13,136,68,36,61,116,56,72,139,68,36,80,15,190,8,176,1,131,249,10,136,68,36,61,116,37,72,139,68,36,80,15,190,8,176,1,131,249,32,136,68,36,61,116,18,72,139,68,36,80,15,190,0,131,248,9,15,148,192,136,68,36,61,138,68,36,61,136,68,36,62,138,68,36,62,168,1,117,2,235,16,72,139,68,36,80,72,131,192,1,72,137,68,36,80,235,128,72,139,68,36,80,72,137,68,36,64,72,139,68,36,64,15,190,8,49,192,131,249,0,136,68,36,60,116,56,72,139,68,36,64,15,190,8,49,192,131,249,32,136,68,36,60,116,37,72,139,68,36,64,15,190,8,49,192,131,249,13,136,68,36,60,116,18,72,139,68,36,64,15,190,0,131,248,10,15,149,192,136,68,36,60,138,68,36,60,168,1,117,2,235,18,235,0,72,139,68,36,64,72,131,192,1,72,137,68,36,64,235,153,72,139,68,36,64,72,137,68,36,72,72,139,68,36,72,15,190,8,49,192,131,249,0,136,68,36,59,116,37,72,139,68,36,72,15,190,8,49,192,131,249,13,136,68,36,59,116,18,72,139,68,36,72,15,190,0,131,248,10,15,149,192,136,68,36,59,138,68,36,59,168,1,117,2,235,18,235,0,72,139,68,36,72,72,131,192,1,72,137,68,36,72,235,172,235,0,72,139,76,36,64,49,192,72,59,76,36,72,136,68,36,58,115,18,72,139,68,36,64,15,190,0,131,248,32,15,148,192,136,68,36,58,138,68,36,58,168,1,117,2,235,18,235,0,72,139,68,36,64,72,131,192,1,72,137,68,36,64,235,192,72,139,76,36,80,72,141,21,170,71,0,0,65,184,6,0,0,0,232,202,134,255,255,131,248,0,15,149,192,52,255,36,1,15,182,192,137,68,36,100,72,139,68,36,64,72,59,68,36,72,115,15,139,5,223,115,0,0,51,68,36,100,131,248,0,116,15,72,139,68,36,72,72,137,68,36,80,233,224,253,255,255,139,5,193,115,0,0,35,68,36,100,131,248,0,116,14,72,139,68,36,80,72,131,192,6,72,137,68,36,80,235,0,72,139,76,36,80,72,141,21,161,71,0,0,65,184,6,0,0,0,232,89,134,255,255,131,248,0,15,133,140,5,0,0,235,0,72,139,76,36,64,232,148,236,255,255,131,248,0,15,132,87,5,0,0,76,141,68,36,112,49,192,137,193,186,16,0,0,0,232,8,239,255,255,199,132,36,140,0,0,0,0,0,0,0,15,182,68,36,112,131,248,31,117,43,15,182,68,36,113,61,139,0,0,0,117,31,72,139,13,208,112,0,0,72,131,233,4,186,4,0,0,0,76,141,132,36,140,0,0,0,232,202,238,255,255,235,90,15,182,68,36,112,131,248,71,117,78,15,182,68,36,113,131,248,85,117,68,15,182,68,36,114,131,248,68,117,58,15,182,68,36,120,131,248,120,117,48,15,182,68,36,116,15,182,76,36,117,193,225,8,9,200,131,192,7,131,224,248,15,182,76,36,118,15,182,84,36,119,193,226,8,9,209,193,225,4,1,200,137,132,36,140,0,0,0,235,0,72,131,61,230,91,0,0,0,15,132,156,0,0,0,131,188,36,140,0,0,0,0,116,41,139,132,36,140,0,0,0,5,255,15,0,0,193,232,12,137,192,137,194,49,201,49,192,65,137,192,232,183,172,255,255,72,137,132,36,144,0,0,0,235,12,72,199,132,36,144,0,0,0,0,0,0,0,72,139,21,10,112,0,0,72,129,194,255,15,0,0,72,193,234,12,49,201,49,192,65,137,192,232,131,172,255,255,72,137,5,12,143,0,0,72,131,188,36,144,0,0,0,0,116,15,72,139,132,36,144,0,0,0,72,137,68,36,48,235,12,72,139,5,235,142,0,0,72,137,68,36,48,72,139,68,36,48,72,137,132,36,128,0,0,0,233,150,0,0,0,72,139,5,45,114,0,0,72,137,132,36,128,0,0,0,131,188,36,140,0,0,0,0,116,64,72,139,5,20,114,0,0,72,137,132,36,144,0,0,0,139,132,36,140,0,0,0,5,255,15,0,0,37,0,240,255,255,137,192,72,3,5,242,113,0,0,72,137,5,235,113,0,0,72,139,5,228,113,0,0,72,137,5,125,142,0,0,235,59,72,199,132,36,144,0,0,0,0,0,0,0,72,139,5,200,113,0,0,72,137,5,97,142,0,0,72,139,5,58,111,0,0,72,5,255,15,0,0,72,37,0,240,255,255,72,3,5,167,113,0,0,72,137,5,160,113,0,0,235,0,72,131,61,54,142,0,0,0,15,132,85,3,0,0,131,61,237,141,0,0,0,116,26,76,139,5,0,111,0,0,72,141,13,107,73,0,0,72,141,21,50,142,0,0,232,61,139,255,255,76,139,5,6,142,0,0,72,139,21,223,110,0,0,49,192,137,193,232,230,236,255,255,72,131,188,36,144,0,0,0,0,116,56,131,61,168,141,0,0,0,116,19,139,148,36,140,0,0,0,72,141,13,75,73,0,0,232,255,138,255,255,68,139,132,36,140,0,0,0,72,139,148,36,144,0,0,0,72,139,13,184,141,0,0,232,83,184,255,255,72,139,132,36,128,0,0,0,15,182,0,61,208,0,0,0,117,96,72,139,132,36,128,0,0,0,15,182,64,1,131,248,13,117,79,72,139,132,36,128,0,0,0,15,182,64,2,61,254,0,0,0,117,60,72,139,132,36,128,0,0,0,15,182,64,3,61,237,0,0,0,117,41,131,61,39,141,0,0,0,116,12,72,141,13,119,72,0,0,232,133,138,255,255,72,139,132,36,128,0,0,0,72,137,5,62,141,0,0,233,246,1,0,0,72,139,132,36,128,0,0,0,15,182,0,131,248,68,117,17,72,139,132,36,128,0,0,0,15,182,64,1,131,248,83,116,33,72,139,132,36,128,0,0,0,15,182,0,131,248,71,117,116,72,139,132,36,128,0,0,0,15,182,64,1,131,248,85,117,99,72,139,132,36,128,0,0,0,15,182,64,2,131,248,68,117,82,72,139,132,36,128,0,0,0,15,182,64,3,131,248,84,117,65,131,61,154,140,0,0,0,116,36,72,139,132,36,128,0,0,0,68,15,182,64,1,72,139,132,36,128,0,0,0,15,182,16,72,141,13,116,68,0,0,232,224,137,255,255,72,139,132,36,128,0,0,0,72,137,5,153,140,0,0,233,79,1,0,0,72,131,61,228,111,0,0,0,15,132,54,1,0,0,72,139,5,215,111,0,0,72,137,68,36,88,72,139,68,36,88,199,0,3,0,0,0,72,139,68,36,72,72,131,192,16,72,139,76,36,64,72,41,200,72,131,192,1,137,193,72,139,68,36,88,137,72,4,72,131,188,36,144,0,0,0,0,116,14,72,139,132,36,144,0,0,0,137,68,36,44,235,11,72,139,5,56,140,0,0,137,68,36,44,139,76,36,44,72,139,68,36,88,137,72,8,72,131,188,36,144,0,0,0,0,116,21,72,139,132,36,144,0,0,0,3,132,36,140,0,0,0,137,68,36,40,235,20,72,139,5,1,140,0,0,72,139,13,218,108,0,0,1,200,137,68,36,40,139,76,36,40,72,139,68,36,88,137,72,12,72,139,68,36,72,72,139,76,36,64,72,41,200,65,137,192,72,139,84,36,64,72,139,76,36,88,72,131,193,16,232,117,129,255,255,72,139,68,36,88,72,139,76,36,72,72,139,84,36,64,72,41,209,198,68,8,16,0,131,61,107,139,0,0,2,118,20,72,139,68,36,88,139,80,8,72,141,13,131,70,0,0,232,193,136,255,255,72,139,68,36,88,139,72,4,131,193,7,131,225,248,72,139,5,204,110,0,0,137,201,72,1,200,72,137,5,192,110,0,0,72,131,61,32,139,0,0,0,117,12,72,139,68,36,88,72,137,5,18,139,0,0,235,0,139,68,36,108,131,192,1,137,68,36,108,235,0,72,131,61,179,87,0,0,0,116,100,72,131,188,36,144,0,0,0,0,116,89,131,61,239,107,0,0,0,116,80,139,5,231,107,0,0,131,192,255,137,5,222,107,0,0,72,139,5,183,87,0,0,72,139,64,48,139,13,205,107,0,0,137,202,72,141,13,196,103,0,0,72,193,226,4,72,1,209,72,139,81,8,139,13,179,107,0,0,65,137,200,72,141,13,169,103,0,0,73,193,224,4,76,1,193,72,139,9,255,208,235,0,232,102,234,255,255,235,30,131,61,145,138,0,0,0,116,19,72,141,13,210,71,0,0,72,141,21,221,138,0,0,232,232,135,255,255,235,0,235,0,72,139,68,36,72,72,137,68,36,80,233,6,248,255,255,235,0,131,124,36,108,0,117,15,131,124,36,104,0,117,8,199,68,36,104,1,0,0,0,131,124,36,108,0,117,92,131,124,36,104,1,117,85,199,68,36,104,2,0,0,0,139,21,185,109,0,0,72,141,5,190,65,0,0,72,141,13,86,65,0,0,131,250,0,72,15,69,193,72,137,68,36,64,72,139,68,36,64,68,139,5,147,109,0,0,185,12,0,0,0,186,16,0,0,0,65,131,248,0,15,69,202,72,99,201,72,1,200,72,137,68,36,72,233,236,249,255,255,72,129,196,152,0,0,0,195,102,144,72,131,236,120,68,137,68,36,112,72,137,84,36,104,72,137,76,36,96,72,139,68,36,104,139,76,36,112,72,1,200,72,137,68,36,88,72,199,68,36,72,0,0,0,0,72,139,5,76,109,0,0,72,137,68,36,64,72,131,61,119,86,0,0,0,116,32,72,139,68,36,104,72,193,232,48,72,131,248,0,116,30,72,139,68,36,104,72,193,232,48,72,61,255,255,0,0,116,13,199,68,36,116,0,0,0,0,233,217,2,0,0,72,139,68,36,104,72,37,0,240,255,255,72,137,68,36,104,72,139,68,36,96,72,37,0,240,255,255,72,137,68,36,96,72,139,68,36,104,72,59,68,36,88,15,131,32,2,0,0,72,139,5,17,86,0,0,72,139,76,36,104,72,193,233,39,72,129,225,255,1,0,0,72,193,225,3,72,1,200,72,137,68,36,80,72,139,68,36,80,72,131,56,0,117,81,72,131,61,186,85,0,0,0,116,12,232,83,166,255,255,72,137,68,36,56,235,10,232,87,200,255,255,72,137,68,36,56,72,139,68,36,56,72,139,76,36,80,72,137,1,72,131,248,0,117,13,199,68,36,116,0,0,0,0,233,59,2,0,0,72,139,68,36,80,72,139,8,72,131,201,3,72,137,8,235,0,72,139,68,36,80,72,139,0,72,37,0,240,255,255,72,137,68,36,80,72,139,68,36,80,72,139,76,36,104,72,193,233,30,72,129,225,255,1,0,0,72,193,225,3,72,1,200,72,137,68,36,80,72,139,68,36,80,72,131,56,0,117,81,72,131,61,42,85,0,0,0,116,12,232,195,165,255,255,72,137,68,36,48,235,10,232,199,199,255,255,72,137,68,36,48,72,139,68,36,48,72,139,76,36,80,72,137,1,72,131,248,0,117,13,199,68,36,116,0,0,0,0,233,171,1,0,0,72,139,68,36,80,72,139,8,72,131,201,3,72,137,8,235,0,72,139,68,36,80,72,139,0,72,37,0,240,255,255,72,137,68,36,80,72,139,68,36,80,72,139,76,36,104,72,193,233,21,72,129,225,255,1,0,0,72,193,225,3,72,1,200,72,137,68,36,80,72,139,68,36,80,72,131,56,0,116,20,72,139,68,36,80,72,139,0,72,37,128,0,0,0,72,131,248,0,116,81,72,131,61,134,84,0,0,0,116,12,232,31,165,255,255,72,137,68,36,40,235,10,232,35,199,255,255,72,137,68,36,40,72,139,68,36,40,72,139,76,36,80,72,137,1,72,131,248,0,117,13,199,68,36,116,0,0,0,0,233,7,1,0,0,72,139,68,36,80,72,139,8,72,131,201,3,72,137,8,235,0,72,139,68,36,80,72,139,0,72,37,0,240,255,255,72,137,68,36,80,72,139,68,36,80,72,139,76,36,104,72,193,233,12,72,129,225,255,1,0,0,72,193,225,3,72,1,200,72,137,68,36,80,72,139,68,36,80,72,131,56,0,117,23,72,139,76,36,72,72,139,68,36,80,72,137,8,72,139,68,36,80,72,137,68,36,72,235,0,72,139,68,36,104,72,5,0,16,0,0,72,137,68,36,104,233,208,253,255,255,72,139,68,36,96,72,59,68,36,64,117,14,72,139,5,173,106,0,0,72,137,68,36,32,235,10,72,139,68,36,96,72,137,68,36,32,72,139,68,36,32,139,76,36,112,72,1,200,72,131,232,1,72,37,0,240,255,255,72,137,68,36,88,72,131,124,36,72,0,116,58,72,139,68,36,72,72,139,0,72,137,68,36,80,72,139,76,36,88,72,131,201,3,72,139,68,36,72,72,137,8,72,139,68,36,88,72,45,0,16,0,0,72,137,68,36,88,72,139,68,36,80,72,137,68,36,72,235,190,199,68,36,116,1,0,0,0,139,68,36,116,72,131,196,120,195,102,102,102,102,102,46,15,31,132,0,0,0,0,0,72,131,236,104,68,137,76,36,96,76,137,68,36,88,137,84,36,84,137,76,36,80,72,139,68,36,88,72,137,68,36,64,131,124,36,96,0,116,10,72,131,61,113,103,0,0,0,117,13,199,68,36,100,1,0,0,0,233,234,2,0,0,131,61,63,134,0,0,1,118,36,139,76,36,96,76,139,76,36,88,68,139,68,36,84,139,84,36,80,72,137,224,137,72,32,72,141,13,177,64,0,0,232,133,131,255,255,139,68,36,96,72,139,76,36,88,72,129,225,255,15,0,0,72,1,200,72,5,255,15,0,0,72,37,0,240,255,255,137,68,36,60,72,131,61,154,82,0,0,0,15,132,139,0,0,0,72,139,68,36,88,72,59,5,200,98,0,0,118,66,139,68,36,60,193,232,12,137,192,137,194,49,201,49,192,65,137,192,232,111,163,255,255,72,137,68,36,64,72,131,248,0,116,25,68,139,68,36,60,72,139,84,36,88,72,139,76,36,64,232,192,251,255,255,131,248,0,117,5,233,32,2,0,0,235,54,76,139,68,36,88,73,129,224,0,240,255,255,139,68,36,60,193,232,12,137,192,137,194,185,2,0,0,0,232,35,163,255,255,72,131,248,0,117,5,233,242,1,0,0,72,139,68,36,88,72,137,68,36,64,233,149,1,0,0,72,129,124,36,88,0,0,4,0,115,5,233,211,1,0,0,72,139,68,36,88,72,59,5,45,98,0,0,118,67,68,139,68,36,60,72,139,84,36,88,72,139,13,202,104,0,0,232,69,251,255,255,131,248,0,117,5,233,165,1,0,0,72,139,5,180,104,0,0,72,137,68,36,64,139,68,36,60,72,3,5,164,104,0,0,72,137,5,157,104,0,0,233,50,1,0,0,72,139,68,36,64,139,76,36,60,72,1,200,72,5,255,15,0,0,72,37,0,240,255,255,72,137,68,36,72,72,139,5,116,104,0,0,72,59,68,36,72,115,12,72,139,68,36,72,72,137,5,97,104,0,0,199,68,36,56,0,0,0,0,49,192,72,131,61,159,132,0,0,0,136,68,36,55,116,17,139,68,36,56,59,5,167,132,0,0,15,146,192,136,68,36,55,138,68,36,55,168,1,117,5,233,195,0,0,0,72,139,5,116,132,0,0,139,76,36,56,72,107,201,24,72,1,200,72,139,0,72,59,68,36,88,15,135,145,0,0,0,72,139,5,84,132,0,0,139,76,36,56,72,107,201,24,72,1,200,72,139,0,72,139,13,63,132,0,0,139,84,36,56,72,107,210,24,72,1,209,72,3,65,8,72,59,68,36,88,118,95,72,139,5,34,132,0,0,139,76,36,56,72,107,201,24,72,1,200,131,120,16,1,117,67,72,139,5,10,132,0,0,139,76,36,56,72,107,201,24,72,1,200,72,139,0,72,139,13,245,131,0,0,139,84,36,56,72,107,210,24,72,1,209,72,3,65,8,72,139,76,36,88,72,129,225,0,240,255,255,139,84,36,60,72,1,209,72,57,200,115,2,235,102,235,18,235,0,139,68,36,56,131,192,1,137,68,36,56,233,15,255,255,255,235,0,235,0,131,124,36,84,0,116,22,76,139,68,36,64,139,68,36,84,137,194,139,68,36,80,137,193,232,215,226,255,255,139,68,36,96,59,68,36,84,118,29,68,139,68,36,96,68,43,68,36,84,72,139,76,36,64,139,68,36,84,72,1,193,49,210,232,160,121,255,255,199,68,36,100,1,0,0,0,235,30,68,139,68,36,96,72,139,84,36,88,72,141,13,32,61,0,0,232,208,128,255,255,199,68,36,100,0,0,0,0,139,68,36,100,72,131,196,104,195,102,102,102,102,102,102,46,15,31,132,0,0,0,0,0,72,129,236,152,0,0,0,72,141,5,34,80,0,0,72,137,132,36,136,0,0,0,72,141,5,19,80,0,0,72,5,241,1,0,0,72,137,132,36,128,0,0,0,232,144,161,255,255,102,199,5,103,131,0,0,0,0,72,131,61,31,131,0,0,0,116,36,72,139,5,22,131,0,0,15,190,0,131,248,0,116,21,72,139,13,7,131,0,0,232,130,223,255,255,131,248,0,15,133,139,0,0,0,72,141,13,84,58,0,0,232,109,223,255,255,131,248,0,117,122,199,5,190,130,0,0,0,0,0,0,102,131,61,22,131,0,0,0,116,21,72,141,13,252,60,0,0,72,141,21,6,131,0,0,232,17,128,255,255,235,12,72,141,13,205,60,0,0,232,3,128,255,255,72,131,61,59,79,0,0,0,117,43,72,131,61,97,130,0,0,0,116,33,72,131,61,95,130,0,0,0,116,23,198,5,158,130,0,0,1,199,132,36,148,0,0,0,1,0,0,0,233,163,9,0,0,199,132,36,148,0,0,0,0,0,0,0,233,147,9,0,0,76,139,132,36,136,0,0,0,49,192,137,193,186,0,16,0,0,232,104,225,255,255,72,139,132,36,128,0,0,0,15,183,64,13,61,85,170,0,0,15,133,237,3,0,0,72,139,140,36,128,0,0,0,72,131,193,17,72,141,21,194,57,0,0,65,184,4,0,0,0,232,83,120,255,255,131,248,0,15,133,198,3,0,0,72,139,132,36,128,0,0,0,15,183,64,21,61,12,2,0,0,124,29,72,139,132,36,128,0,0,0,72,139,64,103,72,3,5,244,98,0,0,72,193,232,32,72,131,248,0,116,17,72,141,13,77,59,0,0,232,46,127,255,255,233,153,8,0,0,198,5,226,129,0,0,5,199,5,168,129,0,0,0,0,0,0,131,61,165,129,0,0,0,116,19,72,141,13,109,61,0,0,72,141,21,241,129,0,0,232,252,126,255,255,72,131,61,148,129,0,0,0,117,46,72,131,61,42,78,0,0,0,116,12,232,195,158,255,255,72,137,68,36,72,235,12,184,0,0,9,0,72,137,68,36,72,235,0,72,139,68,36,72,72,137,5,100,129,0,0,72,131,61,252,77,0,0,0,15,132,64,1,0,0,199,68,36,84,0,0,0,0,72,131,61,78,129,0,0,0,116,109,235,0,72,139,5,67,129,0,0,72,99,76,36,84,15,190,12,8,49,192,131,249,0,136,68,36,71,116,53,72,139,5,40,129,0,0,72,99,76,36,84,15,190,12,8,49,192,131,249,13,136,68,36,71,116,26,72,139,5,13,129,0,0,72,99,76,36,84,15,190,4,8,131,248,10,15,149,192,136,68,36,71,138,68,36,71,168,1,117,2,235,15,235,0,139,68,36,84,131,192,1,137,68,36,84,235,151,235,0,72,131,61,207,128,0,0,0,15,133,177,0,0,0,139,68,36,84,5,1,16,0,0,137,68,36,84,72,139,5,133,77,0,0,72,139,64,40,139,76,36,84,129,193,255,15,0,0,193,249,12,76,99,193,185,1,0,0,0,186,2,0,0,0,76,141,13,144,128,0,0,255,208,72,137,68,36,120,72,131,124,36,120,0,125,103,72,199,5,118,128,0,0,0,0,0,0,72,139,5,63,77,0,0,72,139,64,40,139,76,36,84,129,193,255,15,0,0,193,249,12,76,99,193,49,201,186,2,0,0,0,76,141,13,77,128,0,0,255,208,72,137,68,36,120,72,131,124,36,120,0,124,17,72,139,5,55,128,0,0,72,193,232,32,72,131,248,0,116,17,72,141,13,168,56,0,0,232,129,125,255,255,233,236,6,0,0,235,0,235,0,235,0,72,139,132,36,128,0,0,0,128,56,0,117,11,72,139,132,36,128,0,0,0,198,0,4,72,139,13,247,127,0,0,49,210,65,184,0,16,0,0,232,250,117,255,255,68,15,182,5,195,78,0,0,65,131,192,17,72,139,148,36,128,0,0,0,72,139,13,207,127,0,0,72,129,193,241,1,0,0,232,163,117,255,255,72,139,5,188,127,0,0,102,199,128,252,1,0,0,0,1,72,139,5,172,127,0,0,102,199,128,242,1,0,0,1,0,72,139,5,156,127,0,0,102,199,128,250,1,0,0,255,255,72,139,5,140,127,0,0,198,128,16,2,0,0,255,72,131,61,133,127,0,0,0,15,132,210,0,0,0,72,139,5,112,127,0,0,72,5,0,16,0,0,72,137,68,36,96,72,139,68,36,96,137,193,72,139,5,87,127,0,0,137,136,40,2,0,0,199,68,36,84,0,0,0,0,49,192,129,124,36,84,255,127,0,0,136,68,36,70,125,80,72,139,5,58,127,0,0,72,99,76,36,84,15,190,12,8,49,192,131,249,0,136,68,36,70,116,53,72,139,5,31,127,0,0,72,99,76,36,84,15,190,12,8,49,192,131,249,13,136,68,36,70,116,26,72,139,5,4,127,0,0,72,99,76,36,84,15,190,4,8,131,248,10,15,149,192,136,68,36,70,138,68,36,70,168,1,117,2,235,44,72,139,5,224,126,0,0,72,99,76,36,84,138,20,8,72,139,68,36,96,72,99,76,36,84,136,20,8,139,68,36,84,131,192,1,137,68,36,84,233,106,255,255,255,72,139,68,36,96,72,99,76,36,84,198,4,8,0,72,139,132,36,128,0,0,0,68,139,72,111,72,139,132,36,128,0,0,0,76,139,64,103,72,139,132,36,128,0,0,0,139,80,111,72,139,132,36,128,0,0,0,15,182,8,131,193,1,193,225,9,232,220,247,255,255,131,248,0,117,5,233,50,5,0,0,72,139,132,36,128,0,0,0,72,139,64,103,72,5,0,2,0,0,72,137,5,97,126,0,0,233,52,5,0,0,72,139,140,36,136,0,0,0,72,141,21,232,53,0,0,65,184,4,0,0,0,232,106,116,255,255,131,248,0,15,133,161,2,0,0,72,139,132,36,136,0,0,0,15,183,64,18,131,248,3,116,21,72,139,132,36,136,0,0,0,15,183,64,18,131,248,62,15,133,123,2,0,0,72,139,132,36,136,0,0,0,15,182,80,4,184,3,0,0,0,185,4,0,0,0,131,250,2,15,68,193,136,5,249,125,0,0,131,61,198,125,0,0,0,116,42,15,182,13,233,125,0,0,186,32,0,0,0,184,64,0,0,0,131,249,4,15,68,208,72,141,13,150,57,0,0,76,141,5,251,125,0,0,232,6,123,255,255,15,182,5,191,125,0,0,131,248,4,15,133,13,1,0,0,72,139,132,36,136,0,0,0,72,139,64,24,72,137,5,155,125,0,0,72,139,132,36,136,0,0,0,72,139,140,36,136,0,0,0,72,3,65,32,72,137,68,36,96,199,68,36,84,0,0,0,0,49,192,131,61,213,96,0,0,0,136,68,36,69,117,73,139,76,36,84,72,139,132,36,136,0,0,0,15,183,80,56,49,192,57,209,136,68,36,69,125,47,72,139,68,36,96,72,139,140,36,136,0,0,0,15,183,73,54,72,99,201,72,1,200,72,141,13,251,73,0,0,72,129,193,0,16,0,0,72,57,200,15,146,192,136,68,36,69,138,68,36,69,168,1,117,2,235,114,72,139,68,36,96,131,56,1,117,58,72,139,68,36,96,72,139,64,40,65,137,193,72,139,68,36,96,76,139,64,16,72,139,68,36,96,72,139,64,32,137,194,72,139,68,36,96,72,139,64,8,137,193,232,54,246,255,255,131,248,0,117,5,233,140,3,0,0,235,0,139,68,36,84,131,192,1,137,68,36,84,72,139,132,36,136,0,0,0,15,183,72,54,72,139,68,36,96,72,99,201,72,1,200,72,137,68,36,96,233,44,255,255,255,233,4,1,0,0,72,139,132,36,136,0,0,0,139,64,24,72,137,5,143,124,0,0,72,139,132,36,136,0,0,0,72,139,140,36,136,0,0,0,139,73,28,72,1,200,72,137,68,36,96,199,68,36,84,0,0,0,0,49,192,131,61,199,95,0,0,0,136,68,36,68,117,73,139,76,36,84,72,139,132,36,136,0,0,0,15,183,80,44,49,192,57,209,136,68,36,68,125,47,72,139,68,36,96,72,139,140,36,136,0,0,0,15,183,73,42,72,99,201,72,1,200,72,141,13,237,72,0,0,72,129,193,0,16,0,0,72,57,200,15,146,192,136,68,36,68,138,68,36,68,168,1,117,2,235,107,72,139,68,36,96,131,56,1,117,51,72,139,68,36,96,68,139,72,20,72,139,68,36,96,139,64,8,65,137,192,72,139,68,36,96,139,80,16,72,139,68,36,96,139,72,4,232,47,245,255,255,131,248,0,117,5,233,133,2,0,0,235,0,139,68,36,84,131,192,1,137,68,36,84,72,139,132,36,136,0,0,0,15,183,72,42,72,139,68,36,96,72,99,201,72,1,200,72,137,68,36,96,233,51,255,255,255,235,0,233,110,2,0,0,72,139,132,36,136,0,0,0,15,183,0,61,77,90,0,0,15,133,39,2,0,0,72,139,132,36,136,0,0,0,72,139,140,36,136,0,0,0,139,73,60,129,60,8,80,69,0,0,15,133,7,2,0,0,72,139,132,36,136,0,0,0,72,139,140,36,136,0,0,0,139,73,60,15,183,68,8,4,61,76,1,0,0,116,35,72,139,132,36,136,0,0,0,72,139,140,36,136,0,0,0,139,73,60,15,183,68,8,4,61,100,134,0,0,15,133,197,1,0,0,72,139,132,36,136,0,0,0,72,139,140,36,136,0,0,0,139,73,60,72,1,200,72,137,68,36,112,72,139,68,36,112,15,183,80,24,184,2,0,0,0,185,4,0,0,0,129,250,11,2,0,0,15,68,193,136,5,235,122,0,0,15,182,5,228,122,0,0,131,248,4,117,15,72,139,68,36,112,72,139,64,48,137,68,36,64,235,12,72,139,68,36,112,139,64,52,137,68,36,64,139,68,36,64,137,192,72,137,68,36,88,72,139,76,36,88,72,139,68,36,112,139,64,40,72,1,200,72,137,5,154,122,0,0,131,61,111,122,0,0,0,116,42,15,182,13,146,122,0,0,186,32,0,0,0,184,64,0,0,0,131,249,4,15,68,208,72,141,13,105,54,0,0,76,141,5,164,122,0,0,232,175,119,255,255,72,139,68,36,112,72,139,76,36,112,15,183,73,20,72,99,201,72,1,200,72,131,192,24,72,137,68,36,104,199,68,36,84,0,0,0,0,49,192,131,61,157,93,0,0,0,136,68,36,63,117,56,139,76,36,84,72,139,68,36,112,15,183,80,6,49,192,57,209,136,68,36,63,125,33,72,139,68,36,104,72,131,192,40,72,141,13,212,70,0,0,72,129,193,0,16,0,0,72,57,200,15,146,192,136,68,36,63,138,68,36,63,168,1,117,5,233,145,0,0,0,72,139,68,36,104,139,64,8,137,68,36,44,72,139,68,36,88,72,137,68,36,48,72,139,68,36,112,15,183,64,24,61,11,2,0,0,117,16,72,139,68,36,104,72,99,64,12,72,137,68,36,32,235,13,72,139,68,36,104,139,64,12,72,137,68,36,32,68,139,76,36,44,76,139,68,36,48,72,139,68,36,32,73,1,192,72,139,68,36,104,139,80,16,72,139,68,36,104,139,72,20,232,220,242,255,255,131,248,0,117,2,235,53,235,0,139,68,36,84,131,192,1,137,68,36,84,72,139,68,36,104,72,131,192,40,72,137,68,36,104,233,27,255,255,255,235,47,72,141,13,86,54,0,0,72,141,21,133,121,0,0,232,144,118,255,255,232,235,216,255,255,199,5,17,121,0,0,0,0,0,0,199,132,36,148,0,0,0,0,0,0,0,235,73,235,0,235,0,232,203,216,255,255,15,182,5,36,121,0,0,131,248,4,117,19,15,190,5,215,45,0,0,131,248,2,117,7,198,5,12,121,0,0,3,15,182,5,5,121,0,0,131,248,4,116,10,199,5,198,120,0,0,0,0,0,0,199,132,36,148,0,0,0,1,0,0,0,139,132,36,148,0,0,0,72,129,196,152,0,0,0,195,102,102,102,46,15,31,132,0,0,0,0,0,86,87,83,72,129,236,32,1,0,0,199,132,36,24,1,0,0,0,0,0,0,72,199,132,36,0,1,0,0,0,0,0,0,72,199,132,36,232,0,0,0,0,0,0,0,72,199,132,36,224,0,0,0,0,0,0,0,72,199,132,36,216,0,0,0,0,0,0,0,72,199,132,36,208,0,0,0,0,0,0,0,199,132,36,204,0,0,0,0,0,0,0,72,199,132,36,176,0,0,0,0,0,0,0,72,199,132,36,168,0,0,0,0,0,0,0,72,199,68,36,112,0,0,0,0,72,131,61,171,68,0,0,0,15,132,135,1,0,0,139,5,171,68,0,0,59,5,185,91,0,0,117,33,139,5,161,68,0,0,59,5,167,91,0,0,117,19,15,182,5,150,68,0,0,59,5,148,91,0,0,15,132,183,0,0,0,139,5,124,68,0,0,137,132,36,200,0,0,0,139,5,115,68,0,0,137,132,36,196,0,0,0,15,182,5,105,68,0,0,137,132,36,192,0,0,0,72,131,61,102,68,0,0,0,116,26,68,139,5,85,91,0,0,139,21,83,91,0,0,139,13,81,91,0,0,232,76,137,255,255,235,24,68,139,5,59,91,0,0,139,21,57,91,0,0,139,13,55,91,0,0,232,130,181,255,255,72,131,61,10,68,0,0,0,117,68,72,131,61,32,68,0,0,0,116,29,68,139,132,36,192,0,0,0,139,148,36,196,0,0,0,139,140,36,200,0,0,0,232,3,137,255,255,235,27,68,139,132,36,192,0,0,0,139,148,36,196,0,0,0,139,140,36,200,0,0,0,232,54,181,255,255,235,0,232,255,205,255,255,72,131,61,183,90,0,0,0,116,103,72,131,61,173,67,0,0,0,116,93,199,5,153,67,0,0,8,0,0,0,199,5,147,67,0,0,40,0,0,0,198,5,165,67,0,0,1,102,199,5,157,67,0,0,0,0,68,139,5,124,67,0,0,72,139,13,121,90,0,0,72,141,21,106,67,0,0,232,205,108,255,255,139,13,99,67,0,0,131,193,7,131,225,248,72,139,5,90,90,0,0,137,201,72,1,200,72,137,5,78,90,0,0,68,139,5,79,67,0,0,68,15,175,5,79,67,0,0,65,129,192,255,15,0,0,65,129,224,0,240,255,255,72,139,21,42,67,0,0,72,139,13,35,67,0,0,232,174,236,255,255,72,131,61,22,90,0,0,0,15,132,137,9,0,0,72,131,61,40,67,0,0,0,116,20,72,141,76,36,112,72,141,148,36,28,1,0,0,232,196,142,255,255,235,100,72,131,61,202,66,0,0,0,116,57,72,139,5,193,66,0,0,72,131,120,40,0,116,22,72,139,5,179,66,0,0,72,139,64,40,72,139,64,24,72,137,68,36,88,235,9,49,192,72,137,68,36,88,235,0,72,139,68,36,88,72,137,68,36,80,235,12,184,128,5,0,0,72,137,68,36,80,235,0,72,139,68,36,80,72,137,68,36,112,199,132,36,28,1,0,0,128,0,0,0,72,131,124,36,112,0,116,117,131,188,36,28,1,0,0,0,126,107,72,139,68,36,112,72,131,120,8,0,116,95,72,139,5,105,89,0,0,199,0,0,1,0,0,139,140,36,28,1,0,0,131,193,8,72,139,5,82,89,0,0,137,72,4,68,139,132,36,28,1,0,0,72,139,84,36,112,72,139,13,59,89,0,0,72,131,193,8,232,146,107,255,255,139,140,36,28,1,0,0,131,193,15,131,225,248,72,139,5,30,89,0,0,72,99,201,72,1,200,72,137,5,17,89,0,0,72,131,61,177,117,0,0,0,15,132,174,0,0,0,72,139,5,164,117,0,0,15,182,0,61,208,0,0,0,117,52,72,139,5,147,117,0,0,15,182,64,1,131,248,13,117,36,72,139,5,131,117,0,0,15,182,64,2,61,254,0,0,0,117,18,72,139,5,113,117,0,0,15,182,64,3,61,237,0,0,0,116,105,72,139,5,95,117,0,0,15,182,0,131,248,68,117,16,72,139,5,80,117,0,0,15,182,64,1,131,248,83,116,31,72,139,5,64,117,0,0,15,182,0,131,248,71,117,48,72,139,5,49,117,0,0,15,182,64,1,131,248,85,117,32,72,139,5,33,117,0,0,15,182,64,2,131,248,68,117,16,72,139,5,17,117,0,0,15,182,64,3,131,248,84,116,11,72,199,5,253,116,0,0,0,0,0,0,72,139,5,14,117,0,0,72,131,192,8,72,137,132,36,8,1,0,0,72,139,132,36,8,1,0,0,72,59,5,51,88,0,0,15,131,31,4,0,0,72,139,132,36,8,1,0,0,131,56,14,116,17,72,139,132,36,8,1,0,0,131,56,15,15,133,212,3,0,0,72,139,132,36,8,1,0,0,131,56,14,117,18,72,139,132,36,8,1,0,0,139,64,24,72,137,68,36,72,235,17,72,139,132,36,8,1,0,0,72,139,64,32,72,137,68,36,72,72,139,68,36,72,72,137,132,36,176,0,0,0,72,139,132,36,176,0,0,0,15,182,0,131,248,82,116,20,72,139,132,36,176,0,0,0,15,182,0,131,248,88,15,133,113,3,0,0,72,139,140,36,176,0,0,0,72,131,193,1,72,141,21,187,43,0,0,65,184,3,0,0,0,232,80,106,255,255,131,248,0,15,133,74,3,0,0,72,139,132,36,176,0,0,0,72,131,192,36,72,137,132,36,136,0,0,0,72,139,132,36,176,0,0,0,72,139,140,36,176,0,0,0,139,73,4,72,1,200,72,137,132,36,128,0,0,0,72,139,132,36,136,0,0,0,72,59,132,36,128,0,0,0,15,131,0,3,0,0,72,139,132,36,176,0,0,0,15,182,0,131,248,88,117,18,72,139,132,36,136,0,0,0,72,139,0,72,137,68,36,64,235,15,72,139,132,36,136,0,0,0,139,0,72,137,68,36,64,72,139,68,36,64,72,137,132,36,160,0,0,0,72,139,132,36,160,0,0,0,72,137,132,36,16,1,0,0,72,131,61,145,115,0,0,0,15,132,241,0,0,0,72,139,140,36,16,1,0,0,72,141,21,2,43,0,0,65,184,4,0,0,0,232,137,105,255,255,131,248,0,15,133,206,0,0,0,72,139,5,97,115,0,0,137,193,72,139,132,36,16,1,0,0,137,72,40,72,139,132,36,16,1,0,0,15,182,64,8,131,248,2,124,41,72,139,132,36,16,1,0,0,139,64,4,72,61,148,0,0,0,118,22,72,139,13,41,115,0,0,72,139,132,36,16,1,0,0,72,137,136,140,0,0,0,72,139,132,36,16,1,0,0,198,64,9,0,198,68,36,127,0,199,132,36,28,1,0,0,0,0,0,0,139,132,36,28,1,0,0,72,139,140,36,16,1,0,0,59,65,4,125,50,72,139,132,36,16,1,0,0,72,99,140,36,28,1,0,0,15,182,12,8,15,182,68,36,127,1,200,136,68,36,127,139,132,36,28,1,0,0,131,192,1,137,132,36,28,1,0,0,235,186,15,182,76,36,127,184,0,1,0,0,41,200,136,193,72,139,132,36,16,1,0,0,136,72,9,233,123,1,0,0,131,61,91,114,0,0,0,15,132,108,1,0,0,72,139,140,36,160,0,0,0,72,141,21,33,42,0,0,65,184,4,0,0,0,232,139,104,255,255,131,248,0,15,133,73,1,0,0,72,131,188,36,168,0,0,0,0,117,19,72,139,132,36,160,0,0,0,139,64,36,72,137,132,36,168,0,0,0,199,132,36,24,1,0,0,0,0,0,0,72,139,132,36,160,0,0,0,72,131,192,44,72,137,132,36,152,0,0,0,72,139,132,36,160,0,0,0,72,139,140,36,160,0,0,0,139,73,4,72,1,200,72,137,132,36,144,0,0,0,72,139,140,36,152,0,0,0,49,192,72,59,140,36,144,0,0,0,136,68,36,63,115,22,72,139,132,36,152,0,0,0,15,182,64,1,131,248,0,15,149,192,136,68,36,63,138,68,36,63,168,1,117,5,233,177,0,0,0,72,139,132,36,152,0,0,0,15,182,0,137,68,36,56,133,192,116,13,235,0,139,68,36,56,131,232,5,116,86,235,104,72,139,132,36,152,0,0,0,15,182,64,4,131,224,1,131,248,0,116,62,72,139,132,36,152,0,0,0,15,182,64,3,61,255,0,0,0,116,43,72,139,132,36,152,0,0,0,138,80,3,139,132,36,24,1,0,0,137,193,131,193,1,137,140,36,24,1,0,0,72,99,200,72,141,5,141,121,0,0,136,20,8,235,20,72,139,132,36,152,0,0,0,72,139,64,4,72,137,132,36,168,0,0,0,235,0,72,139,132,36,152,0,0,0,15,182,72,1,72,139,132,36,152,0,0,0,72,99,201,72,1,200,72,137,132,36,152,0,0,0,233,20,255,255,255,235,0,235,0,235,0,72,139,132,36,176,0,0,0,15,182,16,185,4,0,0,0,184,8,0,0,0,131,250,88,15,68,200,72,139,132,36,136,0,0,0,72,99,201,72,1,200,72,137,132,36,136,0,0,0,233,234,252,255,255,235,0,235,0,235,0,72,139,132,36,8,1,0,0,72,139,140,36,8,1,0,0,139,73,4,131,193,7,131,225,248,137,201,72,1,200,72,137,132,36,8,1,0,0,233,204,251,255,255,131,61,119,112,0,0,0,15,132,104,1,0,0,72,139,5,250,83,0,0,199,0,1,1,0,0,72,139,5,237,83,0,0,199,64,4,20,0,0,0,72,139,5,223,83,0,0,72,137,132,36,0,1,0,0,139,140,36,24,1,0,0,72,139,132,36,0,1,0,0,137,72,8,72,139,132,36,0,1,0,0,199,64,12,1,0,0,0,184,1,0,0,0,15,162,193,235,24,137,156,36,188,0,0,0,139,140,36,188,0,0,0,72,139,132,36,0,1,0,0,137,72,16,139,132,36,188,0,0,0,137,193,184,248,255,8,0,72,137,8,72,139,5,123,83,0,0,139,72,4,131,193,7,131,225,248,72,139,5,107,83,0,0,137,201,72,1,200,72,137,5,95,83,0,0,15,49,137,132,36,188,0,0,0,137,148,36,184,0,0,0,139,132,36,184,0,0,0,72,193,224,32,139,140,36,188,0,0,0,72,9,200,72,137,68,36,104,72,131,61,77,60,0,0,0,116,20,72,139,5,116,60,0,0,185,232,3,0,0,255,144,248,0,0,0,235,38,72,131,61,239,59,0,0,0,116,21,72,139,5,230,59,0,0,72,139,64,24,185,232,3,0,0,255,80,40,235,5,232,147,174,255,255,235,0,15,49,137,132,36,188,0,0,0,137,148,36,184,0,0,0,139,132,36,184,0,0,0,72,193,224,32,139,140,36,188,0,0,0,72,9,200,72,43,68,36,104,185,136,19,0,0,49,210,72,247,241,72,137,193,184,72,5,0,0,72,137,8,184,72,5,0,0,72,131,56,1,115,12,184,72,5,0,0,72,199,0,1,0,0,0,235,0,72,139,5,146,82,0,0,199,0,2,1,0,0,72,139,5,133,82,0,0,199,64,4,24,0,0,0,72,139,13,119,82,0,0,72,131,193,8,72,141,21,156,82,0,0,65,184,16,0,0,0,232,193,100,255,255,72,139,5,90,82,0,0,139,72,4,131,193,7,131,225,248,72,139,5,74,82,0,0,137,201,72,1,200,72,137,5,62,82,0,0,72,131,61,86,59,0,0,0,15,132,77,1,0,0,72,139,5,41,82,0,0,72,137,132,36,248,0,0,0,72,139,132,36,248,0,0,0,199,0,6,0,0,0,72,139,132,36,248,0,0,0,199,64,8,24,0,0,0,72,139,132,36,248,0,0,0,199,64,12,0,0,0,0,72,139,140,36,248,0,0,0,72,131,193,16,232,84,136,255,255,137,5,86,110,0,0,131,61,79,110,0,0,0,118,82,72,139,132,36,248,0,0,0,72,131,192,16,72,137,5,34,110,0,0,139,5,52,110,0,0,72,107,192,24,72,131,192,16,137,193,72,139,132,36,248,0,0,0,137,72,4,72,139,132,36,248,0,0,0,139,72,4,131,193,7,131,225,248,72,139,5,143,81,0,0,137,201,72,1,200,72,137,5,131,81,0,0,72,139,5,124,81,0,0,199,0,12,0,0,0,72,139,5,111,81,0,0,199,64,4,16,0,0,0,72,139,13,129,58,0,0,72,139,5,90,81,0,0,72,137,72,8,72,139,5,79,81,0,0,139,72,4,131,193,7,131,225,248,72,139,5,63,81,0,0,137,201,72,1,200,72,137,5,51,81,0,0,72,139,5,44,81,0,0,199,0,20,0,0,0,72,139,5,31,81,0,0,199,64,4,16,0,0,0,72,139,13,57,81,0,0,72,139,5,10,81,0,0,72,137,72,8,72,139,5,255,80,0,0,139,72,4,131,193,7,131,225,248,72,139,5,239,80,0,0,137,201,72,1,200,72,137,5,227,80,0,0,72,139,5,220,80,0,0,199,0,0,0,0,0,72,139,5,207,80,0,0,199,64,4,8,0,0,0,72,139,5,193,80,0,0,139,72,4,131,193,7,131,225,248,72,139,5,177,80,0,0,137,201,72,1,200,72,137,5,165,80,0,0,72,139,5,158,80,0,0,72,139,13,87,109,0,0,72,41,200,137,193,72,139,5,75,109,0,0,137,8,235,11,72,199,5,60,109,0,0,0,0,0,0,15,182,5,21,109,0,0,131,248,5,15,133,190,2,0,0,72,131,61,228,108,0,0,0,15,132,176,2,0,0,72,131,61,182,108,0,0,0,15,132,34,1,0,0,131,61,193,108,0,0,0,15,132,21,1,0,0,199,132,36,28,1,0,0,0,0,0,0,139,140,36,28,1,0,0,49,192,59,13,161,108,0,0,136,68,36,55,115,18,129,188,36,28,1,0,0,128,0,0,0,15,156,192,136,68,36,55,138,68,36,55,168,1,117,5,233,192,0,0,0,72,139,5,93,108,0,0,72,99,140,36,28,1,0,0,72,107,201,24,72,1,200,72,139,8,72,139,5,100,108,0,0,72,5,208,2,0,0,72,99,148,36,28,1,0,0,72,107,210,20,72,1,208,72,137,8,72,139,5,37,108,0,0,72,99,140,36,28,1,0,0,72,107,201,24,72,1,200,72,139,72,8,72,139,5,43,108,0,0,72,5,208,2,0,0,72,99,148,36,28,1,0,0,72,107,210,20,72,1,208,72,137,72,8,72,139,5,235,107,0,0,72,99,140,36,28,1,0,0,72,107,201,24,72,1,200,139,72,16,72,139,5,242,107,0,0,72,5,208,2,0,0,72,99,148,36,28,1,0,0,72,107,210,20,72,1,208,137,72,16,139,132,36,28,1,0,0,131,192,1,137,132,36,28,1,0,0,233,12,255,255,255,139,132,36,28,1,0,0,136,193,72,139,5,180,107,0,0,136,136,232,1,0,0,72,131,61,38,56,0,0,0,15,132,28,1,0,0,139,5,38,56,0,0,102,137,193,72,139,5,144,107,0,0,102,137,72,18,139,5,22,56,0,0,102,137,193,72,139,5,124,107,0,0,102,137,72,20,15,182,5,5,56,0,0,102,137,193,72,139,5,103,107,0,0,102,137,72,22,72,139,5,220,55,0,0,137,193,72,139,5,83,107,0,0,137,72,24,139,13,210,55,0,0,15,175,13,211,55,0,0,15,182,5,208,55,0,0,15,175,200,193,233,3,72,139,5,47,107,0,0,137,72,28,139,5,174,55,0,0,102,137,193,72,139,5,28,107,0,0,102,137,72,36,138,13,171,55,0,0,72,139,5,11,107,0,0,136,72,38,138,13,154,55,0,0,72,139,5,251,106,0,0,136,72,39,138,13,141,55,0,0,72,139,5,235,106,0,0,136,72,40,138,13,124,55,0,0,72,139,5,219,106,0,0,136,72,41,138,13,111,55,0,0,72,139,5,203,106,0,0,136,72,42,138,13,94,55,0,0,72,139,5,187,106,0,0,136,72,43,72,139,21,81,55,0,0,184,35,0,0,0,185,112,0,0,0,72,131,250,0,15,69,193,136,193,72,139,5,151,106,0,0,136,72,15,72,139,5,141,106,0,0,102,199,128,250,1,0,0,4,15,72,139,13,5,78,0,0,72,139,5,118,106,0,0,72,137,72,112,72,131,61,82,106,0,0,0,116,56,72,139,5,73,106,0,0,139,72,8,72,139,5,87,106,0,0,137,136,24,2,0,0,72,139,5,50,106,0,0,139,72,12,72,139,5,40,106,0,0,43,72,8,72,139,5,54,106,0,0,137,136,28,2,0,0,235,0,72,131,61,198,54,0,0,0,15,132,253,1,0,0,232,27,148,255,255,72,139,5,228,54,0,0,72,141,140,36,224,0,0,0,49,210,76,141,132,36,216,0,0,0,76,141,140,36,208,0,0,0,72,199,68,36,32,0,0,0,0,255,80,56,72,137,132,36,240,0,0,0,72,184,5,0,0,0,0,0,0,128,72,57,132,36,240,0,0,0,15,133,140,1,0,0,15,182,5,231,105,0,0,131,248,5,15,133,124,1,0,0,72,131,61,182,105,0,0,0,15,132,110,1,0,0,72,139,132,36,208,0,0,0,72,193,224,2,72,3,132,36,224,0,0,0,72,137,132,36,224,0,0,0,72,139,5,93,54,0,0,72,139,64,64,72,139,148,36,224,0,0,0,185,2,0,0,0,76,141,132,36,232,0,0,0,255,208,72,137,132,36,240,0,0,0,72,131,188,36,240,0,0,0,0,15,140,23,1,0,0,72,139,5,36,54,0,0,72,139,64,56,72,139,148,36,232,0,0,0,72,141,140,36,224,0,0,0,76,141,132,36,216,0,0,0,76,141,140,36,208,0,0,0,76,141,148,36,204,0,0,0,76,137,84,36,32,255,208,72,137,132,36,240,0,0,0,72,131,188,36,240,0,0,0,0,15,140,196,0,0,0,72,139,13,3,105,0,0,72,129,193,192,1,0,0,72,141,21,197,32,0,0,65,184,4,0,0,0,232,202,94,255,255,72,139,132,36,232,0,0,0,137,193,72,139,5,217,104,0,0,137,136,208,1,0,0,72,139,132,36,232,0,0,0,72,193,232,32,137,193,72,139,5,190,104,0,0,137,136,220,1,0,0,72,139,132,36,224,0,0,0,137,193,72,139,5,167,104,0,0,137,136,212,1,0,0,72,139,132,36,208,0,0,0,137,193,72,139,5,144,104,0,0,137,136,200,1,0,0,139,140,36,204,0,0,0,72,139,5,124,104,0,0,137,136,204,1,0,0,72,139,5,15,53,0,0,137,193,72,139,5,102,104,0,0,137,136,196,1,0,0,72,139,5,249,52,0,0,72,193,232,32,137,193,72,139,5,76,104,0,0,137,136,216,1,0,0,235,0,235,0,72,139,5,11,53,0,0,72,139,128,232,0,0,0,72,139,148,36,216,0,0,0,72,139,13,205,75,0,0,255,208,184,16,5,0,0,102,199,0,63,0,184,18,5,0,0,72,199,0,96,5,0,0,184,104,5,0,0,72,185,255,255,0,0,0,152,0,0,72,137,8,184,112,5,0,0,72,185,255,255,0,0,0,154,207,0,72,137,8,184,120,5,0,0,72,185,255,255,0,0,0,146,207,0,72,137,8,184,128,5,0,0,72,185,255,255,0,0,0,154,175,0,72,137,8,184,136,5,0,0,72,185,255,255,0,0,0,146,207,0,72,137,8,184,144,5,0,0,72,185,104,0,0,0,0,137,0,0,72,137,8,184,152,5,0,0,72,199,0,0,0,0,0,72,139,5,86,52,0,0,15,34,216,232,0,0,0,0,88,72,137,198,72,129,198,214,0,0,0,72,137,199,72,129,199,214,2,0,0,72,199,192,152,5,0,0,72,137,193,129,225,255,255,255,0,1,72,250,72,137,193,72,193,233,24,72,137,72,255,15,1,20,37,16,5,0,0,72,199,192,48,0,0,0,15,0,216,102,185,32,0,72,137,240,102,184,1,143,72,193,224,16,102,184,32,0,72,193,224,16,102,137,240,72,171,72,137,240,72,193,232,32,72,171,72,131,198,16,102,255,201,117,214,102,199,4,37,32,5,0,0,255,1,72,199,4,37,34,5,0,0,16,39,1,0,15,1,28,37,32,5,0,0,233,64,4,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,65,88,76,139,76,36,16,233,200,11,0,0,15,31,132,0,0,0,0,0,72,49,210,48,201,235,229,102,15,31,132,0,0,0,0,0,72,49,210,177,1,235,213,102,15,31,132,0,0,0,0,0,72,49,210,177,2,235,197,102,15,31,132,0,0,0,0,0,72,49,210,177,3,235,181,102,15,31,132,0,0,0,0,0,72,49,210,177,4,235,165,102,15,31,132,0,0,0,0,0,72,49,210,177,5,235,149,102,15,31,132,0,0,0,0,0,72,49,210,177,6,235,133,102,15,31,132,0,0,0,0,0,72,49,210,177,7,233,114,255,255,255,102,15,31,68,0,0,90,177,8,233,100,255,255,255,15,31,132,0,0,0,0,0,72,49,210,177,9,233,82,255,255,255,102,15,31,68,0,0,90,177,10,233,68,255,255,255,15,31,132,0,0,0,0,0,90,177,11,233,52,255,255,255,15,31,132,0,0,0,0,0,90,177,12,233,36,255,255,255,15,31,132,0,0,0,0,0,90,177,13,233,20,255,255,255,15,31,132,0,0,0,0,0,90,177,14,233,4,255,255,255,15,31,132,0,0,0,0,0,72,49,210,177,15,233,242,254,255,255,102,15,31,68,0,0,72,49,210,177,16,233,226,254,255,255,102,15,31,68,0,0,90,177,17,233,212,254,255,255,15,31,132,0,0,0,0,0,72,49,210,177,18,233,194,254,255,255,102,15,31,68,0,0,72,49,210,177,19,233,178,254,255,255,102,15,31,68,0,0,72,49,210,177,20,233,162,254,255,255,102,15,31,68,0,0,72,49,210,177,21,233,146,254,255,255,102,15,31,68,0,0,72,49,210,177,22,233,130,254,255,255,102,15,31,68,0,0,72,49,210,177,23,233,114,254,255,255,102,15,31,68,0,0,72,49,210,177,24,233,98,254,255,255,102,15,31,68,0,0,72,49,210,177,25,233,82,254,255,255,102,15,31,68,0,0,72,49,210,177,26,233,66,254,255,255,102,15,31,68,0,0,72,49,210,177,27,233,50,254,255,255,102,15,31,68,0,0,72,49,210,177,28,233,34,254,255,255,102,15,31,68,0,0,72,49,210,177,29,233,18,254,255,255,102,15,31,68,0,0,90,177,30,233,4,254,255,255,15,31,132,0,0,0,0,0,72,49,210,177,31,233,242,253,255,255,102,15,31,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131,61,153,98,0,0,0,15,132,137,7,0,0,131,188,36,24,1,0,0,1,15,142,123,7,0,0,72,131,188,36,168,0,0,0,0,15,132,108,7,0,0,72,131,188,36,0,1,0,0,0,15,132,93,7,0,0,131,61,100,98,0,0,0,116,19,139,148,36,24,1,0,0,72,141,13,99,26,0,0,232,187,95,255,255,72,139,13,28,47,0,0,184,48,5,0,0,72,137,8,184,56,5,0,0,72,199,0,0,0,0,0,72,139,13,121,98,0,0,184,64,5,0,0,72,137,8,72,139,140,36,168,0,0,0,184,80,5,0,0,72,137,8,232,0,0,0,0,94,72,131,198,26,72,199,199,0,128,0,0,72,199,193,38,1,0,0,242,164,233,38,1,0,0,250,252,49,192,142,216,254,6,88,5,243,144,102,131,62,56,5,0,117,8,102,131,62,60,5,0,116,238,15,1,22,16,5,15,32,192,12,1,15,34,192,234,48,128,16,0,16,0,102,184,24,0,142,216,161,48,5,0,0,15,34,216,184,224,0,0,0,15,34,224,185,128,0,0,192,15,50,15,186,232,8,15,48,15,32,192,48,201,9,200,15,186,248,16,15,186,232,31,15,34,192,15,1,21,16,5,0,0,234,115,128,0,0,32,0,15,1,20,37,16,5,0,0,102,184,40,0,142,216,142,192,142,208,15,1,28,37,32,5,0,0,72,139,28,37,80,5,0,0,199,131,208,0,0,0,0,0,0,1,199,131,224,0,0,0,255,255,255,255,139,131,240,0,0,0,13,0,1,0,0,137,131,240,0,0,0,199,131,128,0,0,0,0,0,0,0,199,131,128,2,0,0,0,0,0,0,139,131,128,2,0,0,139,67,32,193,232,24,72,37,255,0,0,0,72,137,195,193,224,10,72,199,196,0,0,9,0,72,41,196,72,137,229,83,72,139,4,37,48,5,0,0,15,34,216,72,49,192,184,137,98,215,54,72,137,193,72,137,199,72,139,28,37,64,5,0,0,72,137,218,72,137,222,76,139,4,37,56,5,0,0,65,255,224,72,139,132,36,168,0,0,0,199,128,208,0,0,0,0,0,0,1,72,139,132,36,168,0,0,0,199,128,224,0,0,0,255,255,255,255,72,139,132,36,168,0,0,0,139,136,240,0,0,0,129,201,255,1,0,0,72,139,132,36,168,0,0,0,137,136,240,0,0,0,72,139,132,36,168,0,0,0,199,128,128,0,0,0,0,0,0,0,72,139,132,36,168,0,0,0,139,72,32,193,233,24,72,139,132,36,0,1,0,0,137,72,16,72,139,132,36,0,1,0,0,139,64,16,137,193,184,248,255,8,0,72,137,8,199,132,36,28,1,0,0,0,0,0,0,139,132,36,28,1,0,0,59,132,36,24,1,0,0,15,141,219,1,0,0,72,99,140,36,28,1,0,0,72,141,5,120,104,0,0,15,182,4,8,72,139,140,36,0,1,0,0,59,65,16,117,5,233,160,1,0,0,72,139,132,36,168,0,0,0,199,128,128,2,0,0,0,0,0,0,72,139,132,36,168,0,0,0,139,128,128,2,0,0,137,132,36,188,0,0,0,235,0,72,139,132,36,168,0,0,0,139,128,0,3,0,0,37,0,16,0,0,131,248,0,116,4,243,144,235,228,72,139,132,36,168,0,0,0,139,136,16,3,0,0,129,225,255,255,255,0,72,99,148,36,28,1,0,0,72,141,5,250,103,0,0,15,182,4,16,193,224,24,9,193,72,139,132,36,168,0,0,0,137,136,16,3,0,0,72,139,132,36,168,0,0,0,139,136,0,3,0,0,129,225,0,0,240,255,129,201,0,197,0,0,72,139,132,36,168,0,0,0,137,136,0,3,0,0,235,0,15,49,137,132,36,188,0,0,0,137,148,36,184,0,0,0,139,132,36,184,0,0,0,72,193,224,32,139,140,36,188,0,0,0,72,9,200,185,72,5,0,0,72,139,9,72,193,225,0,72,1,200,72,137,68,36,96,243,144,15,49,137,132,36,188,0,0,0,137,148,36,184,0,0,0,139,132,36,184,0,0,0,72,193,224,32,139,140,36,188,0,0,0,72,9,200,72,137,68,36,104,72,139,68,36,104,72,59,68,36,96,114,200,235,0,235,0,235,0,72,139,132,36,168,0,0,0,139,128,0,3,0,0,37,0,16,0,0,131,248,0,116,4,243,144,235,228,72,139,132,36,168,0,0,0,139,136,16,3,0,0,129,225,255,255,255,0,72,99,148,36,28,1,0,0,72,141,5,3,103,0,0,15,182,4,16,193,224,24,9,193,72,139,132,36,168,0,0,0,137,136,16,3,0,0,72,139,132,36,168,0,0,0,139,136,0,3,0,0,129,225,0,0,240,255,129,201,0,133,0,0,72,139,132,36,168,0,0,0,137,136,0,3,0,0,235,0,139,132,36,28,1,0,0,131,192,1,137,132,36,28,1,0,0,233,17,254,255,255,235,0,15,49,137,132,36,188,0,0,0,137,148,36,184,0,0,0,139,132,36,184,0,0,0,72,193,224,32,139,140,36,188,0,0,0,72,9,200,185,72,5,0,0,72,107,9,10,72,1,200,72,137,68,36,96,243,144,15,49,137,132,36,188,0,0,0,137,148,36,184,0,0,0,139,132,36,184,0,0,0,72,193,224,32,139,140,36,188,0,0,0,72,9,200,72,137,68,36,104,72,139,68,36,104,72,59,68,36,96,114,200,235,0,199,132,36,28,1,0,0,0,0,0,0,139,132,36,28,1,0,0,59,132,36,24,1,0,0,15,141,175,2,0,0,72,99,140,36,28,1,0,0,72,141,5,12,102,0,0,15,182,4,8,72,139,140,36,0,1,0,0,59,65,16,117,5,233,116,2,0,0,184,88,5,0,0,198,0,0,235,0,72,139,132,36,168,0,0,0,139,128,0,3,0,0,37,0,16,0,0,131,248,0,116,4,243,144,235,228,72,139,132,36,168,0,0,0,139,136,16,3,0,0,129,225,255,255,255,0,72,99,148,36,28,1,0,0,72,141,5,173,101,0,0,15,182,4,16,193,224,24,9,193,72,139,132,36,168,0,0,0,137,136,16,3,0,0,72,139,132,36,168,0,0,0,139,136,0,3,0,0,129,225,0,248,240,255,129,201,8,70,0,0,72,139,132,36,168,0,0,0,137,136,0,3,0,0,199,132,36,188,0,0,0,250,0,0,0,184,88,5,0,0,138,8,49,192,128,249,0,136,68,36,54,117,15,131,188,36,188,0,0,0,0,15,151,192,136,68,36,54,138,68,36,54,168,1,117,5,233,141,0,0,0,235,0,15,49,137,132,36,188,0,0,0,137,148,36,184,0,0,0,139,132,36,184,0,0,0,72,193,224,32,139,140,36,188,0,0,0,72,9,200,185,72,5,0,0,72,139,9,72,193,225,0,72,1,200,72,137,68,36,96,243,144,15,49,137,132,36,188,0,0,0,137,148,36,184,0,0,0,139,132,36,184,0,0,0,72,193,224,32,139,140,36,188,0,0,0,72,9,200,72,137,68,36,104,72,139,68,36,104,72,59,68,36,96,114,200,235,0,235,0,139,132,36,188,0,0,0,131,192,255,137,132,36,188,0,0,0,233,69,255,255,255,184,88,5,0,0,138,0,60,0,15,133,249,0,0,0,235,0,235,0,72,139,132,36,168,0,0,0,139,128,0,3,0,0,37,0,16,0,0,131,248,0,116,4,243,144,235,228,72,139,132,36,168,0,0,0,139,136,16,3,0,0,129,225,255,255,255,0,72,99,148,36,28,1,0,0,72,141,5,86,100,0,0,15,182,4,16,193,224,24,9,193,72,139,132,36,168,0,0,0,137,136,16,3,0,0,72,139,132,36,168,0,0,0,139,136,0,3,0,0,129,225,0,248,240,255,129,201,8,70,0,0,72,139,132,36,168,0,0,0,137,136,0,3,0,0,235,0,15,49,137,132,36,188,0,0,0,137,148,36,184,0,0,0,139,132,36,184,0,0,0,72,193,224,32,139,140,36,188,0,0,0,72,9,200,185,72,5,0,0,72,105,9,250,0,0,0,72,1,200,72,137,68,36,96,243,144,15,49,137,132,36,188,0,0,0,137,148,36,184,0,0,0,139,132,36,184,0,0,0,72,193,224,32,139,140,36,188,0,0,0,72,9,200,72,137,68,36,104,72,139,68,36,104,72,59,68,36,96,114,200,235,0,235,0,184,88,5,0,0,138,0,60,0,116,17,72,139,132,36,0,1,0,0,139,72,12,131,193,1,137,72,12,235,0,139,132,36,28,1,0,0,131,192,1,137,132,36,28,1,0,0,233,61,253,255,255,235,10,199,5,0,91,0,0,0,0,0,0,184,88,5,0,0,72,199,0,0,0,0,0,72,129,196,32,1,0,0,91,95,94,195,102,15,31,132,0,0,0,0,0,83,72,129,236,160,0,0,0,76,137,140,36,152,0,0,0,76,137,132,36,144,0,0,0,72,137,148,36,136,0,0,0,136,140,36,135,0,0,0,128,61,250,90,0,0,0,15,133,42,3,0,0,138,5,238,90,0,0,4,1,136,5,230,90,0,0,15,32,208,15,32,219,72,137,68,36,120,72,137,92,36,112,72,131,61,22,39,0,0,0,15,132,203,1,0,0,15,182,5,29,39,0,0,131,192,7,193,248,3,137,68,36,92,199,5,221,38,0,0,4,0,0,0,199,5,215,38,0,0,4,0,0,0,15,182,5,253,38,0,0,131,248,8,126,23,15,182,13,241,38,0,0,131,233,8,184,255,0,0,0,211,224,137,68,36,88,235,25,15,182,5,218,38,0,0,185,8,0,0,0,41,193,184,255,0,0,0,211,248,137,68,36,88,139,68,36,88,15,182,13,188,38,0,0,211,224,137,68,36,84,15,182,5,178,38,0,0,131,248,8,126,20,15,182,13,166,38,0,0,131,233,8,49,192,211,224,137,68,36,80,235,22,15,182,5,146,38,0,0,185,8,0,0,0,41,193,49,192,211,248,137,68,36,80,139,68,36,84,139,84,36,80,15,182,13,115,38,0,0,211,226,137,209,9,200,137,68,36,76,15,182,5,101,38,0,0,131,248,8,126,20,15,182,13,89,38,0,0,131,233,8,49,192,211,224,137,68,36,72,235,22,15,182,5,69,38,0,0,185,8,0,0,0,41,193,49,192,211,248,137,68,36,72,139,68,36,76,139,84,36,72,15,182,13,38,38,0,0,211,226,137,209,9,200,137,5,38,38,0,0,199,68,36,96,0,0,0,0,199,68,36,104,0,0,0,0,139,68,36,96,139,13,188,29,0,0,209,225,131,193,8,57,200,15,131,144,0,0,0,139,68,36,104,137,68,36,108,199,68,36,100,0,0,0,0,139,68,36,100,59,5,201,37,0,0,115,84,131,124,36,92,2,117,28,139,5,214,37,0,0,102,137,193,72,139,5,164,37,0,0,139,84,36,108,72,1,208,102,137,8,235,22,139,13,186,37,0,0,72,139,5,139,37,0,0,139,84,36,108,72,1,208,137,8,235,0,139,68,36,100,131,192,1,137,68,36,100,139,68,36,92,3,68,36,108,137,68,36,108,235,160,235,0,139,68,36,96,131,192,1,137,68,36,96,139,5,92,37,0,0,3,68,36,104,137,68,36,104,233,89,255,255,255,235,0,102,199,5,44,37,0,0,0,0,102,199,5,37,37,0,0,0,0,72,131,61,43,37,0,0,0,117,98,72,131,61,65,37,0,0,0,117,88,199,68,36,108,0,0,0,0,129,124,36,108,64,1,0,0,115,28,139,68,36,108,72,5,0,128,11,0,102,199,0,32,79,139,68,36,108,131,192,2,137,68,36,108,235,218,235,0,129,124,36,108,208,7,0,0,115,28,139,68,36,108,72,5,0,128,11,0,102,199,0,32,15,139,68,36,108,131,192,2,137,68,36,108,235,218,235,0,72,139,132,36,136,0,0,0,72,137,68,36,64,15,182,132,36,135,0,0,0,131,248,32,125,32,15,182,132,36,135,0,0,0,72,99,200,72,141,5,251,12,0,0,72,107,201,3,72,1,200,72,137,68,36,56,235,14,72,141,5,175,15,0,0,72,137,68,36,56,235,0,76,139,76,36,64,76,139,68,36,56,15,182,148,36,135,0,0,0,72,141,13,67,21,0,0,232,65,85,255,255,199,5,127,36,0,0,0,0,0,0,76,139,156,36,152,0,0,0,76,139,148,36,144,0,0,0,72,139,76,36,112,76,139,76,36,120,76,139,132,36,152,0,0,0,72,139,148,36,144,0,0,0,72,137,224,76,137,88,48,76,137,80,40,72,137,72,32,72,141,13,114,18,0,0,232,242,84,255,255,250,244,235,252,72,129,196,160,0,0,0,91,195,15,31,68,0,0,86,83,72,131,236,88,102,68,137,68,36,86,72,137,84,36,72,72,137,76,36,64,102,68,139,68,36,86,72,139,84,36,72,72,139,76,36,64,232,85,171,255,255,72,141,13,58,17,0,0,232,169,84,255,255,72,131,61,9,36,0,0,0,117,17,72,141,13,91,15,0,0,232,147,84,255,255,233,81,3,0,0,72,131,61,38,56,0,0,0,117,17,72,141,13,110,16,0,0,232,120,84,255,255,233,54,3,0,0,235,0,232,236,182,255,255,232,231,192,255,255,72,131,61,223,51,0,0,0,117,17,72,141,13,162,17,0,0,232,81,84,255,255,233,15,3,0,0,131,61,217,86,0,0,0,116,40,131,61,84,58,0,0,0,117,31,72,139,21,179,51,0,0,72,193,234,10,72,193,234,10,72,131,194,2,72,141,13,37,15,0,0,232,27,84,255,255,235,0,232,100,211,255,255,131,248,0,117,5,233,205,2,0,0,232,5,196,255,255,131,61,22,58,0,0,0,117,39,131,61,17,58,0,0,0,116,30,139,5,5,58,0,0,131,192,1,137,5,252,57,0,0,199,5,246,57,0,0,0,0,0,0,233,100,255,255,255,232,192,221,255,255,15,182,5,137,86,0,0,131,248,1,116,57,72,131,61,116,86,0,0,0,117,17,72,141,13,153,14,0,0,232,174,83,255,255,233,108,2,0,0,131,61,54,86,0,0,2,118,19,72,139,21,81,86,0,0,72,141,13,234,13,0,0,232,141,83,255,255,235,0,15,182,5,68,86,0,0,255,200,137,193,72,137,76,36,48,131,232,4,15,135,41,2,0,0,72,139,68,36,48,72,141,13,70,10,0,0,72,99,4,129,72,1,200,255,224,131,61,234,85,0,0,1,118,26,76,139,5,197,85,0,0,72,139,21,182,85,0,0,72,141,13,180,18,0,0,232,58,83,255,255,72,131,61,170,85,0,0,127,118,12,184,127,0,0,0,72,137,68,36,40,235,12,72,139,5,149,85,0,0,72,137,68,36,40,72,139,68,36,40,102,137,193,184,2,5,0,0,102,137,8,184,4,5,0,0,199,0,0,124,0,0,72,139,13,102,85,0,0,184,8,5,0,0,72,137,8,232,121,101,255,255,233,155,1,0,0,131,61,113,85,0,0,1,118,56,72,139,13,244,56,0,0,72,139,5,173,85,0,0,72,41,193,76,139,13,163,85,0,0,72,139,21,116,85,0,0,72,137,224,72,137,72,32,72,141,13,179,17,0,0,65,184,137,98,215,54,232,163,82,255,255,72,139,5,124,85,0,0,137,193,184,252,255,8,0,137,8,184,248,255,8,0,199,0,137,98,215,54,184,244,255,8,0,199,0,239,190,173,222,72,139,29,46,85,0,0,72,199,192,16,0,0,0,80,72,199,199,0,6,0,0,87,232,0,0,0,0,94,72,131,198,16,72,199,193,65,0,0,0,242,164,72,203,15,32,192,15,186,248,31,15,34,192,102,184,24,0,142,216,142,192,142,208,142,224,142,232,137,222,185,128,0,0,192,15,50,15,186,248,8,15,48,49,192,15,1,24,188,244,255,8,0,137,229,139,84,36,8,137,211,139,68,36,4,137,193,255,230,233,194,0,0,0,131,61,152,84,0,0,1,118,56,72,139,13,27,56,0,0,72,139,5,212,84,0,0,72,41,193,76,139,13,202,84,0,0,72,139,21,155,84,0,0,72,137,224,72,137,72,32,72,141,13,18,17,0,0,65,184,137,98,215,54,232,202,81,255,255,131,61,83,84,0,0,0,116,17,72,139,13,114,84,0,0,184,56,5,0,0,72,137,8,243,144,72,139,29,137,84,0,0,72,139,13,90,84,0,0,184,137,98,215,54,73,137,200,72,137,193,72,137,199,72,137,218,72,137,222,72,199,196,0,0,9,0,72,137,229,131,236,8,65,255,224,235,51,131,61,9,84,0,0,1,118,26,76,139,5,12,84,0,0,72,139,21,29,84,0,0,72,141,13,53,16,0,0,232,89,81,255,255,72,139,53,242,83,0,0,72,139,5,3,84,0,0,255,224,72,141,13,64,14,0,0,232,61,81,255,255,72,131,124,36,72,0,117,88,131,61,70,55,0,0,0,116,6,250,244,235,252,235,71,235,0,228,100,243,144,243,144,243,144,136,68,36,63,15,182,68,36,63,61,255,0,0,0,116,43,15,182,68,36,63,131,224,1,131,248,0,116,30,139,5,17,55,0,0,131,192,1,137,5,8,55,0,0,199,5,2,55,0,0,0,0,0,0,233,112,252,255,255,235,187,235,0,72,184,1,0,0,0,0,0,0,128,72,131,196,88,91,94,195,102,102,102,46,15,31,132,0,0,0,0,0,72,131,236,72,68,137,68,36,68,72,137,84,36,56,72,137,76,36,48,199,68,36,12,0,0,0,0,131,124,36,12,16,115,28,72,139,68,36,48,139,76,36,12,102,199,4,72,0,0,139,68,36,12,131,192,1,137,68,36,12,235,221,199,68,36,12,0,0,0,0,139,68,36,12,59,68,36,68,115,43,72,139,68,36,48,72,139,76,36,56,139,84,36,12,15,182,12,17,102,139,20,72,102,131,194,1,102,137,20,72,139,68,36,12,131,192,1,137,68,36,12,235,203,72,139,68,36,48,102,199,0,0,0,199,68,36,8,0,0,0,0,199,68,36,12,0,0,0,0,131,124,36,12,16,115,50,139,68,36,8,102,137,193,139,68,36,12,102,137,76,68,16,72,139,68,36,48,139,76,36,12,15,183,4,72,3,68,36,8,137,68,36,8,139,68,36,12,131,192,1,137,68,36,12,235,199,199,68,36,12,0,0,0,0,139,68,36,12,59,68,36,68,115,89,72,139,68,36,56,139,76,36,12,128,60,8,0,116,59,139,68,36,12,102,137,194,72,139,68,36,48,72,139,76,36,56,68,139,68,36,12,66,15,182,12,1,65,137,200,102,66,139,76,68,16,102,65,137,201,102,65,131,193,1,102,70,137,76,68,16,15,183,201,102,137,84,72,32,235,0,139,68,36,12,131,192,1,137,68,36,12,235,157,72,131,196,72,195,102,144,72,131,236,72,72,137,84,36,64,72,137,76,36,56,199,68,36,52,0,0,0,0,199,68,36,48,0,0,0,0,199,68,36,44,0,0,0,0,139,68,36,48,209,224,137,68,36,40,72,139,76,36,56,232,6,128,255,255,137,193,139,68,36,40,1,200,137,68,36,48,139,68,36,44,131,192,1,137,68,36,44,72,139,68,36,64,72,99,76,36,44,15,183,4,72,3,68,36,52,137,68,36,52,72,139,68,36,64,72,99,76,36,44,15,183,12,72,139,68,36,48,41,200,137,68,36,48,131,124,36,48,0,125,160,72,139,68,36,64,139,76,36,52,3,76,36,48,72,99,201,15,183,68,72,32,72,131,196,72,195,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,195,245,255,255,60,246,255,255,60,246,255,255,21,247,255,255,164,247,255,255,0,0,0,0,0,0,0,0,0,0,0,0,107,101,114,110,101,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,69,0,68,66,0,78,73,0,66,80,0,79,70,0,66,82,0,85,68,0,68,70,0,67,79,0,84,83,0,78,80,0,83,83,0,71,80,0,80,70,0,49,53,0,77,70,0,65,67,0,77,67,0,88,70,0,50,48,0,67,80,0,50,50,0,50,51,0,50,52,0,50,53,0,50,54,0,50,55,0,72,86,0,86,67,0,83,88,0,51,49,0,0,0,0,222,169,66,144,220,35,56,74,150,251,122,222,208,128,81,106,222,169,66,144,220,35,56,74,150,251,122,222,208,128,81,106,86,16,140,189,54,159,236,68,146,168,166,51,127,129,121,134,246,52,12,28,128,211,250,65,160,73,138,208,108,26,102,170,146,110,87,9,63,109,210,17,142,57,0,160,201,105,114,59,49,45,157,235,136,45,211,17,154,22,0,144,39,63,193,77,48,45,157,235,136,45,211,17,154,22,0,144,39,63,193,77,113,232,104,136,241,228,211,17,188,34,0,128,199,60,136,129,145,110,87,9,63,109,210,17,142,57,0,160,201,105,114,59,161,49,27,91,98,149,210,17,142,63,0,160,201,105,114,59,34,91,78,150,89,100,210,17,142,57,0,160,201,105,114,59,0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,13,0,15,0,17,0,19,0,23,0,27,0,31,0,35,0,43,0,51,0,59,0,67,0,83,0,99,0,115,0,131,0,163,0,195,0,227,0,2,1,0,0,0,0,0,0,0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0,1,0,2,0,3,0,4,0,5,0,7,0,9,0,13,0,17,0,25,0,33,0,49,0,65,0,97,0,129,0,193,0,1,1,129,1,1,2,1,3,1,4,1,6,1,8,1,12,1,16,1,24,1,32,1,48,1,64,1,96,0,0,0,0,16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15,0,40,115,42,193,31,248,210,17,186,75,0,160,201,62,201,59,157,107,189,131,65,127,220,17,190,11,0,21,96,184,79,15,72,97,104,33,73,100,111,110,116,78,101,101,100,69,70,73,109,101,110,117,101,110,116,114,121,0,83,105,109,112,108,101,98,111,111,116,0,102,114,97,109,101,98,117,102,102,101,114,0,98,97,99,107,117,112,0,107,101,114,110,101,108,0,105,98,109,112,99,47,105,110,105,116,114,100,46,98,97,107,0,98,111,111,116,115,112,108,97,115,104,0,101,97,115,121,98,111,111,116,47,109,101,110,117,46,99,102,103,0,115,105,109,112,108,101,98,111,111,116,46,99,102,103,0,118,101,114,98,111,115,101,0,109,117,108,116,105,99,111,114,101,0,105,98,109,112,99,47,99,111,114,101,0,109,111,100,117,108,101,0,105,98,109,112,99,47,105,110,105,116,114,100,0,95,83,77,95,0,69,70,73,32,80,65,82,84,0,82,83,68,84,0,72,100,114,83,0,73,78,84,82,0,70,65,67,80,0,127,69,76,70,0,75,101,114,110,101,108,32,101,110,116,114,121,58,13,10,37,52,68,0,65,80,73,67,0,69,76,54,52,0,32,40,98,97,99,107,117,112,41,0,40,110,117,108,108,41,0,82,83,68,32,80,84,82,32,0,37,99,37,99,68,84,32,100,101,116,101,99,116,101,100,46,46,46,10,0,73,110,105,116,105,97,108,105,122,105,110,103,32,83,77,80,32,40,37,100,32,99,111,114,101,115,41,46,46,46,10,0,69,82,82,79,82,58,32,117,110,97,98,108,101,32,116,111,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,13,10,0,69,82,82,79,82,58,32,110,111,32,107,101,114,110,101,108,32,101,110,116,114,121,32,112,111,105,110,116,13,10,0,80,104,121,115,105,99,97,108,32,82,65,77,32,37,108,100,32,77,101,103,97,98,121,116,101,115,13,10,0,69,82,82,79,82,58,32,122,101,114,111,32,112,97,103,101,32,97,108,108,111,99,97,116,105,111,110,32,101,114,114,111,114,13,10,0,32,71,79,80,58,32,110,111,32,102,114,97,109,101,98,117,102,102,101,114,13,10,0,32,76,70,66,58,32,110,111,32,102,114,97,109,101,98,117,102,102,101,114,13,10,0,32,86,69,83,65,58,32,110,111,32,102,114,97,109,101,98,117,102,102,101,114,13,10,0,32,83,89,83,58,32,117,110,97,98,108,101,32,116,111,32,103,101,116,32,109,101,109,111,114,121,32,109,97,112,13,10,0,32,85,69,70,73,58,32,117,110,97,98,108,101,32,116,111,32,103,101,116,32,109,101,109,111,114,121,32,109,97,112,13,10,0,32,69,56,50,48,58,32,117,110,97,98,108,101,32,116,111,32,103,101,116,32,109,101,109,111,114,121,32,109,97,112,13,10,0,69,82,82,79,82,58,32,117,110,97,98,108,101,32,116,111,32,108,111,99,97,116,101,32,98,111,111,116,32,112,97,114,116,105,116,105,111,110,13,10,0,69,82,82,79,82,58,32,117,110,115,117,112,112,111,114,116,101,100,32,76,105,110,117,120,32,98,111,111,116,32,112,114,111,116,111,99,111,108,32,118,101,114,115,105,111,110,13,10,0,69,82,82,79,82,58,32,117,110,97,98,108,101,32,116,111,32,108,111,97,100,32,115,101,103,109,101,110,116,32,37,48,56,108,120,91,37,120,93,44,32,109,101,109,111,114,121,32,97,108,114,101,97,100,121,32,105,110,32,117,115,101,13,10,0,83,105,109,112,108,101,98,111,111,116,32,108,111,97,100,101,114,44,32,67,111,112,121,114,105,103,104,116,32,40,99,41,32,50,48,50,51,32,98,122,116,44,32,77,73,84,32,108,105,99,101,110,115,101,13,10,0,69,82,82,79,82,58,32,107,101,114,110,101,108,32,110,111,116,32,102,111,117,110,100,13,10,0,69,82,82,79,82,58,32,107,101,114,110,101,108,32,39,37,83,39,32,110,111,116,32,102,111,117,110,100,13,10,0,69,82,82,79,82,58,32,107,101,114,110,101,108,32,115,104,111,117,108,100,32,110,111,116,32,104,97,118,101,32,114,101,116,117,114,110,101,100,13,10,0,32,32,115,101,103,109,101,110,116,32,37,48,56,120,91,37,48,56,120,93,32,45,62,32,37,48,56,120,91,37,48,56,120,93,13,10,0,69,82,82,79,82,58,32,117,110,97,98,108,101,32,116,111,32,100,101,116,101,114,109,105,110,101,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,82,65,77,13,10,0,82,73,80,32,37,48,49,54,120,32,82,83,80,32,37,48,49,54,120,32,67,82,50,32,37,48,49,54,120,32,67,82,51,32,37,48,49,54,120,13,10,13,10,67,111,100,101,13,10,37,68,13,10,83,116,97,99,107,13,10,37,52,68,13,10,0,37,68,13,10,0,65,98,111,114,116,101,100,44,32,108,111,97,100,105,110,103,32,98,97,99,107,117,112,32,99,111,110,102,105,103,117,114,97,116,105,111,110,46,46,46,13,10,0,68,84,66,32,100,101,116,101,99,116,101,100,46,46,46,13,10,0,76,111,97,100,105,110,103,32,108,111,103,111,32,39,37,83,39,32,40,37,108,100,32,98,121,116,101,115,41,46,46,46,13,10,0,76,111,97,100,105,110,103,32,109,111,100,117,108,101,32,39,37,83,39,32,40,37,108,100,32,98,121,116,101,115,41,46,46,46,13,10,0,85,110,99,111,109,112,114,101,115,115,105,110,103,32,40,37,100,32,98,121,116,101,115,41,46,46,46,13,10,0,76,111,97,100,105,110,103,32,76,105,110,117,120,32,107,101,114,110,101,108,32,39,37,83,39,46,46,46,13,10,0,76,111,97,100,105,110,103,32,77,117,108,116,105,98,111,111,116,50,32,69,76,70,37,100,32,107,101,114,110,101,108,32,39,37,83,39,46,46,46,13,10,0,76,111,97,100,105,110,103,32,77,117,108,116,105,98,111,111,116,50,32,80,69,37,100,32,107,101,114,110,101,108,32,39,37,83,39,46,46,46,13,10,0,84,114,97,110,115,102,101,114,105,110,103,32,108,111,110,103,32,109,111,100,101,32,99,111,110,116,114,111,108,32,116,111,32,37,48,56,120,40,37,48,56,120,41,13,10,0,84,114,97,110,115,102,101,114,105,110,103,32,112,114,111,116,32,109,111,100,101,32,99,111,110,116,114,111,108,32,116,111,32,37,48,56,120,40,37,48,56,120,44,32,37,48,56,120,91,37,120,93,41,13,10,0,84,114,97,110,115,102,101,114,105,110,103,32,108,111,110,103,32,109,111,100,101,32,99,111,110,116,114,111,108,32,116,111,32,37,48,56,120,40,37,48,56,120,44,32,37,48,56,120,91,37,120,93,41,13,10,0,84,114,97,110,115,102,101,114,105,110,103,32,114,101,97,108,32,109,111,100,101,32,99,111,110,116,114,111,108,32,116,111,32,48,58,55,67,48,48,32,40,76,66,65,32,37,100,32,115,105,122,101,32,37,100,32,115,101,99,116,111,114,40,115,41,41,13,10,0,69,82,82,79,82,58,32,117,110,107,110,111,119,110,32,107,101,114,110,101,108,32,102,111,114,109,97,116,32,39,37,83,39,13,10,0,87,65,82,78,73,78,71,58,32,117,110,97,98,108,101,32,116,111,32,108,111,97,100,32,39,37,83,39,13,10,0,83,105,109,112,108,101,98,111,111,116,32,69,120,99,101,112,116,105,111,110,32,72,97,110,100,108,101,114,13,10,69,120,99,101,112,116,105,111,110,32,37,48,50,120,32,35,37,115,32,99,111,100,101,32,37,48,49,54,120,13,10,13,10,0,0,40,0,110,0,117,0,108,0,108,0,41,0,0,0,0,0,0,0,47,219,42,52,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,114,181,74,134,0,0,0,0,32,0,0,0,0,0,12,0,128,0,0,0,16,0,0,0,16,0,0,0,8,0,0,0,0,0,218,2,128,130,2,128,130,2,128,182,0,0,0,0,0,0,126,129,165,129,129,189,153,129,129,126,0,0,0,0,0,0,126,255,219,255,255,195,231,255,255,126,0,0,0,0,0,0,0,0,108,254,254,254,254,124,56,16,0,0,0,0,0,0,0,0,16,56,124,254,124,56,16,0,0,0,0,0,0,0,0,24,60,60,231,231,231,24,24,60,0,0,0,0,0,0,0,24,60,126,255,255,126,24,24,60,0,0,0,0,0,0,0,0,0,0,24,60,60,24,0,0,0,0,0,0,255,255,255,255,255,255,231,195,195,231,255,255,255,255,255,255,0,0,0,0,0,60,102,66,66,102,60,0,0,0,0,0,255,255,255,255,255,195,153,189,189,153,195,255,255,255,255,255,0,0,30,14,26,50,120,204,204,204,204,120,0,0,0,0,0,0,60,102,102,102,102,60,24,126,24,24,0,0,0,0,0,0,63,51,63,48,48,48,48,112,240,224,0,0,0,0,0,0,127,99,127,99,99,99,99,103,231,230,192,0,0,0,0,0,0,24,24,219,60,231,60,219,24,24,0,0,0,0,0,128,192,224,240,248,254,248,240,224,192,128,0,0,0,0,0,2,6,14,30,62,254,62,30,14,6,2,0,0,0,0,0,0,24,60,126,24,24,24,126,60,24,0,0,0,0,0,0,0,102,102,102,102,102,102,102,0,102,102,0,0,0,0,0,0,127,219,219,219,123,27,27,27,27,27,0,0,0,0,0,124,198,96,56,108,198,198,108,56,12,198,124,0,0,0,0,0,0,0,0,0,0,0,254,254,254,254,0,0,0,0,0,0,24,60,126,24,24,24,126,60,24,126,0,0,0,0,0,0,24,60,126,24,24,24,24,24,24,24,0,0,0,0,0,0,24,24,24,24,24,24,24,126,60,24,0,0,0,0,0,0,0,0,0,24,12,254,12,24,0,0,0,0,0,0,0,0,0,0,0,48,96,254,96,48,0,0,0,0,0,0,0,0,0,0,0,0,192,192,192,254,0,0,0,0,0,0,0,0,0,0,0,40,108,254,108,40,0,0,0,0,0,0,0,0,0,0,16,56,56,124,124,254,254,0,0,0,0,0,0,0,0,0,254,254,124,124,56,56,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,60,60,60,24,24,24,0,24,24,0,0,0,0,0,102,102,102,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,108,108,254,108,108,108,254,108,108,0,0,0,0,24,24,124,198,194,192,124,6,6,134,198,124,24,24,0,0,0,0,0,0,194,198,12,24,48,96,198,134,0,0,0,0,0,0,56,108,108,56,118,220,204,204,204,118,0,0,0,0,0,48,48,48,32,0,0,0,0,0,0,0,0,0,0,0,0,0,12,24,48,48,48,48,48,48,24,12,0,0,0,0,0,0,48,24,12,12,12,12,12,12,24,48,0,0,0,0,0,0,0,0,0,102,60,255,60,102,0,0,0,0,0,0,0,0,0,0,0,24,24,126,24,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,24,24,48,0,0,0,0,0,0,0,0,0,0,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,24,0,0,0,0,0,0,0,0,2,6,12,24,48,96,192,128,0,0,0,0,0,0,56,108,198,198,214,214,198,198,108,56,0,0,0,0,0,0,24,56,120,24,24,24,24,24,24,126,0,0,0,0,0,0,124,198,6,12,24,48,96,192,198,254,0,0,0,0,0,0,124,198,6,6,60,6,6,6,198,124,0,0,0,0,0,0,12,28,60,108,204,254,12,12,12,30,0,0,0,0,0,0,254,192,192,192,252,6,6,6,198,124,0,0,0,0,0,0,56,96,192,192,252,198,198,198,198,124,0,0,0,0,0,0,254,198,6,6,12,24,48,48,48,48,0,0,0,0,0,0,124,198,198,198,124,198,198,198,198,124,0,0,0,0,0,0,124,198,198,198,126,6,6,6,12,120,0,0,0,0,0,0,0,0,24,24,0,0,0,24,24,0,0,0,0,0,0,0,0,0,24,24,0,0,0,24,24,48,0,0,0,0,0,0,0,6,12,24,48,96,48,24,12,6,0,0,0,0,0,0,0,0,0,126,0,0,126,0,0,0,0,0,0,0,0,0,0,96,48,24,12,6,12,24,48,96,0,0,0,0,0,0,124,198,198,12,24,24,24,0,24,24,0,0,0,0,0,0,0,124,198,198,222,222,222,220,192,124,0,0,0,0,0,0,16,56,108,198,198,254,198,198,198,198,0,0,0,0,0,0,252,102,102,102,124,102,102,102,102,252,0,0,0,0,0,0,60,102,194,192,192,192,192,194,102,60,0,0,0,0,0,0,248,108,102,102,102,102,102,102,108,248,0,0,0,0,0,0,254,102,98,104,120,104,96,98,102,254,0,0,0,0,0,0,254,102,98,104,120,104,96,96,96,240,0,0,0,0,0,0,60,102,194,192,192,222,198,198,102,58,0,0,0,0,0,0,198,198,198,198,254,198,198,198,198,198,0,0,0,0,0,0,60,24,24,24,24,24,24,24,24,60,0,0,0,0,0,0,30,12,12,12,12,12,204,204,204,120,0,0,0,0,0,0,230,102,102,108,120,120,108,102,102,230,0,0,0,0,0,0,240,96,96,96,96,96,96,98,102,254,0,0,0,0,0,0,198,238,254,254,214,198,198,198,198,198,0,0,0,0,0,0,198,230,246,254,222,206,198,198,198,198,0,0,0,0,0,0,124,198,198,198,198,198,198,198,198,124,0,0,0,0,0,0,252,102,102,102,124,96,96,96,96,240,0,0,0,0,0,0,124,198,198,198,198,198,198,214,222,124,12,14,0,0,0,0,252,102,102,102,124,108,102,102,102,230,0,0,0,0,0,0,124,198,198,96,56,12,6,198,198,124,0,0,0,0,0,0,126,126,90,24,24,24,24,24,24,60,0,0,0,0,0,0,198,198,198,198,198,198,198,198,198,124,0,0,0,0,0,0,198,198,198,198,198,198,198,108,56,16,0,0,0,0,0,0,198,198,198,198,214,214,214,254,238,108,0,0,0,0,0,0,198,198,108,124,56,56,124,108,198,198,0,0,0,0,0,0,102,102,102,102,60,24,24,24,24,60,0,0,0,0,0,0,254,198,134,12,24,48,96,194,198,254,0,0,0,0,0,0,60,48,48,48,48,48,48,48,48,60,0,0,0,0,0,0,0,128,192,224,112,56,28,14,6,2,0,0,0,0,0,0,60,12,12,12,12,12,12,12,12,60,0,0,0,0,16,56,108,198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,48,48,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,120,12,124,204,204,204,118,0,0,0,0,0,0,224,96,96,120,108,102,102,102,102,124,0,0,0,0,0,0,0,0,0,124,198,192,192,192,198,124,0,0,0,0,0,0,28,12,12,60,108,204,204,204,204,118,0,0,0,0,0,0,0,0,0,124,198,254,192,192,198,124,0,0,0,0,0,0,56,108,100,96,240,96,96,96,96,240,0,0,0,0,0,0,0,0,0,118,204,204,204,204,204,124,12,204,120,0,0,0,224,96,96,108,118,102,102,102,102,230,0,0,0,0,0,0,24,24,0,56,24,24,24,24,24,60,0,0,0,0,0,0,6,6,0,14,6,6,6,6,6,6,102,102,60,0,0,0,224,96,96,102,108,120,120,108,102,230,0,0,0,0,0,0,56,24,24,24,24,24,24,24,24,60,0,0,0,0,0,0,0,0,0,236,254,214,214,214,214,198,0,0,0,0,0,0,0,0,0,220,102,102,102,102,102,102,0,0,0,0,0,0,0,0,0,124,198,198,198,198,198,124,0,0,0,0,0,0,0,0,0,220,102,102,102,102,102,124,96,96,240,0,0,0,0,0,0,118,204,204,204,204,204,124,12,12,30,0,0,0,0,0,0,220,118,102,96,96,96,240,0,0,0,0,0,0,0,0,0,124,198,96,56,12,198,124,0,0,0,0,0,0,16,48,48,252,48,48,48,48,54,28,0,0,0,0,0,0,0,0,0,204,204,204,204,204,204,118,0,0,0,0,0,0,0,0,0,102,102,102,102,102,60,24,0,0,0,0,0,0,0,0,0,198,198,214,214,214,254,108,0,0,0,0,0,0,0,0,0,198,108,56,56,56,108,198,0,0,0,0,0,0,0,0,0,198,198,198,198,198,198,126,6,12,248,0,0,0,0,0,0,254,204,24,48,96,198,254,0,0,0,0,0,0,14,24,24,24,112,24,24,24,24,14,0,0,0,0,0,0,24,24,24,24,24,24,24,24,24,24,24,24,0,0,0,0,112,24,24,24,14,24,24,24,24,112,0,0,0,0,0,0,118,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,56,108,198,198,198,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,44,0,0,0,4,54,22,54,37,54,71,54,88,54,18,55,36,55,51,55,166,56,183,56,73,57,91,57,106,57,179,57,196,57,213,59,233,59,248,59,0,176,0,0,12,0,0,0,191,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };\nunsigned char loader_rpi_bin[46592] = { 0,0,192,242,161,215,5,16,32,0,0,249,161,0,56,213,33,4,64,146,33,3,0,180,95,32,3,213,255,255,255,23,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,83,105,109,112,108,101,98,111,111,116,32,104,116,116,112,115,58,47,47,99,111,100,101,98,101,114,103,46,111,114,103,47,98,122,116,47,115,105,109,112,108,101,98,111,111,116,0,97,97,114,99,104,54,52,0,0,1,0,130,210,64,66,56,213,0,4,126,146,31,48,0,241,65,1,0,84,32,182,128,210,0,17,30,213,32,121,128,210,0,64,30,213,160,0,0,16,32,64,30,213,128,0,128,210,1,65,30,213,224,3,159,214,31,16,0,241,128,3,0,84,0,225,60,213,0,4,64,178,0,225,28,213,63,226,28,213,0,0,176,210,0,0,127,178,0,17,28,213,0,17,60,213,0,0,56,213,162,0,56,213,0,0,28,213,162,0,28,213,224,127,134,210,64,17,28,213,127,17,28,213,0,6,160,210,64,16,24,213,2,0,129,210,2,26,166,242,2,16,24,213,162,120,128,210,2,64,28,213,162,0,0,16,34,64,28,213,63,0,0,145,1,65,28,213,224,3,159,214,224,2,0,16,0,192,24,213,191,64,0,213,63,0,0,145,142,39,0,20,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,0,0,128,210,1,82,56,213,34,64,56,213,3,64,56,213,4,96,56,213,5,16,56,213,70,32,56,213,123,38,0,20,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,32,0,128,210,1,82,56,213,34,64,56,213,3,64,56,213,4,96,56,213,5,16,56,213,70,32,56,213,91,38,0,20,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,64,0,128,210,1,82,56,213,34,64,56,213,3,64,56,213,4,96,56,213,5,16,56,213,70,32,56,213,59,38,0,20,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,96,0,128,210,1,82,56,213,34,64,56,213,3,64,56,213,4,96,56,213,5,16,56,213,70,32,56,213,27,38,0,20,255,195,0,209,224,23,0,249,225,19,0,249,226,31,0,185,232,23,64,249,232,11,0,249,232,19,64,249,232,7,0,249,1,0,0,20,232,31,64,185,9,5,0,113,233,31,0,185,104,1,0,52,1,0,0,20,232,7,64,249,9,5,0,145,233,7,0,249,8,1,64,57,233,11,64,249,42,5,0,145,234,11,0,249,40,1,0,57,243,255,255,23,255,195,0,145,192,3,95,214,255,131,0,209,224,15,0,249,225,95,0,57,226,19,0,185,232,15,64,249,232,7,0,249,1,0,0,20,232,19,64,185,9,5,0,113,233,19,0,185,8,1,0,52,1,0,0,20,232,95,64,57,233,7,64,249,42,5,0,145,234,7,0,249,40,1,0,57,246,255,255,23,255,131,0,145,192,3,95,214,255,195,0,209,224,19,0,249,225,15,0,249,226,23,0,185,232,19,64,249,232,7,0,249,232,15,64,249,232,3,0,249,1,0,0,20,232,23,64,185,9,5,0,113,233,23,0,185,232,2,0,52,1,0,0,20,232,7,64,249,8,1,64,57,233,3,64,249,41,1,64,57,8,1,9,107,32,1,0,84,1,0,0,20,232,7,64,249,8,1,64,57,233,3,64,249,41,1,64,57,8,1,9,107,232,47,0,185,10,0,0,20,232,7,64,249,8,5,0,145,232,7,0,249,232,3,64,249,8,5,0,145,232,3,0,249,231,255,255,23,255,47,0,185,1,0,0,20,224,47,64,185,255,195,0,145,192,3,95,214,255,67,0,209,224,7,0,249,234,7,64,249,72,1,64,249,9,5,0,145,73,1,0,249,0,1,64,57,255,67,0,145,192,3,95,214,255,67,1,209,253,123,4,169,253,3,1,145,160,3,31,248,161,131,30,248,162,67,30,184,168,3,95,248,168,0,0,180,1,0,0,20,168,131,94,248,168,0,0,181,1,0,0,20,72,0,128,18,168,195,31,184,225,0,0,20,31,32,3,213,64,127,5,16,225,3,31,42,2,158,128,82,168,255,255,151,168,3,95,248,8,1,64,57,8,125,0,113,129,8,0,84,1,0,0,20,168,3,95,248,8,13,0,145,168,3,31,248,168,3,95,248,9,5,0,145,169,3,31,248,8,1,64,57,168,51,30,56,168,3,95,248,8,25,0,145,168,3,31,248,168,51,94,56,104,2,16,54,1,0,0,20,168,3,95,248,9,5,0,145,169,3,31,248,8,1,64,57,232,31,0,185,168,3,95,248,9,5,0,145,169,3,31,248,9,1,64,57,232,31,64,185,8,33,9,11,232,31,0,185,233,31,128,185,168,3,95,248,8,1,9,139,168,3,31,248,1,0,0,20,168,51,94,56,104,1,24,54,1,0,0,20,1,0,0,20,168,3,95,248,9,5,0,145,169,3,31,248,8,1,64,57,104,0,0,52,1,0,0,20,250,255,255,23,1,0,0,20,168,51,94,56,104,1,32,54,1,0,0,20,1,0,0,20,168,3,95,248,9,5,0,145,169,3,31,248,8,1,64,57,104,0,0,52,1,0,0,20,250,255,255,23,1,0,0,20,168,51,94,56,200,0,8,54,1,0,0,20,168,3,95,248,8,9,0,145,168,3,31,248,1,0,0,20,168,3,95,248,73,0,0,240,40,97,2,249,25,0,0,20,168,3,95,248,8,33,64,57,8,225,1,113,33,2,0,84,1,0,0,20,160,131,94,248,161,3,95,248,2,1,128,82,63,255,255,151,168,131,94,248,8,33,0,145,168,131,30,248,168,67,94,184,8,33,0,113,168,67,30,184,168,3,95,248,8,41,0,145,73,0,0,240,40,97,2,249,4,0,0,20,72,0,128,18,168,195,31,184,126,0,0,20,1,0,0,20,31,32,3,213,201,114,5,16,8,0,128,18,40,33,0,185,168,131,94,248,40,13,0,249,168,67,94,184,40,17,0,185,168,67,94,184,224,3,8,42,118,0,0,148,1,0,0,20,1,0,0,20,31,32,3,213,40,113,5,16,8,33,64,185,8,5,0,49,1,5,0,84,1,0,0,20,1,0,0,20,31,32,3,213,64,112,5,16,224,11,0,249,60,1,0,148,232,3,0,42,224,11,64,249,8,36,0,185,65,0,128,82,226,3,31,42,85,1,0,148,232,11,64,249,0,33,0,185,8,33,64,185,8,5,0,113,1,1,0,84,1,0,0,20,31,32,3,213,72,110,5,16,0,193,0,145,1,65,10,145,116,1,0,148,15,0,0,20,31,32,3,213,136,109,5,16,8,33,64,185,8,9,0,113,33,1,0,84,1,0,0,20,31,32,3,213,200,108,5,16,224,3,8,170,1,193,0,145,2,65,10,145,236,1,0,148,1,0,0,20,1,0,0,20,1,0,0,20,31,32,3,213,168,107,5,16,8,33,64,185,232,15,0,185,232,0,0,52,1,0,0,20,232,15,64,185,8,5,0,113,8,5,0,113,233,0,0,84,14,0,0,20,31,32,3,213,64,106,5,16,173,2,0,148,224,31,0,185,13,0,0,20,31,32,3,213,168,105,5,16,224,3,8,170,1,193,0,145,2,65,10,145,238,2,0,148,224,31,0,185,5,0,0,20,71,3,0,148,72,0,128,18,168,195,31,184,40,0,0,20,168,67,94,184,31,32,3,213,9,104,5,16,41,17,64,185,8,1,9,107,232,3,8,42,224,3,8,42,135,3,0,148,232,31,64,185,8,5,0,113,1,1,0,84,1,0,0,20,31,32,3,213,168,102,5,16,8,37,64,185,104,0,0,53,1,0,0,20,174,255,255,23,232,31,64,185,200,0,0,52,1,0,0,20,46,3,0,148,232,31,64,185,168,195,31,184,15,0,0,20,1,0,0,20,31,32,3,213,233,100,5,16,40,17,64,185,8,5,0,113,40,17,0,185,40,243,255,53,1,0,0,20,1,0,0,20,232,31,64,185,136,242,255,52,1,0,0,20,191,195,31,184,1,0,0,20,160,195,95,184,253,123,68,169,255,67,1,145,192,3,95,214,255,3,1,209,31,32,3,213,168,143,5,16,224,27,0,249,73,0,0,240,63,77,5,249,233,27,64,249,41,253,73,211,41,5,0,145,74,0,0,240,73,161,10,185,73,0,0,240,63,165,10,185,8,5,64,249,200,1,0,180,1,0,0,20,232,27,64,249,104,1,0,180,1,0,0,20,72,0,0,240,8,161,74,185,31,32,3,213,41,141,5,16,41,21,64,185,41,17,0,113,8,1,9,107,130,0,0,84,1,0,0,20,255,31,0,249,179,0,0,20,31,32,3,213,8,140,5,16,9,113,64,57,41,29,0,17,41,125,3,19,74,0,0,240,73,169,10,185,9,5,64,249,11,25,64,185,107,17,0,113,12,17,64,185,107,125,12,27,235,3,11,42,41,1,11,139,75,169,74,185,74,0,128,82,74,125,11,27,234,3,10,42,41,1,10,139,74,0,0,240,73,77,5,249,8,133,64,57,8,33,0,113,77,1,0,84,1,0,0,20,31,32,3,213,232,136,5,16,8,133,64,57,9,33,0,113,8,4,128,82,8,33,201,26,232,35,0,185,10,0,0,20,31,32,3,213,232,135,5,16,9,133,64,57,8,1,128,82,9,1,9,107,8,4,128,82,8,41,201,26,232,35,0,185,1,0,0,20,233,35,64,185,31,32,3,213,168,134,5,16,10,129,64,57,41,33,202,26,233,31,0,185,8,141,64,57,8,33,0,113,77,1,0,84,1,0,0,20,31,32,3,213,136,133,5,16,8,141,64,57,9,33,0,113,8,4,128,82,8,33,201,26,232,27,0,185,10,0,0,20,31,32,3,213,136,132,5,16,9,141,64,57,8,1,128,82,9,1,9,107,8,4,128,82,8,41,201,26,232,27,0,185,1,0,0,20,233,31,64,185,234,27,64,185,31,32,3,213,40,131,5,16,11,137,64,57,74,33,203,26,41,1,10,42,233,23,0,185,8,149,64,57,8,33,0,113,77,1,0,84,1,0,0,20,31,32,3,213,232,129,5,16,8,149,64,57,9,33,0,113,8,4,128,82,8,33,201,26,232,19,0,185,10,0,0,20,31,32,3,213,232,128,5,16,9,149,64,57,8,1,128,82,9,1,9,107,8,4,128,82,8,41,201,26,232,19,0,185,1,0,0,20,232,23,64,185,233,19,64,185,31,32,3,213,138,127,5,16,74,145,64,57,41,33,202,26,8,1,9,42,232,47,0,185,255,39,0,185,255,43,0,185,1,0,0,20,232,39,64,185,31,32,3,213,73,126,5,16,41,21,64,185,41,17,0,113,8,1,9,107,194,6,0,84,1,0,0,20,31,32,3,213,104,125,5,16,8,113,64,57,232,15,0,185,8,61,0,113,8,5,0,113,73,1,0,84,1,0,0,20,232,15,64,185,8,97,0,113,96,2,0,84,1,0,0,20,232,15,64,185,8,129,0,113,224,1,0,84,27,0,0,20,232,47,64,185,73,0,0,240,42,77,69,249,31,32,3,213,11,123,5,16,107,17,64,185,74,1,11,139,235,43,64,185,72,105,43,120,41,77,69,249,234,43,64,185,40,105,42,120,14,0,0,20,232,47,64,185,73,0,0,240,42,77,69,249,31,32,3,213,107,121,5,16,107,17,64,185,74,1,11,139,235,43,64,185,72,105,43,184,41,77,69,249,234,43,64,185,40,105,42,184,1,0,0,20,1,0,0,20,232,39,64,185,8,5,0,17,232,39,0,185,72,0,0,240,9,169,74,185,232,43,64,185,8,1,9,11,232,43,0,185,197,255,255,23,232,27,64,249,31,32,3,213,201,118,5,16,41,21,64,185,41,17,0,113,233,3,9,42,8,9,201,154,232,31,0,249,1,0,0,20,224,31,64,249,255,3,1,145,192,3,95,214,255,131,0,209,253,123,1,169,253,67,0,145,224,7,0,249,234,7,64,249,72,13,64,185,9,5,0,113,73,13,0,185,104,1,0,53,1,0,0,20,224,7,64,249,38,254,255,151,8,28,0,18,233,7,64,249,40,9,0,185,233,7,64,249,232,0,128,82,40,13,0,185,1,0,0,20,232,7,64,249,8,9,64,185,8,1,0,18,232,7,0,185,233,7,64,249,40,9,64,185,8,125,1,83,40,9,0,185,224,7,64,185,253,123,65,169,255,131,0,145,192,3,95,214,255,195,0,209,253,123,2,169,253,131,0,145,160,131,31,248,161,67,31,184,226,19,0,185,255,15,0,185,168,67,95,184,136,3,0,52,1,0,0,20,169,67,95,184,40,0,128,82,9,33,201,26,233,11,0,185,232,7,0,185,1,0,0,20,232,7,64,185,233,11,64,185,8,1,9,107,2,2,0,84,1,0,0,20,160,131,95,248,203,255,255,151,224,0,0,52,1,0,0,20,233,7,64,185,232,15,64,185,8,1,9,11,232,15,0,185,1,0,0,20,1,0,0,20,232,7,64,185,8,121,31,83,232,7,0,185,238,255,255,23,1,0,0,20,232,15,64,185,233,19,64,185,0,1,9,11,253,123,66,169,255,195,0,145,192,3,95,214,255,131,0,209,224,15,0,249,225,11,0,249,255,15,0,185,1,0,0,20,232,15,64,185,8,29,0,113,106,1,0,84,1,0,0,20,232,15,64,249,233,15,128,185,8,5,9,139,31,1,0,121,1,0,0,20,232,15,64,185,8,5,0,17,232,15,0,185,244,255,255,23,233,15,64,249,8,3,128,82,40,29,0,121,233,15,64,249,8,19,128,82,40,33,0,121,233,15,64,249,8,14,128,82,40,37,0,121,255,15,0,185,1,0,0,20,232,15,64,185,8,97,0,113,170,1,0,84,1,0,0,20,232,15,64,185,8,1,4,17,233,15,64,249,41,129,0,145,234,15,128,185,40,121,42,120,1,0,0,20,232,15,64,185,8,5,0,17,232,15,0,185,242,255,255,23,255,15,0,185,1,0,0,20,232,15,64,185,8,65,2,113,170,1,0,84,1,0,0,20,232,15,64,185,233,15,64,249,41,129,0,145,234,15,64,185,74,97,0,17,40,217,42,120,1,0,0,20,232,15,64,185,8,5,0,17,232,15,0,185,242,255,255,23,255,15,0,185,1,0,0,20,232,15,64,185,8,33,0,113,202,1,0,84,1,0,0,20,232,15,64,185,8,97,4,17,233,15,64,249,41,129,0,145,234,15,64,185,74,161,2,17,40,217,42,120,1,0,0,20,232,15,64,185,8,5,0,17,232,15,0,185,241,255,255,23,255,15,0,185,1,0,0,20,232,15,64,185,8,193,1,113,202,1,0,84,1,0,0,20,232,15,64,185,8,65,2,17,233,15,64,249,41,129,0,145,234,15,64,185,74,193,2,17,40,217,42,120,1,0,0,20,232,15,64,185,8,5,0,17,232,15,0,185,241,255,255,23,255,15,0,185,1,0,0,20,232,15,64,185,8,21,0,113,106,1,0,84,1,0,0,20,232,11,64,249,233,15,128,185,8,5,9,139,31,1,0,121,1,0,0,20,232,15,64,185,8,5,0,17,232,15,0,185,244,255,255,23,233,11,64,249,8,4,128,82,40,21,0,121,255,15,0,185,1,0,0,20,232,15,64,185,8,129,0,113,138,1,0,84,1,0,0,20,232,15,64,185,233,11,64,249,41,129,0,145,234,15,128,185,40,121,42,120,1,0,0,20,232,15,64,185,8,5,0,17,232,15,0,185,243,255,255,23,255,131,0,145,192,3,95,214,255,3,7,209,253,123,26,169,252,219,0,249,253,131,6,145,168,99,0,209,232,15,0,249,0,9,0,249,1,5,0,249,2,1,0,249,0,9,64,249,161,0,128,82,225,23,0,185,34,32,128,82,68,255,255,151,225,23,64,185,232,15,64,249,224,71,0,185,0,9,64,249,34,0,128,82,62,255,255,151,232,15,64,249,224,67,0,185,0,9,64,249,130,0,128,82,225,3,2,42,56,255,255,151,224,63,0,185,255,59,0,185,1,0,0,20,232,59,64,185,8,77,0,113,130,1,0,84,1,0,0,20,232,59,64,185,233,3,8,42,232,35,1,145,8,1,9,139,31,1,0,57,1,0,0,20,232,59,64,185,8,5,0,17,232,59,0,185,243,255,255,23,255,59,0,185,1,0,0,20,232,59,64,185,233,63,64,185,8,1,9,107,194,2,0,84,1,0,0,20,232,15,64,249,0,9,64,249,97,0,128,82,226,3,31,42,27,255,255,151,224,47,0,185,232,47,64,185,233,59,64,185,234,3,9,42,31,32,3,213,169,177,4,16,41,105,106,56,234,3,9,42,233,35,1,145,40,105,42,56,1,0,0,20,232,59,64,185,8,5,0,17,232,59,0,185,232,255,255,23,232,15,64,249,0,5,64,249,225,35,1,145,98,2,128,82,151,36,0,148,255,55,0,185,1,0,0,20,232,55,64,185,233,71,64,185,234,67,64,185,41,1,10,11,8,1,9,107,226,13,0,84,1,0,0,20,232,15,64,249,0,9,64,249,1,5,64,249,238,36,0,148,224,43,0,185,232,43,64,185,232,19,0,185,8,65,0,113,64,1,0,84,1,0,0,20,232,19,64,185,8,69,0,113,224,4,0,84,1,0,0,20,232,19,64,185,8,73,0,113,96,7,0,84,82,0,0,20,232,15,64,249,233,55,64,185,41,5,0,113,233,3,9,42,234,3,9,42,233,35,1,145,41,1,10,139,41,1,64,57,233,159,0,57,0,9,64,249,65,0,128,82,98,0,128,82,223,254,255,151,224,51,0,185,1,0,0,20,232,51,64,185,8,2,0,52,1,0,0,20,232,159,64,57,233,55,64,185,234,3,9,42,233,3,10,42,41,5,0,17,233,55,0,185,233,35,1,145,41,1,10,139,40,1,0,57,1,0,0,20,232,51,64,185,8,5,0,113,232,51,0,185,240,255,255,23,58,0,0,20,232,15,64,249,0,9,64,249,98,0,128,82,225,3,2,42,198,254,255,151,224,51,0,185,1,0,0,20,232,51,64,185,232,1,0,52,1,0,0,20,232,55,64,185,233,3,8,42,232,3,9,42,8,5,0,17,232,55,0,185,232,35,1,145,8,1,9,139,31,1,0,57,1,0,0,20,232,51,64,185,8,5,0,113,232,51,0,185,241,255,255,23,34,0,0,20,232,15,64,249,0,9,64,249,225,0,128,82,98,1,128,82,174,254,255,151,224,51,0,185,1,0,0,20,232,51,64,185,232,1,0,52,1,0,0,20,232,55,64,185,233,3,8,42,232,3,9,42,8,5,0,17,232,55,0,185,232,35,1,145,8,1,9,139,31,1,0,57,1,0,0,20,232,51,64,185,8,5,0,113,232,51,0,185,241,255,255,23,10,0,0,20,232,43,64,185,233,55,64,185,234,3,9,42,233,3,10,42,41,5,0,17,233,55,0,185,233,35,1,145,40,105,42,56,1,0,0,20,141,255,255,23,232,15,64,249,0,5,64,249,226,71,64,185,225,35,1,145,225,7,0,249,27,36,0,148,233,15,64,249,232,7,64,249,32,1,64,249,233,71,64,185,1,1,9,139,226,67,64,185,20,36,0,148,252,219,64,249,253,123,90,169,255,3,7,145,192,3,95,214,255,3,1,209,253,123,3,169,253,195,0,145,160,3,31,248,168,3,95,248,8,41,64,185,104,5,0,53,1,0,0,20,160,3,95,248,136,252,255,151,224,11,0,185,160,3,95,248,133,252,255,151,232,3,0,42,224,11,64,185,9,29,0,18,8,32,128,82,232,15,0,185,8,125,9,27,8,1,32,11,168,195,30,184,160,3,95,248,123,252,255,151,224,19,0,185,160,3,95,248,120,252,255,151,232,15,64,185,233,3,0,42,224,19,64,185,41,29,0,18,8,125,9,27,8,1,32,11,232,27,0,185,168,195,94,184,233,27,64,185,233,3,41,42,8,33,41,107,160,0,0,84,1,0,0,20,72,0,128,18,168,195,31,184,28,0,0,20,168,195,94,184,8,5,0,17,169,3,95,248,40,41,0,185,168,3,95,248,31,13,0,185,1,0,0,20,169,3,95,248,40,41,64,185,8,5,0,113,40,41,0,185,168,0,0,53,1,0,0,20,40,0,128,82,168,195,31,184,12,0,0,20,160,3,95,248,86,252,255,151,224,95,0,57,232,95,64,57,171,3,95,248,105,13,64,249,42,5,0,145,106,13,0,249,40,1,0,57,191,195,31,184,1,0,0,20,160,195,95,184,253,123,67,169,255,3,1,145,192,3,95,214,255,3,1,209,253,123,3,169,253,195,0,145,160,3,31,248,225,15,0,249,226,11,0,249,168,3,95,248,8,41,64,185,168,7,0,53,1,0,0,20,160,3,95,248,225,15,64,249,30,36,0,148,224,7,0,185,232,7,64,185,8,1,4,113,74,1,0,84,1,0,0,20,232,7,64,185,171,3,95,248,105,13,64,249,42,5,0,145,106,13,0,249,40,1,0,57,191,195,31,184,63,0,0,20,232,7,64,185,8,1,4,113,161,0,0,84,1,0,0,20,40,0,128,82,168,195,31,184,56,0,0,20,232,7,64,185,8,5,4,113,232,7,0,185,160,3,95,248,233,7,128,185,31,32,3,213,72,139,4,16,1,105,105,56,233,7,128,185,31,32,3,213,168,139,4,80,2,121,105,120,9,254,255,151,168,3,95,248,0,41,0,185,160,3,95,248,225,11,64,249,248,35,0,148,224,11,0,185,160,3,95,248,233,11,128,185,31,32,3,213,8,140,4,80,1,105,105,56,233,11,128,185,31,32,3,213,136,140,4,16,2,121,105,120,249,253,255,151,224,15,0,185,233,15,64,185,232,3,31,42,8,1,9,107,169,3,95,248,40,45,0,185,1,0,0,20,168,3,95,248,8,13,64,249,169,3,95,248,41,45,128,185,8,1,9,139,8,1,64,57,169,3,95,248,41,13,64,249,40,1,0,57,169,3,95,248,40,13,64,249,8,5,0,145,40,13,0,249,169,3,95,248,40,41,64,185,8,5,0,113,40,41,0,185,191,195,31,184,1,0,0,20,160,195,95,184,253,123,67,169,255,3,1,145,192,3,95,214,255,67,0,209,72,0,0,208,8,77,69,249,136,8,0,180,1,0,0,20,255,11,0,185,255,15,0,185,1,0,0,20,232,11,64,185,31,32,3,213,169,43,5,16,41,21,64,185,41,9,0,113,8,1,9,107,2,7,0,84,1,0,0,20,31,32,3,213,200,42,5,16,8,113,64,57,232,7,0,185,8,61,0,113,8,5,0,113,73,1,0,84,1,0,0,20,232,7,64,185,8,97,0,113,128,2,0,84,1,0,0,20,232,7,64,185,8,129,0,113,0,2,0,84,29,0,0,20,72,0,0,208,8,145,74,185,73,0,0,208,42,77,69,249,31,32,3,213,75,40,5,16,107,17,64,185,74,1,11,139,235,15,64,185,72,105,43,120,41,77,69,249,234,15,64,185,40,105,42,120,15,0,0,20,72,0,0,208,8,145,74,185,73,0,0,208,42,77,69,249,31,32,3,213,139,38,5,16,107,17,64,185,74,1,11,139,235,15,64,185,72,105,43,184,41,77,69,249,234,15,64,185,40,105,42,184,1,0,0,20,1,0,0,20,232,11,64,185,8,5,0,17,232,11,0,185,72,0,0,208,9,169,74,185,232,15,64,185,8,1,9,11,232,15,0,185,195,255,255,23,1,0,0,20,72,0,0,208,31,77,5,249,255,67,0,145,192,3,95,214,255,67,0,209,224,7,0,249,72,0,0,208,8,77,69,249,200,9,0,180,1,0,0,20,73,0,0,208,40,165,74,185,232,7,0,185,232,7,64,249,8,253,73,211,31,32,3,213,10,34,5,16,74,21,64,185,74,17,0,113,234,3,10,42,8,125,10,155,74,0,0,208,74,161,74,185,8,9,202,154,74,0,0,208,74,169,74,185,8,125,10,155,40,165,10,185,1,0,0,20,232,7,64,185,73,0,0,208,41,165,74,185,8,1,9,107,130,6,0,84,1,0,0,20,31,32,3,213,136,31,5,16,8,113,64,57,232,3,0,185,8,61,0,113,8,5,0,113,73,1,0,84,1,0,0,20,232,3,64,185,8,97,0,113,160,2,0,84,1,0,0,20,232,3,64,185,8,129,0,113,32,2,0,84,30,0,0,20,73,0,0,208,40,77,69,249,31,32,3,213,74,29,5,16,74,17,64,185,8,1,10,139,234,7,64,185,10,1,10,139,232,255,159,82,72,1,0,121,41,77,69,249,234,7,64,185,41,1,10,139,40,1,0,121,15,0,0,20,73,0,0,208,40,77,69,249,31,32,3,213,106,27,5,16,74,17,64,185,10,1,10,139,232,7,64,185,235,3,8,42,8,224,191,18,72,105,43,184,41,77,69,249,234,7,64,185,40,105,42,184,1,0,0,20,1,0,0,20,232,7,64,185,8,5,0,17,232,7,0,185,201,255,255,23,1,0,0,20,255,67,0,145,192,3,95,214,255,131,0,209,224,15,0,249,225,11,0,249,72,0,128,82,232,15,0,185,232,11,64,249,31,1,0,185,1,0,0,20,232,15,64,185,9,5,0,113,233,15,0,185,200,9,0,52,1,0,0,20,232,15,64,249,8,1,64,57,8,193,0,113,107,2,0,84,1,0,0,20,232,15,64,249,8,1,64,57,8,229,0,113,204,1,0,84,1,0,0,20,233,11,64,249,40,1,64,185,8,109,28,83,40,1,0,185,232,15,64,249,8,1,64,57,10,193,0,113,233,11,64,249,40,1,64,185,8,1,10,11,40,1,0,185,50,0,0,20,232,15,64,249,8,1,64,57,8,133,1,113,139,2,0,84,1,0,0,20,232,15,64,249,8,1,64,57,8,153,1,113,236,1,0,84,1,0,0,20,233,11,64,249,40,1,64,185,8,109,28,83,40,1,0,185,232,15,64,249,8,1,64,57,8,133,1,113,10,41,0,17,233,11,64,249,40,1,64,185,8,1,10,11,40,1,0,185,26,0,0,20,232,15,64,249,8,1,64,57,8,5,1,113,139,2,0,84,1,0,0,20,232,15,64,249,8,1,64,57,8,25,1,113,236,1,0,84,1,0,0,20,233,11,64,249,40,1,64,185,8,109,28,83,40,1,0,185,232,15,64,249,8,1,64,57,8,5,1,113,10,41,0,17,233,11,64,249,40,1,64,185,8,1,10,11,40,1,0,185,2,0,0,20,8,0,0,20,1,0,0,20,1,0,0,20,1,0,0,20,232,15,64,249,8,5,0,145,232,15,0,249,176,255,255,23,224,15,64,249,255,131,0,145,192,3,95,214,255,131,0,209,224,15,0,249,225,11,0,249,232,11,64,249,31,1,0,185,1,0,0,20,232,15,64,249,9,1,64,57,8,0,128,82,41,193,0,113,232,15,0,185,11,1,0,84,1,0,0,20,232,15,64,249,8,1,64,57,8,229,0,113,232,199,159,26,232,15,0,185,1,0,0,20,232,15,64,185,104,2,0,54,1,0,0,20,233,11,64,249,40,1,64,185,74,1,128,82,8,125,10,27,40,1,0,185,232,15,64,249,8,1,64,57,10,193,0,113,233,11,64,249,40,1,64,185,8,1,10,11,40,1,0,185,1,0,0,20,232,15,64,249,8,5,0,145,232,15,0,249,224,255,255,23,224,15,64,249,255,131,0,145,192,3,95,214,255,67,0,209,31,32,3,213,8,3,5,16,232,7,0,185,224,63,0,57,1,0,0,20,31,32,3,213,1,0,0,20,72,0,0,208,8,217,68,249,9,16,151,210,8,1,9,139,8,97,0,145,8,1,64,185,8,255,255,55,1,0,0,20,232,7,64,185,8,109,28,18,233,63,64,57,41,13,0,18,8,1,9,42,73,0,0,208,41,217,68,249,10,16,151,210,41,1,10,139,41,129,0,145,40,1,0,185,1,0,0,20,1,0,0,20,31,32,3,213,1,0,0,20,72,0,0,208,8,217,68,249,9,16,151,210,8,1,9,139,8,97,0,145,8,1,64,185,8,255,247,55,1,0,0,20,72,0,0,208,8,217,68,249,9,16,151,210,8,1,9,139,8,1,0,145,8,1,64,185,232,11,0,185,1,0,0,20,232,11,64,185,8,13,0,18,233,63,64,57,8,1,9,107,33,253,255,84,1,0,0,20,234,7,64,185,232,11,64,185,9,109,28,18,8,0,128,82,41,1,10,107,232,3,0,185,65,1,0,84,1,0,0,20,31,32,3,213,136,251,4,16,8,5,64,185,9,0,176,82,8,1,9,107,232,23,159,26,232,3,0,185,1,0,0,20,232,3,64,185,0,1,0,18,255,67,0,145,192,3,95,214,255,67,1,209,253,123,4,169,253,3,1,145,160,195,31,184,161,131,31,184,162,67,31,184,168,195,95,184,168,0,0,52,1,0,0,20,168,131,95,184,232,7,0,53,1,0,0,20,74,0,0,208,31,32,3,213,104,248,4,16,168,131,30,248,9,6,128,82,73,193,9,185,31,5,0,185,105,0,128,82,137,0,160,114,9,9,0,185,0,1,128,82,0,13,0,185,0,17,0,185,31,21,0,185,31,25,0,185,169,0,128,82,137,0,160,114,9,29,0,185,137,0,128,82,9,33,0,185,9,37,0,185,31,41,0,185,31,45,0,185,148,255,255,151,8,28,0,18,104,4,0,52,1,0,0,20,31,32,3,213,40,245,4,16,8,21,64,185,200,3,0,52,1,0,0,20,31,32,3,213,136,244,4,16,8,41,64,185,40,3,0,52,1,0,0,20,31,32,3,213,232,243,4,16,9,21,64,185,169,195,31,184,8,25,64,185,168,131,31,184,168,195,95,184,8,129,12,113,162,0,0,84,1,0,0,20,8,100,128,82,168,195,31,184,1,0,0,20,168,131,95,184,8,97,9,113,162,0,0,84,1,0,0,20,8,75,128,82,168,131,31,184,1,0,0,20,8,4,128,82,168,67,31,184,1,0,0,20,1,0,0,20,31,32,3,213,232,245,4,16,8,5,64,249,40,3,0,180,1,0,0,20,9,4,128,82,74,0,0,208,31,32,3,213,8,240,4,16,73,193,9,185,31,5,0,185,41,0,144,82,137,0,160,114,9,9,0,185,0,1,128,82,0,13,0,185,0,17,0,185,31,32,3,213,201,243,4,16,233,19,0,249,41,5,64,249,9,21,0,185,31,25,0,185,31,29,0,185,86,255,255,151,232,19,64,249,31,5,0,249,1,0,0,20,168,195,95,184,8,1,5,113,162,0,0,84,1,0,0,20,8,40,128,82,168,195,31,184,1,0,0,20,168,131,95,184,8,33,3,113,162,0,0,84,1,0,0,20,8,25,128,82,168,131,31,184,1,0,0,20,168,67,95,184,8,61,0,113,160,1,0,84,1,0,0,20,168,67,95,184,8,65,0,113,32,1,0,84,1,0,0,20,168,67,95,184,8,97,0,113,160,0,0,84,1,0,0,20,8,4,128,82,168,67,31,184,1,0,0,20,137,17,128,82,74,0,0,208,31,32,3,213,136,233,4,16,232,11,0,249,73,193,9,185,31,5,0,185,105,0,144,82,137,0,160,114,9,9,0,185,0,1,128,82,224,31,0,185,0,13,0,185,0,17,0,185,169,195,95,184,9,21,0,185,169,131,95,184,9,25,0,185,137,0,144,82,137,0,160,114,9,29,0,185,0,33,0,185,0,37,0,185,169,195,95,184,9,41,0,185,169,131,95,184,9,45,0,185,41,1,144,82,137,0,160,114,9,49,0,185,0,53,0,185,0,57,0,185,31,61,0,185,31,65,0,185,169,0,144,82,137,0,160,114,9,69,0,185,137,0,128,82,9,73,0,185,9,77,0,185,170,67,95,184,10,81,0,185,202,0,144,82,138,0,160,114,10,85,0,185,9,89,0,185,9,93,0,185,42,0,128,82,10,97,0,185,42,0,128,82,138,0,160,114,10,101,0,185,0,105,0,185,0,109,0,185,10,0,130,82,10,113,0,185,31,117,0,185,10,1,128,82,138,0,160,114,10,121,0,185,9,125,0,185,9,129,0,185,31,133,0,185,31,137,0,185,245,254,255,151,8,28,0,18,8,17,0,52,1,0,0,20,31,32,3,213,72,225,4,16,8,81,64,185,169,67,95,184,8,1,9,107,33,16,0,84,1,0,0,20,31,32,3,213,104,224,4,16,8,109,64,185,9,1,128,82,9,0,176,114,8,1,9,107,33,15,0,84,1,0,0,20,31,32,3,213,104,223,4,16,8,113,64,185,136,14,0,52,1,0,0,20,31,32,3,213,200,222,4,16,9,113,64,185,41,117,0,18,233,3,9,42,31,32,3,213,42,227,4,16,73,5,0,249,9,133,64,185,73,17,0,185,9,21,64,185,73,21,0,185,9,25,64,185,73,25,0,185,9,81,64,185,73,113,0,57,41,0,128,82,73,117,0,57,8,97,64,185,8,6,0,52,1,0,0,20,31,32,3,213,40,220,4,16,8,81,64,185,232,15,0,185,8,61,0,113,192,0,0,84,1,0,0,20,232,15,64,185,8,65,0,113,160,1,0,84,24,0,0,20,31,32,3,213,201,223,4,16,168,0,128,82,40,149,0,57,40,141,0,57,40,133,0,57,63,129,0,57,40,137,0,57,72,1,128,82,40,145,0,57,24,0,0,20,31,32,3,213,105,222,4,16,168,0,128,82,40,149,0,57,40,133,0,57,202,0,128,82,42,141,0,57,63,129,0,57,40,137,0,57,104,1,128,82,40,145,0,57,12,0,0,20,31,32,3,213,233,220,4,16,8,1,128,82,40,149,0,57,40,141,0,57,40,133,0,57,63,129,0,57,40,137,0,57,8,2,128,82,40,145,0,57,1,0,0,20,47,0,0,20,31,32,3,213,104,214,4,16,8,81,64,185,232,11,0,185,8,61,0,113,192,0,0,84,1,0,0,20,232,11,64,185,8,65,0,113,160,1,0,84,24,0,0,20,31,32,3,213,8,218,4,16,169,0,128,82,9,149,0,57,9,141,0,57,9,133,0,57,74,1,128,82,10,129,0,57,9,137,0,57,31,145,0,57,24,0,0,20,31,32,3,213,168,216,4,16,169,0,128,82,9,149,0,57,9,133,0,57,202,0,128,82,10,141,0,57,106,1,128,82,10,129,0,57,9,137,0,57,31,145,0,57,12,0,0,20,31,32,3,213,40,215,4,16,9,1,128,82,9,149,0,57,9,141,0,57,9,133,0,57,10,2,128,82,10,129,0,57,9,137,0,57,31,145,0,57,1,0,0,20,1,0,0,20,35,0,0,20,31,32,3,213,136,213,4,16,8,5,64,249,40,3,0,180,1,0,0,20,9,4,128,82,74,0,0,208,31,32,3,213,168,207,4,16,73,193,9,185,31,5,0,185,41,0,144,82,137,0,160,114,9,9,0,185,0,1,128,82,0,13,0,185,0,17,0,185,31,32,3,213,105,211,4,16,233,3,0,249,41,5,64,249,9,21,0,185,31,25,0,185,31,29,0,185,83,254,255,151,232,3,64,249,31,5,0,249,1,0,0,20,31,32,3,213,8,210,4,16,31,113,0,57,31,25,0,185,31,21,0,185,1,0,0,20,253,123,68,169,255,67,1,145,192,3,95,214,255,131,0,209,253,123,1,169,253,67,0,145,72,0,0,176,232,3,0,249,8,217,68,249,9,6,130,210,9,4,160,242,8,1,9,139,31,1,0,185,74,0,0,176,31,32,3,213,136,202,4,16,9,4,128,82,73,193,9,185,31,5,0,185,73,0,144,82,105,0,160,114,9,9,0,185,137,1,128,82,9,13,0,185,0,1,128,82,0,17,0,185,73,0,128,82,9,21,0,185,9,32,129,82,169,7,160,114,9,25,0,185,31,29,0,185,41,254,255,151,232,3,64,249,9,217,68,249,139,0,128,210,11,4,160,242,41,1,11,139,41,1,64,185,169,195,31,184,169,195,95,184,41,101,14,18,169,195,31,184,169,195,95,184,10,0,136,82,74,0,160,114,41,1,10,42,169,195,31,184,169,195,95,184,10,217,68,249,74,1,11,139,73,1,0,185,8,217,68,249,137,18,128,210,9,4,160,242,8,1,9,139,31,1,0,185,191,195,31,184,1,0,0,20,168,195,95,184,8,89,2,113,2,1,0,84,1,0,0,20,31,32,3,213,1,0,0,20,168,195,95,184,8,5,0,17,168,195,31,184,247,255,255,23,72,0,0,176,8,217,68,249,9,19,128,210,9,4,160,242,9,1,9,139,8,0,152,82,40,1,0,185,191,195,31,184,1,0,0,20,168,195,95,184,8,89,2,113,2,1,0,84,1,0,0,20,31,32,3,213,1,0,0,20,168,195,95,184,8,5,0,17,168,195,31,184,247,255,255,23,72,0,0,176,9,217,68,249,10,19,128,210,10,4,160,242,41,1,10,139,63,1,0,185,9,217,68,249,138,8,130,210,10,4,160,242,42,1,10,139,233,255,128,82,73,1,0,185,9,217,68,249,138,4,130,210,10,4,160,242,42,1,10,139,73,0,128,82,73,1,0,185,9,217,68,249,10,5,130,210,10,4,160,242,42,1,10,139,105,1,128,82,73,1,0,185,9,217,68,249,138,5,130,210,10,4,160,242,42,1,10,139,9,12,128,82,73,1,0,185,8,217,68,249,9,6,130,210,9,4,160,242,9,1,9,139,40,96,128,82,40,1,0,185,73,0,0,176,136,0,128,82,40,137,10,185,73,0,0,176,40,141,10,185,253,123,65,169,255,131,0,145,192,3,95,214,255,195,1,209,253,123,6,169,253,131,1,145,31,32,3,213,104,192,4,16,160,243,31,56,31,32,3,213,233,81,4,16,169,3,31,248,169,3,95,248,41,29,64,185,41,29,0,17,41,125,3,83,169,131,29,184,8,5,64,249,232,23,0,249,232,23,64,249,72,43,0,180,1,0,0,20,168,243,95,56,232,39,0,185,8,41,0,113,64,1,0,84,1,0,0,20,232,39,64,185,8,53,0,113,1,2,0,84,1,0,0,20,73,0,0,176,136,0,128,82,40,141,10,185,75,1,0,20,73,0,0,176,136,0,128,82,40,141,10,185,168,3,95,248,10,25,64,185,73,0,0,176,40,137,74,185,8,1,10,11,40,137,10,185,65,1,0,20,72,0,0,176,8,141,74,185,169,3,95,248,41,29,64,185,8,1,9,11,8,21,0,17,31,32,3,213,201,186,4,16,41,21,64,185,8,1,9,107,131,1,0,84,1,0,0,20,73,0,0,176,136,0,128,82,40,141,10,185,168,3,95,248,10,25,64,185,73,0,0,176,40,137,74,185,8,1,10,11,40,137,10,185,1,0,0,20,72,0,0,176,8,137,74,185,169,3,95,248,41,25,64,185,8,1,9,11,8,21,0,17,31,32,3,213,9,184,4,16,41,25,64,185,8,1,9,107,201,11,0,84,1,0,0,20,72,0,0,176,9,137,74,185,169,195,30,184,31,32,3,213,233,182,4,16,42,25,64,185,171,3,95,248,107,25,64,185,74,1,11,107,74,21,0,113,10,137,10,185,10,137,74,185,168,195,94,184,8,1,10,107,168,195,30,184,191,195,29,184,168,195,94,184,41,17,64,185,8,125,9,27,168,67,30,184,168,195,94,184,168,131,30,184,1,0,0,20,168,131,94,184,31,32,3,213,73,180,4,16,41,25,64,185,8,1,9,107,98,3,0,84,1,0,0,20,232,23,64,249,169,195,93,184,0,1,9,139,232,23,64,249,169,67,94,184,1,1,9,139,31,32,3,213,200,178,4,16,2,17,64,185,196,247,255,151,1,0,0,20,168,131,94,184,8,5,0,17,168,131,30,184,31,32,3,213,200,177,4,16,10,17,64,185,169,195,93,184,41,1,10,11,169,195,29,184,9,17,64,185,168,67,94,184,8,1,9,11,168,67,30,184,225,255,255,23,72,0,0,176,9,137,74,185,169,131,30,184,8,137,74,185,31,32,3,213,233,175,4,16,41,17,64,185,8,125,9,27,168,195,29,184,1,0,0,20,168,131,94,184,31,32,3,213,9,175,4,16,41,25,64,185,8,1,9,107,162,2,0,84,1,0,0,20,232,23,64,249,169,195,93,184,0,1,9,139,31,32,3,213,232,173,4,16,2,17,64,185,225,3,31,42,181,247,255,151,1,0,0,20,168,131,94,184,8,5,0,17,168,131,30,184,31,32,3,213,200,172,4,16,9,17,64,185,168,195,93,184,8,1,9,11,168,195,29,184,231,255,255,23,1,0,0,20,168,3,95,248,8,9,64,185,233,3,8,42,31,32,3,213,72,61,4,16,8,1,9,139,232,15,0,249,168,243,95,56,8,1,0,113,109,1,0,84,1,0,0,20,168,243,95,56,169,3,95,248,41,17,64,185,8,1,9,107,162,0,0,84,1,0,0,20,168,243,95,56,232,23,0,185,4,0,0,20,232,3,31,42,232,23,0,185,1,0,0,20,232,15,64,249,233,23,64,185,170,3,95,248,74,21,64,185,41,125,10,27,233,3,9,42,8,1,9,139,232,27,0,249,72,0,0,176,8,137,74,185,31,32,3,213,171,167,4,16,105,17,64,185,8,125,9,27,73,0,0,176,42,141,74,185,107,113,64,57,107,29,0,17,107,125,3,19,74,125,11,27,8,1,10,11,168,195,29,184,168,3,95,248,8,29,64,185,10,5,0,17,40,141,74,185,8,1,10,11,40,141,10,185,191,131,30,184,1,0,0,20,168,131,94,184,169,3,95,248,41,25,64,185,8,1,9,107,2,17,0,84,1,0,0,20,168,195,93,184,168,67,30,184,168,3,95,248,9,29,64,185,40,0,128,82,41,5,0,113,8,33,201,26,168,3,30,184,191,195,30,184,1,0,0,20,169,195,94,184,168,3,95,248,10,29,64,185,8,0,128,82,41,1,10,107,232,19,0,185,226,0,0,84,1,0,0,20,168,3,94,184,8,1,0,113,232,7,159,26,232,19,0,185,1,0,0,20,232,19,64,185,40,11,0,54,1,0,0,20,31,32,3,213,40,161,4,16,8,113,64,57,232,15,0,185,8,61,0,113,8,5,0,113,73,1,0,84,1,0,0,20,232,15,64,185,8,97,0,113,96,3,0,84,1,0,0,20,232,15,64,185,8,129,0,113,128,5,0,84,64,0,0,20,232,27,64,249,8,1,64,57,169,3,94,184,8,1,9,10,168,0,0,52,1,0,0,20,232,255,159,82,232,11,0,185,5,0,0,20,72,0,0,176,8,145,74,185,232,11,0,185,1,0,0,20,232,11,64,185,233,23,64,249,170,67,94,184,40,105,42,120,168,67,94,184,8,9,0,17,168,67,30,184,43,0,0,20,232,27,64,249,8,1,64,57,169,3,94,184,8,1,9,10,168,0,0,52,1,0,0,20,8,224,191,18,232,7,0,185,5,0,0,20,72,0,0,176,8,145,74,185,232,7,0,185,1,0,0,20,232,7,64,185,233,23,64,249,170,67,94,184,40,105,42,184,168,67,94,184,8,13,0,17,168,67,30,184,22,0,0,20,232,27,64,249,8,1,64,57,169,3,94,184,8,1,9,10,168,0,0,52,1,0,0,20,8,0,128,18,232,3,0,185,5,0,0,20,72,0,0,176,8,145,74,185,232,3,0,185,1,0,0,20,232,3,64,185,233,23,64,249,170,67,94,184,40,105,42,184,168,67,94,184,8,17,0,17,168,67,30,184,1,0,0,20,1,0,0,20,168,195,94,184,8,5,0,17,168,195,30,184,168,3,94,184,8,125,1,83,168,3,30,184,154,255,255,23,72,0,0,176,8,145,74,185,233,23,64,249,170,67,94,184,40,105,42,184,1,0,0,20,168,131,94,184,8,5,0,17,168,131,30,184,168,131,93,184,233,3,8,42,232,27,64,249,8,1,9,139,232,27,0,249,31,32,3,213,136,148,4,16,9,17,64,185,168,195,93,184,8,1,9,11,168,195,29,184,117,255,255,23,1,0,0,20,1,0,0,20,1,0,0,20,31,32,3,213,1,0,0,20,72,0,0,176,8,217,68,249,9,3,130,210,9,4,160,242,8,1,9,139,8,1,64,185,8,255,47,55,1,0,0,20,168,243,95,56,73,0,0,176,41,217,68,249,41,5,72,145,40,1,0,185,253,123,70,169,255,195,1,145,192,3,95,214,253,123,190,169,252,11,0,249,253,3,0,145,255,3,8,209,231,83,128,61,230,79,128,61,229,75,128,61,228,71,128,61,227,67,128,61,226,63,128,61,225,59,128,61,224,55,128,61,167,131,24,248,166,3,24,248,165,131,23,248,164,3,23,248,163,131,22,248,162,3,22,248,161,131,21,248,160,131,31,248,232,15,128,18,168,67,31,184,232,6,128,18,168,3,31,184,232,67,3,145,8,1,2,145,168,131,30,248,168,163,2,209,8,225,0,145,168,3,30,248,168,131,0,145,168,131,29,248,232,3,31,170,168,131,28,248,1,0,0,20,168,131,95,248,8,1,64,57,232,88,0,52,1,0,0,20,168,131,95,248,8,1,64,57,8,149,0,113,33,87,0,84,1,0,0,20,168,131,95,248,8,5,0,145,168,131,31,248,168,131,95,248,8,1,64,57,8,149,0,113,97,0,0,84,1,0,0,20,176,2,0,20,232,3,31,42,168,3,27,184,168,195,27,184,1,0,0,20,168,131,95,248,9,1,64,57,232,3,31,42,41,193,0,113,232,207,0,185,11,1,0,84,1,0,0,20,168,131,95,248,8,1,64,57,8,233,0,113,232,167,159,26,232,207,0,185,1,0,0,20,232,207,64,185,8,2,0,54,1,0,0,20,168,195,91,184,8,9,8,11,8,121,31,83,168,195,27,184,168,131,95,248,8,1,64,57,169,195,91,184,8,1,9,11,8,193,0,113,168,195,27,184,168,131,95,248,8,5,0,145,168,131,31,248,227,255,255,23,168,131,95,248,8,1,64,57,8,177,1,113,33,1,0,84,1,0,0,20,168,3,91,184,8,5,0,17,168,3,27,184,168,131,95,248,8,5,0,145,168,131,31,248,1,0,0,20,168,131,95,248,8,1,64,57,8,141,1,113,161,4,0,84,1,0,0,20,168,163,0,209,8,97,0,145,232,99,0,249,168,3,95,184,233,3,8,42,233,203,0,185,200,1,248,54,1,0,0,20,233,99,64,249,232,203,64,185,8,33,0,17,40,1,0,185,8,1,0,113,236,0,0,84,1,0,0,20,233,203,64,185,168,3,94,248,8,193,41,139,232,95,0,249,7,0,0,20,169,131,93,248,232,3,9,170,41,33,0,145,169,131,29,248,232,95,0,249,1,0,0,20,232,95,64,249,8,1,128,185,168,131,28,248,160,131,92,56,252,253,255,151,168,131,95,248,8,5,0,145,168,131,31,248,153,255,255,23,168,131,95,248,8,1,64,57,8,145,1,113,33,20,0,84,1,0,0,20,168,3,91,184,8,4,0,53,1,0,0,20,168,163,0,209,8,97,0,145,232,87,0,249,168,3,95,184,233,3,8,42,233,183,0,185,200,1,248,54,1,0,0,20,233,87,64,249,232,183,64,185,8,33,0,17,40,1,0,185,8,1,0,113,236,0,0,84,1,0,0,20,233,183,64,185,168,3,94,248,8,193,41,139,232,83,0,249,7,0,0,20,169,131,93,248,232,3,9,170,41,33,0,145,169,131,29,248,232,83,0,249,1,0,0,20,232,83,64,249,8,1,128,185,168,131,28,248,31,0,0,20,168,163,0,209,8,97,0,145,232,75,0,249,168,3,95,184,233,3,8,42,233,159,0,185,200,1,248,54,1,0,0,20,233,75,64,249,232,159,64,185,8,33,0,17,40,1,0,185,8,1,0,113,236,0,0,84,1,0,0,20,233,159,64,185,168,3,94,248,8,193,41,139,232,71,0,249,7,0,0,20,169,131,93,248,232,3,9,170,41,33,0,145,169,131,29,248,232,71,0,249,1,0,0,20,232,71,64,249,8,1,64,249,168,131,28,248,1,0,0,20,232,3,31,42,168,131,27,184,168,131,92,184,72,1,248,54,1,0,0,20,169,131,92,248,232,3,31,170,8,1,9,235,168,131,28,248,168,131,91,184,8,5,0,17,168,131,27,184,1,0,0,20,72,2,128,82,168,67,27,184,170,67,155,184,169,175,1,209,232,3,31,42,40,105,42,56,1,0,0,20,168,131,92,248,233,231,3,178,233,204,140,242,10,125,73,155,75,253,127,211,74,253,66,211,74,1,11,11,75,1,128,82,74,125,11,27,8,1,10,107,8,193,0,17,224,3,8,42,168,67,91,184,11,5,0,113,171,67,27,184,232,3,0,42,170,175,1,209,72,201,43,56,168,131,92,248,9,125,73,155,40,253,66,147,8,253,73,139,168,131,28,248,1,0,0,20,168,131,92,248,233,3,31,42,233,135,0,185,232,0,0,180,1,0,0,20,168,67,91,184,8,1,0,113,232,215,159,26,232,135,0,185,1,0,0,20,232,135,64,185,168,251,7,55,1,0,0,20,168,131,91,184,40,1,0,52,1,0,0,20,168,67,91,184,10,5,0,113,170,67,27,184,169,175,1,209,168,5,128,82,40,201,42,56,1,0,0,20,168,195,91,184,8,5,0,113,203,2,0,84,1,0,0,20,168,195,91,184,8,69,0,113,76,2,0,84,1,0,0,20,1,0,0,20,168,67,91,184,170,195,91,184,73,2,128,82,41,1,10,107,8,1,9,107,45,1,0,84,1,0,0,20,168,67,91,184,10,5,0,113,170,67,27,184,169,175,1,209,8,4,128,82,40,201,42,56,243,255,255,23,1,0,0,20,169,67,155,184,168,175,1,209,8,1,9,139,168,131,26,248,191,0,0,20,168,131,95,248,8,1,64,57,8,225,1,113,224,0,0,84,1,0,0,20,168,131,95,248,8,1,64,57,8,193,1,113,97,18,0,84,1,0,0,20,168,131,95,248,8,1,64,57,8,225,1,113,97,4,0,84,1,0,0,20,168,3,91,184,8,4,0,53,1,0,0,20,168,163,0,209,8,97,0,145,232,63,0,249,168,3,95,184,233,3,8,42,233,131,0,185,200,1,248,54,1,0,0,20,233,63,64,249,232,131,64,185,8,33,0,17,40,1,0,185,8,1,0,113,236,0,0,84,1,0,0,20,233,131,64,185,168,3,94,248,8,193,41,139,232,59,0,249,7,0,0,20,169,131,93,248,232,3,9,170,41,33,0,145,169,131,29,248,232,59,0,249,1,0,0,20,232,59,64,249,8,1,128,185,168,131,28,248,31,0,0,20,168,163,0,209,8,97,0,145,232,51,0,249,168,3,95,184,233,3,8,42,233,111,0,185,200,1,248,54,1,0,0,20,233,51,64,249,232,111,64,185,8,33,0,17,40,1,0,185,8,1,0,113,236,0,0,84,1,0,0,20,233,111,64,185,168,3,94,248,8,193,41,139,232,47,0,249,7,0,0,20,169,131,93,248,232,3,9,170,41,33,0,145,169,131,29,248,232,47,0,249,1,0,0,20,232,47,64,249,8,1,64,249,168,131,28,248,1,0,0,20,8,2,128,82,168,67,27,184,170,67,155,184,169,175,1,209,232,3,31,42,40,105,42,56,168,131,95,248,8,1,64,57,8,193,1,113,161,0,0,84,1,0,0,20,8,2,128,82,168,195,27,184,1,0,0,20,1,0,0,20,168,131,92,184,8,13,0,18,224,3,8,42,232,3,0,42,168,67,25,56,168,67,89,56,9,37,0,113,10,6,128,82,233,6,128,82,41,193,138,26,8,1,9,11,169,67,91,184,42,5,0,113,170,67,27,184,169,175,1,209,40,201,42,56,168,131,92,248,8,253,68,147,168,131,28,248,1,0,0,20,168,131,92,248,233,3,31,42,233,87,0,185,232,0,0,180,1,0,0,20,168,67,91,184,8,1,0,113,232,215,159,26,232,87,0,185,1,0,0,20,232,87,64,185,40,252,7,55,1,0,0,20,168,195,91,184,8,5,0,113,203,2,0,84,1,0,0,20,168,195,91,184,8,65,0,113,76,2,0,84,1,0,0,20,1,0,0,20,168,67,91,184,170,195,91,184,9,2,128,82,41,1,10,107,8,1,9,107,45,1,0,84,1,0,0,20,168,67,91,184,10,5,0,113,170,67,27,184,169,175,1,209,8,6,128,82,40,201,42,56,243,255,255,23,1,0,0,20,169,67,155,184,168,175,1,209,8,1,9,139,168,131,26,248,36,0,0,20,168,131,95,248,8,1,64,57,8,205,1,113,97,6,0,84,1,0,0,20,168,163,0,209,8,97,0,145,232,39,0,249,168,3,95,184,233,3,8,42,233,83,0,185,200,1,248,54,1,0,0,20,233,39,64,249,232,83,64,185,8,33,0,17,40,1,0,185,8,1,0,113,236,0,0,84,1,0,0,20,233,83,64,185,168,3,94,248,8,193,41,139,232,35,0,249,7,0,0,20,169,131,93,248,232,3,9,170,41,33,0,145,169,131,29,248,232,35,0,249,1,0,0,20,232,35,64,249,8,1,64,249,168,131,26,248,1,0,0,20,168,131,90,248,200,0,0,181,1,0,0,20,31,32,3,213,72,227,3,48,168,131,26,248,1,0,0,20,1,0,0,20,168,131,90,248,8,1,64,57,8,1,0,52,1,0,0,20,168,131,90,248,9,5,0,145,169,131,26,248,0,1,64,57,133,252,255,151,247,255,255,23,1,0,0,20,1,0,0,20,1,0,0,20,1,0,0,20,168,131,95,248,8,1,64,57,8,77,1,113,65,6,0,84,1,0,0,20,168,163,0,209,8,97,0,145,232,27,0,249,168,3,95,184,233,3,8,42,233,63,0,185,200,1,248,54,1,0,0,20,233,27,64,249,232,63,64,185,8,33,0,17,40,1,0,185,8,1,0,113,236,0,0,84,1,0,0,20,233,63,64,185,168,3,94,248,8,193,41,139,232,23,0,249,7,0,0,20,169,131,93,248,232,3,9,170,41,33,0,145,169,131,29,248,232,23,0,249,1,0,0,20,232,23,64,249,8,1,64,249,168,3,28,248,168,3,92,248,200,0,0,181,1,0,0,20,31,32,3,213,232,220,3,16,168,3,28,248,1,0,0,20,1,0,0,20,168,3,92,248,8,1,64,121,8,1,0,52,1,0,0,20,168,3,92,248,9,9,0,145,169,3,28,248,0,1,64,57,77,252,255,151,247,255,255,23,171,0,0,20,168,131,95,248,8,1,64,57,8,17,1,113,193,20,0,84,1,0,0,20,168,163,0,209,8,97,0,145,232,15,0,249,168,3,95,184,233,3,8,42,233,39,0,185,200,1,248,54,1,0,0,20,233,15,64,249,232,39,64,185,8,33,0,17,40,1,0,185,8,1,0,113,236,0,0,84,1,0,0,20,233,39,64,185,168,3,94,248,8,193,41,139,232,11,0,249,7,0,0,20,169,131,93,248,232,3,9,170,41,33,0,145,169,131,29,248,232,11,0,249,1,0,0,20,232,11,64,249,8,1,64,249,168,131,28,248,168,195,91,184,8,1,0,113,172,0,0,84,1,0,0,20,40,0,128,82,168,195,27,184,1,0,0,20,1,0,0,20,136,3,128,82,168,67,27,184,1,0,0,20,168,67,91,184,232,2,248,55,1,0,0,20,168,131,92,248,169,67,91,184,8,41,201,154,8,13,0,18,224,3,8,42,232,3,0,42,168,67,25,56,168,67,89,56,9,37,0,113,10,6,128,82,233,6,128,82,41,193,138,26,8,1,9,11,168,67,25,56,160,67,89,56,11,252,255,151,1,0,0,20,168,67,91,184,8,17,0,113,168,67,27,184,233,255,255,23,64,7,128,82,4,252,255,151,0,4,128,82,2,252,255,151,168,131,92,248,168,3,29,248,232,3,31,42,168,67,27,184,1,0,0,20,168,67,91,184,8,61,0,113,236,4,0,84,1,0,0,20,168,3,93,248,169,67,155,184,8,105,105,56,8,125,4,83,168,67,25,56,168,67,89,56,9,37,0,113,10,6,128,82,234,11,0,185,233,6,128,82,233,15,0,185,41,193,138,26,8,1,9,11,168,67,25,56,160,67,89,56,233,251,255,151,234,11,64,185,233,15,64,185,168,3,93,248,171,67,155,184,8,105,107,56,8,13,0,18,168,67,25,56,168,67,89,56,11,37,0,113,41,193,138,26,8,1,9,11,168,67,25,56,160,67,89,56,219,251,255,151,0,4,128,82,217,251,255,151,1,0,0,20,168,67,91,184,8,5,0,17,168,67,27,184,216,255,255,23,0,4,128,82,210,251,255,151,232,3,31,42,168,67,27,184,1,0,0,20,168,67,91,184,8,61,0,113,172,3,0,84,1,0,0,20,168,3,93,248,169,67,155,184,8,105,105,56,8,129,0,113,11,1,0,84,1,0,0,20,168,3,93,248,169,67,155,184,8,105,105,56,8,253,1,113,171,0,0,84,1,0,0,20,192,5,128,82,224,7,0,185,6,0,0,20,168,3,93,248,169,67,155,184,0,105,105,56,224,7,0,185,1,0,0,20,224,7,64,185,181,251,255,151,1,0,0,20,168,67,91,184,8,5,0,17,168,67,27,184,226,255,255,23,160,1,128,82,174,251,255,151,64,1,128,82,172,251,255,151,168,131,92,248,8,65,0,145,168,131,28,248,1,0,0,20,168,195,91,184,8,5,0,113,168,195,27,184,136,240,255,53,1,0,0,20,1,0,0,20,1,0,0,20,6,0,0,20,1,0,0,20,168,131,95,248,0,1,64,57,156,251,255,151,1,0,0,20,168,131,95,248,8,5,0,145,168,131,31,248,56,253,255,23,255,3,8,145,252,11,64,249,253,123,194,168,192,3,95,214,255,131,0,209,224,31,0,185,72,0,0,144,8,89,69,249,200,0,0,181,1,0,0,20,8,224,59,213,73,0,0,144,40,89,5,249,1,0,0,20,40,224,59,213,232,11,0,249,72,0,0,144,8,89,69,249,9,125,128,210,8,9,201,154,234,31,64,185,8,125,10,155,9,9,201,154,232,11,64,249,8,1,9,139,232,11,0,249,1,0,0,20,40,224,59,213,232,7,0,249,1,0,0,20,232,7,64,249,233,11,64,249,8,1,9,235,67,255,255,84,1,0,0,20,255,131,0,145,192,3,95,214,255,131,0,209,253,123,1,169,253,67,0,145,160,195,31,184,8,36,148,82,232,0,160,114,232,11,0,185,1,0,0,20,72,0,0,144,8,93,69,249,8,145,0,145,8,1,64,185,169,195,95,184,8,1,9,10,9,0,128,82,233,7,0,185,136,2,0,52,1,0,0,20,72,0,0,144,8,93,69,249,8,193,0,145,8,1,64,185,9,0,144,82,201,47,160,114,8,1,9,10,9,0,128,82,233,7,0,185,40,1,0,53,1,0,0,20,232,11,64,185,9,5,0,113,233,11,0,185,8,1,0,113,232,7,159,26,232,7,0,185,1,0,0,20,232,7,64,185,168,0,0,54,1,0,0,20,32,0,128,82,183,255,255,151,223,255,255,23,233,11,64,185,40,0,128,82,41,1,0,113,232,3,0,185,141,1,0,84,1,0,0,20,72,0,0,144,8,93,69,249,8,193,0,145,8,1,64,185,9,0,144,82,201,47,160,114,8,1,9,106,232,7,159,26,232,3,0,185,1,0,0,20,234,3,64,185,40,0,128,18,233,3,31,42,74,1,0,18,74,1,0,114,0,17,137,26,253,123,65,169,255,131,0,145,192,3,95,214,255,195,0,209,253,123,2,169,253,131,0,145,160,131,31,184,168,131,95,184,9,0,144,82,201,47,160,114,8,1,9,42,232,19,0,185,8,72,136,82,232,1,160,114,232,15,0,185,1,0,0,20,72,0,0,144,8,93,69,249,8,193,0,145,8,1,64,185,233,19,64,185,8,1,9,10,9,0,128,82,233,11,0,185,40,1,0,53,1,0,0,20,232,15,64,185,9,5,0,113,233,15,0,185,8,1,0,113,232,7,159,26,232,11,0,185,1,0,0,20,232,11,64,185,168,0,0,54,1,0,0,20,32,0,128,82,122,255,255,151,234,255,255,23,72,0,0,144,8,93,69,249,8,193,0,145,8,1,64,185,168,67,31,184,232,15,64,185,8,1,0,113,13,1,0,84,1,0,0,20,168,67,95,184,168,0,128,55,1,0,0,20,168,67,95,184,72,1,160,54,1,0,0,20,168,67,95,184,73,0,0,144,41,93,69,249,41,193,0,145,40,1,0,185,8,0,128,18,168,195,31,184,23,0,0,20,168,67,95,184,9,0,144,82,201,47,160,114,8,1,9,10,72,1,0,52,1,0,0,20,168,67,95,184,73,0,0,144,41,93,69,249,41,193,0,145,40,1,0,185,40,0,128,18,168,195,31,184,9,0,0,20,1,0,0,20,168,131,95,184,73,0,0,144,41,93,69,249,41,193,0,145,40,1,0,185,191,195,31,184,1,0,0,20,160,195,95,184,253,123,66,169,255,195,0,145,192,3,95,214,255,195,0,209,253,123,2,169,253,131,0,145,160,131,31,184,161,67,31,184,255,19,0,185,72,0,0,144,31,193,10,185,168,131,95,184,40,4,248,54,1,0,0,20,72,0,0,144,232,7,0,249,11,197,74,185,234,3,31,42,73,0,160,82,107,1,0,113,42,17,138,26,9,224,166,82,32,1,10,42,1,197,74,185,235,255,255,151,232,7,64,249,224,19,0,185,8,197,74,185,168,1,0,52,1,0,0,20,232,19,64,185,72,1,0,53,1,0,0,20,32,0,0,240,0,184,30,145,55,252,255,151,40,0,128,18,73,0,0,144,40,193,10,185,191,195,31,184,175,0,0,20,168,131,95,184,8,121,0,18,168,131,31,184,1,0,0,20,32,0,128,82,61,255,255,151,64,1,0,52,1,0,0,20,32,0,0,240,0,168,35,145,39,252,255,151,8,0,128,18,73,0,0,144,40,193,10,185,191,195,31,184,159,0,0,20,73,0,0,144,40,93,69,249,8,193,0,145,8,1,64,185,42,93,69,249,74,193,0,145,72,1,0,185,168,67,95,184,42,93,69,249,74,33,0,145,72,1,0,185,168,131,95,184,41,93,69,249,41,49,0,145,40,1,0,185,168,131,95,184,73,32,181,82,8,1,9,107,161,0,0,84,1,0,0,20,0,125,128,82,252,254,255,151,15,0,0,20,168,131,95,184,73,0,161,82,8,1,9,107,224,0,0,84,1,0,0,20,168,131,95,184,9,224,166,82,8,1,9,107,161,0,0,84,1,0,0,20,128,12,128,82,239,254,255,151,1,0,0,20,1,0,0,20,32,0,128,82,79,255,255,151,224,19,0,185,64,1,0,52,1,0,0,20,32,0,0,240,0,68,36,145,245,251,255,151,232,19,64,185,73,0,0,144,40,193,10,185,191,195,31,184,109,0,0,20,72,0,0,144,8,93,69,249,8,65,0,145,8,1,64,185,232,19,0,185,168,131,95,184,232,0,0,52,1,0,0,20,168,131,95,184,9,224,166,82,8,1,9,107,129,0,0,84,1,0,0,20,191,195,31,184,94,0,0,20,168,131,95,184,73,224,166,82,8,1,9,107,193,0,0,84,1,0,0,20,232,19,64,185,8,1,27,18,168,195,31,184,85,0,0,20,168,131,95,184,73,32,181,82,8,1,9,107,161,0,0,84,1,0,0,20,232,19,64,185,168,195,31,184,77,0,0,20,168,131,95,184,73,0,161,82,8,1,9,107,65,1,0,84,1,0,0,20,234,19,64,185,171,67,95,184,41,0,128,18,232,3,31,42,74,1,11,107,8,1,137,26,168,195,31,184,64,0,0,20,168,131,95,184,41,64,160,82,8,1,9,107,1,3,0,84,1,0,0,20,72,0,0,144,9,93,69,249,41,113,0,145,42,1,64,185,233,19,64,185,41,1,10,42,233,19,0,185,9,93,69,249,41,97,0,145,42,1,64,185,233,19,64,185,41,1,10,42,233,19,0,185,8,93,69,249,8,81,0,145,9,1,64,185,232,19,64,185,8,1,9,42,232,19,0,185,232,19,64,185,168,195,31,184,37,0,0,20,168,131,95,184,73,96,160,82,8,1,9,107,193,2,0,84,1,0,0,20,232,19,64,185,8,49,0,18,233,19,64,185,41,1,19,18,8,25,9,42,233,19,64,185,41,1,18,18,8,33,9,42,233,19,64,185,41,1,17,18,8,33,9,42,137,0,152,82,41,255,191,114,8,1,9,10,73,0,0,144,40,193,10,185,232,19,64,185,8,61,16,18,168,195,31,184,12,0,0,20,1,0,0,20,1,0,0,20,1,0,0,20,1,0,0,20,1,0,0,20,232,19,64,185,137,0,152,82,41,255,191,114,8,1,9,10,168,195,31,184,1,0,0,20,160,195,95,184,253,123,66,169,255,195,0,145,192,3,95,214,255,3,1,209,253,123,3,169,253,195,0,145,160,3,31,248,225,15,0,249,232,15,64,249,232,7,0,249,64,0,128,82,136,254,255,151,224,0,0,52,1,0,0,20,8,0,128,18,73,0,0,144,40,193,10,185,191,195,31,184,66,0,0,20,72,0,0,144,8,93,69,249,9,17,0,145,8,64,128,82,40,0,160,114,40,1,0,185,72,0,0,144,8,201,74,185,168,0,0,54,1,0,0,20,168,3,95,248,232,3,0,249,5,0,0,20,168,3,95,248,8,217,119,211,232,3,0,249,1,0,0,20,232,3,64,249,225,3,8,42,0,2,128,82,64,36,162,114,3,255,255,151,72,0,0,144,8,193,74,185,136,0,0,52,1,0,0,20,191,195,31,184,38,0,0,20,0,4,128,82,166,254,255,151,224,23,0,185,64,1,0,52,1,0,0,20,32,0,0,240,0,28,28,145,76,251,255,151,232,23,64,185,73,0,0,144,40,193,10,185,191,195,31,184,25,0,0,20,255,19,0,185,1,0,0,20,232,19,64,185,8,1,2,113,202,1,0,84,1,0,0,20,72,0,0,144,8,93,69,249,8,129,0,145,8,1,64,185,233,7,64,249,234,19,128,185,40,121,42,184,1,0,0,20,232,19,64,185,8,5,0,17,232,19,0,185,241,255,255,23,72,0,0,144,8,193,74,185,8,1,0,113,232,7,159,26,168,195,31,184,1,0,0,20,160,195,95,184,253,123,67,169,255,3,1,145,192,3,95,214,255,67,1,209,253,123,4,169,253,3,1,145,160,131,31,184,169,131,95,184,72,13,153,82,104,79,160,114,8,9,201,26,168,3,31,184,8,4,128,82,168,131,30,184,191,67,30,184,8,212,144,82,40,0,160,114,232,35,0,185,1,0,0,20,72,0,0,144,8,93,69,249,8,145,0,145,8,1,64,185,8,5,0,18,9,0,128,82,233,31,0,185,40,1,0,52,1,0,0,20,232,35,64,185,9,5,0,113,233,35,0,185,8,1,0,113,232,7,159,26,232,31,0,185,1,0,0,20,232,31,64,185,168,0,0,54,1,0,0,20,32,0,128,82,246,253,255,151,235,255,255,23,232,35,64,185,8,1,0,113,12,1,0,84,1,0,0,20,32,0,0,240,0,212,24,145,254,250,255,151,40,0,128,18,168,195,31,184,180,0,0,20,72,0,0,144,8,93,69,249,9,177,0,145,40,1,64,185,8,121,29,18,40,1,0,185,64,1,128,82,227,253,255,151,168,3,95,184,8,5,0,113,168,195,30,184,168,195,94,184,136,0,0,53,1,0,0,20,191,131,30,184,71,0,0,20,168,195,94,184,8,61,16,18,40,1,0,53,1,0,0,20,168,195,94,184,8,61,16,83,168,195,30,184,168,131,94,184,8,65,0,113,168,131,30,184,1,0,0,20,168,195,94,184,8,29,8,18,40,1,0,53,1,0,0,20,168,195,94,184,8,93,24,83,168,195,30,184,168,131,94,184,8,33,0,113,168,131,30,184,1,0,0,20,168,195,94,184,8,13,4,18,40,1,0,53,1,0,0,20,168,195,94,184,8,109,28,83,168,195,30,184,168,131,94,184,8,17,0,113,168,131,30,184,1,0,0,20,168,195,94,184,8,5,2,18,40,1,0,53,1,0,0,20,168,195,94,184,8,117,30,83,168,195,30,184,168,131,94,184,8,9,0,113,168,131,30,184,1,0,0,20,168,195,94,184,40,1,248,55,1,0,0,20,168,195,94,184,8,121,31,83,168,195,30,184,168,131,94,184,8,5,0,113,168,131,30,184,1,0,0,20,168,131,94,184,8,1,0,113,201,0,0,84,1,0,0,20,168,131,94,184,8,5,0,113,168,131,30,184,1,0,0,20,168,131,94,184,8,29,0,113,169,0,0,84,1,0,0,20,232,0,128,82,168,131,30,184,1,0,0,20,1,0,0,20,72,0,0,144,8,209,74,185,8,5,0,113,169,0,0,84,1,0,0,20,168,3,95,184,168,67,31,184,6,0,0,20,169,131,94,184,40,0,128,82,8,33,201,26,168,67,31,184,1,0,0,20,168,67,95,184,8,9,0,113,200,0,0,84,1,0,0,20,72,0,128,82,168,67,31,184,191,131,30,184,1,0,0,20,72,0,0,144,8,209,74,185,8,5,0,113,233,0,0,84,1,0,0,20,168,67,95,184,8,5,24,18,8,125,2,83,168,67,30,184,1,0,0,20,169,67,95,56,168,67,94,184,8,33,9,42,168,67,31,184,73,0,0,144,233,11,0,249,40,93,69,249,8,177,0,145,8,1,64,185,8,85,16,18,170,67,95,184,8,1,10,42,41,93,69,249,41,177,0,145,40,1,0,185,64,1,128,82,224,27,0,185,100,253,255,151,232,11,64,249,224,27,64,185,8,93,69,249,9,177,0,145,40,1,64,185,8,1,30,50,40,1,0,185,92,253,255,151,8,226,132,82,232,35,0,185,1,0,0,20,72,0,0,144,8,93,69,249,8,177,0,145,8,1,64,185,9,0,128,82,233,15,0,185,40,1,8,55,1,0,0,20,232,35,64,185,9,5,0,113,233,35,0,185,8,1,0,113,232,7,159,26,232,15,0,185,1,0,0,20,232,15,64,185,168,0,0,54,1,0,0,20,64,1,128,82,69,253,255,151,236,255,255,23,232,35,64,185,8,1,0,113,12,1,0,84,1,0,0,20,32,0,0,240,0,96,40,145,77,250,255,151,40,0,128,18,168,195,31,184,3,0,0,20,191,195,31,184,1,0,0,20,160,195,95,184,253,123,68,169,255,67,1,145,192,3,95,214,255,67,1,209,253,123,4,169,253,3,1,145,255,19,0,249,72,0,0,144,8,93,69,249,8,241,3,145,8,1,64,185,8,29,16,18,9,125,16,83,72,0,0,144,9,209,10,185,8,209,74,185,8,5,0,113,2,1,0,84,1,0,0,20,32,0,0,240,0,236,40,145,49,250,255,151,40,0,128,18,168,195,31,184,84,1,0,20,73,0,0,144,40,93,69,249,8,161,0,145,31,1,0,185,40,93,69,249,8,177,0,145,8,1,64,185,168,3,31,248,168,3,95,248,8,1,104,178,168,3,31,248,168,3,95,248,170,0,128,146,8,1,10,138,168,3,31,248,168,3,95,248,41,93,69,249,41,177,0,145,40,1,0,185,8,226,132,210,168,131,30,248,1,0,0,20,64,1,128,82,6,253,255,151,1,0,0,20,72,0,0,144,8,93,69,249,8,177,0,145,8,1,64,185,8,9,8,18,9,0,128,82,233,31,0,185,40,1,0,52,1,0,0,20,168,131,94,248,9,5,0,241,169,131,30,248,8,1,0,241,232,7,159,26,232,31,0,185,1,0,0,20,232,31,64,185,136,253,7,55,1,0,0,20,168,131,94,248,8,1,0,241,12,1,0,84,1,0,0,20,32,0,0,208,0,144,34,145,251,249,255,151,40,0,128,18,168,195,31,184,30,1,0,20,40,0,0,240,9,93,69,249,42,161,0,145,9,224,129,82,73,1,0,185,8,93,69,249,9,177,0,145,40,1,64,185,42,0,128,82,202,1,160,114,8,1,10,42,40,1,0,185,64,1,128,82,218,252,255,151,0,80,131,82,192,0,160,114,189,254,255,151,232,3,0,42,8,125,64,147,168,3,31,248,168,0,0,180,1,0,0,20,168,3,95,248,168,195,31,184,5,1,0,20,41,0,0,240,40,93,69,249,10,225,0,145,8,0,128,18,72,1,0,185,41,93,69,249,41,209,0,145,40,1,0,185,40,0,0,240,232,11,0,249,225,3,31,42,31,193,10,185,40,0,0,240,31,197,10,185,40,0,0,240,31,32,3,213,41,206,3,16,63,5,0,185,31,201,10,185,224,3,1,42,115,253,255,151,232,11,64,249,8,193,74,185,200,0,0,52,1,0,0,20,40,0,0,240,8,193,74,185,168,195,31,184,232,0,0,20,64,0,161,82,65,53,128,82,104,253,255,151,40,0,0,240,8,193,74,185,200,0,0,52,1,0,0,20,40,0,0,240,8,193,74,185,168,195,31,184,221,0,0,20,200,0,128,210,168,131,30,248,191,3,31,248,1,0,0,20,168,3,95,248,9,0,128,82,233,15,0,185,40,1,248,55,1,0,0,20,168,131,94,248,9,5,0,241,169,131,30,248,8,1,0,241,232,7,159,26,232,15,0,185,1,0,0,20,232,15,64,185,136,3,0,54,1,0,0,20,32,0,128,82,146,252,255,151,64,32,181,82,1,0,144,82,225,63,170,114,71,253,255,151,232,3,0,42,8,125,64,147,168,3,31,248,40,0,0,240,8,193,74,185,8,5,0,49,160,1,0,84,1,0,0,20,40,0,0,240,8,193,74,185,40,1,0,52,1,0,0,20,32,0,0,208,0,200,46,145,143,249,255,151,40,0,0,240,8,193,74,185,168,195,31,184,177,0,0,20,216,255,255,23,168,3,95,248,168,0,248,54,1,0,0,20,168,131,94,248,168,0,0,181,1,0,0,20,8,0,128,18,168,195,31,184,167,0,0,20,168,3,95,248,8,33,113,146,168,0,0,181,1,0,0,20,40,0,128,18,168,195,31,184,160,0,0,20,168,3,95,248,168,0,240,54,1,0,0,20,40,0,128,210,232,19,0,249,1,0,0,20,32,64,160,82,225,3,31,42,225,11,0,185,25,253,255,151,225,11,64,185,64,96,160,82,22,253,255,151,40,0,0,240,0,197,10,185,40,0,0,240,8,193,74,185,200,0,0,52,1,0,0,20,40,0,0,240,8,193,74,185,168,195,31,184,137,0,0,20,0,8,143,82,160,47,160,114,54,254,255,151,232,3,0,42,8,125,64,147,168,3,31,248,168,0,0,180,1,0,0,20,168,3,95,248,168,195,31,184,126,0,0,20,40,0,0,240,1,197,74,185,96,224,160,82,253,252,255,151,40,0,0,240,8,193,74,185,200,0,0,52,1,0,0,20,40,0,0,240,8,193,74,185,168,195,31,184,114,0,0,20,64,0,128,82,91,252,255,151,160,0,0,52,1,0,0,20,8,0,128,18,168,195,31,184,107,0,0,20,40,0,0,240,8,93,69,249,9,17,0,145,8,1,128,82,40,0,160,114,40,1,0,185,0,2,128,82,64,100,182,114,225,3,31,42,228,252,255,151,40,0,0,240,8,193,74,185,200,0,0,52,1,0,0,20,40,0,0,240,8,193,74,185,168,195,31,184,89,0,0,20,0,4,128,82,133,252,255,151,160,0,0,52,1,0,0,20,8,0,128,18,168,195,31,184,82,0,0,20,191,3,31,248,8,212,144,210,40,0,160,242,168,131,30,248,1,0,0,20,169,3,95,248,8,0,128,82,41,9,0,241,232,7,0,185,234,0,0,84,1,0,0,20,168,131,94,248,8,1,0,241,232,7,159,26,232,7,0,185,1,0,0,20,232,7,64,185,232,2,0,54,1,0,0,20,40,0,0,240,8,93,69,249,8,145,0,145,8,1,64,185,168,1,88,54,1,0,0,20,40,0,0,240,8,93,69,249,8,129,0,145,8,1,64,185,170,3,95,248,73,5,0,145,169,3,31,248,31,32,3,213,169,181,3,16,40,121,42,184,4,0,0,20,32,0,128,82,246,251,255,151,1,0,0,20,222,255,255,23,168,3,95,248,8,9,0,241,160,0,0,84,1,0,0,20,8,0,128,18,168,195,31,184,35,0,0,20,40,0,0,240,8,201,74,185,200,2,80,54,1,0,0,20,40,0,0,240,8,197,74,185,1,1,31,50,64,192,176,82,157,252,255,151,40,0,0,240,8,193,74,185,200,0,0,52,1,0,0,20,40,0,0,240,8,193,74,185,168,195,31,184,18,0,0,20,40,0,0,240,8,93,69,249,9,161,0,145,40,1,64,185,8,1,31,50,40,1,0,185,1,0,0,20,41,0,0,240,40,201,74,185,8,121,31,18,40,201,10,185,234,19,64,249,40,201,74,185,8,1,10,170,40,201,10,185,191,195,31,184,1,0,0,20,160,195,95,184,253,123,68,169,255,67,1,145,192,3,95,214,255,131,0,209,253,123,1,169,253,67,0,145,224,7,0,249,225,3,0,249,224,7,64,249,225,3,64,249,80,253,255,151,253,123,65,169,255,131,0,145,192,3,95,214,255,131,0,209,253,123,1,169,253,67,0,145,41,0,0,240,40,109,69,249,232,7,0,249,40,109,69,249,8,5,64,145,40,109,5,249,224,7,64,249,225,3,31,42,2,0,130,82,145,239,255,151,224,7,64,249,253,123,65,169,255,131,0,145,192,3,95,214,255,131,1,209,253,123,5,169,253,67,1,145,160,3,31,248,161,131,30,248,162,67,30,184,168,131,94,248,169,67,94,184,8,1,9,139,232,23,0,249,255,15,0,249,40,0,0,240,8,109,69,249,232,11,0,249,40,0,0,240,8,113,69,249,104,1,0,180,1,0,0,20,168,131,94,248,8,253,112,211,40,1,0,180,1,0,0,20,169,131,94,248,232,255,159,210,8,193,73,235,128,0,0,84,1,0,0,20,191,195,31,184,148,0,0,20,40,0,0,240,10,109,69,249,9,96,128,210,136,64,128,210,8,8,224,242,74,129,64,241,9,49,137,154,104,128,128,210,8,1,9,170,232,7,0,249,168,131,94,248,8,205,116,146,168,131,30,248,168,3,95,248,8,205,116,146,168,3,31,248,1,0,0,20,168,131,94,248,233,23,64,249,8,1,9,235,226,10,0,84,1,0,0,20,40,0,0,240,8,113,69,249,169,131,94,248,43,253,112,211,234,3,31,42,9,64,128,82,107,1,0,241,42,17,138,26,169,131,94,248,41,253,94,211,41,33,64,146,41,193,42,139,8,13,9,139,232,19,0,249,232,19,64,249,8,1,64,249,8,2,0,181,1,0,0,20,170,255,255,151,232,19,64,249,0,1,0,249,128,0,0,181,1,0,0,20,191,195,31,184,101,0,0,20,233,19,64,249,40,1,64,249,106,224,128,210,8,1,10,170,40,1,0,249,1,0,0,20,1,0,0,20,232,19,64,249,8,1,64,249,8,205,116,146,232,19,0,249,232,19,64,249,169,131,94,248,41,253,85,211,41,33,64,146,8,13,9,139,232,19,0,249,232,19,64,249,8,1,64,249,8,2,8,55,1,0,0,20,142,255,255,151,232,19,64,249,0,1,0,249,128,0,0,181,1,0,0,20,191,195,31,184,73,0,0,20,233,19,64,249,40,1,64,249,106,224,128,210,8,1,10,170,40,1,0,249,1,0,0,20,1,0,0,20,232,19,64,249,8,1,64,249,8,205,116,146,232,19,0,249,232,19,64,249,169,131,94,248,41,253,76,211,41,33,64,146,8,13,9,139,232,19,0,249,232,19,64,249,8,1,64,249,8,1,0,181,1,0,0,20,232,15,64,249,233,19,64,249,40,1,0,249,232,19,64,249,232,15,0,249,1,0,0,20,1,0,0,20,168,131,94,248,8,5,64,145,168,131,30,248,167,255,255,23,168,3,95,248,233,11,64,249,8,1,9,235,193,0,0,84,1,0,0,20,40,0,0,240,8,109,69,249,232,3,0,249,4,0,0,20,168,3,95,248,232,3,0,249,1,0,0,20,232,3,64,249,169,67,94,184,8,1,9,139,8,5,0,241,8,205,116,146,232,23,0,249,1,0,0,20,232,15,64,249,40,2,0,180,1,0,0,20,232,15,64,249,8,1,64,249,232,19,0,249,232,23,64,249,233,7,64,249,8,1,9,170,233,15,64,249,40,1,0,249,1,0,0,20,232,23,64,249,8,5,64,241,232,23,0,249,232,19,64,249,232,15,0,249,239,255,255,23,40,0,128,82,168,195,31,184,1,0,0,20,160,195,95,184,253,123,69,169,255,131,1,145,192,3,95,214,255,67,1,209,253,123,4,169,253,3,1,145,191,131,31,248,9,0,56,213,40,0,0,240,9,217,4,249,8,217,68,249,8,45,124,146,9,6,154,210,8,1,9,235,129,1,0,84,1,0,0,20,41,0,0,240,104,0,128,82,40,161,43,57,8,224,167,210,41,0,0,240,40,217,4,249,41,0,0,240,8,230,167,210,40,93,5,249,11,0,0,20,136,0,128,82,41,0,0,240,40,161,43,57,8,192,191,210,41,0,0,240,40,217,4,249,136,198,191,210,41,0,0,240,40,93,5,249,1,0,0,20,40,0,0,208,8,85,69,185,41,0,0,240,40,121,5,249,40,0,0,240,8,125,69,249,232,7,0,180,1,0,0,20,40,0,0,240,8,125,69,249,8,1,72,241,66,7,0,84,1,0,0,20,40,0,0,240,8,125,69,249,8,1,64,57,8,65,3,113,129,6,0,84,1,0,0,20,40,0,0,240,8,125,69,249,8,5,64,57,8,53,0,113,193,5,0,84,1,0,0,20,40,0,0,240,8,125,69,249,8,9,64,57,8,249,3,113,1,5,0,84,1,0,0,20,40,0,0,240,8,125,69,249,8,13,64,57,8,181,3,113,65,4,0,84,1,0,0,20,40,0,0,240,232,15,0,249,9,125,69,249,41,29,64,57,10,125,69,249,74,25,64,57,41,33,10,42,10,125,69,249,74,21,64,57,42,65,10,42,233,3,10,42,41,125,64,147,169,131,31,248,41,0,0,240,233,19,0,249,32,121,69,249,1,125,69,249,168,131,95,248,226,3,8,42,102,238,255,151,234,15,64,249,233,19,64,249,40,121,69,249,72,125,5,249,168,131,95,248,8,253,63,145,8,205,116,146,10,5,64,145,40,121,69,249,8,1,10,139,40,121,5,249,4,0,0,20,40,0,0,240,31,125,5,249,1,0,0,20,226,3,31,42,226,23,0,185,224,3,2,42,225,3,2,42,41,244,255,151,31,32,3,213,8,132,3,16,9,21,64,185,42,0,0,240,73,1,11,185,9,25,64,185,42,0,0,240,73,5,11,185,8,113,64,57,41,0,0,240,40,9,11,185,142,245,255,151,225,23,64,185,40,0,0,240,9,217,68,249,41,253,85,211,169,3,31,248,8,217,68,249,8,1,96,145,8,253,85,211,168,131,30,248,40,0,0,240,9,0,130,210,9,113,5,249,0,113,69,249,2,0,144,82,80,238,255,151,191,131,31,248,1,0,0,20,168,131,95,248,8,17,0,241,2,2,0,84,1,0,0,20,41,0,0,240,40,113,69,249,170,131,95,248,74,9,0,145,8,49,10,139,8,13,28,145,41,113,69,249,170,131,95,248,40,121,42,248,1,0,0,20,168,131,95,248,8,5,0,145,168,131,31,248,239,255,255,23,191,131,31,248,1,0,0,20,168,131,95,248,8,1,32,241,2,5,0,84,1,0,0,20,168,131,95,248,8,249,127,211,8,213,118,211,232,7,0,249,169,131,95,248,170,3,95,248,8,0,128,82,41,1,10,235,232,19,0,185,3,1,0,84,1,0,0,20,168,131,95,248,169,131,94,248,8,1,9,235,232,39,159,26,232,19,0,185,1,0,0,20,233,7,64,249,235,19,64,185,10,96,128,210,136,64,128,210,8,8,224,242,107,1,0,18,107,1,0,114,10,17,138,154,40,128,128,210,8,1,10,170,8,41,9,139,41,0,0,240,41,113,69,249,170,131,95,248,74,1,16,145,40,121,42,248,1,0,0,20,168,131,95,248,8,5,0,145,168,131,31,248,215,255,255,23,31,32,3,213,168,120,3,16,8,5,64,249,8,2,0,180,1,0,0,20,41,0,0,240,8,0,142,210,40,109,5,249,31,32,3,213,169,119,3,16,32,5,64,249,33,5,64,249,40,17,64,185,41,25,64,185,8,125,9,27,8,253,63,17,2,77,20,18,114,254,255,151,1,0,0,20,40,0,0,240,8,121,69,249,41,0,0,240,40,109,5,249,253,123,68,169,255,67,1,145,192,3,95,214,255,131,1,209,253,123,5,169,253,67,1,145,31,32,3,213,136,122,3,16,232,23,0,249,218,252,255,151,225,23,64,249,32,0,128,210,68,254,255,151,224,23,64,249,40,0,0,240,31,137,6,249,33,0,0,208,33,216,31,145,2,1,128,82,249,237,255,151,128,11,0,53,1,0,0,20,31,32,3,213,136,120,3,16,9,85,64,185,169,131,31,184,9,81,64,185,169,67,31,184,8,37,64,249,168,3,30,248,191,131,30,248,1,0,0,20,168,67,95,184,9,0,128,82,233,39,0,185,8,1,0,52,1,0,0,20,40,0,0,240,8,137,70,249,8,1,0,241,232,23,159,26,232,39,0,185,1,0,0,20,232,39,64,185,104,8,0,54,1,0,0,20,168,3,94,248,169,131,94,248,0,1,9,139,31,32,3,213,33,117,3,16,29,254,255,151,191,195,31,184,1,0,0,20,168,67,95,184,9,0,128,82,233,35,0,185,40,1,0,52,1,0,0,20,168,195,95,184,169,131,95,184,8,1,9,11,8,1,8,113,232,135,159,26,232,35,0,185,1,0,0,20,232,35,64,185,232,4,0,54,1,0,0,20,168,195,95,184,233,3,8,42,31,32,3,213,104,114,3,16,0,1,9,139,31,32,3,213,225,253,2,16,2,2,128,82,191,237,255,151,96,2,0,53,1,0,0,20,168,195,95,184,234,3,8,42,31,32,3,213,8,113,3,16,233,3,8,170,41,1,10,139,41,17,64,249,42,0,0,240,73,137,6,249,169,195,95,184,8,1,9,139,1,65,0,145,31,32,3,213,0,128,3,16,2,2,128,82,128,237,255,151,10,0,0,20,1,0,0,20,169,131,95,184,168,195,95,184,8,1,9,11,168,195,31,184,168,67,95,184,8,5,0,113,168,67,31,184,205,255,255,23,1,0,0,20,168,131,94,248,8,5,0,145,168,131,30,248,178,255,255,23,83,0,0,20,224,3,31,170,31,32,3,213,33,109,3,16,225,15,0,249,220,253,255,151,232,15,64,249,8,249,71,57,8,85,1,113,33,9,0,84,1,0,0,20,31,32,3,213,8,108,3,16,8,253,71,57,8,169,2,113,97,8,0,84,1,0,0,20,8,56,128,82,168,195,31,184,1,0,0,20,168,195,95,184,8,249,7,113,98,7,0,84,1,0,0,20,168,195,95,184,9,9,0,113,31,32,3,213,40,106,3,16,8,73,105,56,8,1,2,113,193,5,0,84,1,0,0,20,168,195,95,184,9,9,0,17,31,32,3,213,40,105,3,16,8,73,105,56,8,49,0,113,64,1,0,84,1,0,0,20,168,195,95,184,9,9,0,17,31,32,3,213,40,104,3,16,8,73,105,56,8,189,3,113,193,3,0,84,1,0,0,20,168,195,95,184,9,25,0,17,31,32,3,213,40,103,3,16,8,73,105,184,41,0,0,240,40,137,6,249,31,32,3,213,192,118,3,16,224,11,0,249,33,0,0,208,33,100,41,145,130,0,128,82,226,15,0,185,50,237,255,151,226,15,64,185,232,11,64,249,0,33,0,145,33,0,0,208,33,80,31,145,44,237,255,151,233,11,64,249,168,195,95,184,8,1,7,113,10,2,128,82,8,9,202,26,40,13,0,121,6,0,0,20,1,0,0,20,168,195,95,184,8,65,0,17,168,195,31,184,196,255,255,23,1,0,0,20,1,0,0,20,40,0,0,240,8,137,70,249,200,12,0,180,1,0,0,20,40,0,0,240,0,137,70,249,31,32,3,213,65,98,3,16,225,3,0,249,133,253,255,151,232,3,64,249,42,0,0,240,233,3,8,170,73,149,6,249,8,249,71,57,8,85,1,113,65,4,0,84,1,0,0,20,31,32,3,213,200,96,3,16,8,253,71,57,8,169,2,113,129,3,0,84,1,0,0,20,31,32,3,213,8,96,3,16,8,45,64,57,232,2,0,53,1,0,0,20,31,32,3,213,104,95,3,16,8,49,64,57,8,9,0,113,33,2,0,84,1,0,0,20,40,0,0,240,8,149,70,249,8,53,64,57,136,1,0,52,1,0,0,20,40,0,0,240,8,149,70,249,8,45,64,121,232,0,0,53,1,0,0,20,40,0,0,240,8,149,70,249,8,37,64,185,168,0,0,53,1,0,0,20,40,0,0,240,31,137,6,249,51,0,0,20,42,0,0,240,72,149,70,249,8,29,64,121,41,0,0,240,43,137,70,249,8,1,11,139,43,0,0,240,104,153,6,249,72,149,70,249,8,37,64,185,75,149,70,249,107,65,64,57,8,125,11,27,75,149,70,249,107,29,64,121,8,1,11,11,74,149,70,249,75,53,64,57,74,0,128,82,74,125,11,27,8,1,10,107,232,3,8,42,41,137,70,249,8,1,9,139,41,0,0,240,40,157,6,249,191,195,31,184,1,0,0,20,168,195,95,184,8,33,0,113,34,2,0,84,1,0,0,20,40,0,0,208,8,153,70,249,169,195,95,184,0,1,9,139,168,195,95,184,9,97,25,83,31,32,3,213,40,105,3,16,1,73,41,139,48,253,255,151,1,0,0,20,168,195,95,184,8,5,0,17,168,195,31,184,238,255,255,23,40,0,0,240,31,65,13,185,1,0,0,20,1,0,0,20,253,123,69,169,255,131,1,145,192,3,95,214,255,195,1,209,31,32,3,213,8,80,3,16,9,5,64,249,233,51,0,249,8,113,64,57,8,29,0,17,8,125,3,19,232,43,0,185,232,51,64,249,104,0,0,181,1,0,0,20,198,1,0,20,255,75,0,185,255,91,0,185,1,0,0,20,232,75,64,185,31,32,3,213,9,78,3,16,41,25,64,185,8,1,9,107,42,6,0,84,1,0,0,20,232,91,64,185,232,95,0,185,255,79,0,185,1,0,0,20,232,79,64,185,31,32,3,213,169,76,3,16,41,21,64,185,8,1,9,107,106,3,0,84,1,0,0,20,232,43,64,185,8,9,0,113,1,1,0,84,1,0,0,20,40,0,0,208,8,145,74,185,233,51,64,249,234,95,128,185,40,105,42,120,7,0,0,20,40,0,0,208,8,145,74,185,233,51,64,249,234,95,128,185,40,105,42,184,1,0,0,20,1,0,0,20,232,79,64,185,8,5,0,17,232,79,0,185,233,43,64,185,232,95,64,185,8,1,9,11,232,95,0,185,225,255,255,23,1,0,0,20,232,75,64,185,8,5,0,17,232,75,0,185,31,32,3,213,72,72,3,16,9,17,64,185,232,91,64,185,8,1,9,11,232,91,0,185,203,255,255,23,41,0,0,208,136,0,128,82,40,137,10,185,41,0,0,208,40,141,10,185,40,0,0,240,8,165,70,249,40,5,0,180,1,0,0,20,40,0,0,240,8,165,70,249,8,1,64,57,136,4,0,53,1,0,0,20,40,0,0,240,8,165,70,249,8,5,64,57,8,5,0,113,193,3,0,84,1,0,0,20,40,0,0,240,8,165,70,249,8,9,64,57,8,37,0,113,1,3,0,84,1,0,0,20,40,0,0,240,8,165,70,249,8,13,64,57,104,2,0,53,1,0,0,20,40,0,0,240,8,165,70,249,8,17,64,57,200,1,0,53,1,0,0,20,40,0,0,240,8,165,70,249,8,29,64,57,8,97,0,113,32,1,0,84,1,0,0,20,40,0,0,240,8,165,70,249,8,29,64,57,8,129,0,113,96,0,0,84,1,0,0,20,92,1,0,20,40,0,0,240,9,165,70,249,41,69,64,57,41,1,27,18,233,63,0,185,9,165,70,249,42,53,64,57,9,165,70,249,41,49,64,57,41,33,10,11,233,71,0,185,9,165,70,249,41,61,64,57,8,165,70,249,8,57,64,57,8,33,9,11,232,67,0,185,232,71,64,185,8,5,0,113,203,0,0,84,1,0,0,20,232,67,64,185,8,5,0,113,106,0,0,84,1,0,0,20,66,1,0,20,31,32,3,213,8,62,3,16,9,21,64,185,234,71,64,185,42,1,10,107,73,0,128,82,74,13,201,26,234,51,0,185,8,25,64,185,234,67,64,185,8,1,10,107,8,13,201,26,232,47,0,185,41,0,0,240,40,165,70,249,8,29,64,57,8,125,3,19,42,165,70,249,74,25,64,57,41,165,70,249,41,21,64,57,41,33,10,42,8,125,9,27,8,73,0,17,232,59,0,185,255,95,0,185,255,75,0,185,255,83,0,185,232,71,64,185,232,79,0,185,8,0,128,18,232,75,0,185,1,0,0,20,233,83,64,185,232,71,64,185,234,67,64,185,10,125,10,27,8,0,128,82,41,1,10,107,232,39,0,185,42,1,0,84,1,0,0,20,232,59,64,185,41,0,0,240,41,81,77,185,8,1,9,107,232,39,159,26,232,39,0,185,1,0,0,20,232,39,64,185,232,33,0,54,1,0,0,20,40,0,0,240,8,165,70,249,233,59,128,185,234,3,9,42,74,5,0,17,234,59,0,185,8,105,105,56,232,87,0,185,232,87,64,185,8,253,1,113,141,2,0,84,1,0,0,20,255,55,0,185,232,87,64,185,8,253,1,113,232,87,0,185,41,0,0,240,40,165,70,249,234,59,128,185,235,3,10,42,107,5,0,17,235,59,0,185,8,105,106,56,41,165,70,249,41,29,64,57,41,125,3,19,8,125,9,27,8,73,0,17,232,91,0,185,7,0,0,20,40,0,128,82,232,55,0,185,232,87,64,185,8,5,0,17,232,87,0,185,1,0,0,20,233,87,64,185,232,83,64,185,8,1,9,11,232,83,0,185,1,0,0,20,232,87,64,185,9,5,0,113,233,87,0,185,8,28,0,52,1,0,0,20,232,55,64,185,8,2,0,52,1,0,0,20,41,0,0,240,40,165,70,249,234,59,128,185,235,3,10,42,107,5,0,17,235,59,0,185,8,105,106,56,41,165,70,249,41,29,64,57,41,125,3,19,8,125,9,27,8,73,0,17,232,91,0,185,1,0,0,20,232,79,64,185,233,71,64,185,8,1,9,107,97,4,0,84,1,0,0,20,255,79,0,185,232,47,64,185,232,35,0,185,232,63,64,185,8,1,0,53,1,0,0,20,232,67,64,185,233,75,64,185,8,1,9,107,8,5,0,113,232,31,0,185,4,0,0,20,232,75,64,185,232,31,0,185,1,0,0,20,232,35,64,185,233,31,64,185,8,1,9,11,31,32,3,213,201,44,3,16,41,17,64,185,8,125,9,27,233,51,64,185,234,79,64,185,41,1,10,11,234,43,64,185,41,125,10,27,8,1,9,11,232,95,0,185,232,75,64,185,8,5,0,17,232,75,0,185,1,0,0,20,232,47,64,185,233,75,64,185,8,1,9,11,8,1,0,113,237,19,0,84,1,0,0,20,232,47,64,185,233,75,64,185,8,1,9,11,31,32,3,213,201,41,3,16,41,25,64,185,41,5,0,113,8,1,9,107,170,18,0,84,1,0,0,20,232,51,64,185,233,79,64,185,8,1,9,11,8,1,0,113,77,17,0,84,1,0,0,20,232,51,64,185,233,79,64,185,8,1,9,11,31,32,3,213,201,39,3,16,41,21,64,185,41,5,0,113,8,1,9,107,10,16,0,84,1,0,0,20,31,32,3,213,232,38,3,16,8,133,64,57,8,33,0,113,205,1,0,84,1,0,0,20,40,0,0,240,8,165,70,249,233,91,64,185,41,9,0,17,8,201,105,56,31,32,3,213,137,37,3,16,41,133,64,57,41,33,0,113,8,33,201,26,232,27,0,185,14,0,0,20,40,0,0,240,8,165,70,249,233,91,64,185,41,9,0,17,8,201,105,56,31,32,3,213,9,36,3,16,42,133,64,57,9,1,128,82,41,1,10,107,8,41,201,26,232,27,0,185,1,0,0,20,233,27,64,185,31,32,3,213,232,34,3,16,10,129,64,57,41,33,202,26,233,23,0,185,8,141,64,57,8,33,0,113,205,1,0,84,1,0,0,20,40,0,0,240,8,165,70,249,233,91,64,185,41,5,0,17,8,201,105,56,31,32,3,213,41,33,3,16,41,141,64,57,41,33,0,113,8,33,201,26,232,19,0,185,14,0,0,20,40,0,0,240,8,165,70,249,233,91,64,185,41,5,0,17,8,201,105,56,31,32,3,213,169,31,3,16,42,141,64,57,9,1,128,82,41,1,10,107,8,41,201,26,232,19,0,185,1,0,0,20,233,23,64,185,234,19,64,185,31,32,3,213,104,30,3,16,11,137,64,57,74,33,203,26,41,1,10,42,233,15,0,185,8,149,64,57,8,33,0,113,205,1,0,84,1,0,0,20,40,0,0,240,8,165,70,249,233,91,64,185,41,1,0,17,8,201,105,56,31,32,3,213,137,28,3,16,41,149,64,57,41,33,0,113,8,33,201,26,232,11,0,185,14,0,0,20,40,0,0,240,8,165,70,249,233,91,64,185,41,1,0,17,8,201,105,56,31,32,3,213,9,27,3,16,42,149,64,57,9,1,128,82,41,1,10,107,8,41,201,26,232,11,0,185,1,0,0,20,232,15,64,185,233,11,64,185,31,32,3,213,202,25,3,16,74,145,64,57,41,33,202,26,8,1,9,42,232,111,0,185,232,43,64,185,8,9,0,113,225,0,0,84,1,0,0,20,232,111,64,185,233,51,64,249,234,95,128,185,40,105,42,120,6,0,0,20,232,111,64,185,233,51,64,249,234,95,128,185,40,105,42,184,1,0,0,20,1,0,0,20,233,43,64,185,232,95,64,185,8,1,9,11,232,95,0,185,1,0,0,20,232,79,64,185,8,5,0,17,232,79,0,185,30,255,255,23,225,254,255,23,255,195,1,145,192,3,95,214,255,195,0,209,253,123,2,169,253,131,0,145,160,131,31,184,168,131,95,184,8,9,0,113,227,0,0,84,1,0,0,20,168,131,95,184,233,99,29,50,8,1,9,107,131,0,0,84,1,0,0,20,191,195,31,184,71,0,0,20,168,131,95,184,41,0,0,240,41,65,77,185,8,1,9,107,35,1,0,84,1,0,0,20,168,131,95,184,41,0,0,240,41,65,77,185,41,253,15,17,8,1,9,107,41,4,0,84,1,0,0,20,168,131,95,184,8,85,22,18,41,0,0,240,40,65,13,185,255,11,0,249,1,0,0,20,232,11,64,249,8,33,0,241,194,2,0,84,1,0,0,20,40,0,0,208,8,153,70,249,41,0,0,240,41,65,77,185,41,125,7,83,233,3,9,42,8,1,9,139,233,11,64,249,0,1,9,139,232,11,64,249,9,225,121,211,31,32,3,213,136,38,3,16,1,9,9,139,27,251,255,151,1,0,0,20,232,11,64,249,8,5,0,145,232,11,0,249,233,255,255,23,1,0,0,20,168,131,95,184,41,0,0,240,41,65,77,185,9,1,9,107,31,32,3,213,200,36,3,16,8,89,105,184,168,131,31,184,168,131,95,184,8,9,0,113,227,0,0,84,1,0,0,20,168,131,95,184,233,99,29,50,8,1,9,107,163,0,0,84,1,0,0,20,232,3,31,42,232,15,0,185,4,0,0,20,168,131,95,184,232,15,0,185,1,0,0,20,232,15,64,185,168,195,31,184,1,0,0,20,160,195,95,184,253,123,66,169,255,195,0,145,192,3,95,214,255,67,2,209,253,123,8,169,253,3,2,145,31,32,3,213,40,178,3,16,160,3,31,248,41,0,0,208,41,149,70,249,41,45,64,185,169,67,30,184,191,195,29,184,191,131,29,184,191,115,29,56,31,32,3,213,233,160,3,16,41,1,8,145,169,131,28,248,232,31,0,249,168,3,95,248,200,0,0,180,1,0,0,20,168,3,95,248,8,1,64,57,136,0,0,53,1,0,0,20,191,195,31,184,139,2,0,20,168,3,95,248,232,19,0,249,31,32,3,213,232,174,3,16,232,23,0,249,1,0,0,20,232,19,64,249,8,1,64,57,9,0,128,82,233,31,0,185,232,3,0,52,1,0,0,20,232,19,64,249,9,1,64,57,8,0,128,82,41,129,0,113,232,31,0,185,0,3,0,84,1,0,0,20,232,19,64,249,9,1,64,57,8,0,128,82,41,53,0,113,232,31,0,185,32,2,0,84,1,0,0,20,232,19,64,249,9,1,64,57,8,0,128,82,41,41,0,113,232,31,0,185,64,1,0,84,1,0,0,20,232,23,64,249,31,32,3,213,233,170,3,16,41,241,31,145,8,1,9,235,232,39,159,26,232,31,0,185,1,0,0,20,232,31,64,185,232,12,0,54,1,0,0,20,232,19,64,249,8,1,64,57,168,8,56,54,1,0,0,20,232,19,64,249,8,1,64,57,168,1,40,55,1,0,0,20,232,19,64,249,8,1,64,57,9,17,0,18,232,19,64,249,8,5,64,57,40,101,26,51,232,103,0,121,232,19,64,249,8,5,0,145,232,19,0,249,52,0,0,20,232,19,64,249,8,1,64,57,104,2,32,55,1,0,0,20,232,19,64,249,8,1,64,57,9,13,0,18,232,19,64,249,8,5,64,57,8,21,0,18,8,101,26,83,8,49,9,42,233,19,64,249,41,9,64,57,41,21,0,18,8,1,9,42,232,103,0,121,232,19,64,249,8,9,0,145,232,19,0,249,30,0,0,20,232,19,64,249,8,1,64,57,8,3,24,55,1,0,0,20,232,19,64,249,8,1,64,57,9,9,0,18,232,19,64,249,8,5,64,57,8,21,0,18,8,77,20,83,8,73,9,42,233,19,64,249,41,9,64,57,41,21,0,18,8,25,9,42,233,19,64,249,41,13,64,57,41,21,0,18,8,1,9,42,232,103,0,121,233,19,64,249,40,1,64,57,8,13,0,17,40,1,0,57,3,0,0,20,255,103,0,121,1,0,0,20,1,0,0,20,1,0,0,20,5,0,0,20,232,19,64,249,8,1,64,57,232,103,0,121,1,0,0,20,232,19,64,249,8,5,0,145,232,19,0,249,232,103,64,121,8,113,1,113,161,1,0,84,1,0,0,20,232,19,64,249,8,1,64,57,8,129,0,113,1,1,0,84,1,0,0,20,8,4,128,82,232,103,0,121,232,19,64,249,8,5,0,145,232,19,0,249,1,0,0,20,232,103,64,121,233,23,64,249,40,1,0,121,1,0,0,20,232,23,64,249,8,9,0,145,232,23,0,249,118,255,255,23,232,23,64,249,31,1,0,121,72,0,0,144,225,3,31,42,31,97,7,185,72,0,0,144,31,181,3,249,31,32,3,213,160,220,3,16,2,68,128,82,232,233,255,151,1,0,0,20,168,131,92,248,31,32,3,213,105,139,3,16,41,1,8,145,8,1,9,235,67,6,0,84,1,0,0,20,168,115,93,56,72,1,0,52,1,0,0,20,169,115,93,56,8,0,128,18,8,1,41,11,168,115,29,56,168,131,94,248,8,5,0,145,168,131,30,248,30,0,0,20,168,67,94,184,8,9,0,113,227,0,0,84,1,0,0,20,168,67,94,184,233,99,29,50,8,1,9,107,131,0,0,84,1,0,0,20,191,195,31,184,209,1,0,20,41,0,0,208,40,149,70,249,8,53,64,57,8,5,0,113,168,115,29,56,168,67,94,184,41,149,70,249,41,53,64,57,8,125,9,27,232,3,8,42,41,0,0,208,41,157,70,249,8,1,9,139,168,131,30,248,160,67,94,184,195,254,255,151,160,67,30,184,1,0,0,20,160,131,94,248,31,32,3,213,129,133,3,16,225,11,0,249,11,250,255,151,232,11,64,249,168,131,28,248,1,0,0,20,168,131,92,248,8,1,64,57,136,0,0,53,1,0,0,20,191,195,31,184,177,1,0,20,168,131,92,248,8,1,64,57,8,21,0,113,192,52,0,84,1,0,0,20,168,131,92,248,8,1,64,57,8,149,3,113,32,52,0,84,1,0,0,20,168,131,92,248,8,1,64,57,8,185,0,113,129,1,0,84,1,0,0,20,168,131,92,248,8,5,64,57,8,185,0,113,224,50,0,84,1,0,0,20,168,131,92,248,8,5,64,57,8,129,0,113,64,50,0,84,1,0,0,20,168,131,92,248,8,45,64,57,8,61,0,113,1,16,0,84,1,0,0,20,168,195,93,184,200,0,0,52,1,0,0,20,168,131,92,248,8,1,64,57,72,4,48,54,1,0,0,20,31,32,3,213,192,207,3,16,225,3,31,42,2,68,128,82,128,233,255,151,168,131,92,248,8,1,64,57,8,17,0,18,168,195,29,184,168,195,93,184,8,5,0,113,203,0,0,84,1,0,0,20,168,195,93,184,8,81,0,113,13,1,0,84,1,0,0,20,191,131,29,184,191,195,29,184,168,131,92,248,8,129,0,145,168,131,28,248,136,255,255,23,168,195,93,184,8,5,0,113,169,1,128,82,9,125,9,27,31,32,3,213,104,204,3,16,8,197,41,139,232,35,0,249,1,0,0,20,191,3,30,184,1,0,0,20,168,3,94,184,8,21,0,113,170,2,0,84,1,0,0,20,168,131,92,248,169,3,94,184,41,121,31,83,41,9,0,17,9,201,105,56,168,131,92,248,170,3,94,184,74,121,31,83,74,5,0,17,8,201,106,56,8,33,9,42,233,35,64,249,170,3,158,184,40,121,42,120,1,0,0,20,168,3,94,184,8,5,0,17,168,3,30,184,234,255,255,23,191,3,30,184,1,0,0,20,168,3,94,184,8,25,0,113,202,2,0,84,1,0,0,20,168,131,92,248,169,3,94,184,41,121,31,83,41,61,0,17,9,201,105,56,168,131,92,248,170,3,94,184,74,121,31,83,74,57,0,17,8,201,106,56,8,33,9,42,233,35,64,249,170,3,94,184,74,21,0,17,40,217,42,120,1,0,0,20,168,3,94,184,8,5,0,17,168,3,30,184,233,255,255,23,168,131,92,248,9,117,64,57,168,131,92,248,8,113,64,57,8,33,9,42,233,35,64,249,40,45,0,121,168,131,92,248,9,125,64,57,168,131,92,248,8,121,64,57,8,33,9,42,233,35,64,249,40,49,0,121,232,35,64,249,8,105,0,241,232,35,0,249,168,195,93,184,8,5,0,113,168,195,29,184,168,195,93,184,9,0,128,82,233,15,0,185,40,1,0,53,1,0,0,20,232,35,64,249,31,32,3,213,41,194,3,16,8,1,9,235,232,39,159,26,232,15,0,185,1,0,0,20,232,15,64,185,8,1,0,18,168,131,29,184,13,1,0,20,168,131,92,248,8,45,64,57,40,33,24,55,1,0,0,20,168,131,93,184,168,12,0,53,1,0,0,20,191,3,30,184,1,0,0,20,168,3,94,184,8,33,0,113,202,1,0,84,1,0,0,20,168,131,92,248,169,3,158,184,8,105,105,56,170,3,158,184,31,32,3,213,201,190,3,16,40,121,42,120,1,0,0,20,168,3,94,184,8,5,0,17,168,3,30,184,241,255,255,23,1,0,0,20,168,3,94,184,9,0,128,82,233,11,0,185,104,1,0,52,1,0,0,20,168,3,94,184,9,5,0,113,31,32,3,213,200,188,3,16,8,217,105,120,8,129,0,113,232,23,159,26,232,11,0,185,1,0,0,20,232,11,64,185,200,0,0,54,1,0,0,20,168,3,94,184,8,5,0,113,168,3,30,184,236,255,255,23,168,131,92,248,8,33,64,57,8,129,0,113,64,6,0,84,1,0,0,20,170,3,158,184,232,3,10,42,8,5,0,17,168,3,30,184,31,32,3,213,233,185,3,16,232,3,9,170,10,5,10,139,200,5,128,82,72,1,0,121,168,131,92,248,8,33,64,57,170,3,158,184,235,3,10,42,107,5,0,17,171,3,30,184,40,121,42,120,168,131,92,248,8,37,64,57,8,129,0,113,96,3,0,84,1,0,0,20,168,131,92,248,8,37,64,57,170,3,158,184,233,3,10,42,41,5,0,17,169,3,30,184,31,32,3,213,233,182,3,16,40,121,42,120,168,131,92,248,8,41,64,57,8,129,0,113,128,1,0,84,1,0,0,20,168,131,92,248,8,41,64,57,170,3,158,184,233,3,10,42,41,5,0,17,169,3,30,184,31,32,3,213,41,181,3,16,40,121,42,120,1,0,0,20,1,0,0,20,1,0,0,20,169,3,158,184,31,32,3,213,72,180,3,16,8,5,9,139,31,1,0,121,3,0,0,20,191,131,29,184,1,0,0,20,232,31,64,249,8,1,64,121,8,189,0,113,193,0,0,84,1,0,0,20,232,31,64,249,8,9,0,145,232,31,0,249,1,0,0,20,191,3,30,184,1,0,0,20,169,3,158,184,31,32,3,213,232,177,3,16,8,121,105,120,9,0,128,82,233,7,0,185,8,2,0,52,1,0,0,20,232,31,64,249,169,3,158,184,8,121,105,120,9,0,128,82,233,7,0,185,40,1,0,52,1,0,0,20,232,31,64,249,169,3,158,184,8,121,105,120,8,189,0,113,232,7,159,26,232,7,0,185,1,0,0,20,232,7,64,185,8,6,0,54,1,0,0,20,169,3,158,184,31,32,3,213,200,174,3,16,8,5,9,139,8,1,64,121,232,111,0,121,232,111,64,121,8,5,1,113,75,1,0,84,1,0,0,20,232,111,64,121,8,105,1,113,204,0,0,84,1,0,0,20,232,111,64,121,8,129,0,17,232,111,0,121,1,0,0,20,232,31,64,249,169,3,158,184,8,5,9,139,8,1,64,121,232,107,0,121,232,107,64,121,8,5,1,113,75,1,0,84,1,0,0,20,232,107,64,121,8,105,1,113,204,0,0,84,1,0,0,20,232,107,64,121,8,129,0,17,232,107,0,121,1,0,0,20,232,111,64,121,233,107,64,121,8,1,9,107,96,0,0,84,1,0,0,20,6,0,0,20,1,0,0,20,168,3,94,184,8,5,0,17,168,3,30,184,186,255,255,23,169,3,158,184,31,32,3,213,8,169,3,16,8,5,9,139,8,1,64,121,232,8,0,53,1,0,0,20,168,131,92,248,9,85,64,57,168,131,92,248,8,81,64,57,8,61,16,83,8,97,9,42,169,131,92,248,41,109,64,57,8,33,9,42,169,131,92,248,41,105,64,57,8,1,9,42,168,67,30,184,168,131,92,248,8,45,64,57,232,2,32,54,1,0,0,20,232,31,64,249,169,3,158,184,8,121,105,120,8,189,0,113,128,0,0,84,1,0,0,20,191,195,31,184,55,0,0,20,168,3,94,184,9,5,0,17,232,31,64,249,8,197,41,139,232,31,0,249,191,115,29,56,191,131,29,184,191,195,29,184,31,32,3,213,168,83,3,16,8,1,8,145,168,131,28,248,61,254,255,23,168,67,94,184,8,9,0,113,227,0,0,84,1,0,0,20,168,67,94,184,233,99,29,50,8,1,9,107,131,0,0,84,1,0,0,20,191,195,31,184,31,0,0,20,168,67,94,184,41,0,0,240,40,97,7,185,168,131,92,248,9,125,64,57,168,131,92,248,8,121,64,57,8,61,16,83,8,97,9,42,169,131,92,248,41,117,64,57,8,33,9,42,169,131,92,248,41,113,64,57,9,1,9,42,232,3,9,42,8,125,64,147,41,0,0,240,40,181,3,249,8,0,0,20,1,0,0,20,1,0,0,20,1,0,0,20,168,131,92,248,8,129,0,145,168,131,28,248,23,254,255,23,40,0,128,82,168,195,31,184,1,0,0,20,160,195,95,184,253,123,72,169,255,67,2,145,192,3,95,214,255,195,1,209,253,123,6,169,253,131,1,145,160,3,31,248,161,131,30,248,162,3,30,248,191,131,29,248,40,0,0,240,9,97,71,185,233,39,0,185,255,31,0,185,255,27,0,185,9,64,128,82,233,23,0,185,255,79,0,57,8,97,71,185,8,9,0,113,195,1,0,84,1,0,0,20,168,3,95,248,41,0,0,240,41,181,67,249,8,1,9,235,2,1,0,84,1,0,0,20,168,131,94,248,168,0,0,180,1,0,0,20,168,3,94,248,136,0,0,181,1,0,0,20,191,131,31,248,231,0,0,20,168,3,95,248,169,131,94,248,8,1,9,139,41,0,0,240,41,181,67,249,8,1,9,235,9,1,0,84,1,0,0,20,40,0,0,240,8,181,67,249,169,3,95,248,8,1,9,235,168,131,30,248,1,0,0,20,168,131,94,248,232,27,0,249,160,131,94,248,251,232,255,151,168,3,95,248,8,10,0,180,1,0,0,20,168,3,95,248,41,0,0,176,42,149,70,249,74,53,64,57,75,89,23,83,234,3,11,42,74,125,64,147,8,9,202,154,232,35,0,185,168,3,95,248,41,149,70,249,41,53,64,57,42,89,23,83,233,3,10,42,42,125,64,147,9,9,202,154,41,125,10,155,8,1,9,235,232,23,0,249,232,23,64,249,8,253,73,211,232,31,0,185,232,23,64,249,8,33,64,146,232,27,0,185,233,27,64,185,8,64,128,82,8,1,9,107,232,23,0,185,232,35,64,185,136,3,0,52,1,0,0,20,1,0,0,20,232,35,64,185,9,5,0,113,233,35,0,185,9,0,128,82,233,15,0,185,232,0,0,52,1,0,0,20,232,39,64,185,8,1,0,113,232,7,159,26,232,15,0,185,1,0,0,20,232,15,64,185,200,0,0,54,1,0,0,20,224,39,64,185,151,252,255,151,224,39,0,185,238,255,255,23,232,39,64,185,136,0,0,53,1,0,0,20,191,131,31,248,153,0,0,20,1,0,0,20,41,0,0,176,40,149,70,249,8,53,64,57,234,31,64,185,8,1,10,107,8,5,0,113,232,79,0,57,232,39,64,185,41,149,70,249,41,53,64,57,8,125,9,27,233,31,64,185,8,1,9,11,8,5,0,113,232,3,8,42,41,0,0,176,41,157,70,249,8,1,9,139,168,131,29,248,1,0,0,20,1,0,0,20,232,27,64,249,9,0,128,82,233,11,0,185,8,1,0,180,1,0,0,20,40,0,0,240,8,145,73,185,8,1,0,113,232,23,159,26,232,11,0,185,1,0,0,20,232,11,64,185,8,14,0,54,1,0,0,20,40,0,0,240,8,149,73,185,72,2,0,53,1,0,0,20,40,0,0,240,8,145,73,185,200,1,0,53,1,0,0,20,40,0,0,176,8,217,68,249,9,3,130,210,9,4,160,242,8,1,9,139,8,1,64,185,200,0,32,55,1,0,0,20,41,0,0,240,40,0,128,82,40,145,9,185,91,0,0,20,232,79,64,57,72,1,0,52,1,0,0,20,233,79,64,57,8,0,128,18,8,1,41,11,232,79,0,57,168,131,93,248,8,5,0,145,168,131,29,248,23,0,0,20,232,39,64,185,104,0,0,53,1,0,0,20,76,0,0,20,41,0,0,176,40,149,70,249,8,53,64,57,8,5,0,113,232,79,0,57,232,39,64,185,41,149,70,249,41,53,64,57,8,125,9,27,232,3,8,42,41,0,0,176,41,157,70,249,8,1,9,139,168,131,29,248,224,39,64,185,57,252,255,151,224,39,0,185,1,0,0,20,232,23,64,185,233,27,64,249,8,1,9,235,169,0,0,84,1,0,0,20,232,27,64,249,232,23,0,185,1,0,0,20,232,23,64,185,8,1,8,113,226,1,0,84,1,0,0,20,160,131,93,248,31,32,3,213,193,50,3,16,225,3,0,249,117,247,255,151,232,3,64,249,160,3,94,248,233,27,64,185,1,1,9,139,226,23,64,185,254,230,255,151,255,27,0,185,16,0,0,20,160,131,93,248,161,3,94,248,106,247,255,151,232,27,64,185,72,1,0,52,1,0,0,20,160,3,94,248,168,3,94,248,233,27,64,185,1,1,9,139,226,23,64,185,240,230,255,151,255,27,0,185,1,0,0,20,1,0,0,20,232,23,64,185,233,3,8,42,168,3,94,248,8,1,9,139,168,3,30,248,232,23,64,185,233,3,8,42,232,27,64,249,8,1,9,235,232,27,0,249,8,64,128,82,232,23,0,185,168,131,94,248,233,27,64,249,0,1,9,235,145,235,255,151,133,255,255,23,68,235,255,151,168,131,94,248,233,27,64,249,8,1,9,235,168,131,31,248,1,0,0,20,160,131,95,248,253,123,70,169,255,195,1,145,192,3,95,214,40,0,0,240,31,181,3,249,40,0,0,240,31,97,7,185,192,3,95,214,255,67,2,209,253,123,8,169,253,3,2,145,191,67,29,184,40,0,0,240,8,149,73,185,232,0,0,52,1,0,0,20,18,250,255,151,32,0,0,144,0,84,47,145,8,240,255,151,1,0,0,20,40,0,0,240,31,205,4,249,41,0,0,240,72,0,160,210,40,209,4,249,32,0,0,144,0,224,38,145,51,252,255,151,96,1,0,53,1,0,0,20,40,0,0,240,8,149,73,185,72,85,0,53,1,0,0,20,32,0,0,144,0,224,29,145,42,252,255,151,160,84,0,52,1,0,0,20,43,0,0,240,105,209,68,249,40,0,0,240,168,131,28,248,9,213,4,249,41,0,0,240,233,35,0,249,42,181,67,249,74,29,0,145,76,241,125,146,106,209,68,249,74,1,12,139,106,209,4,249,33,181,67,249,2,213,68,249,224,3,31,170,192,254,255,151,233,35,64,249,168,131,92,248,8,213,68,249,41,181,67,249,8,1,9,139,31,1,0,57,196,255,255,151,168,131,92,248,31,32,3,213,73,140,2,16,42,21,64,185,43,0,0,176,106,1,11,185,42,25,64,185,43,0,0,176,106,5,11,185,41,113,64,57,42,0,0,176,73,9,11,185,41,0,0,176,63,145,10,185,41,0,0,240,63,193,38,57,8,213,68,249,168,131,31,248,1,0,0,20,168,131,95,248,8,1,64,57,168,78,0,52,1,0,0,20,1,0,0,20,168,131,95,248,8,1,64,57,9,0,128,82,233,63,0,185,8,4,0,52,1,0,0,20,168,131,95,248,9,1,64,57,40,0,128,82,41,53,0,113,232,59,0,185,192,2,0,84,1,0,0,20,168,131,95,248,9,1,64,57,40,0,128,82,41,41,0,113,232,59,0,185,224,1,0,84,1,0,0,20,168,131,95,248,9,1,64,57,40,0,128,82,41,129,0,113,232,59,0,185,0,1,0,84,1,0,0,20,168,131,95,248,8,1,64,57,8,37,0,113,232,23,159,26,232,59,0,185,1,0,0,20,232,59,64,185,232,63,0,185,1,0,0,20,232,63,64,185,200,0,0,54,1,0,0,20,168,131,95,248,8,5,0,145,168,131,31,248,214,255,255,23,168,131,95,248,168,131,30,248,1,0,0,20,168,131,94,248,8,1,64,57,9,0,128,82,233,55,0,185,200,2,0,52,1,0,0,20,168,131,94,248,9,1,64,57,8,0,128,82,41,129,0,113,232,55,0,185,224,1,0,84,1,0,0,20,168,131,94,248,9,1,64,57,8,0,128,82,41,53,0,113,232,55,0,185,0,1,0,84,1,0,0,20,168,131,94,248,8,1,64,57,8,41,0,113,232,7,159,26,232,55,0,185,1,0,0,20,232,55,64,185,232,0,0,54,1,0,0,20,1,0,0,20,168,131,94,248,8,5,0,145,168,131,30,248,223,255,255,23,168,131,94,248,168,3,31,248,1,0,0,20,168,3,95,248,8,1,64,57,9,0,128,82,233,51,0,185,232,1,0,52,1,0,0,20,168,3,95,248,9,1,64,57,8,0,128,82,41,53,0,113,232,51,0,185,0,1,0,84,1,0,0,20,168,3,95,248,8,1,64,57,8,41,0,113,232,7,159,26,232,51,0,185,1,0,0,20,232,51,64,185,232,0,0,54,1,0,0,20,1,0,0,20,168,3,95,248,8,5,0,145,168,3,31,248,230,255,255,23,1,0,0,20,169,131,94,248,170,3,95,248,8,0,128,82,41,1,10,235,232,47,0,185,2,1,0,84,1,0,0,20,168,131,94,248,8,1,64,57,8,129,0,113,232,23,159,26,232,47,0,185,1,0,0,20,232,47,64,185,232,0,0,54,1,0,0,20,1,0,0,20,168,131,94,248,8,5,0,145,168,131,30,248,236,255,255,23,160,131,95,248,33,0,0,144,33,192,36,145,194,0,128,82,33,230,255,151,8,0,0,113,232,23,159,26,168,131,29,184,40,0,0,240,8,149,73,185,169,131,93,184,8,1,9,74,168,0,0,52,1,0,0,20,168,3,95,248,168,131,31,248,103,255,255,23,40,0,0,240,8,149,73,185,169,131,93,184,8,1,9,10,200,0,0,52,1,0,0,20,168,131,95,248,8,25,0,145,168,131,31,248,1,0,0,20,1,0,0,20,160,131,95,248,33,0,0,144,33,252,31,145,34,1,128,82,5,230,255,151,192,0,0,53,1,0,0,20,40,0,128,82,41,0,0,240,40,193,38,57,1,0,0,20,168,131,94,248,169,3,95,248,8,1,9,235,163,0,0,84,1,0,0,20,168,3,95,248,168,131,31,248,73,255,255,23,160,131,95,248,33,0,0,144,33,100,31,145,34,1,128,82,242,229,255,151,64,1,0,53,1,0,0,20,168,67,93,184,8,5,0,17,168,67,29,184,8,5,0,113,109,0,0,84,1,0,0,20,178,1,0,20,174,1,0,20,160,131,95,248,33,0,0,144,33,40,30,145,226,0,128,82,227,229,255,151,0,1,0,53,1,0,0,20,160,131,94,248,31,32,3,213,193,106,3,16,20,235,255,151,160,131,30,248,160,1,0,20,160,131,95,248,33,0,0,144,33,192,49,145,98,1,128,82,214,229,255,151,192,12,0,53,1,0,0,20,160,131,94,248,31,32,3,213,129,115,2,16,7,235,255,151,160,131,30,248,1,0,0,20,169,131,94,248,170,3,95,248,8,0,128,82,41,1,10,235,232,43,0,185,2,1,0,84,1,0,0,20,168,131,94,248,8,1,64,57,8,129,0,113,232,23,159,26,232,43,0,185,1,0,0,20,232,43,64,185,200,0,0,54,1,0,0,20,168,131,94,248,8,5,0,145,168,131,30,248,237,255,255,23,160,131,94,248,31,32,3,213,97,112,2,16,237,234,255,151,160,131,30,248,1,0,0,20,169,131,94,248,170,3,95,248,8,0,128,82,41,1,10,235,232,39,0,185,2,1,0,84,1,0,0,20,168,131,94,248,8,1,64,57,8,129,0,113,232,23,159,26,232,39,0,185,1,0,0,20,232,39,64,185,200,0,0,54,1,0,0,20,168,131,94,248,8,5,0,145,168,131,30,248,237,255,255,23,160,131,94,248,31,32,3,213,65,109,2,16,211,234,255,151,160,131,30,248,40,0,0,176,8,1,75,185,8,1,5,113,99,3,0,84,1,0,0,20,40,0,0,176,8,1,75,185,8,65,64,113,200,2,0,84,1,0,0,20,40,0,0,176,8,5,75,185,8,33,3,113,35,2,0,84,1,0,0,20,40,0,0,176,8,5,75,185,8,65,64,113,136,1,0,84,1,0,0,20,40,0,0,176,8,9,75,185,8,61,0,113,227,0,0,84,1,0,0,20,40,0,0,176,8,9,75,185,8,129,0,113,201,1,0,84,1,0,0,20,31,32,3,213,200,99,2,16,9,21,64,185,42,0,0,176,73,1,11,185,9,25,64,185,42,0,0,176,73,5,11,185,8,113,64,57,41,0,0,176,40,9,11,185,1,0,0,20,52,1,0,20,160,131,95,248,33,0,0,144,33,220,36,145,66,1,128,82,107,229,255,151,160,23,0,53,1,0,0,20,168,131,94,248,8,1,64,57,8,141,0,113,225,15,0,84,1,0,0,20,168,131,94,248,8,5,0,145,168,131,30,248,160,131,94,248,161,115,0,209,57,234,255,151,160,131,30,248,160,131,94,248,161,131,0,209,53,234,255,151,160,131,30,248,160,131,94,248,161,147,0,209,49,234,255,151,160,131,30,248,31,32,3,213,200,94,2,16,8,133,64,57,8,33,0,113,77,1,0,84,1,0,0,20,168,67,94,184,31,32,3,213,233,93,2,16,41,133,64,57,41,33,0,113,8,33,201,26,232,35,0,185,10,0,0,20,168,67,94,184,31,32,3,213,233,92,2,16,42,133,64,57,9,1,128,82,41,1,10,107,8,37,201,26,232,35,0,185,1,0,0,20,233,35,64,185,31,32,3,213,200,91,2,16,10,129,64,57,41,33,202,26,233,31,0,185,8,141,64,57,8,33,0,113,77,1,0,84,1,0,0,20,168,3,94,184,31,32,3,213,137,90,2,16,41,141,64,57,41,33,0,113,8,33,201,26,232,27,0,185,10,0,0,20,168,3,94,184,31,32,3,213,137,89,2,16,42,141,64,57,9,1,128,82,41,1,10,107,8,37,201,26,232,27,0,185,1,0,0,20,233,31,64,185,234,27,64,185,31,32,3,213,72,88,2,16,11,137,64,57,74,33,203,26,41,1,10,42,233,23,0,185,8,149,64,57,8,33,0,113,77,1,0,84,1,0,0,20,168,195,93,184,31,32,3,213,233,86,2,16,41,149,64,57,41,33,0,113,8,33,201,26,232,19,0,185,10,0,0,20,168,195,93,184,31,32,3,213,233,85,2,16,42,149,64,57,9,1,128,82,41,1,10,107,8,37,201,26,232,19,0,185,1,0,0,20,232,23,64,185,233,19,64,185,31,32,3,213,170,84,2,16,74,145,64,57,41,33,202,26,8,1,9,42,41,0,0,176,40,145,10,185,1,0,0,20,169,131,94,248,170,3,95,248,8,0,128,82,41,1,10,235,232,15,0,185,2,1,0,84,1,0,0,20,168,131,94,248,8,1,64,57,8,129,0,113,232,23,159,26,232,15,0,185,1,0,0,20,232,15,64,185,200,0,0,54,1,0,0,20,168,131,94,248,8,5,0,145,168,131,30,248,237,255,255,23,1,0,0,20,168,131,94,248,169,3,95,248,8,1,9,235,130,6,0,84,1,0,0,20,160,131,94,248,46,250,255,151,128,4,0,52,1,0,0,20,41,0,0,208,40,209,68,249,42,0,0,176,72,165,6,249,40,0,0,208,8,181,67,249,8,29,0,145,10,241,125,146,40,209,68,249,8,1,10,139,40,209,4,249,40,0,0,208,8,181,73,185,72,1,0,52,1,0,0,20,40,0,0,208,2,181,67,249,0,0,0,240,0,84,29,145,31,32,3,213,129,245,2,16,226,237,255,151,1,0,0,20,40,0,0,208,9,181,67,249,42,0,0,176,73,81,13,185,1,181,67,249,40,0,0,176,2,165,70,249,224,3,31,170,181,252,255,151,191,253,255,151,12,0,0,20,40,0,0,208,8,181,73,185,8,1,0,52,1,0,0,20,0,0,0,240,0,196,28,145,31,32,3,213,225,242,2,16,205,237,255,151,1,0,0,20,1,0,0,20,1,0,0,20,208,247,255,151,113,0,0,20,168,131,94,248,169,3,95,248,8,1,9,235,130,13,0,84,1,0,0,20,160,131,95,248,1,0,0,240,33,36,34,145,194,0,128,82,164,228,255,151,160,12,0,53,1,0,0,20,168,131,94,248,41,0,0,208,40,205,4,249,1,0,0,20,169,131,94,248,170,3,95,248,8,0,128,82,41,1,10,235,232,11,0,185,130,3,0,84,1,0,0,20,168,131,94,248,8,1,64,57,9,0,128,82,233,11,0,185,200,2,0,52,1,0,0,20,168,131,94,248,9,1,64,57,8,0,128,82,41,129,0,113,232,11,0,185,224,1,0,84,1,0,0,20,168,131,94,248,9,1,64,57,8,0,128,82,41,53,0,113,232,11,0,185,0,1,0,84,1,0,0,20,168,131,94,248,8,1,64,57,8,41,0,113,232,7,159,26,232,11,0,185,1,0,0,20,232,11,64,185,168,2,0,54,1,0,0,20,168,131,94,248,8,1,64,57,8,113,1,113,97,1,0,84,1,0,0,20,168,131,94,248,8,5,64,57,8,129,0,113,193,0,0,84,1,0,0,20,168,131,94,248,8,5,0,145,168,131,30,248,1,0,0,20,1,0,0,20,168,131,94,248,8,5,0,145,168,131,30,248,202,255,255,23,1,0,0,20,169,131,94,248,170,3,95,248,8,0,128,82,41,1,10,235,232,7,0,185,2,1,0,84,1,0,0,20,168,131,94,248,8,1,64,57,8,129,0,113,232,23,159,26,232,7,0,185,1,0,0,20,232,7,64,185,200,0,0,54,1,0,0,20,168,131,94,248,8,5,0,145,168,131,30,248,237,255,255,23,168,131,94,248,8,1,64,57,8,2,0,52,1,0,0,20,168,131,94,248,8,1,64,57,8,53,0,113,96,1,0,84,1,0,0,20,168,131,94,248,8,1,64,57,8,41,0,113,192,0,0,84,1,0,0,20,168,131,94,248,41,0,0,208,40,221,4,249,1,0,0,20,1,0,0,20,1,0,0,20,1,0,0,20,1,0,0,20,1,0,0,20,168,3,95,248,168,131,31,248,138,253,255,23,1,0,0,20,40,0,0,208,8,205,68,249,232,0,0,181,1,0,0,20,31,32,3,213,8,142,1,16,41,0,0,208,40,205,4,249,1,0,0,20,40,0,0,208,8,149,73,185,136,1,0,53,1,0,0,20,31,32,3,213,232,142,1,16,8,253,64,57,8,5,0,113,193,0,0,84,1,0,0,20,40,0,128,82,41,0,0,208,40,193,38,57,1,0,0,20,253,123,72,169,255,67,2,145,192,3,95,214,255,67,1,209,253,123,4,169,253,3,1,145,40,0,0,208,31,225,4,249,40,0,0,144,8,121,69,249,41,0,0,144,40,109,5,249,40,0,0,208,9,209,68,249,40,0,0,208,9,229,4,249,8,229,68,249,104,27,0,180,1,0,0,20,40,0,0,208,9,209,68,249,63,5,0,185,8,209,68,249,31,1,0,185,40,0,0,208,9,229,68,249,41,33,0,145,9,229,4,249,8,229,68,249,168,131,31,248,169,131,95,248,72,0,128,82,40,1,0,185,40,0,0,208,232,19,0,249,10,149,73,185,105,2,128,82,136,3,128,82,74,1,0,113,8,17,137,26,169,131,95,248,40,5,0,185,168,131,95,248,0,33,0,145,1,0,0,240,33,108,27,145,98,1,128,82,195,227,255,151,232,19,64,249,8,149,73,185,40,1,0,52,1,0,0,20,168,131,95,248,0,73,0,145,1,0,0,240,33,140,31,145,66,1,128,82,185,227,255,151,1,0,0,20,168,131,95,248,8,5,64,185,8,29,0,17,10,113,29,18,41,0,0,208,40,229,68,249,234,3,10,42,8,1,10,139,40,229,4,249,40,0,0,208,8,221,68,249,168,9,0,180,1,0,0,20,40,0,0,208,8,221,68,249,168,131,30,248,1,0,0,20,168,131,94,248,8,1,64,57,9,0,128,82,233,31,0,185,232,1,0,52,1,0,0,20,168,131,94,248,9,1,64,57,8,0,128,82,41,53,0,113,232,31,0,185,0,1,0,84,1,0,0,20,168,131,94,248,8,1,64,57,8,41,0,113,232,7,159,26,232,31,0,185,1,0,0,20,232,31,64,185,232,0,0,54,1,0,0,20,1,0,0,20,168,131,94,248,8,5,0,145,168,131,30,248,230,255,255,23,40,0,0,208,232,7,0,249,8,229,68,249,168,131,31,248,169,131,95,248,40,0,128,82,40,1,0,185,168,131,94,248,8,37,0,145,41,0,0,208,233,11,0,249,42,221,68,249,8,1,10,235,170,131,95,248,72,5,0,185,168,131,95,248,0,33,0,145,33,221,68,249,168,131,94,248,41,221,68,249,8,1,9,235,226,3,8,42,117,227,255,151,234,7,64,249,233,11,64,249,168,131,95,248,8,33,0,145,171,131,94,248,44,221,68,249,107,1,12,235,8,1,11,139,31,1,0,57,168,131,95,248,8,5,64,185,8,29,0,17,11,113,29,18,72,229,68,249,235,3,11,42,8,1,11,139,72,229,4,249,168,131,95,248,8,33,0,145,40,221,4,249,1,0,0,20,42,0,0,144,31,32,3,213,168,32,2,16,9,4,128,82,73,193,9,185,31,5,0,185,169,0,128,82,41,0,160,114,9,9,0,185,0,1,128,82,0,13,0,185,31,17,0,185,31,21,0,185,31,25,0,185,31,29,0,185,222,232,255,151,8,28,0,18,8,1,0,52,1,0,0,20,31,32,3,213,104,30,2,16,8,25,64,185,41,0,0,208,40,233,4,249,5,0,0,20,41,0,0,208,8,128,160,210,40,233,4,249,1,0,0,20,42,0,0,208,72,233,68,249,8,169,107,146,72,233,4,249,41,0,0,208,40,229,68,249,168,3,31,248,171,3,95,248,200,0,128,82,104,1,0,185,171,3,95,248,8,3,128,82,104,9,0,185,168,3,95,248,31,13,0,185,168,3,95,248,31,9,0,249,168,3,95,248,11,128,128,210,11,13,0,249,172,3,95,248,72,0,128,82,136,33,0,185,172,3,95,248,159,37,0,185,172,3,95,248,139,21,0,249,74,233,68,249,74,1,16,241,171,3,95,248,106,25,0,249,171,3,95,248,42,0,128,82,106,57,0,185,170,3,95,248,95,61,0,185,42,0,0,144,74,217,68,249,171,3,95,248,106,33,0,249,171,3,95,248,10,16,160,210,106,37,0,249,170,3,95,248,72,81,0,185,170,3,95,248,104,1,128,82,72,85,0,185,170,3,95,248,8,11,128,82,72,5,0,185,168,3,95,248,8,5,64,185,8,29,0,17,10,113,29,18,40,229,68,249,234,3,10,42,8,1,10,139,40,229,4,249,1,0,0,20,253,123,68,169,255,67,1,145,192,3,95,214,255,67,2,209,253,123,8,169,253,3,2,145,191,67,29,184,191,3,29,184,40,0,0,208,8,213,68,249,40,65,0,180,1,0,0,20,40,0,0,208,8,213,68,249,232,31,0,249,1,0,0,20,40,0,0,208,8,145,73,185,9,0,128,82,233,39,0,185,168,1,0,53,1,0,0,20,168,3,93,184,9,0,128,82,233,39,0,185,8,1,0,53,1,0,0,20,232,31,64,249,8,1,64,57,8,1,0,113,232,7,159,26,232,39,0,185,1,0,0,20,232,39,64,185,8,62,0,54,1,0,0,20,1,0,0,20,232,31,64,249,8,1,64,57,9,0,128,82,233,35,0,185,8,4,0,52,1,0,0,20,232,31,64,249,9,1,64,57,40,0,128,82,41,53,0,113,232,31,0,185,192,2,0,84,1,0,0,20,232,31,64,249,9,1,64,57,40,0,128,82,41,41,0,113,232,31,0,185,224,1,0,84,1,0,0,20,232,31,64,249,9,1,64,57,40,0,128,82,41,129,0,113,232,31,0,185,0,1,0,84,1,0,0,20,232,31,64,249,8,1,64,57,8,37,0,113,232,23,159,26,232,31,0,185,1,0,0,20,232,31,64,185,232,35,0,185,1,0,0,20,232,35,64,185,200,0,0,54,1,0,0,20,232,31,64,249,8,5,0,145,232,31,0,249,214,255,255,23,232,31,64,249,232,23,0,249,1,0,0,20,232,23,64,249,8,1,64,57,9,0,128,82,233,27,0,185,200,2,0,52,1,0,0,20,232,23,64,249,9,1,64,57,8,0,128,82,41,129,0,113,232,27,0,185,224,1,0,84,1,0,0,20,232,23,64,249,9,1,64,57,8,0,128,82,41,53,0,113,232,27,0,185,0,1,0,84,1,0,0,20,232,23,64,249,8,1,64,57,8,41,0,113,232,7,159,26,232,27,0,185,1,0,0,20,232,27,64,185,232,0,0,54,1,0,0,20,1,0,0,20,232,23,64,249,8,5,0,145,232,23,0,249,223,255,255,23,232,23,64,249,232,27,0,249,1,0,0,20,232,27,64,249,8,1,64,57,9,0,128,82,233,23,0,185,232,1,0,52,1,0,0,20,232,27,64,249,9,1,64,57,8,0,128,82,41,53,0,113,232,23,0,185,0,1,0,84,1,0,0,20,232,27,64,249,8,1,64,57,8,41,0,113,232,7,159,26,232,23,0,185,1,0,0,20,232,23,64,185,232,0,0,54,1,0,0,20,1,0,0,20,232,27,64,249,8,5,0,145,232,27,0,249,230,255,255,23,1,0,0,20,233,23,64,249,234,27,64,249,8,0,128,82,41,1,10,235,232,19,0,185,2,1,0,84,1,0,0,20,232,23,64,249,8,1,64,57,8,129,0,113,232,23,159,26,232,19,0,185,1,0,0,20,232,19,64,185,232,0,0,54,1,0,0,20,1,0,0,20,232,23,64,249,8,5,0,145,232,23,0,249,236,255,255,23,224,31,64,249,1,0,0,240,33,192,36,145,194,0,128,82,134,226,255,151,8,0,0,113,232,23,159,26,168,195,28,184,232,23,64,249,233,27,64,249,8,1,9,235,2,1,0,84,1,0,0,20,40,0,0,208,8,149,73,185,169,195,92,184,8,1,9,74,168,0,0,52,1,0,0,20,232,27,64,249,232,31,0,249,82,255,255,23,40,0,0,208,8,149,73,185,169,195,92,184,8,1,9,10,200,0,0,52,1,0,0,20,232,31,64,249,8,25,0,145,232,31,0,249,1,0,0,20,1,0,0,20,224,31,64,249,1,0,0,240,33,0,48,145,194,0,128,82,101,226,255,151,0,40,0,53,1,0,0,20,1,0,0,20,224,23,64,249,174,247,255,151,224,37,0,52,1,0,0,20,224,3,31,170,1,2,128,210,162,163,0,209,81,250,255,151,191,67,31,184,168,131,93,56,8,125,0,113,161,1,0,84,1,0,0,20,168,147,93,56,8,45,2,113,33,1,0,84,1,0,0,20,40,0,0,208,8,181,67,249,129,0,128,210,0,17,0,241,162,51,0,209,66,250,255,151,29,0,0,20,168,131,93,56,8,29,1,113,33,3,0,84,1,0,0,20,168,147,93,56,8,85,1,113,161,2,0,84,1,0,0,20,168,163,93,56,8,17,1,113,33,2,0,84,1,0,0,20,168,3,94,56,8,225,1,113,161,1,0,84,1,0,0,20,168,195,93,56,169,211,93,56,8,33,9,42,8,29,0,17,8,113,29,18,169,227,93,56,170,243,93,56,41,33,10,42,8,17,9,11,168,67,31,184,1,0,0,20,1,0,0,20,40,0,0,144,8,109,69,249,168,131,30,248,168,67,95,184,40,2,0,52,1,0,0,20,40,0,0,144,9,109,69,249,169,131,31,248,169,67,95,184,41,253,63,17,41,77,20,18,233,3,9,42,234,3,9,42,9,109,69,249,41,1,10,139,9,109,5,249,8,109,69,249,41,0,0,208,40,225,4,249,14,0,0,20,191,131,31,248,41,0,0,144,40,109,69,249,42,0,0,208,72,225,4,249,40,0,0,208,8,181,67,249,8,253,63,145,10,205,116,146,40,109,69,249,8,1,10,139,40,109,5,249,1,0,0,20,40,0,0,208,8,181,73,185,72,1,0,52,1,0,0,20,40,0,0,208,2,181,67,249,0,0,0,240,0,120,25,145,31,32,3,213,161,156,2,16,27,235,255,151,1,0,0,20,40,0,0,208,1,181,67,249,40,0,0,208,2,225,68,249,224,3,31,170,241,249,255,151,168,131,95,248,104,2,0,180,1,0,0,20,40,0,0,208,8,181,73,185,40,1,0,52,1,0,0,20,162,67,95,184,0,0,0,240,0,152,42,145,31,32,3,213,33,154,2,16,7,235,255,151,1,0,0,20,40,0,0,208,0,225,68,249,161,131,95,248,162,67,95,184,24,226,255,151,1,0,0,20,168,131,94,248,8,1,64,57,8,65,3,113,33,4,0,84,1,0,0,20,168,131,94,248,8,5,64,57,8,53,0,113,129,3,0,84,1,0,0,20,168,131,94,248,8,9,64,57,8,249,3,113,225,2,0,84,1,0,0,20,168,131,94,248,8,13,64,57,8,181,3,113,65,2,0,84,1,0,0,20,40,0,0,208,8,181,73,185,200,0,0,52,1,0,0,20,0,0,0,240,0,36,32,145,229,234,255,151,1,0,0,20,168,131,94,248,41,0,0,144,40,125,5,249,41,0,0,144,40,109,69,249,8,5,64,145,40,109,5,249,144,0,0,20,168,131,94,248,8,1,64,57,8,17,1,113,225,0,0,84,1,0,0,20,168,131,94,248,8,5,64,57,8,77,1,113,128,1,0,84,1,0,0,20,168,131,94,248,8,1,64,57,8,29,1,113,33,4,0,84,1,0,0,20,168,131,94,248,8,5,64,57,8,85,1,113,129,3,0,84,1,0,0,20,168,131,94,248,8,9,64,57,8,17,1,113,225,2,0,84,1,0,0,20,168,131,94,248,8,13,64,57,8,81,1,113,65,2,0,84,1,0,0,20,40,0,0,208,8,181,73,185,72,1,0,52,1,0,0,20,168,131,94,248,1,1,64,57,168,131,94,248,2,5,64,57,0,0,0,240,0,64,34,145,179,234,255,151,1,0,0,20,168,131,94,248,41,0,0,144,40,125,5,249,97,0,0,20,40,0,0,208,8,229,68,249,72,11,0,180,1,0,0,20,40,0,0,208,8,229,68,249,232,35,0,249,233,35,64,249,104,0,128,82,40,1,0,185,232,27,64,249,8,65,0,145,233,23,64,249,8,1,9,235,8,5,0,145,233,35,64,249,40,5,0,185,168,131,95,248,168,0,0,180,1,0,0,20,168,131,95,248,232,15,0,185,5,0,0,20,40,0,0,208,8,225,68,249,232,15,0,185,1,0,0,20,232,15,64,185,233,35,64,249,40,9,0,185,168,131,95,248,232,0,0,180,1,0,0,20,168,131,95,248,169,67,95,184,8,1,9,11,232,11,0,185,8,0,0,20,40,0,0,208,8,225,68,249,41,0,0,208,41,181,67,249,8,1,9,11,232,11,0,185,1,0,0,20,232,11,64,185,233,35,64,249,40,13,0,185,232,35,64,249,0,65,0,145,225,23,64,249,232,27,64,249,233,23,64,249,8,1,9,235,226,3,8,42,47,225,255,151,232,35,64,249,8,65,0,145,233,27,64,249,234,23,64,249,41,1,10,235,8,1,9,139,31,1,0,57,40,0,0,208,8,181,73,185,8,9,0,113,9,1,0,84,1,0,0,20,232,35,64,249,1,9,64,185,0,0,0,240,0,64,29,145,101,234,255,151,1,0,0,20,232,35,64,249,8,5,64,185,8,29,0,17,10,113,29,18,41,0,0,208,40,229,68,249,234,3,10,42,8,1,10,139,40,229,4,249,40,0,0,208,8,237,68,249,200,0,0,181,1,0,0,20,232,35,64,249,41,0,0,208,40,237,4,249,1,0,0,20,1,0,0,20,168,67,93,184,8,5,0,17,168,67,29,184,1,0,0,20,1,0,0,20,52,250,255,151,12,0,0,20,40,0,0,208,8,181,73,185,8,1,0,52,1,0,0,20,0,0,0,240,0,196,28,145,31,32,3,213,129,129,2,16,66,234,255,151,1,0,0,20,1,0,0,20,1,0,0,20,232,27,64,249,232,31,0,249,255,253,255,23,1,0,0,20,168,67,93,184,8,1,0,53,1,0,0,20,168,3,93,184,168,0,0,53,1,0,0,20,40,0,128,82,168,3,29,184,1,0,0,20,168,67,93,184,72,3,0,53,1,0,0,20,168,3,93,184,8,5,0,113,193,2,0,84,1,0,0,20,72,0,128,82,168,3,29,184,41,0,0,208,43,149,73,185,10,0,0,240,74,29,48,145,8,0,0,240,8,9,36,145,107,1,0,113,8,17,138,154,232,23,0,249,232,23,64,249,43,149,73,185,138,1,128,82,9,2,128,82,107,1,0,113,41,17,138,26,8,193,41,139,232,27,0,249,156,254,255,23,253,123,72,169,255,67,2,145,192,3,95,214,255,67,1,209,253,123,4,169,253,3,1,145,160,131,31,184,161,67,31,184,162,131,30,248,163,67,30,184,168,131,94,248,232,11,0,249,168,67,94,184,200,0,0,52,1,0,0,20,40,0,0,176,8,181,67,249,168,0,0,181,1,0,0,20,40,0,128,82,168,195,31,184,102,0,0,20,40,0,0,176,8,181,73,185,8,5,0,113,73,1,0,84,1,0,0,20,161,131,95,184,162,67,95,184,163,131,94,248,164,67,94,184,0,0,0,208,0,16,49,145,245,233,255,151,1,0,0,20,168,67,94,184,169,131,94,248,41,45,64,146,8,1,9,139,8,253,63,145,8,205,116,146,232,15,0,185,168,131,94,248,9,0,0,208,41,85,69,185,8,1,9,235,98,0,0,84,1,0,0,20,68,0,0,20,168,131,94,248,41,0,0,176,41,233,68,249,8,1,9,235,105,2,0,84,1,0,0,20,8,0,0,240,0,109,69,249,161,131,94,248,226,15,64,185,33,241,255,151,96,0,0,53,1,0,0,20,54,0,0,20,9,0,0,240,40,109,69,249,232,11,0,249,232,15,64,185,234,3,8,42,40,109,69,249,8,1,10,139,40,109,5,249,18,0,0,20,232,11,64,249,233,15,64,185,8,1,9,139,8,253,63,145,8,205,116,146,232,15,0,249,8,0,0,240,8,109,69,249,233,15,64,249,8,1,9,235,194,0,0,84,1,0,0,20,232,15,64,249,9,0,0,240,40,109,5,249,1,0,0,20,1,0,0,20,168,67,95,184,40,1,0,52,1,0,0,20,168,131,95,184,224,3,8,42,168,67,95,184,225,3,8,42,226,11,64,249,146,248,255,151,1,0,0,20,168,67,94,184,169,67,95,184,8,1,9,107,105,1,0,84,1,0,0,20,232,11,64,249,169,67,95,184,0,1,9,139,168,67,94,184,169,67,95,184,2,1,9,107,225,3,31,42,121,224,255,151,1,0,0,20,40,0,128,82,168,195,31,184,8,0,0,20,161,131,94,248,162,67,94,184,0,0,0,208,0,144,32,145,158,233,255,151,191,195,31,184,1,0,0,20,160,195,95,184,253,123,68,169,255,67,1,145,192,3,95,214,255,67,1,209,253,123,4,169,253,3,1,145,31,32,3,213,136,191,2,16,168,3,31,248,40,0,0,144,31,193,30,121,40,0,0,176,8,205,68,249,136,1,0,180,1,0,0,20,40,0,0,176,8,205,68,249,8,1,64,57,232,0,0,52,1,0,0,20,40,0,0,176,0,205,68,249,184,245,255,151,32,3,0,53,1,0,0,20,0,0,0,208,0,180,31,145,179,245,255,151,128,2,0,53,1,0,0,20,40,0,0,176,31,193,38,57,40,0,0,144,8,193,94,121,8,1,0,52,1,0,0,20,0,0,0,208,0,28,42,145,31,32,3,213,129,103,2,16,114,233,255,151,5,0,0,20,0,0,0,208,0,64,43,145,110,233,255,151,1,0,0,20,191,195,31,184,38,1,0,20,162,3,95,248,224,3,31,170,1,0,130,210,68,248,255,151,31,32,3,213,192,185,2,16,1,0,0,208,33,152,27,145,66,0,128,82,71,224,255,151,64,5,0,53,1,0,0,20,31,32,3,213,200,184,2,16,0,225,0,145,1,0,0,208,33,164,27,145,98,0,128,82,62,224,255,151,32,4,0,53,1,0,0,20,31,32,3,213,168,183,2,16,8,237,64,57,8,1,1,113,97,3,0,84,1,0,0,20,41,0,0,208,168,0,128,82,40,129,39,57,40,0,0,176,31,193,38,57,40,0,0,176,8,181,73,185,200,0,0,52,1,0,0,20,0,0,0,208,0,180,27,145,68,233,255,151,1,0,0,20,40,0,0,176,9,181,67,249,225,3,9,42,8,181,67,249,227,3,8,42,224,3,31,42,2,1,160,210,40,255,255,151,96,0,0,53,1,0,0,20,224,0,0,20,230,0,0,20,160,3,95,248,1,0,0,208,33,144,45,145,130,0,128,82,24,224,255,151,224,11,0,53,1,0,0,20,168,3,95,248,8,17,64,57,8,9,0,113,65,11,0,84,1,0,0,20,168,3,95,248,8,37,64,121,8,221,2,113,161,10,0,84,1,0,0,20,136,0,128,82,41,0,0,208,40,129,39,57,168,3,95,248,8,13,64,249,41,0,0,208,40,245,4,249,40,0,0,176,8,181,73,185,8,1,0,52,1,0,0,20,0,0,0,208,0,12,26,145,31,32,3,213,1,92,2,16,22,233,255,151,1,0,0,20,168,3,95,248,169,3,95,248,41,17,64,249,8,1,9,139,232,15,0,249,255,15,0,185,1,0,0,20,40,0,0,176,8,145,73,185,9,0,128,82,233,11,0,185,168,2,0,53,1,0,0,20,233,15,64,185,168,3,95,248,10,113,64,121,8,0,128,82,41,1,10,107,232,11,0,185,170,1,0,84,1,0,0,20,232,15,64,249,169,3,95,248,41,109,64,121,8,193,41,139,31,32,3,213,105,172,2,16,41,5,64,145,8,1,9,235,232,39,159,26,232,11,0,185,1,0,0,20,232,11,64,185,8,4,0,54,1,0,0,20,232,15,64,249,8,1,64,185,8,5,0,113,33,2,0,84,1,0,0,20,232,15,64,249,8,5,64,249,224,3,8,42,232,15,64,249,8,17,64,249,225,3,8,42,232,15,64,249,2,9,64,249,232,15,64,249,8,21,64,249,227,3,8,42,206,254,255,151,96,0,0,53,1,0,0,20,134,0,0,20,1,0,0,20,232,15,64,185,8,5,0,17,232,15,0,185,168,3,95,248,9,109,64,121,232,15,64,249,8,193,41,139,232,15,0,249,199,255,255,23,129,0,0,20,168,3,95,248,8,1,64,121,169,73,139,82,8,1,9,107,1,14,0,84,1,0,0,20,168,3,95,248,169,3,95,248,41,61,64,185,8,105,105,184,9,170,136,82,8,1,9,107,1,13,0,84,1,0,0,20,168,3,95,248,169,3,95,248,41,61,64,185,8,1,9,139,8,49,64,121,8,45,8,113,1,12,0,84,1,0,0,20,168,3,95,248,169,3,95,248,41,61,64,185,8,1,9,139,8,9,64,121,137,76,149,82,8,1,9,107,225,10,0,84,1,0,0,20,136,0,128,82,41,0,0,208,40,129,39,57,168,3,95,248,169,3,95,248,41,61,64,185,8,1,9,139,168,131,30,248,168,131,94,248,8,25,64,249,232,3,8,42,232,11,0,249,233,11,64,249,168,131,94,248,8,41,64,185,8,1,9,139,41,0,0,208,40,245,4,249,40,0,0,176,8,181,73,185,8,1,0,52,1,0,0,20,0,0,0,208,0,4,35,145,31,32,3,213,97,76,2,16,153,232,255,151,1,0,0,20,168,131,94,248,169,131,94,248,41,41,64,121,8,193,41,139,8,97,0,145,232,19,0,249,255,15,0,185,1,0,0,20,40,0,0,176,8,145,73,185,9,0,128,82,233,7,0,185,104,2,0,53,1,0,0,20,233,15,64,185,168,131,94,248,10,13,64,121,8,0,128,82,41,1,10,107,232,7,0,185,106,1,0,84,1,0,0,20,232,19,64,249,8,161,0,145,31,32,3,213,233,156,2,16,41,5,64,145,8,1,9,235,232,39,159,26,232,7,0,185,1,0,0,20,232,7,64,185,8,3,0,54,1,0,0,20,232,19,64,249,0,21,64,185,232,19,64,249,1,17,64,185,232,11,64,249,233,19,64,249,41,13,128,185,2,1,9,139,232,19,64,249,3,9,64,185,88,254,255,151,96,0,0,53,1,0,0,20,16,0,0,20,1,0,0,20,232,15,64,185,8,5,0,17,232,15,0,185,232,19,64,249,8,161,0,145,232,19,0,249,209,255,255,23,12,0,0,20,0,0,0,208,0,148,33,145,31,32,3,213,129,68,2,16,90,232,255,151,1,0,0,20,64,248,255,151,40,0,0,176,31,193,38,57,191,195,31,184,15,0,0,20,1,0,0,20,1,0,0,20,57,248,255,151,40,0,0,208,8,129,103,57,8,17,0,113,160,0,0,84,1,0,0,20,40,0,0,176,31,193,38,57,1,0,0,20,40,0,128,82,168,195,31,184,1,0,0,20,160,195,95,184,253,123,68,169,255,67,1,145,192,3,95,214,255,131,4,209,253,123,16,169,252,139,0,249,253,3,4,145,31,32,3,213,40,21,3,16,232,63,0,249,31,32,3,213,72,22,3,16,232,67,0,249,31,32,3,213,104,24,3,16,168,131,24,248,191,67,28,184,191,3,28,184,191,195,27,184,191,3,26,248,191,131,25,248,136,0,128,82,168,3,25,184,8,0,0,240,8,125,69,249,72,71,0,180,1,0,0,20,8,0,0,240,8,125,69,249,8,1,64,57,8,65,3,113,129,70,0,84,1,0,0,20,8,0,0,240,8,125,69,249,8,5,64,57,8,53,0,113,193,69,0,84,1,0,0,20,8,0,0,240,8,125,69,249,8,9,64,57,8,249,3,113,1,69,0,84,1,0,0,20,8,0,0,240,8,125,69,249,8,13,64,57,8,181,3,113,65,68,0,84,1,0,0,20,8,0,0,240,232,59,0,249,9,125,69,249,41,29,64,57,10,125,69,249,74,25,64,57,41,33,10,42,10,125,69,249,74,21,64,57,41,65,10,42,169,3,30,184,9,125,69,249,41,45,64,57,10,125,69,249,74,41,64,57,41,33,10,42,10,125,69,249,74,37,64,57,41,65,10,42,169,195,29,184,9,125,69,249,41,61,64,57,10,125,69,249,74,57,64,57,41,33,10,42,10,125,69,249,74,53,64,57,41,65,10,42,169,131,29,184,9,125,69,249,41,141,64,57,10,125,69,249,74,137,64,57,41,33,10,42,10,125,69,249,74,133,64,57,41,65,10,42,169,67,29,184,9,125,69,249,41,157,64,57,10,125,69,249,74,153,64,57,41,33,10,42,10,125,69,249,74,149,64,57,41,65,10,42,169,3,29,184,9,125,69,249,170,195,93,184,41,1,10,139,169,3,27,248,8,125,69,249,169,195,93,184,8,1,9,139,169,3,93,184,8,1,9,139,168,131,26,248,168,131,93,184,169,195,93,184,170,3,93,184,41,1,10,11,8,1,9,107,35,60,0,84,1,0,0,20,40,0,0,176,8,221,68,249,168,2,0,180,1,0,0,20,40,0,0,176,8,221,68,249,8,1,64,57,8,2,0,52,1,0,0,20,1,0,0,20,40,0,0,176,8,221,68,249,169,195,91,184,8,1,9,139,8,1,64,57,232,0,0,52,1,0,0,20,1,0,0,20,168,195,91,184,8,5,0,17,168,195,27,184,245,255,255,23,1,0,0,20,168,195,91,184,8,5,0,17,168,195,27,184,168,195,91,184,8,13,0,17,8,117,30,18,168,3,28,184,1,0,0,20,168,3,91,248,169,131,90,248,8,1,9,235,194,16,0,84,1,0,0,20,168,3,91,248,8,13,64,57,169,3,91,248,41,9,64,57,8,33,9,42,169,3,91,248,41,5,64,57,8,65,9,42,169,3,91,248,41,1,64,57,8,97,9,42,168,195,28,184,168,3,91,248,8,17,0,145,168,3,27,248,168,195,92,184,8,37,0,113,97,0,0,84,1,0,0,20,113,0,0,20,168,195,92,184,8,5,0,113,225,3,0,84,1,0,0,20,168,3,91,248,168,3,26,248,1,0,0,20,169,3,91,248,170,131,90,248,8,0,128,82,41,1,10,235,232,111,0,185,2,1,0,84,1,0,0,20,168,3,91,248,8,1,64,57,8,1,0,113,232,7,159,26,232,111,0,185,1,0,0,20,232,111,64,185,232,0,0,54,1,0,0,20,1,0,0,20,168,3,91,248,8,5,0,145,168,3,27,248,236,255,255,23,168,3,91,248,8,13,0,145,8,245,126,146,168,3,27,248,79,0,0,20,168,195,92,184,8,9,0,113,129,0,0,84,1,0,0,20,191,3,26,248,72,0,0,20,168,195,92,184,8,13,0,113,129,8,0,84,1,0,0,20,168,3,91,248,8,13,64,57,169,3,91,248,41,9,64,57,8,33,9,42,169,3,91,248,41,5,64,57,8,65,9,42,168,131,28,184,168,3,91,248,8,17,0,145,168,3,27,248,168,3,91,248,8,13,64,57,169,3,91,248,41,9,64,57,8,33,9,42,169,3,91,248,41,5,64,57,8,65,9,42,168,195,28,184,168,3,91,248,8,17,0,145,168,3,27,248,168,195,92,184,169,67,93,184,41,5,0,113,8,1,9,107,226,3,0,84,1,0,0,20,168,3,90,248,136,3,0,180,1,0,0,20,160,3,90,248,1,0,0,208,33,164,45,145,226,0,128,82,47,222,255,151,160,2,0,53,1,0,0,20,8,0,0,240,8,125,69,249,169,131,93,184,8,1,9,139,169,195,92,184,0,1,9,139,1,0,0,208,33,192,45,145,34,1,128,82,35,222,255,151,32,1,0,53,1,0,0,20,168,3,91,248,168,131,25,248,168,131,92,184,8,13,0,17,8,117,30,18,168,67,28,184,11,0,0,20,168,3,91,248,169,131,92,184,8,1,9,139,8,13,0,145,8,245,126,146,168,3,27,248,1,0,0,20,1,0,0,20,1,0,0,20,120,255,255,23,168,131,89,248,232,17,0,181,1,0,0,20,168,67,93,184,168,195,28,184,168,67,93,184,34,1,128,82,8,37,0,17,168,67,29,184,168,3,94,184,8,37,0,17,168,3,30,184,8,0,0,240,232,51,0,249,8,125,69,249,169,195,92,184,0,1,9,139,1,0,0,208,33,192,45,145,207,221,255,151,232,51,64,249,9,125,69,249,170,195,93,184,41,1,10,139,170,3,93,184,41,1,10,139,169,131,25,248,9,125,69,249,170,3,94,184,41,1,10,139,169,3,27,248,8,125,69,249,169,3,94,184,8,1,9,139,169,3,92,184,8,1,9,139,8,113,0,145,168,3,26,248,1,0,0,20,168,3,91,248,169,131,89,248,8,1,9,235,195,1,0,84,1,0,0,20,168,3,91,248,8,1,64,57,169,3,90,248,40,1,0,57,1,0,0,20,168,3,91,248,8,5,0,145,168,3,27,248,168,3,90,248,8,5,0,145,168,3,26,248,240,255,255,23,160,131,89,248,1,0,0,208,33,124,24,145,2,2,128,82,166,221,255,151,168,131,89,248,8,65,0,145,168,131,25,248,168,195,91,56,169,131,89,248,40,13,0,57,168,195,91,184,8,125,8,83,8,29,0,18,169,131,89,248,40,9,0,57,168,195,91,184,8,125,8,83,8,29,0,18,169,131,89,248,40,5,0,57,168,131,89,248,31,1,0,57,168,131,89,248,8,17,0,145,168,131,25,248,168,195,92,56,169,131,89,248,40,13,0,57,168,195,92,184,8,125,8,83,8,29,0,18,169,131,89,248,40,9,0,57,168,195,92,184,8,125,8,83,8,29,0,18,169,131,89,248,40,5,0,57,168,131,89,248,31,1,0,57,168,131,89,248,8,17,0,145,168,131,25,248,40,0,0,176,8,221,68,249,40,1,0,180,1,0,0,20,160,131,89,248,40,0,0,176,1,221,68,249,168,195,91,184,2,5,0,113,117,221,255,151,1,0,0,20,168,131,89,248,169,195,91,184,8,1,9,139,0,5,0,241,168,3,92,184,169,195,91,184,8,1,9,107,2,5,0,17,225,3,31,42,131,221,255,151,168,131,89,248,169,3,92,184,0,1,9,139,1,0,0,208,33,192,24,145,130,0,128,82,99,221,255,151,168,3,92,184,9,113,0,17,168,3,93,184,8,1,9,11,168,3,29,184,168,3,92,184,9,113,0,17,168,3,94,184,8,1,9,11,168,3,30,184,168,3,92,184,9,113,0,17,168,131,93,184,8,1,9,11,168,131,29,184,113,0,0,20,168,3,92,184,169,67,92,184,8,1,9,107,162,1,0,84,1,0,0,20,168,131,89,248,169,3,92,184,0,1,9,139,168,131,89,248,169,67,92,184,1,1,9,139,168,3,94,184,169,67,92,184,2,1,9,107,68,221,255,151,41,0,0,20,168,3,92,184,169,67,92,184,8,1,9,107,137,4,0,84,1,0,0,20,8,0,0,240,9,125,69,249,170,3,94,184,41,1,10,139,169,3,27,248,8,125,69,249,169,3,94,184,8,1,9,139,169,3,92,184,8,1,9,139,169,67,92,184,8,1,9,235,168,3,26,248,1,0,0,20,168,3,91,248,169,131,89,248,170,67,92,184,41,1,10,139,8,1,9,235,195,1,0,84,1,0,0,20,168,3,91,248,8,1,64,57,169,3,90,248,40,1,0,57,1,0,0,20,168,3,91,248,8,5,0,145,168,3,27,248,168,3,90,248,8,5,0,145,168,3,26,248,238,255,255,23,1,0,0,20,1,0,0,20,168,195,91,56,169,131,89,248,40,177,31,56,168,195,91,184,8,125,8,83,8,29,0,18,169,131,89,248,40,161,31,56,168,195,91,184,8,125,8,83,8,29,0,18,169,131,89,248,40,145,31,56,168,131,89,248,8,33,0,241,31,1,0,57,40,0,0,176,8,221,68,249,40,1,0,180,1,0,0,20,160,131,89,248,40,0,0,176,1,221,68,249,168,195,91,184,2,5,0,113,1,221,255,151,1,0,0,20,168,131,89,248,169,195,91,184,8,1,9,139,0,5,0,241,168,3,92,184,169,195,91,184,8,1,9,107,2,5,0,17,225,3,31,42,15,221,255,151,168,3,92,184,169,67,92,184,9,1,9,107,168,3,93,184,8,1,9,11,168,3,29,184,168,3,92,184,169,67,92,184,9,1,9,107,168,3,94,184,8,1,9,11,168,3,30,184,168,3,92,184,169,67,92,184,9,1,9,107,168,131,93,184,8,1,9,11,168,131,29,184,1,0,0,20,168,3,94,56,9,0,0,240,233,47,0,249,42,125,69,249,72,29,0,57,168,3,94,184,8,125,8,83,8,29,0,18,42,125,69,249,72,25,0,57,168,3,94,184,8,125,16,83,8,29,0,18,42,125,69,249,72,21,0,57,168,131,93,56,42,125,69,249,72,61,0,57,168,131,93,184,8,125,8,83,8,29,0,18,42,125,69,249,72,57,0,57,168,131,93,184,8,125,16,83,8,29,0,18,42,125,69,249,72,53,0,57,168,67,93,56,42,125,69,249,72,141,0,57,168,67,93,184,8,125,8,83,8,29,0,18,42,125,69,249,72,137,0,57,168,67,93,184,8,125,16,83,8,29,0,18,42,125,69,249,72,133,0,57,168,3,93,56,42,125,69,249,72,157,0,57,168,3,93,184,8,125,8,83,8,29,0,18,42,125,69,249,72,153,0,57,168,3,93,184,8,125,16,83,8,29,0,18,41,125,69,249,40,149,0,57,1,0,0,20,1,0,0,20,31,32,3,213,40,79,1,16,8,5,64,249,40,11,0,180,1,0,0,20,31,32,3,213,136,78,1,16,8,21,64,185,9,0,0,208,41,1,75,185,8,1,9,107,65,2,0,84,1,0,0,20,31,32,3,213,136,77,1,16,8,25,64,185,9,0,0,208,41,5,75,185,8,1,9,107,65,1,0,84,1,0,0,20,31,32,3,213,136,76,1,16,8,113,64,57,9,0,0,208,41,9,75,185,8,1,9,107,160,3,0,84,1,0,0,20,31,32,3,213,136,75,1,16,232,43,0,249,9,21,64,185,169,195,30,184,9,25,64,185,169,131,30,184,8,113,64,57,168,67,30,184,8,0,0,208,0,1,75,185,8,0,0,208,1,5,75,185,8,0,0,208,2,9,75,185,85,226,255,151,232,43,64,249,8,5,64,249,232,0,0,181,1,0,0,20,160,195,94,184,161,131,94,184,162,67,94,184,77,226,255,151,1,0,0,20,194,239,255,151,1,0,0,20,40,0,0,144,8,229,68,249,40,4,0,180,1,0,0,20,31,32,3,213,168,71,1,16,8,5,64,249,136,3,0,180,1,0,0,20,9,0,0,208,31,32,3,213,225,70,1,16,225,35,0,249,8,1,128,82,40,97,10,185,8,5,128,82,40,4,0,185,40,0,128,82,40,116,0,57,63,60,0,121,40,0,0,144,232,39,0,249,0,229,68,249,34,4,64,185,90,220,255,151,232,35,64,249,233,39,64,249,8,5,64,185,8,29,0,17,10,113,29,18,40,229,68,249,234,3,10,42,8,1,10,139,40,229,4,249,1,0,0,20,1,0,0,20,40,0,0,144,8,229,68,249,136,54,0,180,1,0,0,20,10,0,0,208,31,32,3,213,8,62,1,16,9,4,128,82,73,193,9,185,31,5,0,185,9,4,128,82,105,0,160,114,9,9,0,185,137,0,128,82,9,13,0,185,31,17,0,185,31,21,0,185,31,25,0,185,31,29,0,185,0,1,128,82,200,225,255,151,8,28,0,18,104,4,0,52,1,0,0,20,31,32,3,213,168,59,1,16,8,13,64,185,8,1,2,113,169,3,0,84,1,0,0,20,41,0,0,144,233,31,0,249,42,229,68,249,8,32,128,82,72,1,0,185,31,32,3,213,72,58,1,16,232,27,0,249,10,13,64,185,43,229,68,249,106,5,0,185,41,229,68,249,32,33,0,145,9,13,64,185,34,33,0,113,1,97,0,145,32,220,255,151,232,27,64,249,233,31,64,249,8,13,64,185,8,29,0,17,10,113,29,18,40,229,68,249,234,3,10,42,8,1,10,139,40,229,4,249,1,0,0,20,40,0,0,144,10,229,68,249,201,1,128,82,73,1,0,185,10,229,68,249,137,3,128,82,73,5,0,185,8,229,68,249,8,33,0,145,168,131,31,248,160,131,95,248,225,3,31,42,130,2,128,82,33,220,255,151,160,131,95,248,1,0,0,176,33,108,32,145,2,1,128,82,3,220,255,151,232,63,64,249,170,131,95,248,41,0,128,82,73,61,0,57,169,131,95,248,40,17,0,185,191,179,27,56,191,67,25,184,1,0,0,20,168,67,89,184,8,81,0,113,170,1,0,84,1,0,0,20,168,131,95,248,169,67,153,184,9,105,105,56,168,179,91,56,8,1,9,11,168,179,27,56,1,0,0,20,168,67,89,184,8,5,0,17,168,67,25,184,242,255,255,23,169,179,91,56,8,32,128,82,8,1,9,107,169,131,95,248,40,33,0,57,31,32,3,213,0,179,2,16,224,23,0,249,225,3,31,42,130,5,128,82,249,219,255,151,224,23,64,249,1,0,0,176,33,72,30,145,130,0,128,82,219,219,255,151,232,67,64,249,233,23,64,249,42,0,128,82,42,33,0,57,10,5,128,82,42,5,0,185,40,37,0,185,8,0,0,208,8,125,69,249,104,14,0,180,1,0,0,20,8,0,0,208,8,125,69,249,8,1,64,57,8,65,3,113,129,2,0,84,1,0,0,20,8,0,0,208,8,125,69,249,8,5,64,57,8,53,0,113,193,1,0,84,1,0,0,20,8,0,0,208,8,125,69,249,8,9,64,57,8,249,3,113,1,1,0,84,1,0,0,20,8,0,0,208,8,125,69,249,8,13,64,57,8,181,3,113,192,4,0,84,1,0,0,20,8,0,0,208,8,125,69,249,8,1,64,57,8,17,1,113,1,1,0,84,1,0,0,20,8,0,0,208,8,125,69,249,8,5,64,57,8,77,1,113,192,1,0,84,1,0,0,20,8,0,0,208,8,125,69,249,8,1,64,57,8,29,1,113,33,9,0,84,1,0,0,20,8,0,0,208,8,125,69,249,8,5,64,57,8,85,1,113,97,8,0,84,1,0,0,20,8,0,0,208,8,125,69,249,8,9,64,57,8,17,1,113,161,7,0,84,1,0,0,20,8,0,0,208,8,125,69,249,8,13,64,57,8,81,1,113,225,6,0,84,1,0,0,20,168,131,88,248,31,32,3,213,169,168,2,16,42,5,64,185,74,17,0,145,42,5,0,185,40,41,0,185,31,32,3,213,224,171,2,16,224,19,0,249,225,3,31,42,130,18,128,82,226,31,0,185,159,219,255,151,224,19,64,249,1,0,0,176,33,252,37,145,130,0,128,82,129,219,255,151,232,31,64,185,233,19,64,249,42,0,128,82,42,33,0,57,40,5,0,185,8,0,0,208,8,125,69,249,40,41,0,185,191,179,27,56,191,67,25,184,1,0,0,20,168,67,89,184,8,81,2,113,202,1,0,84,1,0,0,20,169,67,153,184,31,32,3,213,104,168,2,16,9,105,105,56,168,179,91,56,8,1,9,11,168,179,27,56,1,0,0,20,168,67,89,184,8,5,0,17,168,67,25,184,241,255,255,23,169,179,91,56,8,32,128,82,8,1,9,107,31,32,3,213,169,166,2,16,40,37,0,57,1,0,0,20,191,179,27,56,191,67,25,184,1,0,0,20,168,67,89,184,8,177,0,113,202,1,0,84,1,0,0,20,169,67,153,184,31,32,3,213,40,161,2,16,9,105,105,56,168,179,91,56,8,1,9,11,168,179,27,56,1,0,0,20,168,67,89,184,8,5,0,17,168,67,25,184,241,255,255,23,169,179,91,56,8,32,128,82,8,1,9,107,31,32,3,213,105,159,2,16,40,37,0,57,31,32,3,213,128,160,2,16,224,11,0,249,225,3,31,42,130,9,128,82,89,219,255,151,224,11,64,249,1,0,0,176,33,204,38,145,130,0,128,82,59,219,255,151,233,11,64,249,40,0,128,82,40,33,0,57,168,3,89,184,8,5,0,17,10,113,29,83,232,3,10,42,8,125,64,147,8,145,0,145,40,5,0,185,191,67,25,184,1,0,0,20,168,67,89,184,169,3,89,184,8,1,9,107,202,4,0,84,1,0,0,20,170,67,153,184,31,32,3,213,232,156,2,16,9,177,0,145,232,3,9,170,8,13,10,139,31,1,0,57,170,67,153,184,232,3,9,170,10,13,10,139,8,1,128,82,72,5,0,57,168,67,89,184,171,67,153,184,234,3,9,170,74,13,11,139,72,9,0,57,168,67,89,184,8,113,29,83,8,97,3,17,171,67,153,184,234,3,9,170,74,13,11,139,72,13,0,57,170,67,89,184,72,0,128,82,74,1,0,113,8,21,159,26,170,67,153,184,41,13,10,139,40,5,0,185,1,0,0,20,168,67,89,184,8,5,0,17,168,67,25,184,216,255,255,23,191,179,27,56,191,67,25,184,1,0,0,20,168,67,89,184,31,32,3,213,9,152,2,16,41,5,64,185,8,1,9,107,202,1,0,84,1,0,0,20,169,67,153,184,31,32,3,213,40,151,2,16,9,105,105,56,168,179,91,56,8,1,9,11,168,179,27,56,1,0,0,20,168,67,89,184,8,5,0,17,168,67,25,184,238,255,255,23,169,179,91,56,8,32,128,82,8,1,9,107,31,32,3,213,105,149,2,16,40,37,0,57,41,0,0,144,40,229,68,249,8,5,64,185,8,29,0,17,10,113,29,18,40,229,68,249,234,3,10,42,8,1,10,139,40,229,4,249,40,0,0,144,8,193,102,57,104,3,0,52,1,0,0,20,41,0,0,144,233,7,0,249,42,229,68,249,40,32,128,82,72,1,0,185,42,229,68,249,136,2,128,82,72,5,0,185,168,3,89,184,42,229,68,249,72,9,0,185,168,3,89,184,42,229,68,249,72,13,0,185,40,229,68,249,31,17,0,185,40,229,68,249,8,5,64,185,8,29,0,17,10,113,29,18,40,229,68,249,234,3,10,42,8,1,10,139,40,229,4,249,1,0,0,20,40,0,0,144,232,3,0,249,10,229,68,249,73,32,128,82,73,1,0,185,10,229,68,249,9,3,128,82,73,5,0,185,8,229,68,249,0,33,0,145,31,32,3,213,193,38,1,16,2,2,128,82,182,218,255,151,232,3,64,249,9,229,68,249,41,5,64,185,41,29,0,17,42,113,29,18,9,229,68,249,234,3,10,42,41,1,10,139,9,229,4,249,9,229,68,249,63,1,0,185,10,229,68,249,9,1,128,82,73,5,0,185,9,229,68,249,41,5,64,185,41,29,0,17,42,113,29,18,9,229,68,249,234,3,10,42,41,1,10,139,9,229,4,249,8,229,68,249,41,0,0,144,42,209,68,249,8,1,10,235,41,209,68,249,40,1,0,185,4,0,0,20,40,0,0,144,31,209,4,249,1,0,0,20,232,159,128,210,136,8,160,242,168,3,31,248,168,3,95,248,8,162,24,213,168,3,95,248,9,163,128,210,40,1,0,249,8,7,56,213,168,3,31,248,168,3,95,248,8,13,64,146,8,125,96,211,168,3,31,248,40,163,134,210,40,163,182,242,168,3,31,248,168,3,95,248,72,32,24,213,223,63,3,213,168,3,95,248,9,164,128,210,40,1,0,249,8,0,0,208,9,113,69,249,41,5,0,145,9,32,24,213,9,113,69,249,41,5,0,145,10,165,128,210,73,1,0,249,9,113,69,249,42,0,130,210,41,1,10,139,41,32,24,213,8,113,69,249,41,0,130,210,8,1,9,139,9,166,128,210,40,1,0,249,159,59,3,213,223,63,3,213,8,16,56,213,168,3,31,248,168,3,95,248,41,0,129,210,9,24,160,242,8,1,9,170,168,3,31,248,168,3,95,248,201,3,130,146,233,158,191,242,8,1,9,138,168,3,31,248,168,3,95,248,8,16,24,213,223,63,3,213,168,3,95,248,9,161,128,210,40,1,0,249,40,0,0,144,8,193,102,57,104,13,0,52,1,0,0,20,40,0,0,144,8,181,73,185,232,0,0,52,1,0,0,20,161,3,89,184,0,0,0,176,0,8,37,145,149,227,255,151,1,0,0,20,40,0,0,144,8,209,68,249,9,168,128,210,40,1,0,249,8,167,128,210,31,1,0,249,168,3,89,184,8,5,0,113,226,3,8,42,225,3,30,170,1,0,0,148,224,3,30,170,254,3,1,170,0,144,0,145,1,28,128,210,32,4,0,248,33,32,0,145,66,4,0,81,162,255,255,53,76,0,0,20,1,0,130,210,64,66,56,213,0,4,126,146,31,48,0,241,65,1,0,84,32,182,128,210,0,17,30,213,32,121,128,210,0,64,30,213,160,0,0,16,32,64,30,213,128,0,128,210,1,65,30,213,224,3,159,214,31,16,0,241,128,3,0,84,0,225,60,213,0,4,64,178,0,225,28,213,63,226,28,213,0,0,176,210,0,0,127,178,0,17,28,213,0,17,60,213,0,0,56,213,162,0,56,213,0,0,28,213,162,0,28,213,224,127,134,210,64,17,28,213,127,17,28,213,0,6,160,210,64,16,24,213,2,0,129,210,2,26,166,242,2,16,24,213,162,120,128,210,2,64,28,213,162,0,0,16,34,64,28,213,63,0,0,145,1,65,28,213,224,3,159,214,63,0,0,145,2,160,128,210,64,4,65,248,0,192,24,213,191,64,0,213,94,132,67,248,31,32,3,213,31,32,3,213,31,32,3,213,31,32,3,213,126,255,255,180,64,132,65,248,0,162,24,213,64,4,66,248,64,32,24,213,64,132,66,248,0,32,24,213,64,4,67,248,32,32,24,213,64,132,64,248,159,59,3,213,0,16,24,213,223,63,3,213,255,3,109,178,160,0,56,213,0,4,64,146,1,212,118,211,255,99,33,203,224,15,31,248,192,74,0,88,65,4,68,248,192,3,95,214,1,0,0,20,8,171,128,210,31,1,0,249,252,139,64,249,253,123,80,169,255,131,4,145,192,3,95,214,255,195,2,209,253,123,10,169,253,131,2,145,160,243,31,56,161,3,31,248,162,131,30,248,163,3,30,248,164,131,29,248,165,3,29,248,166,131,28,248,40,0,0,176,8,17,108,57,8,29,0,53,1,0,0,20,41,0,0,176,40,17,108,57,8,5,0,17,40,17,44,57,168,0,56,213,8,5,64,146,104,0,0,180,95,32,3,213,255,255,255,23,8,0,0,208,8,113,69,249,8,5,0,145,8,32,24,213,31,135,8,213,159,59,3,213,223,63,3,213,8,16,56,213,168,3,28,248,168,3,92,248,137,0,130,146,8,1,9,138,168,3,28,248,168,3,92,248,8,16,24,213,223,63,3,213,31,32,3,213,200,241,0,16,8,5,64,249,168,20,0,180,1,0,0,20,31,32,3,213,40,241,0,16,9,113,64,57,41,29,0,17,41,125,3,19,233,55,0,185,10,0,0,208,137,0,128,82,73,137,10,185,10,0,0,208,73,141,10,185,8,133,64,57,8,33,0,113,77,1,0,84,1,0,0,20,31,32,3,213,72,239,0,16,8,133,64,57,9,33,0,113,232,31,128,82,8,33,201,26,232,51,0,185,10,0,0,20,31,32,3,213,72,238,0,16,9,133,64,57,8,1,128,82,9,1,9,107,232,31,128,82,8,41,201,26,232,51,0,185,1,0,0,20,233,51,64,185,31,32,3,213,8,237,0,16,10,129,64,57,41,33,202,26,233,47,0,185,8,141,64,57,8,33,0,113,77,1,0,84,1,0,0,20,31,32,3,213,232,235,0,16,8,141,64,57,9,33,0,113,232,3,31,42,8,33,201,26,232,43,0,185,10,0,0,20,31,32,3,213,232,234,0,16,9,141,64,57,8,1,128,82,9,1,9,107,232,3,31,42,8,41,201,26,232,43,0,185,1,0,0,20,233,47,64,185,234,43,64,185,31,32,3,213,136,233,0,16,11,137,64,57,74,33,203,26,41,1,10,42,233,39,0,185,8,149,64,57,8,33,0,113,77,1,0,84,1,0,0,20,31,32,3,213,72,232,0,16,8,149,64,57,9,33,0,113,232,3,31,42,8,33,201,26,232,35,0,185,10,0,0,20,31,32,3,213,72,231,0,16,9,149,64,57,8,1,128,82,9,1,9,107,232,3,31,42,8,41,201,26,232,35,0,185,1,0,0,20,232,39,64,185,233,35,64,185,31,32,3,213,234,229,0,16,74,145,64,57,41,33,202,26,8,1,9,42,9,0,0,208,40,145,10,185,255,59,0,185,255,67,0,185,1,0,0,20,232,59,64,185,31,32,3,213,105,118,0,16,41,25,64,185,41,121,31,83,41,33,0,17,8,1,9,107,226,6,0,84,1,0,0,20,232,67,64,185,232,71,0,185,255,63,0,185,1,0,0,20,232,63,64,185,31,32,3,213,233,226,0,16,41,21,64,185,8,1,9,107,34,4,0,84,1,0,0,20,232,55,64,185,8,9,0,113,97,1,0,84,1,0,0,20,8,0,0,208,8,145,74,185,31,32,3,213,105,225,0,16,41,5,64,249,234,71,64,185,41,1,10,139,40,1,0,121,10,0,0,20,8,0,0,208,8,145,74,185,31,32,3,213,73,224,0,16,41,5,64,249,234,71,64,185,41,1,10,139,40,1,0,185,1,0,0,20,1,0,0,20,232,63,64,185,8,5,0,17,232,63,0,185,233,55,64,185,232,71,64,185,8,1,9,11,232,71,0,185,219,255,255,23,1,0,0,20,232,59,64,185,8,5,0,17,232,59,0,185,31,32,3,213,200,221,0,16,9,17,64,185,232,67,64,185,8,1,9,11,232,67,0,185,195,255,255,23,1,0,0,20,161,243,95,56,0,0,0,176,0,72,48,145,91,226,255,151,8,0,0,208,31,145,10,185,11,65,56,213,234,3,0,145,9,32,56,213,40,32,56,213,171,3,28,248,170,131,27,248,233,43,0,249,232,39,0,249,161,3,95,248,162,131,94,248,163,3,94,248,164,131,93,248,165,3,93,248,166,131,92,248,167,3,92,248,171,131,91,248,234,43,64,249,232,39,64,249,233,3,0,145,43,1,0,249,42,5,0,249,40,9,0,249,0,0,0,176,0,168,43,145,64,226,255,151,161,131,94,248,162,3,92,248,0,0,0,176,0,92,30,145,59,226,255,151,1,0,0,20,95,32,3,213,255,255,255,23,253,123,74,169,255,195,2,145,192,3,95,214,255,131,0,209,253,123,1,169,253,67,0,145,9,0,0,176,40,81,69,185,224,3,8,42,8,0,0,176,8,85,69,185,41,81,69,185,2,1,9,107,225,3,31,42,251,216,255,151,34,234,255,151,0,0,0,176,0,228,45,145,37,226,255,151,1,235,255,151,1,0,0,20,15,242,255,151,235,244,255,151,40,0,0,144,8,233,68,249,200,0,0,181,1,0,0,20,0,0,0,176,0,16,38,145,26,226,255,151,140,0,0,20,40,0,0,144,8,181,73,185,8,2,0,52,1,0,0,20,40,0,0,144,8,149,73,185,136,1,0,53,1,0,0,20,40,0,0,144,8,233,68,249,9,128,128,210,8,9,201,154,8,9,201,154,1,9,0,145,0,0,0,144,0,136,37,145,8,226,255,151,1,0,0,20,1,0,0,20,110,248,255,151,96,0,0,53,1,0,0,20,117,0,0,20,183,245,255,151,8,0,0,240,8,149,73,185,168,1,0,53,1,0,0,20,8,0,0,240,8,145,73,185,40,1,0,52,1,0,0,20,9,0,0,240,40,149,73,185,8,5,0,17,40,149,9,185,8,0,0,240,31,145,9,185,208,255,255,23,176,249,255,151,40,0,0,144,8,245,68,249,200,0,0,181,1,0,0,20,0,0,0,144,0,28,39,145,234,225,255,151,92,0,0,20,8,0,0,240,8,181,73,185,8,9,0,113,9,1,0,84,1,0,0,20,40,0,0,144,1,245,68,249,0,0,0,144,0,152,39,145,223,225,255,151,1,0,0,20,40,0,0,144,8,129,103,57,168,195,31,184,8,17,0,113,192,0,0,84,1,0,0,20,168,195,95,184,8,21,0,113,32,6,0,84,67,0,0,20,8,0,0,240,8,181,73,185,8,5,0,113,9,2,0,84,1,0,0,20,40,0,0,144,1,245,68,249,9,0,0,240,35,209,68,249,8,0,0,240,8,229,68,249,41,209,68,249,4,1,9,235,0,0,0,144,0,180,26,145,34,81,140,82,226,218,166,114,194,225,255,151,1,0,0,20,8,0,0,240,8,193,102,57,8,2,0,52,1,0,0,20,40,0,0,144,9,245,68,249,10,167,128,210,73,1,0,249,159,59,3,213,8,245,68,249,224,26,0,88,1,4,64,248,96,26,0,88,255,3,109,178,255,15,31,248,254,3,8,170,192,3,95,214,10,0,0,20,40,0,0,144,8,245,68,249,160,25,0,88,1,4,64,248,32,25,0,88,255,3,109,178,254,3,8,170,192,3,95,214,1,0,0,20,20,0,0,20,8,0,0,240,8,181,73,185,8,5,0,113,201,0,0,84,1,0,0,20,0,0,0,144,0,228,39,145,157,225,255,151,1,0,0,20,8,0,0,176,8,125,69,249,224,3,8,170,225,3,31,170,226,3,31,170,227,3,31,170,30,1,160,210,223,3,0,145,192,3,95,214,1,0,0,20,0,0,0,144,0,120,41,145,143,225,255,151,1,0,0,20,8,0,0,240,8,149,73,185,168,0,0,52,1,0,0,20,95,32,3,213,255,255,255,23,16,0,0,20,1,0,0,20,8,0,0,176,8,217,68,249,9,3,130,210,9,4,160,242,8,1,9,139,8,1,64,185,232,0,32,55,1,0,0,20,9,0,0,240,40,149,73,185,8,5,0,17,40,149,9,185,87,255,255,23,243,255,255,23,253,123,65,169,255,131,0,145,192,3,95,214,255,3,1,209,224,31,0,249,225,27,0,249,226,47,0,185,255,11,0,185,1,0,0,20,232,11,64,185,8,65,0,113,98,1,0,84,1,0,0,20,232,31,64,249,233,11,64,185,8,5,9,139,31,1,0,121,1,0,0,20,232,11,64,185,8,5,0,17,232,11,0,185,244,255,255,23,255,11,0,185,1,0,0,20,232,11,64,185,233,47,64,185,8,1,9,107,34,2,0,84,1,0,0,20,233,31,64,249,232,27,64,249,234,11,64,185,8,105,106,56,234,3,8,42,232,3,9,170,8,5,10,139,8,1,64,121,8,5,0,17,40,121,42,120,1,0,0,20,232,11,64,185,8,5,0,17,232,11,0,185,237,255,255,23,232,31,64,249,31,1,0,121,255,7,0,185,255,11,0,185,1,0,0,20,232,11,64,185,8,65,0,113,66,2,0,84,1,0,0,20,232,7,64,185,233,11,64,185,234,3,9,42,233,51,0,145,40,121,42,120,232,31,64,249,233,11,64,185,9,121,105,120,232,7,64,185,8,1,9,11,232,7,0,185,1,0,0,20,232,11,64,185,8,5,0,17,232,11,0,185,237,255,255,23,255,11,0,185,1,0,0,20,232,11,64,185,233,47,64,185,8,1,9,107,98,3,0,84,1,0,0,20,232,27,64,249,233,11,64,185,8,1,9,139,8,1,64,57,8,2,0,52,1,0,0,20,232,11,64,185,233,31,64,249,41,129,0,145,234,27,64,249,235,11,64,185,74,105,107,56,237,3,10,42,236,51,0,145,138,121,109,120,235,3,10,42,107,5,0,17,139,121,45,120,40,121,42,120,1,0,0,20,1,0,0,20,232,11,64,185,8,5,0,17,232,11,0,185,227,255,255,23,255,3,1,145,192,3,95,214,255,195,0,209,253,123,2,169,253,131,0,145,160,131,31,248,225,11,0,249,255,15,0,185,255,11,0,185,255,7,0,185,1,0,0,20,233,11,64,185,72,0,128,82,8,125,9,27,232,3,0,185,160,131,95,248,223,217,255,151,232,3,64,185,8,1,0,11,232,11,0,185,232,7,64,185,8,5,0,17,232,7,0,185,232,11,64,249,233,7,128,185,9,121,105,120,232,15,64,185,8,1,9,11,232,15,0,185,232,11,64,249,233,7,128,185,9,121,105,120,232,11,64,185,8,1,9,107,232,11,0,185,1,0,0,20,232,11,64,185,200,252,255,54,1,0,0,20,232,11,64,249,8,129,0,145,233,15,64,185,234,11,64,185,41,1,10,11,0,217,105,120,253,123,66,169,255,195,0,145,192,3,95,214,0,0,0,0,137,98,215,54,0,0,0,0,160,217,8,0,0,0,0,0,0,0,0,0,0,0,0,0,107,101,114,110,101,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,188,180,8,0,0,240,8,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,13,0,15,0,17,0,19,0,23,0,27,0,31,0,35,0,43,0,51,0,59,0,67,0,83,0,99,0,115,0,131,0,163,0,195,0,227,0,2,1,0,0,0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,1,0,2,0,3,0,4,0,5,0,7,0,9,0,13,0,17,0,25,0,33,0,49,0,65,0,97,0,129,0,193,0,1,1,129,1,1,2,1,3,1,4,1,6,1,8,1,12,1,16,1,24,1,32,1,48,1,64,1,96,16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15,0,0,0,1,99,104,111,115,101,110,0,0,0,0,0,3,0,0,0,0,2,0,69,77,77,67,58,32,116,105,109,101,111,117,116,32,119,97,105,116,105,110,103,32,102,111,114,32,105,110,104,105,98,105,116,32,102,108,97,103,13,10,0,76,111,97,100,105,110,103,32,109,111,100,117,108,101,32,39,37,83,39,32,40,37,108,100,32,98,121,116,101,115,41,46,46,46,13,10,0,76,111,97,100,105,110,103,32,77,117,108,116,105,98,111,111,116,50,32,69,76,70,54,52,32,107,101,114,110,101,108,32,39,37,83,39,46,46,46,13,10,0,84,114,97,110,115,102,101,114,105,110,103,32,99,111,110,116,114,111,108,32,116,111,32,37,48,56,120,40,37,48,56,120,44,32,37,48,56,120,91,37,120,93,41,13,10,0,83,105,109,112,108,101,98,111,111,116,0,77,90,0,65,82,77,0,76,111,97,100,105,110,103,32,76,105,110,117,120,32,107,101,114,110,101,108,46,46,46,13,10,0,13,69,77,77,67,58,32,116,105,109,101,111,117,116,32,119,97,105,116,105,110,103,32,102,111,114,32,114,101,97,100,121,32,116,111,32,114,101,97,100,10,0,87,65,82,78,73,78,71,58,32,117,110,97,98,108,101,32,116,111,32,108,111,97,100,32,39,37,83,39,13,10,0,37,68,13,10,0,76,111,97,100,105,110,103,32,108,111,103,111,32,39,37,83,39,32,40,37,108,100,32,98,121,116,101,115,41,46,46,46,13,10,0,101,97,115,121,98,111,111,116,47,109,101,110,117,46,99,102,103,0,118,101,114,98,111,115,101,0,82,83,68,84,0,67,111,100,101,13,10,37,68,13,10,83,116,97,99,107,13,10,37,52,68,13,10,0,69,77,77,67,58,32,102,97,105,108,101,100,32,116,111,32,115,101,110,100,32,83,68,32,65,80,80,32,99,111,109,109,97,110,100,13,10,0,98,111,111,116,0,109,101,110,117,101,110,116,114,121,0,32,40,98,97,99,107,117,112,41,0,114,112,105,47,99,111,114,101,0,69,70,73,32,80,65,82,84,0,109,117,108,116,105,99,111,114,101,0,68,84,66,32,100,101,116,101,99,116,101,100,46,46,46,13,10,0,82,83,68,32,80,84,82,32,0,69,82,82,79,82,58,32,117,110,97,98,108,101,32,116,111,32,108,111,97,100,32,115,101,103,109,101,110,116,32,37,48,56,108,120,91,37,120,93,44,32,109,101,109,111,114,121,32,97,108,114,101,97,100,121,32,105,110,32,117,115,101,13,10,0,69,82,82,79,82,58,32,117,110,107,110,111,119,110,32,107,101,114,110,101,108,32,102,111,114,109,97,116,32,39,37,83,39,13,10,0,107,101,114,110,101,108,0,37,99,37,99,68,84,32,100,101,116,101,99,116,101,100,46,46,46,10,0,69,77,77,67,58,32,102,97,105,108,101,100,32,116,111,32,114,101,115,101,116,32,69,77,77,67,13,10,0,76,111,97,100,105,110,103,32,77,117,108,116,105,98,111,111,116,50,32,80,69,54,52,32,107,101,114,110,101,108,32,39,37,83,39,46,46,46,13,10,0,69,77,77,67,58,32,98,117,115,121,44,32,116,105,109,101,100,32,111,117,116,13,10,0,114,112,105,47,105,110,105,116,114,100,46,98,97,107,0,69,77,77,67,58,32,102,97,105,108,101,100,32,116,111,32,115,101,110,100,32,99,111,109,109,97,110,100,13,10,0,98,97,99,107,117,112,0,98,111,111,116,115,112,108,97,115,104,0,73,110,105,116,105,97,108,105,122,105,110,103,32,83,77,80,32,40,37,100,32,99,111,114,101,115,41,46,46,46,10,0,80,104,121,115,105,99,97,108,32,82,65,77,32,37,108,100,32,77,101,103,97,98,121,116,101,115,13,10,0,70,65,67,80,0,69,82,82,79,82,58,32,117,110,97,98,108,101,32,116,111,32,100,101,116,101,114,109,105,110,101,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,82,65,77,13,10,0,65,80,73,67,0,115,105,109,112,108,101,98,111,111,116,46,99,102,103,0,69,82,82,79,82,58,32,110,111,32,107,101,114,110,101,108,32,101,110,116,114,121,32,112,111,105,110,116,13,10,0,75,101,114,110,101,108,32,101,110,116,114,121,58,13,10,37,52,68,0,84,114,97,110,115,102,101,114,105,110,103,32,99,111,110,116,114,111,108,32,116,111,32,56,48,48,48,48,13,10,0,69,77,77,67,58,32,102,97,105,108,101,100,32,116,111,32,103,101,116,32,115,116,97,98,108,101,32,99,108,111,99,107,13,10,0,69,77,77,67,58,32,83,68,72,67,73,32,118,101,114,115,105,111,110,32,116,111,111,32,111,108,100,13,10,0,80,65,82,84,0,69,82,82,79,82,58,32,107,101,114,110,101,108,32,115,104,111,117,108,100,32,110,111,116,32,104,97,118,101,32,114,101,116,117,114,110,101,100,13,10,0,69,82,82,79,82,58,32,107,101,114,110,101,108,32,39,37,83,39,32,110,111,116,32,102,111,117,110,100,13,10,0,85,110,99,111,109,112,114,101,115,115,105,110,103,32,109,111,100,117,108,101,32,39,37,83,39,32,40,37,100,32,98,121,116,101,115,41,46,46,46,13,10,0,69,82,82,79,82,58,32,107,101,114,110,101,108,32,110,111,116,32,102,111,117,110,100,13,10,0,32,32,69,83,82,32,37,48,49,54,120,32,32,32,69,76,82,32,37,48,49,54,120,10,32,83,80,83,82,32,37,48,49,54,120,32,32,32,70,65,82,32,37,48,49,54,120,10,83,67,84,76,82,32,37,48,49,54,120,32,32,32,84,67,82,32,37,48,49,54,120,10,32,32,83,80,48,32,37,48,49,54,120,32,32,32,83,80,49,32,37,48,49,54,120,10,84,84,66,82,48,32,37,48,49,54,120,32,84,84,66,82,49,32,37,48,49,54,120,10,10,0,127,69,76,70,0,99,104,111,115,101,110,0,98,111,111,116,97,114,103,115,0,83,105,109,112,108,101,98,111,111,116,32,108,111,97,100,101,114,44,32,67,111,112,121,114,105,103,104,116,32,40,99,41,32,50,48,50,51,32,98,122,116,44,32,77,73,84,32,108,105,99,101,110,115,101,13,10,0,69,77,77,67,58,32,69,77,77,67,32,65,67,77,68,52,49,32,114,101,116,117,114,110,101,100,32,101,114,114,111,114,13,10,0,65,98,111,114,116,101,100,44,32,108,111,97,100,105,110,103,32,98,97,99,107,117,112,32,99,111,110,102,105,103,117,114,97,116,105,111,110,46,46,46,13,10,0,109,111,100,117,108,101,0,114,112,105,47,105,110,105,116,114,100,0,83,105,109,112,108,101,98,111,111,116,32,69,120,99,101,112,116,105,111,110,32,72,97,110,100,108,101,114,13,10,69,120,99,101,112,116,105,111,110,32,35,37,48,50,120,13,10,13,10,0,32,32,115,101,103,109,101,110,116,32,37,48,56,120,91,37,48,56,120,93,32,45,62,32,37,48,56,120,91,37,48,56,120,93,13,10,0,40,110,117,108,108,41,0,102,114,97,109,101,98,117,102,102,101,114,0,40,0,110,0,117,0,108,0,108,0,41,0,0,0,0,0,40,115,42,193,31,248,210,17,186,75,0,160,201,62,201,59,114,181,74,134,0,0,0,0,32,0,0,0,0,0,12,0,128,0,0,0,16,0,0,0,16,0,0,0,8,0,0,0,0,0,218,2,128,130,2,128,130,2,128,182,0,0,0,0,0,0,126,129,165,129,129,189,153,129,129,126,0,0,0,0,0,0,126,255,219,255,255,195,231,255,255,126,0,0,0,0,0,0,0,0,108,254,254,254,254,124,56,16,0,0,0,0,0,0,0,0,16,56,124,254,124,56,16,0,0,0,0,0,0,0,0,24,60,60,231,231,231,24,24,60,0,0,0,0,0,0,0,24,60,126,255,255,126,24,24,60,0,0,0,0,0,0,0,0,0,0,24,60,60,24,0,0,0,0,0,0,255,255,255,255,255,255,231,195,195,231,255,255,255,255,255,255,0,0,0,0,0,60,102,66,66,102,60,0,0,0,0,0,255,255,255,255,255,195,153,189,189,153,195,255,255,255,255,255,0,0,30,14,26,50,120,204,204,204,204,120,0,0,0,0,0,0,60,102,102,102,102,60,24,126,24,24,0,0,0,0,0,0,63,51,63,48,48,48,48,112,240,224,0,0,0,0,0,0,127,99,127,99,99,99,99,103,231,230,192,0,0,0,0,0,0,24,24,219,60,231,60,219,24,24,0,0,0,0,0,128,192,224,240,248,254,248,240,224,192,128,0,0,0,0,0,2,6,14,30,62,254,62,30,14,6,2,0,0,0,0,0,0,24,60,126,24,24,24,126,60,24,0,0,0,0,0,0,0,102,102,102,102,102,102,102,0,102,102,0,0,0,0,0,0,127,219,219,219,123,27,27,27,27,27,0,0,0,0,0,124,198,96,56,108,198,198,108,56,12,198,124,0,0,0,0,0,0,0,0,0,0,0,254,254,254,254,0,0,0,0,0,0,24,60,126,24,24,24,126,60,24,126,0,0,0,0,0,0,24,60,126,24,24,24,24,24,24,24,0,0,0,0,0,0,24,24,24,24,24,24,24,126,60,24,0,0,0,0,0,0,0,0,0,24,12,254,12,24,0,0,0,0,0,0,0,0,0,0,0,48,96,254,96,48,0,0,0,0,0,0,0,0,0,0,0,0,192,192,192,254,0,0,0,0,0,0,0,0,0,0,0,40,108,254,108,40,0,0,0,0,0,0,0,0,0,0,16,56,56,124,124,254,254,0,0,0,0,0,0,0,0,0,254,254,124,124,56,56,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,60,60,60,24,24,24,0,24,24,0,0,0,0,0,102,102,102,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,108,108,254,108,108,108,254,108,108,0,0,0,0,24,24,124,198,194,192,124,6,6,134,198,124,24,24,0,0,0,0,0,0,194,198,12,24,48,96,198,134,0,0,0,0,0,0,56,108,108,56,118,220,204,204,204,118,0,0,0,0,0,48,48,48,32,0,0,0,0,0,0,0,0,0,0,0,0,0,12,24,48,48,48,48,48,48,24,12,0,0,0,0,0,0,48,24,12,12,12,12,12,12,24,48,0,0,0,0,0,0,0,0,0,102,60,255,60,102,0,0,0,0,0,0,0,0,0,0,0,24,24,126,24,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,24,24,48,0,0,0,0,0,0,0,0,0,0,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,24,0,0,0,0,0,0,0,0,2,6,12,24,48,96,192,128,0,0,0,0,0,0,56,108,198,198,214,214,198,198,108,56,0,0,0,0,0,0,24,56,120,24,24,24,24,24,24,126,0,0,0,0,0,0,124,198,6,12,24,48,96,192,198,254,0,0,0,0,0,0,124,198,6,6,60,6,6,6,198,124,0,0,0,0,0,0,12,28,60,108,204,254,12,12,12,30,0,0,0,0,0,0,254,192,192,192,252,6,6,6,198,124,0,0,0,0,0,0,56,96,192,192,252,198,198,198,198,124,0,0,0,0,0,0,254,198,6,6,12,24,48,48,48,48,0,0,0,0,0,0,124,198,198,198,124,198,198,198,198,124,0,0,0,0,0,0,124,198,198,198,126,6,6,6,12,120,0,0,0,0,0,0,0,0,24,24,0,0,0,24,24,0,0,0,0,0,0,0,0,0,24,24,0,0,0,24,24,48,0,0,0,0,0,0,0,6,12,24,48,96,48,24,12,6,0,0,0,0,0,0,0,0,0,126,0,0,126,0,0,0,0,0,0,0,0,0,0,96,48,24,12,6,12,24,48,96,0,0,0,0,0,0,124,198,198,12,24,24,24,0,24,24,0,0,0,0,0,0,0,124,198,198,222,222,222,220,192,124,0,0,0,0,0,0,16,56,108,198,198,254,198,198,198,198,0,0,0,0,0,0,252,102,102,102,124,102,102,102,102,252,0,0,0,0,0,0,60,102,194,192,192,192,192,194,102,60,0,0,0,0,0,0,248,108,102,102,102,102,102,102,108,248,0,0,0,0,0,0,254,102,98,104,120,104,96,98,102,254,0,0,0,0,0,0,254,102,98,104,120,104,96,96,96,240,0,0,0,0,0,0,60,102,194,192,192,222,198,198,102,58,0,0,0,0,0,0,198,198,198,198,254,198,198,198,198,198,0,0,0,0,0,0,60,24,24,24,24,24,24,24,24,60,0,0,0,0,0,0,30,12,12,12,12,12,204,204,204,120,0,0,0,0,0,0,230,102,102,108,120,120,108,102,102,230,0,0,0,0,0,0,240,96,96,96,96,96,96,98,102,254,0,0,0,0,0,0,198,238,254,254,214,198,198,198,198,198,0,0,0,0,0,0,198,230,246,254,222,206,198,198,198,198,0,0,0,0,0,0,124,198,198,198,198,198,198,198,198,124,0,0,0,0,0,0,252,102,102,102,124,96,96,96,96,240,0,0,0,0,0,0,124,198,198,198,198,198,198,214,222,124,12,14,0,0,0,0,252,102,102,102,124,108,102,102,102,230,0,0,0,0,0,0,124,198,198,96,56,12,6,198,198,124,0,0,0,0,0,0,126,126,90,24,24,24,24,24,24,60,0,0,0,0,0,0,198,198,198,198,198,198,198,198,198,124,0,0,0,0,0,0,198,198,198,198,198,198,198,108,56,16,0,0,0,0,0,0,198,198,198,198,214,214,214,254,238,108,0,0,0,0,0,0,198,198,108,124,56,56,124,108,198,198,0,0,0,0,0,0,102,102,102,102,60,24,24,24,24,60,0,0,0,0,0,0,254,198,134,12,24,48,96,194,198,254,0,0,0,0,0,0,60,48,48,48,48,48,48,48,48,60,0,0,0,0,0,0,0,128,192,224,112,56,28,14,6,2,0,0,0,0,0,0,60,12,12,12,12,12,12,12,12,60,0,0,0,0,16,56,108,198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,48,48,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,120,12,124,204,204,204,118,0,0,0,0,0,0,224,96,96,120,108,102,102,102,102,124,0,0,0,0,0,0,0,0,0,124,198,192,192,192,198,124,0,0,0,0,0,0,28,12,12,60,108,204,204,204,204,118,0,0,0,0,0,0,0,0,0,124,198,254,192,192,198,124,0,0,0,0,0,0,56,108,100,96,240,96,96,96,96,240,0,0,0,0,0,0,0,0,0,118,204,204,204,204,204,124,12,204,120,0,0,0,224,96,96,108,118,102,102,102,102,230,0,0,0,0,0,0,24,24,0,56,24,24,24,24,24,60,0,0,0,0,0,0,6,6,0,14,6,6,6,6,6,6,102,102,60,0,0,0,224,96,96,102,108,120,120,108,102,230,0,0,0,0,0,0,56,24,24,24,24,24,24,24,24,60,0,0,0,0,0,0,0,0,0,236,254,214,214,214,214,198,0,0,0,0,0,0,0,0,0,220,102,102,102,102,102,102,0,0,0,0,0,0,0,0,0,124,198,198,198,198,198,124,0,0,0,0,0,0,0,0,0,220,102,102,102,102,102,124,96,96,240,0,0,0,0,0,0,118,204,204,204,204,204,124,12,12,30,0,0,0,0,0,0,220,118,102,96,96,96,240,0,0,0,0,0,0,0,0,0,124,198,96,56,12,198,124,0,0,0,0,0,0,16,48,48,252,48,48,48,48,54,28,0,0,0,0,0,0,0,0,0,204,204,204,204,204,204,118,0,0,0,0,0,0,0,0,0,102,102,102,102,102,60,24,0,0,0,0,0,0,0,0,0,198,198,214,214,214,254,108,0,0,0,0,0,0,0,0,0,198,108,56,56,56,108,198,0,0,0,0,0,0,0,0,0,198,198,198,198,198,198,126,6,12,248,0,0,0,0,0,0,254,204,24,48,96,198,254,0,0,0,0,0,0,14,24,24,24,112,24,24,24,24,14,0,0,0,0,0,0,24,24,24,24,24,24,24,24,24,24,24,24,0,0,0,0,112,24,24,24,14,24,24,24,24,112,0,0,0,0,0,0,118,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,56,108,198,198,198,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/inflate.h",
    "content": "/*\n * src/inflate.h\n * https://gitlab.com/bztsrc/simpleboot\n *\n * tinflate  -  tiny inflate\n *\n * Copyright (c) 2003 by Joergen Ibsen / Jibz\n * All Rights Reserved\n * http://www.ibsensoftware.com/\n *\n * Copyright (c) 2014-2016 by Paul Sokolovsky\n *\n * This software is provided 'as-is', without any express\n * or implied warranty.  In no event will the authors be\n * held liable for any damages arising from the use of\n * this software.\n *\n * Permission is granted to anyone to use this software\n * for any purpose, including commercial applications,\n * and to alter it and redistribute it freely, subject to\n * the following restrictions:\n *\n * 1. The origin of this software must not be\n *    misrepresented; you must not claim that you\n *    wrote the original software. If you use this\n *    software in a product, an acknowledgment in\n *    the product documentation would be appreciated\n *    but is not required.\n *\n * 2. Altered source versions must be plainly marked\n *    as such, and must not be misrepresented as\n *    being the original software.\n *\n * 3. This notice may not be removed or altered from\n *    any source distribution.\n */\n\n#define TINF_OK             0\n#define TINF_DONE           1\n#define TINF_DATA_ERROR    (-3)\n#define TINF_CHKSUM_ERROR  (-4)\n#define TINF_DICT_ERROR    (-5)\n#define TINF_CHKSUM_NONE  0\n#define TINF_CHKSUM_ADLER 1\n#define TINF_CHKSUM_CRC   2\n\ntypedef struct {\n   unsigned short table[16];  /* table of code length counts */\n   unsigned short trans[288]; /* code -> symbol translation table */\n} TINF_TREE;\n\nstruct TINF_DATA;\ntypedef struct TINF_DATA {\n   const unsigned char *source;\n\n   unsigned int tag;\n   unsigned int bitcount;\n\n    unsigned int destSize;\n    unsigned char *dest;\n\n    int btype;\n    int bfinal;\n    unsigned int curlen;\n    int lzOff;\n\n   TINF_TREE ltree; /* dynamic length/symbol tree */\n   TINF_TREE dtree; /* dynamic distance tree */\n} TINF_DATA;\nTINF_DATA d;\n\n#define TINF_PUT(d, c) \\\n    { \\\n        *d->dest++ = c; \\\n    }\n\n/* --------------------------------------------------- *\n * -- uninitialized global data (static structures) -- *\n * --------------------------------------------------- */\n\nconst unsigned char length_bits[30] = {\n   0, 0, 0, 0, 0, 0, 0, 0,\n   1, 1, 1, 1, 2, 2, 2, 2,\n   3, 3, 3, 3, 4, 4, 4, 4,\n   5, 5, 5, 5\n};\nconst unsigned short length_base[30] = {\n   3, 4, 5, 6, 7, 8, 9, 10,\n   11, 13, 15, 17, 19, 23, 27, 31,\n   35, 43, 51, 59, 67, 83, 99, 115,\n   131, 163, 195, 227, 258\n};\n\nconst unsigned char dist_bits[30] = {\n   0, 0, 0, 0, 1, 1, 2, 2,\n   3, 3, 4, 4, 5, 5, 6, 6,\n   7, 7, 8, 8, 9, 9, 10, 10,\n   11, 11, 12, 12, 13, 13\n};\nconst unsigned short dist_base[30] = {\n   1, 2, 3, 4, 5, 7, 9, 13,\n   17, 25, 33, 49, 65, 97, 129, 193,\n   257, 385, 513, 769, 1025, 1537, 2049, 3073,\n   4097, 6145, 8193, 12289, 16385, 24577\n};\n\n/* special ordering of code length codes */\nconst unsigned char clcidx[] = {\n   16, 17, 18, 0, 8, 7, 9, 6,\n   10, 5, 11, 4, 12, 3, 13, 2,\n   14, 1, 15\n};\n\n/* ----------------------- *\n * -- utility functions -- *\n * ----------------------- */\n\n/* build the fixed huffman trees */\nstatic void tinf_build_fixed_trees(TINF_TREE *lt, TINF_TREE *dt)\n{\n   int i;\n\n   /* build fixed length tree */\n   for (i = 0; i < 7; ++i) lt->table[i] = 0;\n\n   lt->table[7] = 24;\n   lt->table[8] = 152;\n   lt->table[9] = 112;\n\n   for (i = 0; i < 24; ++i) lt->trans[i] = 256 + i;\n   for (i = 0; i < 144; ++i) lt->trans[24 + i] = i;\n   for (i = 0; i < 8; ++i) lt->trans[24 + 144 + i] = 280 + i;\n   for (i = 0; i < 112; ++i) lt->trans[24 + 144 + 8 + i] = 144 + i;\n\n   /* build fixed distance tree */\n   for (i = 0; i < 5; ++i) dt->table[i] = 0;\n\n   dt->table[5] = 32;\n\n   for (i = 0; i < 32; ++i) dt->trans[i] = i;\n}\n\n/* given an array of code lengths, build a tree */\nstatic void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned int num)\n{\n   unsigned short offs[16];\n   unsigned int i, sum;\n\n   /* clear code length count table */\n   for (i = 0; i < 16; ++i) t->table[i] = 0;\n\n   /* scan symbol lengths, and sum code length counts */\n   for (i = 0; i < num; ++i) t->table[lengths[i]]++;\n\n   t->table[0] = 0;\n\n   /* compute offset table for distribution sort */\n   for (sum = 0, i = 0; i < 16; ++i)\n   {\n      offs[i] = sum;\n      sum += t->table[i];\n   }\n\n   /* create code->symbol translation table (symbols sorted by code) */\n   for (i = 0; i < num; ++i)\n   {\n      if (lengths[i]) t->trans[offs[lengths[i]]++] = i;\n   }\n}\n\n/* ---------------------- *\n * -- decode functions -- *\n * ---------------------- */\n\nunsigned char uzlib_get_byte(TINF_DATA *d)\n{\n   return *d->source++;\n}\n\n/* get one bit from source stream */\nstatic int tinf_getbit(TINF_DATA *d)\n{\n   unsigned int bit;\n\n   /* check if tag is empty */\n   if (!d->bitcount--)\n   {\n      /* load next tag */\n      d->tag = uzlib_get_byte(d);\n      d->bitcount = 7;\n   }\n\n   /* shift bit out of tag */\n   bit = d->tag & 0x01;\n   d->tag >>= 1;\n\n   return bit;\n}\n\n/* read a num bit value from a stream and add base */\nstatic unsigned int tinf_read_bits(TINF_DATA *d, int num, int base)\n{\n   unsigned int val = 0;\n\n   /* read num bits */\n   if (num)\n   {\n      unsigned int limit = 1 << (num);\n      unsigned int mask;\n\n      for (mask = 1; mask < limit; mask *= 2)\n         if (tinf_getbit(d)) val += mask;\n   }\n\n   return val + base;\n}\n\n/* given a data stream and a tree, decode a symbol */\nstatic int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t)\n{\n   int sum = 0, cur = 0, len = 0;\n\n   /* get more bits while code value is above sum */\n   do {\n\n      cur = 2*cur + tinf_getbit(d);\n\n      ++len;\n\n      sum += t->table[len];\n      cur -= t->table[len];\n\n   } while (cur >= 0);\n\n   return t->trans[sum + cur];\n}\n\n/* given a data stream, decode dynamic trees from it */\nstatic void tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)\n{\n   unsigned char lengths[288+32];\n   unsigned int hlit, hdist, hclen;\n   unsigned int i, num, length;\n\n   /* get 5 bits HLIT (257-286) */\n   hlit = tinf_read_bits(d, 5, 257);\n\n   /* get 5 bits HDIST (1-32) */\n   hdist = tinf_read_bits(d, 5, 1);\n\n   /* get 4 bits HCLEN (4-19) */\n   hclen = tinf_read_bits(d, 4, 4);\n\n   for (i = 0; i < 19; ++i) lengths[i] = 0;\n\n   /* read code lengths for code length alphabet */\n   for (i = 0; i < hclen; ++i)\n   {\n      /* get 3 bits code length (0-7) */\n      unsigned int clen = tinf_read_bits(d, 3, 0);\n\n      lengths[clcidx[i]] = clen;\n   }\n\n   /* build code length tree, temporarily use length tree */\n   tinf_build_tree(lt, lengths, 19);\n\n   /* decode code lengths for the dynamic trees */\n   for (num = 0; num < hlit + hdist; )\n   {\n      int sym = tinf_decode_symbol(d, lt);\n\n      switch (sym)\n      {\n      case 16:\n         /* copy previous code length 3-6 times (read 2 bits) */\n         {\n            unsigned char prev = lengths[num - 1];\n            for (length = tinf_read_bits(d, 2, 3); length; --length)\n            {\n               lengths[num++] = prev;\n            }\n         }\n         break;\n      case 17:\n         /* repeat code length 0 for 3-10 times (read 3 bits) */\n         for (length = tinf_read_bits(d, 3, 3); length; --length)\n         {\n            lengths[num++] = 0;\n         }\n         break;\n      case 18:\n         /* repeat code length 0 for 11-138 times (read 7 bits) */\n         for (length = tinf_read_bits(d, 7, 11); length; --length)\n         {\n            lengths[num++] = 0;\n         }\n         break;\n      default:\n         /* values 0-15 represent the actual code lengths */\n         lengths[num++] = sym;\n         break;\n      }\n   }\n\n   /* build dynamic trees */\n   tinf_build_tree(lt, lengths, hlit);\n   tinf_build_tree(dt, lengths + hlit, hdist);\n}\n\n/* ----------------------------- *\n * -- block inflate functions -- *\n * ----------------------------- */\n\n/* given a stream and two trees, inflate a block of data */\nstatic int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)\n{\n    if (d->curlen == 0) {\n        unsigned int offs;\n        int dist;\n        int sym = tinf_decode_symbol(d, lt);\n\n        /* literal byte */\n        if (sym < 256) {\n            TINF_PUT(d, sym);\n            return TINF_OK;\n        }\n\n        /* end of block */\n        if (sym == 256) {\n            return TINF_DONE;\n        }\n\n        /* substring from sliding dictionary */\n        sym -= 257;\n        /* possibly get more bits from length code */\n        d->curlen = tinf_read_bits(d, length_bits[sym], length_base[sym]);\n\n        dist = tinf_decode_symbol(d, dt);\n        /* possibly get more bits from distance code */\n        offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]);\n        d->lzOff = -offs;\n    }\n\n    /* copy next byte from dict substring */\n    d->dest[0] = d->dest[d->lzOff];\n    d->dest++;\n    d->curlen--;\n    return TINF_OK;\n}\n\n/* inflate an uncompressed block of data */\nstatic int tinf_inflate_uncompressed_block(TINF_DATA *d)\n{\n    if (d->curlen == 0) {\n        unsigned int length, invlength;\n\n        /* get length */\n        length = uzlib_get_byte(d) + 256 * uzlib_get_byte(d);\n        /* get one's complement of length */\n        invlength = uzlib_get_byte(d) + 256 * uzlib_get_byte(d);\n        /* check length */\n        if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR;\n\n        /* increment length to properly return TINF_DONE below, without\n           producing data at the same time */\n        d->curlen = length + 1;\n\n        /* make sure we start next block on a byte boundary */\n        d->bitcount = 0;\n    }\n\n    if (--d->curlen == 0) {\n        return TINF_DONE;\n    }\n\n    unsigned char c = uzlib_get_byte(d);\n    TINF_PUT(d, c);\n    return TINF_OK;\n}\n\n/* ---------------------- *\n * -- public functions -- *\n * ---------------------- */\n\nuint64_t pb_init(uint64_t size);\nvoid pb_draw(uint64_t curr);\nvoid pb_fini(void);\n\nint uncompress(uint8_t *in, uint8_t *out, uint32_t outsiz)\n{\n   uint8_t f;\n   int res;\n\n   /* skip over gzip header */\n   if(!in || !out) return TINF_DATA_ERROR;\n   memset(&d, 0, sizeof(TINF_DATA));\n   if(in[0] == 0x1f) {\n      in += 3;\n      f = *in++; in += 6;\n      if(f & 4) { res = *in++; res += (*in++ << 8); in += res; }\n      if(f & 8) { while(*in++ != 0); }\n      if(f & 16) { while(*in++ != 0); }\n      if(f & 2) in += 2;\n      d.source = in;\n   } else\n   if(in[8] == 0x78) {\n      memcpy(out, in, 8);\n      out += 8; outsiz -= 8;\n      d.source = in + 10;\n   } else return TINF_DATA_ERROR;\n   d.btype = -1;\n   d.dest = out;\n   d.destSize = outsiz;\n   pb_init(outsiz);\n   do {\n     do {\n        /* start a new block */\n        if (d.btype == -1) {\nnext_blk:\n            /* read final block flag */\n            d.bfinal = tinf_getbit(&d);\n            /* read block type (2 bits) */\n            d.btype = tinf_read_bits(&d, 2, 0);\n\n            //printf(\"Started new block: type=%d final=%d\\n\", d.btype, d.bfinal);\n\n            if (d.btype == 1) {\n                /* build fixed huffman trees */\n                tinf_build_fixed_trees(&d.ltree, &d.dtree);\n            } else if (d.btype == 2) {\n                /* decode trees from stream */\n                tinf_decode_trees(&d, &d.ltree, &d.dtree);\n            }\n        }\n\n        /* process current block */\n        switch (d.btype)\n        {\n        case 0:\n            /* decompress uncompressed block */\n            res = tinf_inflate_uncompressed_block(&d);\n            break;\n        case 1:\n        case 2:\n            /* decompress block with fixed/dyanamic huffman trees */\n            /* trees were decoded previously, so it's the same routine for both */\n            res = tinf_inflate_block_data(&d, &d.ltree, &d.dtree);\n            break;\n        default:\n            pb_fini();\n            return TINF_DATA_ERROR;\n        }\n        pb_draw(outsiz - d.destSize);\n        if (res == TINF_DONE && !d.bfinal) {\n            /* the block has ended (without producing more data), but we\n               can't return without data, so start procesing next block */\n            goto next_blk;\n        }\n\n        if (res != TINF_OK) {\n            pb_fini();\n            return res;\n        }\n\n    } while (--d.destSize);\n   } while(!res);\n   return TINF_OK;\n}\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/loader.h",
    "content": "/*\n * src/loader.h\n * https://gitlab.com/bztsrc/simpleboot\n *\n * Copyright (C) 2023 bzt (bztsrc@gitlab), MIT license\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * @brief Defines for the Simpleboot loader\n */\n\n#ifndef NULL\n#define NULL (void*)0\n#endif\n\n#define FB_COLOR(r,g,b) (((vidmode.framebuffer_red_mask_size > 8 ? (r) << (vidmode.framebuffer_red_mask_size - 8) : \\\n                          (r) >> (8 - vidmode.framebuffer_red_mask_size)) << vidmode.framebuffer_red_field_position) |\\\n                         ((vidmode.framebuffer_green_mask_size > 8 ? (g) << (vidmode.framebuffer_green_mask_size - 8) : \\\n                          (g) >> (8 - vidmode.framebuffer_green_mask_size)) << vidmode.framebuffer_green_field_position) |\\\n                         ((vidmode.framebuffer_blue_mask_size > 8 ? (b) << (vidmode.framebuffer_blue_mask_size - 8) : \\\n                          (b) >> (8 - vidmode.framebuffer_blue_mask_size)) << vidmode.framebuffer_blue_field_position))\n\nenum { MODE_UNKNOWN, MODE_VBR, MODE_PE32, MODE_MB32, MODE_MB64, MODE_LIN };\n\n/*** ELF defines and structs ***/\n\n#define ELFMAG      \"\\177ELF\"\n#define SELFMAG     4\n#define EI_CLASS    4       /* File class byte index */\n#define ELFCLASS32  1       /* 32-bit objects */\n#define ELFCLASS64  2       /* 64-bit objects */\n#define EI_DATA     5       /* Data encoding byte index */\n#define ELFDATA2LSB 1       /* 2's complement, little endian */\n#define PT_LOAD     1       /* Loadable program segment */\n#define PT_DYNAMIC  2       /* Dynamic linking information */\n#define PT_INTERP   3       /* Program interpreter */\n#define PF_X (1 << 0)       /* Segment is executable */\n#define PF_W (1 << 1)       /* Segment is writable */\n#define PF_R (1 << 2)       /* Segment is readable */\n#define EM_386      3       /* Intel 80386 */\n#define EM_X86_64   62      /* AMD x86_64 architecture */\n#define EM_AARCH64  183     /* ARM aarch64 architecture */\n#define EM_RISCV    243     /* RISC-V riscv64 architecture */\n\ntypedef struct {\n  unsigned char e_ident[16];/* Magic number and other info */\n  uint16_t  e_type;         /* Object file type */\n  uint16_t  e_machine;      /* Architecture */\n  uint32_t  e_version;      /* Object file version */\n  uint32_t  e_entry;        /* Entry point virtual address */\n  uint32_t  e_phoff;        /* Program header table file offset */\n  uint32_t  e_shoff;        /* Section header table file offset */\n  uint32_t  e_flags;        /* Processor-specific flags */\n  uint16_t  e_ehsize;       /* ELF header size in bytes */\n  uint16_t  e_phentsize;    /* Program header table entry size */\n  uint16_t  e_phnum;        /* Program header table entry count */\n  uint16_t  e_shentsize;    /* Section header table entry size */\n  uint16_t  e_shnum;        /* Section header table entry count */\n  uint16_t  e_shstrndx;     /* Section header string table index */\n} __attribute__((packed)) Elf32_Ehdr;\n\ntypedef struct {\n  unsigned char e_ident[16];/* Magic number and other info */\n  uint16_t  e_type;         /* Object file type */\n  uint16_t  e_machine;      /* Architecture */\n  uint32_t  e_version;      /* Object file version */\n  uint64_t  e_entry;        /* Entry point virtual address */\n  uint64_t  e_phoff;        /* Program header table file offset */\n  uint64_t  e_shoff;        /* Section header table file offset */\n  uint32_t  e_flags;        /* Processor-specific flags */\n  uint16_t  e_ehsize;       /* ELF header size in bytes */\n  uint16_t  e_phentsize;    /* Program header table entry size */\n  uint16_t  e_phnum;        /* Program header table entry count */\n  uint16_t  e_shentsize;    /* Section header table entry size */\n  uint16_t  e_shnum;        /* Section header table entry count */\n  uint16_t  e_shstrndx;     /* Section header string table index */\n} __attribute__((packed)) Elf64_Ehdr;\n\ntypedef struct {\n  uint32_t  p_type;         /* Segment type */\n  uint32_t  p_offset;       /* Segment file offset */\n  uint32_t  p_vaddr;        /* Segment virtual address */\n  uint32_t  p_paddr;        /* Segment physical address */\n  uint32_t  p_filesz;       /* Segment size in file */\n  uint32_t  p_memsz;        /* Segment size in memory */\n  uint32_t  p_align;        /* Segment alignment */\n} __attribute__((packed)) Elf32_Phdr;\n\ntypedef struct {\n  uint32_t  p_type;         /* Segment type */\n  uint32_t  p_flags;        /* Segment flags */\n  uint64_t  p_offset;       /* Segment file offset */\n  uint64_t  p_vaddr;        /* Segment virtual address */\n  uint64_t  p_paddr;        /* Segment physical address */\n  uint64_t  p_filesz;       /* Segment size in file */\n  uint64_t  p_memsz;        /* Segment size in memory */\n  uint64_t  p_align;        /* Segment alignment */\n} __attribute__((packed)) Elf64_Phdr;\n\n/*** PE32+ defines and structs ***/\n\n#define MZ_MAGIC                    0x5a4d      /* \"MZ\" */\n#define PE_MAGIC                    0x00004550  /* \"PE\\0\\0\" */\n#define IMAGE_FILE_MACHINE_I386     0x014c      /* Intel 386 architecture */\n#define IMAGE_FILE_MACHINE_AMD64    0x8664      /* AMD x86_64 architecture */\n#define IMAGE_FILE_MACHINE_ARM64    0xaa64      /* ARM aarch64 architecture */\n#define IMAGE_FILE_MACHINE_RISCV64  0x5064      /* RISC-V riscv64 architecture */\n#define PE_OPT_MAGIC_PE32PLUS       0x020b      /* PE32+ format */\n\ntypedef struct {\n  uint16_t  magic;        /* MZ magic */\n  uint16_t  reserved[29]; /* reserved */\n  uint32_t  peaddr;       /* address of pe header */\n} __attribute__((packed)) mz_hdr;\n\ntypedef struct {\n  uint32_t  magic;        /* PE magic */\n  uint16_t  machine;      /* machine type */\n  uint16_t  sections;     /* number of sections */\n  uint32_t  timestamp;    /* time_t */\n  uint32_t  sym_table;    /* symbol table offset */\n  uint32_t  numsym;       /* number of symbols */\n  uint16_t  opt_hdr_size; /* size of optional header */\n  uint16_t  flags;        /* flags */\n  uint16_t  file_type;    /* file type, PE32PLUS magic */\n  uint8_t   ld_major;     /* linker major version */\n  uint8_t   ld_minor;     /* linker minor version */\n  uint32_t  text_size;    /* size of text section(s) */\n  uint32_t  data_size;    /* size of data section(s) */\n  uint32_t  bss_size;     /* size of bss section(s) */\n  uint32_t  entry_point;  /* file offset of entry point */\n  uint32_t  code_base;    /* relative code addr in ram */\n  union {\n    struct {\n      uint32_t data_base; /* the preferred load address */\n      uint32_t img_base;  /* the preferred load address */\n    } pe32;\n    struct {\n      uint64_t img_base;  /* the preferred load address */\n    } pe64;\n  } data;\n} __attribute__((packed)) pe_hdr;\n\ntypedef struct {\n  char      name[8];      /* section name */\n  uint32_t  vsiz;         /* virtual size */\n  uint32_t  vaddr;        /* virtual address */\n  uint32_t  rsiz;         /* size of raw data */\n  uint32_t  raddr;        /* pointer to raw data */\n  uint32_t  reloc;        /* pointer to relocations */\n  uint32_t  ln;           /* pointer to line numbers */\n  uint16_t  nreloc;       /* number of relocations */\n  uint16_t  nln;          /* number of line numbers */\n  uint32_t  chr;          /* characteristics */\n} __attribute__((packed)) pe_sec;\n\n/*** Linux kernel header ***/\n#define HDRSMAG \"HdrS\"\n#define E820_MAX_ENTRIES_ZEROPAGE 128\n#define LOADED_HIGH   (1<<0)\n#define CAN_USE_HEAP  (1<<7)\n#define XLF_KERNEL_64 (1<<0)\n/* holy fucking shit, these go to orig_video_isVGA... undocumented, I had to grep the kernel source to figure out */\n#define VIDEO_TYPE_VLFB 0x23  /* VESA VGA in graphic mode\t*/\n#define VIDEO_TYPE_EFI  0x70  /* EFI graphic mode */\n/* for hdr.vid_mode */\n#define VIDEO_MODE_ASK  0xfffd\n#define VIDEO_MODE_CUR  0x0f04\n\ntypedef struct {\n  uint8_t   setup_sects;      /* if 0, WR 4 */\n  uint16_t  root_flags;\n  uint32_t  syssize;\n  uint16_t  ram_size;         /* DO NOT USE */\n  uint16_t  vid_mode;         /* WR */\n  uint16_t  root_dev;\n  uint16_t  boot_flag;        /* 0xAA55 magic */\n  /* 0x200 */\n  uint16_t  jump;\n  uint32_t  header;           /* magic \"HdrS\" */\n  uint16_t  version;          /* boot protocol version, 0x20c minimum */\n  uint32_t  realmode_swtch;\n  uint16_t  start_sys_seg;    /* obsolete, 0x1000 */\n  uint16_t  kernel_version;   /* pointer to kernel version string */\n  uint8_t   type_of_loader;   /* WR 0x14 */\n  uint8_t   loadflags;        /* WR, bit 1: LOADED_HIGH, bit 7: heap_end_ptr is valid */\n  uint16_t  setup_move_size;\n  uint32_t  code32_start;\n  uint32_t  ramdisk_image;    /* WR, initrd load address (set by boot loader) */\n  uint32_t  ramdisk_size;     /* WR, initrd size (set by boot loader) */\n  uint32_t  bootsect_klundge; /* DO NOT USE */\n  uint16_t  heap_end_ptr;     /* WR */\n  uint8_t   ext_loader_ver;\n  uint8_t   ext_loader_type;\n  uint32_t  cmd_line_ptr;     /* WR */\n  uint32_t  initrd_addr_max;\n  /* we might not have these, check version */\n  uint32_t  kernel_alignment;\n  uint8_t   reloc_kernel;\n  uint8_t   min_alignment;\n  uint16_t  xloadflags;\n  uint32_t  cmdline_size;\n  uint32_t  hw_subarch;       /* WR 0 */\n  uint64_t  hw_subarch_data;  /* WR 0 */\n  uint32_t  payload_offset;\n  uint32_t  payload_length;\n  uint64_t  setup_data;\n  uint64_t  pref_address;     /* prefered loading address */\n  uint32_t  init_size;\n  uint32_t  handover_offset;  /* EFI entry point, obsolete */\n  uint32_t  kernel_info_offset; /* v2.15+ WR 0 */\n} __attribute__((packed)) linux_boot_t;\n\ntypedef struct {\n  uint64_t  addr;\n  uint64_t  size;\n  uint32_t  type;\n} __attribute__((packed)) linux_e820_entry_t;\n\n/* The so-called \"zeropage\" */\ntypedef struct {\n  /* screen info                0x000 */\n  uint8_t   orig_x;           /* 0x00 */\n  uint8_t   orig_y;           /* 0x01 */\n  uint16_t  ext_mem_k;        /* 0x02 */\n  uint16_t  orig_video_page;  /* 0x04 */\n  uint8_t   orig_video_mode;  /* 0x06 */\n  uint8_t   orig_video_cols;  /* 0x07 */\n  uint8_t   flags;            /* 0x08 */\n  uint8_t   unused2;          /* 0x09 */\n  uint16_t  orig_video_ega_bx;/* 0x0a */\n  uint16_t  unused3;          /* 0x0c */\n  uint8_t   orig_video_lines; /* 0x0e */\n  uint8_t   orig_video_isVGA; /* 0x0f */\n  uint16_t  orig_video_points;/* 0x10 */\n  /* VESA graphic mode -- linear frame buffer */\n  uint16_t  lfb_width;        /* 0x12 */\n  uint16_t  lfb_height;       /* 0x14 */\n  uint16_t  lfb_depth;        /* 0x16 */\n  uint32_t  lfb_base;         /* 0x18 */\n  uint32_t  lfb_size;         /* 0x1c */\n  uint16_t  cl_magic, cl_offset; /* 0x20 */\n  uint16_t  lfb_linelength;   /* 0x24 */\n  uint8_t   red_size;         /* 0x26 */\n  uint8_t   red_pos;          /* 0x27 */\n  uint8_t   green_size;       /* 0x28 */\n  uint8_t   green_pos;        /* 0x29 */\n  uint8_t   blue_size;        /* 0x2a */\n  uint8_t   blue_pos;         /* 0x2b */\n  uint8_t   rsvd_size;        /* 0x2c */\n  uint8_t   rsvd_pos;         /* 0x2d */\n  uint16_t  vesapm_seg;       /* 0x2e */\n  uint16_t  vesapm_off;       /* 0x30 */\n  uint16_t  pages;            /* 0x32 */\n  uint16_t  vesa_attributes;  /* 0x34 */\n  uint32_t  capabilities;     /* 0x36 */\n  uint32_t  ext_lfb_base;     /* 0x3a */\n  uint8_t   _reserved[2];     /* 0x3e */\n  uint8_t   apm_bios_info[0x054 - 0x040]; /* 0x040 */\n  uint8_t   _pad2[4];         /* 0x054 */\n  uint64_t  tboot_addr;       /* 0x058 */\n  uint8_t   ist_info[0x070 - 0x060]; /* 0x060 */\n  uint64_t  acpi_rsdp_addr;   /* 0x070 */\n  uint8_t   _pad3[8];         /* 0x078 */\n  uint8_t   hd0_info[16]; /* obsolete! */ /* 0x080 */\n  uint8_t   hd1_info[16]; /* obsolete! */ /* 0x090 */\n  /* sys_desc_table, obsolete    0x0a0 */\n  uint16_t  length;\n  uint8_t   table[14];\n  /* olpc_ofw_header             0x0b0 */\n  uint32_t  ofw_magic;\n  uint32_t  ofw_version;\n  uint32_t  cif_handler;\n  uint32_t  irq_desc_table;\n  uint32_t  ext_ramdisk_image;/* 0x0c0 */\n  uint32_t  ext_ramdisk_size; /* 0x0c4 */\n  uint32_t  ext_cmd_line_ptr; /* 0x0c8 */\n  uint8_t   _pad4[112];       /* 0x0cc */\n  uint32_t  cc_blob_address;  /* 0x13c */\n  uint8_t   edid_info[0x1c0 - 0x140]; /* 0x140 */\n  /* efi_info                    0x1c0 */\n  uint32_t  efi_loader_signature;\n  uint32_t  efi_systab;\n  uint32_t  efi_memdesc_size;\n  uint32_t  efi_memdesc_version;\n  uint32_t  efi_memmap;\n  uint32_t  efi_memmap_size;\n  uint32_t  efi_systab_hi;\n  uint32_t  efi_memmap_hi;\n  uint32_t  alt_mem_k;        /* 0x1e0 */\n  uint32_t  scratch;    /* Scratch field! */  /* 0x1e4 */\n  uint8_t   e820_entries;     /* 0x1e8 */\n  uint8_t   eddbuf_entries;   /* 0x1e9 */\n  uint8_t   edd_mbr_sig_buf_entries; /* 0x1ea */\n  uint8_t   kbd_status;       /* 0x1eb */\n  uint8_t   secure_boot;      /* 0x1ec */\n  uint8_t   _pad5[2];         /* 0x1ed */\n  uint8_t   sentinel;         /* 0x1ef */\n  uint8_t   _pad6[1];         /* 0x1f0 */\n  linux_boot_t hdr;    /* setup header */  /* 0x1f1 */\n  uint8_t   _pad7[0x290-0x1f1-sizeof(linux_boot_t)];\n  uint8_t   edd_mbr_sig_buffer[0x2d0 - 0x290];  /* 0x290 */\n  linux_e820_entry_t e820_table[E820_MAX_ENTRIES_ZEROPAGE]; /* 0x2d0 */\n  uint8_t   _pad8[48];        /* 0xcd0 */\n  uint8_t   eddbuf[0xeec - 0xd00]; /* 0xd00 */\n  uint8_t   _pad9[276];       /* 0xeec */\n} __attribute__((packed)) linux_boot_params_t;\n\n/*** EFI ***/\n\n#ifndef EFIAPI\n# ifdef _MSC_EXTENSIONS\n#  define EFIAPI __cdecl\n# else\n#  ifdef __x86_64__\n#   define EFIAPI __attribute__((ms_abi))\n#  else\n#   define EFIAPI\n#  endif\n# endif\n#endif\n#define EFI_ERROR(a)           (((intn_t) a) < 0)\n#define EFI_SUCCESS                            0\n#define EFI_LOAD_ERROR        0x8000000000000001\n#define EFI_BUFFER_TOO_SMALL  0x8000000000000005\n\ntypedef void     *efi_handle_t;\ntypedef void     *efi_event_t;\ntypedef int64_t  intn_t;\ntypedef uint8_t  boolean_t;\ntypedef uint64_t uintn_t;\ntypedef uint64_t efi_status_t;\ntypedef uint64_t efi_physical_address_t;\ntypedef uint64_t efi_virtual_address_t;\n\ntypedef enum {\n    AllocateAnyPages,\n    AllocateMaxAddress,\n    AllocateAddress,\n    MaxAllocateType\n} efi_allocate_type_t;\n\ntypedef enum {\n    EfiReservedMemoryType,\n    EfiLoaderCode,\n    EfiLoaderData,\n    EfiBootServicesCode,\n    EfiBootServicesData,\n    EfiRuntimeServicesCode,\n    EfiRuntimeServicesData,\n    EfiConventionalMemory,\n    EfiUnusableMemory,\n    EfiACPIReclaimMemory,\n    EfiACPIMemoryNVS,\n    EfiMemoryMappedIO,\n    EfiMemoryMappedIOPortSpace,\n    EfiPalCode,\n    EfiPersistentMemory,\n    EfiUnacceptedMemoryType,\n    EfiMaxMemoryType\n} efi_memory_type_t;\n\ntypedef struct {\n  uint32_t  Type;\n  uint32_t  Pad;\n  uint64_t  PhysicalStart;\n  uint64_t  VirtualStart;\n  uint64_t  NumberOfPages;\n  uint64_t  Attribute;\n} efi_memory_descriptor_t;\n#define NextMemoryDescriptor(Ptr,Size)  ((efi_memory_descriptor_t *) (((uint8_t *) Ptr) + Size))\n\ntypedef enum {\n    AllHandles,\n    ByRegisterNotify,\n    ByProtocol\n} efi_locate_search_type_t;\n\ntypedef struct {\n    uint64_t    Signature;\n    uint32_t    Revision;\n    uint32_t    HeaderSize;\n    uint32_t    CRC32;\n    uint32_t    Reserved;\n} efi_table_header_t;\n\ntypedef struct {\n    uint16_t    Year;       /* 1998 - 2XXX */\n    uint8_t     Month;      /* 1 - 12 */\n    uint8_t     Day;        /* 1 - 31 */\n    uint8_t     Hour;       /* 0 - 23 */\n    uint8_t     Minute;     /* 0 - 59 */\n    uint8_t     Second;     /* 0 - 59 */\n    uint8_t     Pad1;\n    uint32_t    Nanosecond; /* 0 - 999,999,999 */\n    int16_t     TimeZone;   /* -1440 to 1440 or 2047 */\n    uint8_t     Daylight;\n    uint8_t     Pad2;\n} efi_time_t;\n\ntypedef struct {\n  uint32_t  Data1;\n  uint16_t  Data2;\n  uint16_t  Data3;\n  uint8_t   Data4[8];\n} __attribute__((packed)) guid_t;\n\n\n/* Simple text input / output interface */\ntypedef struct {\n    uint16_t    ScanCode;\n    uint16_t    UnicodeChar;\n} efi_input_key_t;\n\ntypedef efi_status_t (EFIAPI *efi_input_reset_t)(void *This, boolean_t ExtendedVerification);\ntypedef efi_status_t (EFIAPI *efi_input_read_key_t)(void *This, efi_input_key_t *Key);\n\ntypedef struct {\n    efi_input_reset_t           Reset;\n    efi_input_read_key_t        ReadKeyStroke;\n    efi_event_t                 WaitForKey;\n} simple_input_interface_t;\n\ntypedef efi_status_t (EFIAPI *efi_text_reset_t)(void *This, boolean_t ExtendedVerification);\ntypedef efi_status_t (EFIAPI *efi_text_output_string_t)(void *This, uint16_t *String);\ntypedef efi_status_t (EFIAPI *efi_text_test_string_t)(void *This, uint16_t *String);\ntypedef efi_status_t (EFIAPI *efi_text_query_mode_t)(void *This, uintn_t ModeNumber, uintn_t *Column, uintn_t *Row);\ntypedef efi_status_t (EFIAPI *efi_text_set_mode_t)(void *This, uintn_t ModeNumber);\ntypedef efi_status_t (EFIAPI *efi_text_set_attribute_t)(void *This, uintn_t Attribute);\ntypedef efi_status_t (EFIAPI *efi_text_clear_screen_t)(void *This);\ntypedef efi_status_t (EFIAPI *efi_text_set_cursor_t)(void *This, uintn_t Column, uintn_t Row);\ntypedef efi_status_t (EFIAPI *efi_text_enable_cursor_t)(void *This,  boolean_t Enable);\n\ntypedef struct {\n    int32_t                     MaxMode;\n    int32_t                     Mode;\n    int32_t                     Attribute;\n    int32_t                     CursorColumn;\n    int32_t                     CursorRow;\n    boolean_t                   CursorVisible;\n} simple_text_output_mode_t;\n\ntypedef struct {\n    efi_text_reset_t            Reset;\n    efi_text_output_string_t    OutputString;\n    efi_text_test_string_t      TestString;\n    efi_text_query_mode_t       QueryMode;\n    efi_text_set_mode_t         SetMode;\n    efi_text_set_attribute_t    SetAttribute;\n    efi_text_clear_screen_t     ClearScreen;\n    efi_text_set_cursor_t       SetCursorPosition;\n    efi_text_enable_cursor_t    EnableCursor;\n    simple_text_output_mode_t   *Mode;\n} simple_text_output_interface_t;\n\n/* EFI services */\n\ntypedef struct {\n  efi_physical_address_t Memory;\n  uintn_t NoPages;\n} memalloc_t;\n\ntypedef efi_status_t (EFIAPI *efi_allocate_pages_t)(efi_allocate_type_t Type, efi_memory_type_t MemoryType,\n    uintn_t NoPages, efi_physical_address_t *Memory);\ntypedef efi_status_t (EFIAPI *efi_free_pages_t)(efi_physical_address_t Memory, uintn_t NoPages);\ntypedef efi_status_t (EFIAPI *efi_get_memory_map_t)(uintn_t *MemoryMapSize, efi_memory_descriptor_t *MemoryMap,\n    uintn_t *MapKey, uintn_t *DescriptorSize, uint32_t *DescriptorVersion);\ntypedef efi_status_t (EFIAPI *efi_allocate_pool_t)(efi_memory_type_t PoolType, uintn_t Size, void **Buffer);\ntypedef efi_status_t (EFIAPI *efi_free_pool_t)(void *Buffer);\ntypedef efi_status_t (EFIAPI *efi_handle_protocol_t)(efi_handle_t Handle, guid_t *Protocol, void **Interface);\ntypedef efi_status_t (EFIAPI *efi_locate_handle_t)(efi_locate_search_type_t SearchType, guid_t *Protocol,\n    void *SearchKey, uintn_t *BufferSize, efi_handle_t *Buffer);\ntypedef efi_status_t (EFIAPI *efi_exit_boot_services_t)(efi_handle_t ImageHandle, uintn_t MapKey);\ntypedef efi_status_t (EFIAPI *efi_stall_t)(uintn_t Microseconds);\ntypedef efi_status_t (EFIAPI *efi_locate_protocol_t)(guid_t *Protocol, void *Registration, void **Interface);\n\ntypedef struct {\n    efi_table_header_t          Hdr;\n\n    void*                       RaiseTPL;\n    void*                       RestoreTPL;\n\n    efi_allocate_pages_t        AllocatePages;\n    efi_free_pages_t            FreePages;\n    efi_get_memory_map_t        GetMemoryMap;\n    efi_allocate_pool_t         AllocatePool;\n    efi_free_pool_t             FreePool;\n\n    void*                       CreateEvent;\n    void*                       SetTimer;\n    void*                       WaitForEvent;\n    void*                       SignalEvent;\n    void*                       CloseEvent;\n    void*                       CheckEvent;\n\n    void*                       InstallProtocolInterface;\n    void*                       ReinstallProtocolInterface;\n    void*                       UninstallProtocolInterface;\n    efi_handle_protocol_t       HandleProtocol;\n    efi_handle_protocol_t       PCHandleProtocol;\n    void*                       RegisterProtocolNotify;\n    efi_locate_handle_t         LocateHandle;\n    void*                       LocateDevicePath;\n    void*                       InstallConfigurationTable;\n\n    void*                       LoadImage;\n    void*                       StartImage;\n    void*                       Exit;\n    void*                       UnloadImage;\n    efi_exit_boot_services_t    ExitBootServices;\n\n    void*                       GetNextHighMonotonicCount;\n    efi_stall_t                 Stall;\n    void*                       SetWatchdogTimer;\n\n    void*                       ConnectController;\n    void*                       DisconnectController;\n\n    void*                       OpenProtocol;\n    void*                       CloseProtocol;\n    void*                       OpenProtocolInformation;\n\n    void*                       ProtocolsPerHandle;\n    void*                       LocateHandleBuffer;\n    efi_locate_protocol_t       LocateProtocol;\n    void*                       InstallMultipleProtocolInterfaces;\n    void*                       UninstallMultipleProtocolInterfaces;\n\n    void*                       CalculateCrc32;\n} efi_boot_services_t;\n\n/* EFI system table */\n\n#define ACPI_TABLE_GUID                 { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} }\n#define ACPI_20_TABLE_GUID              { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81} }\n#define SMBIOS_TABLE_GUID               { 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} }\n\ntypedef struct {\n    guid_t      VendorGuid;\n    void        *VendorTable;\n} efi_configuration_table_t;\n\ntypedef struct {\n    efi_table_header_t              Hdr;\n\n    uint16_t                        *FirmwareVendor;\n    uint32_t                        FirmwareRevision;\n\n    efi_handle_t                    ConsoleInHandle;\n    simple_input_interface_t        *ConIn;\n\n    efi_handle_t                    ConsoleOutHandle;\n    simple_text_output_interface_t  *ConOut;\n\n    efi_handle_t                    ConsoleErrorHandle;\n    simple_text_output_interface_t  *StdErr;\n\n    void                            *RuntimeServices;\n    efi_boot_services_t             *BootServices;\n\n    uintn_t                         NumberOfTableEntries;\n    efi_configuration_table_t       *ConfigurationTable;\n} efi_system_table_t;\n\n/* Device Path Protocol */\n\n#define EFI_DEVICE_PATH_PROTOCOL_GUID  { 0x09576E91, 0x6D3F, 0x11D2, {0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B} }\n\ntypedef struct {\n    uint8_t     Type;               /* 4 - Media Device Path */\n    uint8_t     SubType;            /* 1 - Hard Disk */\n    uint8_t     Length[2];\n    uint32_t    PartitionNumber;\n    uint64_t    PartitionStart;\n    uint64_t    PartitionSize;\n    guid_t      PartitionSignature; /* UniquePartitionGUID */\n    uint8_t     PartitionFormat;    /* 2 - GPT */\n    uint8_t     SignatureFormat;    /* 2 - GUID */\n} __attribute__((packed)) efi_hard_disk_device_path_t;\n\n/* Loaded image protocol */\n\n#define EFI_LOADED_IMAGE_PROTOCOL_GUID { 0x5B1B31A1, 0x9562, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B} }\n\ntypedef struct {\n    uint32_t                Revision;\n    efi_handle_t            ParentHandle;\n    void                    *SystemTable;\n    efi_handle_t            DeviceHandle;\n    void                    *FilePath;\n    void                    *Reserved;\n    uint32_t                LoadOptionsSize;\n    void                    *LoadOptions;\n    void                    *ImageBase;\n    uint64_t                ImageSize;\n    efi_memory_type_t       ImageCodeType;\n    efi_memory_type_t       ImageDataType;\n} efi_loaded_image_protocol_t;\n\n/* Simple File System Protocol */\n\n#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID { 0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} }\n#define EFI_FILE_INFO_GUID  { 0x9576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} }\n\n#define EFI_FILE_MODE_READ      0x0000000000000001\n\ntypedef struct {\n    uint64_t                Size;\n    uint64_t                FileSize;\n    uint64_t                PhysicalSize;\n    efi_time_t              CreateTime;\n    efi_time_t              LastAccessTime;\n    efi_time_t              ModificationTime;\n    uint64_t                Attribute;\n    uint16_t                FileName[262];\n} efi_file_info_t;\n\ntypedef struct efi_file_handle_s efi_file_handle_t;\n\ntypedef efi_status_t (EFIAPI *efi_volume_open_t)(void *This, efi_file_handle_t **Root);\ntypedef struct {\n    uint64_t                Revision;\n    efi_volume_open_t       OpenVolume;\n} efi_simple_file_system_protocol_t;\n\ntypedef efi_status_t (EFIAPI *efi_file_open_t)(efi_file_handle_t *File, efi_file_handle_t **NewHandle, uint16_t *FileName,\n    uint64_t OpenMode, uint64_t Attributes);\ntypedef efi_status_t (EFIAPI *efi_file_close_t)(efi_file_handle_t *File);\ntypedef efi_status_t (EFIAPI *efi_file_delete_t)(efi_file_handle_t *File);\ntypedef efi_status_t (EFIAPI *efi_file_read_t)(efi_file_handle_t *File, uintn_t *BufferSize, void *Buffer);\ntypedef efi_status_t (EFIAPI *efi_file_write_t)(efi_file_handle_t *File, uintn_t *BufferSize, void *Buffer);\ntypedef efi_status_t (EFIAPI *efi_file_get_pos_t)(efi_file_handle_t *File, uint64_t *Position);\ntypedef efi_status_t (EFIAPI *efi_file_set_pos_t)(efi_file_handle_t *File, uint64_t Position);\ntypedef efi_status_t (EFIAPI *efi_file_get_info_t)(efi_file_handle_t *File, guid_t *InformationType, uintn_t *BufferSize,\n    void *Buffer);\ntypedef efi_status_t (EFIAPI *efi_file_set_info_t)(efi_file_handle_t *File, guid_t *InformationType, uintn_t BufferSize,\n    void *Buffer);\ntypedef efi_status_t (EFIAPI *efi_file_flush_t)(efi_file_handle_t *File);\n\nstruct efi_file_handle_s {\n    uint64_t                Revision;\n    efi_file_open_t         Open;\n    efi_file_close_t        Close;\n    efi_file_delete_t       Delete;\n    efi_file_read_t         Read;\n    efi_file_write_t        Write;\n    efi_file_get_pos_t      GetPosition;\n    efi_file_set_pos_t      SetPosition;\n    efi_file_get_info_t     GetInfo;\n    efi_file_set_info_t     SetInfo;\n    efi_file_flush_t        Flush;\n};\n\n/* Graphics Output Protocol */\n\n#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID { 0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a } }\n\ntypedef enum {\n  PixelRedGreenBlueReserved8BitPerColor,\n  PixelBlueGreenRedReserved8BitPerColor,\n  PixelBitMask,\n  PixelBltOnly,\n  PixelFormatMax\n} efi_gop_pixel_format_t;\n\ntypedef struct {\n    uint32_t                RedMask;\n    uint32_t                GreenMask;\n    uint32_t                BlueMask;\n    uint32_t                ReservedMask;\n} efi_gop_pixel_bitmask_t;\n\ntypedef struct {\n    uint32_t                Version;\n    uint32_t                HorizontalResolution;\n    uint32_t                VerticalResolution;\n    efi_gop_pixel_format_t  PixelFormat;\n    efi_gop_pixel_bitmask_t PixelInformation;\n    uint32_t                PixelsPerScanLine;\n} efi_gop_mode_info_t;\n\ntypedef struct {\n    uint32_t                MaxMode;\n    uint32_t                Mode;\n    efi_gop_mode_info_t     *Information;\n    uintn_t                 SizeOfInfo;\n    efi_physical_address_t  FrameBufferBase;\n    uintn_t                 FrameBufferSize;\n} efi_gop_mode_t;\n\ntypedef efi_status_t (EFIAPI *efi_gop_query_mode_t)(void *This, uint32_t ModeNumber, uintn_t *SizeOfInfo,\n    efi_gop_mode_info_t **Info);\ntypedef efi_status_t (EFIAPI *efi_gop_set_mode_t)(void *This, uint32_t ModeNumber);\ntypedef efi_status_t (EFIAPI *efi_gop_blt_t)(void *This, uint32_t *BltBuffer, uintn_t BltOperation,\n    uintn_t SourceX, uintn_t SourceY, uintn_t DestinationX, uintn_t DestionationY, uintn_t Width, uintn_t Height, uintn_t Delta);\n\ntypedef struct {\n    efi_gop_query_mode_t    QueryMode;\n    efi_gop_set_mode_t      SetMode;\n    efi_gop_blt_t           Blt;\n    efi_gop_mode_t          *Mode;\n} efi_gop_t;\n\n/* EDID Protocol */\n\n#define EFI_EDID_ACTIVE_GUID     { 0xbd8c1056, 0x9f36, 0x44ec, { 0x92, 0xa8, 0xa6, 0x33, 0x7f, 0x81, 0x79, 0x86 } }\n#define EFI_EDID_DISCOVERED_GUID { 0x1c0c34f6, 0xd380, 0x41fa, { 0xa0, 0x49, 0x8a, 0xd0, 0x6c, 0x1a, 0x66, 0xaa } }\n\ntypedef struct {\n  uint32_t SizeOfEdid;\n  uint8_t *Edid;\n} efi_edid_t;\n\n/* GUID Partitioning Table */\n\n#define EFI_PTAB_HEADER_ID  \"EFI PART\"\n#define EFI_PART_TYPE_EFI_SYSTEM_PART_GUID  { 0xc12a7328, 0xf81f, 0x11d2, {0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b} }\n/* this is actually the same as 1 << GRUB_GPT_PART_ATTR_OFFSET_LEGACY_BIOS_BOOTABLE */\n#define EFI_PART_USED_BY_OS 0x0000000000000004\n\ntypedef struct {\n  uint64_t  Signature;\n  uint32_t  Revision;\n  uint32_t  HeaderSize;\n  uint32_t  CRC32;\n  uint32_t  Reserved;\n  uint64_t  MyLBA;\n  uint64_t  AlternateLBA;\n  uint64_t  FirstUsableLBA;\n  uint64_t  LastUsableLBA;\n  guid_t    DiskGUID;\n  uint64_t  PartitionEntryLBA;\n  uint32_t  NumberOfPartitionEntries;\n  uint32_t  SizeOfPartitionEntry;\n  uint32_t  PartitionEntryArrayCRC32;\n} __attribute__((packed)) gpt_header_t;\n\ntypedef struct {\n  guid_t    PartitionTypeGUID;\n  guid_t    UniquePartitionGUID;\n  uint64_t  StartingLBA;\n  uint64_t  EndingLBA;\n  uint64_t  Attributes;\n  uint16_t  PartitionName[36];\n} __attribute__((packed)) gpt_entry_t;\n\n/* EFI System Partition */\n\ntypedef struct {\n  uint8_t   jmp[3];\n  char      oem[8];\n  uint16_t  bps;\n  uint8_t   spc;\n  uint16_t  rsc;\n  uint8_t   nf;\n  uint8_t   nr0;\n  uint8_t   nr1;\n  uint16_t  ts16;\n  uint8_t   media;\n  uint16_t  spf16;\n  uint16_t  spt;\n  uint16_t  nh;\n  uint32_t  hs;\n  uint32_t  ts32;\n  uint32_t  spf32;\n  uint32_t  flg;\n  uint32_t  rc;\n  char      vol[6];\n  char      fst[8];\n  char      dmy[20];\n  char      fst2[8];\n} __attribute__((packed)) esp_bpb_t;\n\ntypedef struct {\n  char      name[8];\n  char      ext[3];\n  uint8_t   attr[9];\n  uint16_t  ch;\n  uint32_t  attr2;\n  uint16_t  cl;\n  uint32_t  size;\n} __attribute__((packed)) esp_dir_t;\n\n/* PCI Option ROM */\n\ntypedef struct {\n  uint8_t   magic[2];     /* 0xaa55 */\n  uint16_t  InitializationSize;\n  uint32_t  EfiSignature; /* 0x0EF1 */\n  uint16_t  EfiSubsystem; /* 0xA */\n  uint16_t  EfiMachineType;\n  uint8_t   Reserved[0x0A];\n  uint16_t  EfiImageHeaderOffset;\n  uint32_t  PcirOffset;\n  uint32_t  Signature;    /* \"PCIR\" */\n  uint16_t  VendorId;\n  uint16_t  DeviceId;\n  uint16_t  Reserved0;\n  uint16_t  Length;\n  uint8_t   Revision;\n  uint8_t   ClassCode[3];\n  uint16_t  ImageLength;\n  uint16_t  CodeRevision;\n  uint8_t   CodeType;\n  uint8_t   Indicator;\n  uint16_t  Reserved1;\n  uint8_t   checksum;\n  uint8_t   Reserved2;\n} __attribute__((packed)) pcirom_t;\n\n/*** FOSSBIOS ***/\n\n/* Boot Catalog */\n\ntypedef struct {\n  uint8_t   magic[6];   /* 0xB0, 0x07, 0xCA, 0x7A, 0x10, 0xC0 */\n  uint8_t   chksum;     /* same as in PCI ROM, ACPI etc. sum to zero */\n  uint8_t   numentries;\n  struct {\n    uint16_t  arch;     /* 0 = x86, 1 = ARM, 2 = RISC-V */\n    uint8_t   wordsize; /* in bytes */\n    uint8_t   endian;   /* 0 = little-endian */\n    uint32_t  lba;\n  } __attribute__((packed)) entries[256];\n} __attribute__((packed)) fb_boot_t;\n\n/* System Services */\n\n#define FB_MEMENT_TYPE(size) ((size) & 7)\n#define FB_MEM_FREE     0\n#define FB_MEM_USED     1 /* allocated for Boot Loader / OS, reclaimable */\n#define FB_MEM_BIOS     2 /* allocated for FOSSBIOS internally, reclaimable */\n#define FB_MEM_ROM      3 /* read-only ROM area */\n#define FB_MEM_MMIO     4 /* memory mapped input / ouput */\n#define FB_MEM_NVS      5 /* non-volatile data, saved during hybernation */\n#define FB_MEM_BAD      7 /* other unusable */\n\ntypedef struct {\n  uint64_t  base;\n  uint64_t  size;\n} __attribute__((packed)) fb_mement_t;\n\ntypedef int (*fb_udelay_t)(uint64_t usec);\ntypedef uint8_t* (*fb_exit_t)(void);\n\ntypedef struct {\n  uint8_t       magic[4];     /* 'S','Y','S',16 */\n  uint32_t      nummap;\n  fb_mement_t   *memmap;\n  void          *boot;\n  void          *shell;\n  fb_exit_t     exit;\n  fb_udelay_t   udelay;\n  void          *memcpy;\n  void          *memset;\n  void          *memcmp;\n  void          *alloc;\n  void          *free;\n  void          *mark;\n  void          *getenv;\n  void          *setenv;\n  void          *printf;\n  void          *devadd;\n  void          *resadd;\n  void          *memadd;\n  void          *lstadd;\n} __attribute__((packed)) fb_system_t;\n\n/* Video Services */\n\ntypedef struct {\n  uint32_t  width;\n  uint32_t  height;\n  uint32_t  pitch;\n  uint8_t   bpp;\n  uint8_t   red;\n  uint8_t   green;\n  uint8_t   blue;\n  uint8_t   reserved[16];\n} __attribute__((packed)) fb_vidmode_t;\n\ntypedef int (*fb_vsetmode_t)(uint16_t mode);\n\ntypedef struct {\n  uint8_t       magic[4];     /* 'V','I','D',6 */\n  uint16_t      nummodes;\n  uint16_t      curmode;\n  void          *next;\n  fb_vidmode_t  *vidmodes;\n  uint8_t       *edid;\n  uint8_t       *lfb;\n  fb_vsetmode_t setmode;\n  void          *blit;\n} __attribute__((packed)) fb_video_t;\n\n/* Storage Service */\n\ntypedef int (*fb_sread_t)(uint16_t dev, uint32_t blksize, uint64_t lba, void *buf);\n\ntypedef struct {\n  uint8_t       magic[4];     /* 'B','L','K',3 */\n  uint16_t      num;\n  uint16_t      size;\n  void          *data;\n  fb_sread_t    read;\n  void          *write;\n} __attribute__((packed)) fb_storage_t;\n\n/* Serial Services */\n\ntypedef void (*fb_ssend_t)(uint16_t dev, uint8_t chr);\ntypedef uint8_t* (*fb_srecv_t)(uint16_t dev);\ntypedef int (*fb_spend_t)(uint16_t dev);\ntypedef void (*fb_ssetmode_t)(uint16_t dev, uint32_t baud, uint8_t bits, uint8_t parity, uint8_t stop);\n\ntypedef struct {\n  uint8_t       magic[4];     /* 'S','E','R',5 */\n  uint16_t      num;\n  uint16_t      size;\n  void          *data;\n  fb_ssend_t    send;\n  fb_srecv_t    recv;\n  fb_spend_t    pend;\n  fb_ssetmode_t setmode;\n} __attribute__((packed)) fb_serial_t;\n\n/* Input Services */\n\ntypedef uint32_t (*fb_getkey_t)(void);\ntypedef uint32_t (*fb_haskey_t)(void);\n\ntypedef struct {\n  uint8_t       magic[4];     /* 'I','N','P',4 */\n  uint32_t      mbz;\n  fb_getkey_t   getkey;\n  fb_haskey_t   haskey;\n  void          *getptr;\n  void          *setptr;\n} __attribute__((packed)) fb_input_t;\n\n/* FOSSBIOS Main Structure */\n\ntypedef struct {\n  uint8_t       magic[4];     /* 'F','B','S',12 */\n  uint16_t      arch;\n  uint8_t       wordsize;\n  uint8_t       endian;\n  void          *oem;\n  void          *conf;\n  fb_system_t   *system;\n  void          *proc;\n  fb_video_t    *video;\n  fb_storage_t  *storage;\n  fb_serial_t   *serial;\n  fb_input_t    *input;\n  void          *clock;\n  void          *audio;\n  void          *net;\n  void          *power;\n} __attribute__((packed)) fossbios_t;\n\n#define FOSSBIOS_MAGIC  0xF055B105\ntypedef void (*fb_loader_t)(uint32_t magic, fossbios_t *mainstruct, uint16_t bootdev);\n\n/* FOSSBIOS ROM module */\n\ntypedef struct {\n  uint8_t   magic[2];     /* 0xaa55 */\n  uint16_t  size;\n  uint8_t   fossmagic[4]; /* 0xF0, 0x55, 0xB1, 0x05 */\n  uint16_t  arch;\n  uint8_t   wordsize;\n  uint8_t   endian;\n  uint32_t  compressed;\n  uint32_t  uncompressed;\n  uint8_t   type;\n  uint8_t   initorder;\n  uint16_t  numreloc;\n  uint32_t  pcir_offs;\n  uint8_t   pcir[24];\n  uint32_t  entry;\n  uint32_t  bss;\n  uint32_t  crc;\n} __attribute__((packed)) fb_rom_t;\n\n/*** ACPI ***/\n\ntypedef struct {\n    char magic[8];      /* \"RSD PTR \" */\n    uint8_t chksum;\n    char OEM[6];\n    uint8_t rev;        /* 2 */\n    uint32_t rsdt;\n} __attribute__((packed)) rsdp_t;\n\ntypedef struct {\n    char magic[4];\n    uint32_t size;\n    uint8_t rev;\n    uint8_t chksum;\n    char OEM[6];\n    char OEMtableid[8];\n    uint32_t OEMrev;\n    uint32_t creatid;\n    uint32_t creatrev;\n} __attribute__((packed)) sdt_hdr_t;\n\ntypedef struct {\n    sdt_hdr_t hdr;\n    uint32_t table_ptr[2];\n} __attribute__((packed)) rsdt_t;\n\ntypedef struct {\n    uint8_t type;   /* 0 processor */\n    uint8_t size;   /* 8 */\n    uint8_t acpi_id;\n    uint8_t apic_id;\n    uint32_t flags; /* bit 0: enabled, bit 1: available */\n} __attribute__((packed)) cpu_entry_t;\n\ntypedef struct {\n    sdt_hdr_t hdr;  /* magic \"APIC\" */\n    uint32_t lapic_addr;\n    uint32_t flags;\n    cpu_entry_t cpus[4];\n} __attribute__((packed)) apic_t;\n\ntypedef struct {\n    sdt_hdr_t hdr;  /* magic \"FACP\" */\n    uint32_t firmwarectrl;\n    uint32_t dsdt;\n    uint8_t  reserved[96];\n    uint64_t x_dsdt;\n} __attribute__((packed)) fadt_t;\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/loader_cb.c",
    "content": "/*\n * src/loader_cb.c\n * https://gitlab.com/bztsrc/simpleboot\n *\n * Copyright (C) 2023 bzt (bztsrc@gitlab), MIT license\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * @brief The main Simpleboot loader program as a coreboot payload\n *\n * Memory layout when booted with coreboot:\n *      0x510 -   0x5A0   GDT and AP startup data\n *     0x1000 - 0x20000   paging tables (0x8000 - 0x80FF relocated AP startup code)\n *    0x20000 - 0x90000   config + logo + tags; from the top to bottom: kernel's stack\n *    0x90000 - 0xA0000   Linux kernel only: zero page + cmdline\n *    0xA0000 - 0xFFFFF   VRAM and BIOS ROM\n *   0x100000 -      x    kernel segments, followed by the modules, each page aligned (from 1M)\n * 0x03000000 -      x    libpayload and loader (from 48M)\n *\n * Compilation:\n *\n * Step 1: Install dependencies\n * ----------------------------\n *\n * Install coreboot's dependencies: bison, build-essentials, curl, flex, git, gnat, libncurses5-dev, m4, zlib.\n * Please refer to https://doc.coreboot.org/tutorial/part1.html to an up-to-date list.\n *\n * Step 2: Get coreboot\n * --------------------\n *\n * git clone https://review.coreboot.org/coreboot && cd coreboot && git submodule update --init\n *\n * Step 3: Add Simpleboot to coreboot\n * ----------------------------------\n *\n * Replace \"/path/to/simpleboot\" with the directory where you've downloaded Simpleboot.\n * NOTE: a symlink really should work here, but it DOES NOT. You must physically copy the directory.\n *\n * cp -r /path/to/simpleboot payloads/external\n *\n * If you haven't downloaded Simpleboot yet, then this also works:\n *\n * git clone https://gitlab.com/bztsrc/simpleboot payloads/external\n *\n * Step 4: Create coreboot toolchain\n * ---------------------------------\n *\n * This will take a while. Replace \"CPUS=4\" with the number of CPU cores you have. This step takes a while.\n *\n * make crossgcc-i386 CPUS=4\n *\n * Step 5: Configure coreboot\n * --------------------------\n *\n * Now configure coreboot for your motherboard (or qemu) and Simpleboot.\n *\n * make menuconfig\n *     select 'Mainboard' menu\n *     beside 'Mainboard vendor' should be '(Emulation)'\n *     beside 'Mainboard model' should be 'QEMU x86 i440fx/piix4'\n *     select 'Exit'\n *     select 'Devices'\n *     select 'Display'\n *     beside 'Framebuffer mode' should be 'Linear \"high-resolution\" framebuffer'\n *     select 'Exit'\n *     select 'Exit'\n *     select 'Payload' menu\n *     select 'Payload to add'\n *     choose 'Simpleboot'\n *     select 'Exit'\n *     select 'Exit'\n * Also add the desired device drivers (like AHCI and maybe USB if you want to boot from stick too)\n * and set the desired screen resolution. Finally\n *     select 'Exit'\n *     select 'Yes'\n *\n * Step 5: Build coreboot\n * ----------------------\n *\n * make -C payloads/external/simpleboot && make\n *\n * Step 6: Add files to ROM (optional)\n * -----------------------------------\n *\n * If you wish, you can add your custom simpleboot.cfg to the ROM. If you don't, then it will be loaded from disk.\n *\n * ./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/simpleboot.cfg -n simpleboot.cfg\n *\n * If you wish, you can also add your custom logo.tga (it will be displayed automatically if added).\n *\n * ./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/logo.tga -n logo.tga\n *\n * If you wish, you can add a device tree blob too (in GUDT, FDT and DSDT; depending which format your kernel understands).\n *\n * ./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/devices.gud -n devices\n * ./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/devices.dtb -n devices\n * ./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/DSDT.aml -n devices\n *\n * Finally, you can also add a default kernel and default initrd too (not just set their default filenames\n * with -k and -i, but their actual file content can be embedded in the ROM):\n *\n * ./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/kernel -n kernel\n * ./build/cbfstool build/coreboot.rom add -t raw -f /path/to/your/initrd -n initrd\n *\n * If exists, these are only used as a very last resort fallback option when absolutely all the other methods have failed.\n *\n * Step 7: Test your new ROM\n * -------------------------\n *\n * Replace \"/path/to/your/disk.img\" with your disk image.\n *\n * qemu-system-x86_64 -bios build/coreboot.rom -drive file=/path/to/your/disk.img,format=raw -serial stdio\n *\n */\n\n/**\n * The longest path we can handle\n */\n#define PATH_MAX 1024\n/**\n * Maximum size of MBI tags in pages (30 * 4096 = 122k)\n */\n#define TAGS_MAX 30\n\n/*\n * DO NOT try to use payloads/libpayload/Makefile.payload that would compile all C files, not just this one\n * DO NOT try to include payload.h that's a real header dependency hell! Just copy'n'paste the prototypes that we actually need\n */\n#define CBFS_METADATA_MAX_SIZE 256\n#include <kconfig.h>\n#include <stdint.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <string.h>\n#include <sysinfo.h>\n#include <storage/storage.h>\n#if CONFIG(LP_ARCH_X86)\n#include <x86/arch/io.h>\n#endif\n#if CONFIG(LP_USB)\nstatic void* usbdev = NULL;\nvoid usbdisk_create(void* dev) { if(!usbdev) usbdev = dev; }\nvoid usbdisk_remove(void* dev) { if(usbdev == dev) usbdev = NULL; }\n#endif\nvoid arch_ndelay(uint64_t n);\nvoid console_init(void);\nint havekey(void);\nint getchar(void);\nvoid video_console_clear(void);\nvoid storage_initialize(void);\nint usb_initialize(void);\nint usb_exit(void);\nvoid usb_poll(void);\nint readwrite_blocks_512(void *dev, int start, int n, int dir, uint8_t *buf);\nvoid halt(void);\nssize_t _cbfs_boot_lookup(const char *name, int force_ro, void *mdata);\nvoid *_cbfs_load(const char *name, void *buf, size_t *size_inout, int force_ro);\nextern char _end;\nstatic inline size_t cbfs_load(const char *name, void *buf, size_t size)\n{ return _cbfs_load(name, buf, &size, 0) ? size : 0; }\nstatic inline size_t cbfs_get_size(const char *name)\n{\n    uint8_t mdata[CBFS_METADATA_MAX_SIZE];\n    size_t ret;\n    ret = _cbfs_boot_lookup(name, 0, &mdata) < 0 ? 0 : (mdata[8] << 24) | (mdata[9] << 16) | (mdata[10] << 8) | mdata[11];\n    return ret;\n}\n\n#include \"../simpleboot.h\"\n#include \"loader.h\"\n#include \"inflate.h\"\n\n#define sleep(n) arch_ndelay((uint64_t)(n) * 1000000)\n\n#define send_ipi(a,m,v) do { \\\n        while(*((volatile uint32_t*)(lapic + 0x300)) & (1 << 12)) __asm__ __volatile__ (\"pause\" : : : \"memory\"); \\\n        *((volatile uint32_t*)(lapic + 0x310)) = (*((volatile uint32_t*)(lapic + 0x310)) & 0x00ffffff) | (a << 24); \\\n        *((volatile uint32_t*)(lapic + 0x300)) = (*((volatile uint32_t*)(lapic + 0x300)) & m) | v;  \\\n    } while(0)\n\nesp_bpb_t *bpb;\nmultiboot_mmap_entry_t *memmap;\nmultiboot_tag_module_t *initrd;\nmultiboot_tag_framebuffer_t vidmode;\nuint64_t mmio_base, file_size, rsdp_ptr, dsdt_ptr, file_buf, page_buf, ram, *pt, root_dir;\nuint32_t fb_w, fb_h, fb_bpp, fb_bg, logo_size, verbose, num_memmap, pb_b, pb_m, pb_l, rq, bkp, smp;\nuint16_t wcname[PATH_MAX];\nuint8_t rpi, *tags_buf, *tags_ptr, *logo_buf, *kernel_entry, kernel_mode, kernel_buf[4096], *kernel_mem, *pb_fb;\nchar *conf_buf, *kernel, *cmdline;\nlinux_boot_params_t *zero_page;\n\n/**\n * Convert hex string into integer\n */\nchar *gethex(char *ptr, uint32_t *ret)\n{\n    int len = 2;\n    *ret = 0;\n    for(;len--;ptr++) {\n        if(*ptr>='0' && *ptr<='9') {          *ret <<= 4; *ret += (uint32_t)(*ptr - '0'); }\n        else if(*ptr >= 'a' && *ptr <= 'f') { *ret <<= 4; *ret += (uint32_t)(*ptr - 'a' + 10); }\n        else if(*ptr >= 'A' && *ptr <= 'F') { *ret <<= 4; *ret += (uint32_t)(*ptr - 'A' + 10); }\n        else break;\n    }\n    return ptr;\n}\n\n/**\n * Convert decimal string to integer\n */\nchar *getint(char *ptr, uint32_t *ret)\n{\n    for(*ret = 0; *ptr >= '0' && *ptr <= '9'; ptr++) { *ret *= 10; *ret += (uint32_t)(*ptr - '0'); }\n    return ptr;\n}\n\n/**\n * Hexdump\n */\nvoid hexdump(void *data, int n)\n{\n    uint8_t *ptr = (uint8_t*)data;\n    int i, j;\n    for(j = 0; j < n; j++, ptr += 16) {\n        printf(\"%08x: \", (uint32_t)(uintptr_t)ptr);\n        for(i = 0; i < 16; i++) printf(\"%02x \", ptr[i]);\n        printf(\" \");\n        for(i = 0; i < 16; i++) printf(\"%c\", ptr[i] >= 32 && ptr[i] < 127 ? ptr[i] : '.');\n        printf(\"\\r\\n\");\n    }\n}\n\n/**************** Progress bar ****************/\n\n/**\n * Initialize the progress bar\n */\nuint64_t pb_init(uint64_t size)\n{\n    uint32_t c, i, x;\n\n    pb_fb = NULL; pb_m = (size >> 9) + 1; pb_l = 0;\n    if(!vidmode.framebuffer_addr || !size || pb_m < vidmode.framebuffer_width - 4) return 0;\n    pb_b = (vidmode.framebuffer_bpp + 7) >> 3;\n    pb_fb = (uint8_t*)(uintptr_t)vidmode.framebuffer_addr + (vidmode.framebuffer_height - 4) * vidmode.framebuffer_pitch + 2 * pb_b;\n    c = FB_COLOR(32, 32, 32);\n    for(i = x = 0; x < vidmode.framebuffer_width - 4; x++, i += pb_b)\n        switch(vidmode.framebuffer_bpp) {\n            case 15: case 16: *((uint16_t*)(pb_fb + i)) = *((uint16_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = c; break;\n            case 24: case 32: *((uint32_t*)(pb_fb + i)) = *((uint32_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = c; break;\n        }\n    return size / (vidmode.framebuffer_width - 4);\n}\n\n/**\n * Draw the progress bar\n */\nvoid pb_draw(uint64_t curr)\n{\n    uint32_t i;\n\n    if(pb_fb) {\n        i = pb_l; pb_l = ((curr >> 9) * (vidmode.framebuffer_width - 4) / pb_m) * pb_b;\n        for(; i < pb_l; i++)\n            switch(vidmode.framebuffer_bpp) {\n                case 15: case 16: *((uint16_t*)(pb_fb + i)) = *((uint16_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = 0xFFFF; break;\n                case 24: case 32: *((uint32_t*)(pb_fb + i)) = *((uint32_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = 0xFFFFFF; break;\n            }\n    }\n}\n\n/**\n * Close the progress bar\n */\nvoid pb_fini(void)\n{\n    uint32_t i, x;\n\n    if(pb_fb)\n        for(i = x = 0; x < vidmode.framebuffer_width - 2; x++, i += pb_b)\n            switch(vidmode.framebuffer_bpp) {\n                case 15: case 16: *((uint16_t*)(pb_fb + i)) = *((uint16_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = fb_bg; break;\n                case 24: case 32: *((uint32_t*)(pb_fb + i)) = *((uint32_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = fb_bg; break;\n            }\n    pb_fb = NULL;\n}\n\nuint64_t data_lba, fat_lba;\nuint8_t vbr[512], data[512];\nuint32_t fat[1024], fat_cache, file_clu;\nuint16_t lfn[261];\nguid_t bootuuid;\n\n/**\n * Load a sector from boot drive using libpayload\n */\nvoid loadsec(uint64_t lba, void *dst)\n{\n    uint8_t i;\n\n    if(havekey()) { getchar(); rq = 1; }\n#if CONFIG(LP_USB)\n    /* USB storage */\n    if(usbdev)\n        readwrite_blocks_512(usbdev, lba, 1, 0x80/*cbw_direction_data_in*/, dst);\n    else\n#endif\n    /* AHCI storage */\n    if(storage_device_count())\n        storage_read_blocks512(0, lba, 1, dst);\n#if CONFIG(LP_ARCH_X86)\n    else {\n        /* fallback primary ATA IDE */\n        i = inb(0x1F6);\n        if(i != 0 && i != 0xFF) {\n            while((inb(0x1F7) & 0xC0) != 0x40);\n            outb(1, 0x1F2);\n            outb(lba, 0x1F3);\n            outb(lba >> 8, 0x1F4);\n            outb(lba >> 16, 0x1F5);\n            outb((lba >> 24) | 0xE0, 0x1F6);\n            outb(0x20, 0x1F7);  /* cmd 0x20 - read sectors */\n            while((inb(0x1F7) & 0xC0) != 0x40);\n            insl(0x1F0, dst, 512/4);\n        }\n    }\n#endif\n}\n\n/**\n * Get the next cluster from FAT\n */\nuint32_t nextclu(uint32_t clu)\n{\n    uint64_t i;\n\n    if(clu < 2 || clu >= 0x0FFFFFF8) return 0;\n    if(clu < fat_cache || clu > fat_cache + 1023) {\n        fat_cache = clu & ~1023;\n        for(i = 0; i < 8; i++) loadsec(fat_lba + (fat_cache >> 7) + i, &fat[i << 7]);\n    }\n    clu = fat[clu - fat_cache];\n    return clu < 2 || clu >= 0x0FFFFFF8 ? 0 : clu;\n}\n\n/**\n * Allocate and zero out a page\n */\nuint64_t page_alloc(void)\n{\n    uint64_t page = page_buf;\n    if(page == 0x20000) return 0;\n    page_buf += 4096;\n    memset((void*)(uintptr_t)page, 0, 4096);\n    return page;\n}\n\n/**\n * Initialize firmware related stuff\n */\nvoid fw_init(void)\n{\n    guid_t espGuid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID;\n    uint64_t i, j, k, l, n;\n\n    console_init();\n#if CONFIG(LP_ARCH_X86)\n    /* make sure SSE is enabled, because some say there are buggy firmware in the wild not enabling (and also needed if we come\n     * from boot_x86.asm). No supported check, because according to AMD64 Spec Vol 2, all long mode capable CPUs must also\n     * support SSE2 at least. We don't need them, but it's more than likely that a kernel is compiled using SSE instructions. */\n    __asm__ __volatile__ (\n    \"movl %%cr0, %%eax;andb $0xF1, %%al;movl %%eax, %%cr0;\"     /* clear MP, EM, TS (FPU emulation off) */\n    \"movl %%cr4, %%eax;orw $3 << 9, %%ax;movl %%eax, %%cr4;\"    /* set OSFXSR, OSXMMEXCPT (enable SSE) */\n    :::\"rax\");\n    /* ridiculous, libpayload is a huge library, yet has no function to initialize serial port properly... */\n    __asm__ __volatile__(\n        \"movl %0, %%edx;\"\n        \"xorb %%al, %%al;outb %%al, %%dx;\"               /* IER int off */\n        \"movb $0x80, %%al;addb $2,%%dl;outb %%al, %%dx;\" /* LCR set divisor mode */\n        \"movb $1, %%al;subb $3,%%dl;outb %%al, %%dx;\"    /* DLL divisor lo 115200 */\n        \"xorb %%al, %%al;incb %%dl;outb %%al, %%dx;\"     /* DLH divisor hi */\n        \"incb %%dl;outb %%al, %%dx;\"                     /* FCR fifo off */\n        \"movb $0x43, %%al;incb %%dl;outb %%al, %%dx;\"    /* LCR 8N1, break on */\n        \"movb $0x8, %%al;incb %%dl;outb %%al, %%dx;\"     /* MCR Aux out 2 */\n        \"xorb %%al, %%al;subb $4,%%dl;inb %%dx, %%al\"    /* clear receiver/transmitter */\n    : : \"a\"(CONFIG_LP_SERIAL_IOBASE + 1): );\n#endif\n    storage_initialize();\n#if CONFIG(LP_USB)\n    usb_initialize();\n    usbdev = NULL;\n    usb_poll(); /* this calls usbdisk_create() if it detects any USB storages */\n#endif\n    video_console_clear();\n\n    /* initialize everything to zero */\n#ifdef DEBUG\n    verbose = 3;\n#else\n    verbose = 0;\n#endif\n    bpb = NULL; memmap = NULL; initrd = NULL; num_memmap = bkp = rq = smp = 0;\n    zero_page = NULL;\n    conf_buf = kernel = cmdline = NULL; kernel_entry = logo_buf = tags_ptr = NULL; kernel_mode = MODE_MB64;\n    root_dir = rsdp_ptr = dsdt_ptr = ram = 0;\n    memset(&vidmode, 0, sizeof(vidmode)); fb_bg = 0; pb_fb = NULL;\n    vidmode.framebuffer_addr = (uint64_t)lib_sysinfo.framebuffer.physical_address;\n    vidmode.framebuffer_pitch = lib_sysinfo.framebuffer.bytes_per_line;\n    vidmode.framebuffer_width = lib_sysinfo.framebuffer.x_resolution;\n    vidmode.framebuffer_height = lib_sysinfo.framebuffer.y_resolution;\n    vidmode.framebuffer_bpp = lib_sysinfo.framebuffer.bits_per_pixel;\n    vidmode.framebuffer_type = 1;\n    vidmode.framebuffer_red_field_position = lib_sysinfo.framebuffer.red_mask_pos;\n    vidmode.framebuffer_red_mask_size = lib_sysinfo.framebuffer.red_mask_size;\n    vidmode.framebuffer_green_field_position = lib_sysinfo.framebuffer.green_mask_pos;\n    vidmode.framebuffer_green_mask_size = lib_sysinfo.framebuffer.green_mask_pos;\n    vidmode.framebuffer_blue_field_position = lib_sysinfo.framebuffer.blue_mask_pos;\n    vidmode.framebuffer_blue_mask_size = lib_sysinfo.framebuffer.blue_mask_size;\n    /* things with fixed address */\n    tags_buf = (uint8_t*)0x20000; file_buf = 0x100000;\n    pt = (uint64_t*)0x1000; page_buf = 0x9000;\n    memset(pt, 0, 8 * 4096);\n    /* the GUDT format is strongly preferred here, however this actually could be an FDT or a DSDT blob as well,\n     * if the magic bytes match, it will be loaded and will work. Can be overriden by using the module directive */\n    dsdt_ptr = (uint64_t)(uintptr_t)_cbfs_load(\"devices\", NULL, NULL, 0);\n#if CONFIG(LP_ARCH_ARM64)\n    __asm__ __volatile__(\"mrs %0, midr_el1;\":\"=r\"(mmio_base)::);\n    switch(mmio_base & 0xFFF0) {\n        case 0xD030: rpi = 3; mmio_base = 0x3F000000; emmc_base = 0x3F300000; break;     /* Raspberry Pi 3 */\n        default:     rpi = 4; mmio_base = 0xFE000000; emmc_base = 0xFE340000; break;     /* Raspberry Pi 4 */\n    }\n    /* set up paging */\n    j = mmio_base >> 21; k = (mmio_base + 0x800000) >> 21;\n    /* TTBR0 */\n    for(i = 0; i < 4; i++)\n        pt[i] = (uintptr_t)pt + ((i + 2) * 4096) + (3|(3<<8)|(1<<10));\n    for(i = 0; i < 4 * 512; i++) pt[1024 + i] = (uintptr_t)i * 2 * 1024 * 1024 +\n        /* if we're mapping the mmio area, use device SH=2 memory type */\n        (1 | (1<<10) | (i >= j && i < k ? (2<<8) | (1<<2) | (1L<<54) : (3<<8)));\n    /* dynamically map framebuffer */\n    if(vidmode.framebuffer_addr) {\n        /* map new pages from the page table area */\n        fw_map(vidmode.framebuffer_addr, vidmode.framebuffer_addr,\n            (vidmode.framebuffer_pitch * vidmode.framebuffer_height + 4095) & ~4095);\n    }\n    /* TTBR1 */\n    /* pt[512] = nothing for now; */\n#endif\n#if CONFIG(LP_ARCH_X86)\n    /* set up the same page tables we have with BIOS, but don't active it yet */\n    pt[0] = (uintptr_t)pt + 4096 + 3;\n    for(i = 0; i < 5; i++) pt[512 + i] = (uintptr_t)pt + (i + 2) * 4096 + 3;\n    for(i = 0; i < 6 * 512; i++) pt[1024 + i] = (uint64_t)i * 2 * 1024 * 1024 + 0x83;\n#endif\n\n    /* get boot partition's root directory */\n    loadsec(1, &vbr);\n    if(!memcmp(&vbr, EFI_PTAB_HEADER_ID, 8)) {\n        /* found GPT */\n        j = ((gpt_header_t*)&vbr)->SizeOfPartitionEntry;\n        l = ((gpt_header_t*)&vbr)->PartitionEntryLBA;\n        n = ((gpt_header_t*)&vbr)->NumberOfPartitionEntries;\n        /* look for ESP in the first 8 sectors only. Should be the very first entry anyway */\n        for(k = 0; k < 8 && n; k++) {\n            loadsec(l + k, &vbr);\n            for(i = 0; i + j <= 512; i += j, n--) {\n                /* does ESP type match? */\n                if(!root_dir && !memcmp(&((gpt_entry_t*)&vbr[i])->PartitionTypeGUID, &espGuid, sizeof(guid_t))) {\n                    root_dir = ((gpt_entry_t*)&vbr[i])->StartingLBA;\n                    memcpy(&bootuuid, &(((gpt_entry_t*)&vbr[i])->UniquePartitionGUID), sizeof(guid_t));\n                    k = 8; break;\n                }\n            }\n        }\n    } else {\n        /* fallback to MBR partitioning scheme */\n        loadsec(0, &vbr);\n        if(vbr[510] == 0x55 && vbr[511] == 0xAA)\n            for(i = 0x1c0; i < 510; i += 16)\n                if(vbr[i - 2] == 0x80/*active*/ && (vbr[i + 2] == 0xC/*FAT32*/ || vbr[i + 2] == 0xEF/*ESP*/)) {\n                    root_dir = (uint64_t)(*((uint32_t*)&vbr[i + 6]));\n                    memcpy(&bootuuid.Data1, \"PART\", 4); memcpy(bootuuid.Data4, \"boot\", 4);\n                    bootuuid.Data3 = (i - 0x1c0) / 16;\n                    break;\n                }\n    }\n    if(root_dir) {\n        loadsec(root_dir, &vbr);\n        bpb = (esp_bpb_t*)&vbr;\n        if(vbr[510] != 0x55 || vbr[511] != 0xAA || bpb->bps != 512 || !bpb->spc || bpb->spf16 || !bpb->spf32)\n            root_dir = 0;\n        else {\n            /* calculate the LBA address of the FAT and the first data sector */\n            fat_lba = bpb->rsc + root_dir;\n            data_lba = bpb->spf32 * bpb->nf + bpb->rsc - 2 * bpb->spc + root_dir;\n            /* load the beginning of the FAT into the cache */\n            for(i = 0; i < 8; i++) loadsec(fat_lba + i, &fat[i << 7]);\n            fat_cache = 0;\n        }\n    }\n}\n\n/**\n * Display a boot splash\n */\nvoid fw_bootsplash(void)\n{\n    uint32_t c;\n    uint8_t *fb = (uint8_t*)(uintptr_t)vidmode.framebuffer_addr;\n    int i, j, k, l, x, y, w, h, o, m, p, px, py, b = (vidmode.framebuffer_bpp + 7) >> 3;\n\n    /* clear screen */\n    video_console_clear();\n    if(!fb) return;\n    for(j = y = 0; y < (int)vidmode.framebuffer_height; y++, j += vidmode.framebuffer_pitch)\n        for(i = j, x = 0; x < (int)vidmode.framebuffer_width; x++, i += b)\n            if(b == 2) *((uint16_t*)(fb + i)) = (uint16_t)fb_bg; else *((uint32_t*)(fb + i)) = fb_bg;\n    /* only indexed RLE compressed TGA images supported */\n    if(!logo_buf || logo_buf[0] || logo_buf[1] != 1 || logo_buf[2] != 9 || logo_buf[3] || logo_buf[4] ||\n        (logo_buf[7] != 24 && logo_buf[7] != 32)) return;\n    /* uncompress image */\n    o = (logo_buf[17] & 0x20); w = (logo_buf[13] << 8) + logo_buf[12]; h = (logo_buf[15] << 8) + logo_buf[14];\n    if(w < 1 || h < 1) return;\n    px = ((int)vidmode.framebuffer_width - w) / 2; py = ((int)vidmode.framebuffer_height - h) / 2;\n    m = ((logo_buf[7] >> 3) * ((logo_buf[6] << 8) | logo_buf[5])) + 18; y = i = 0;\n    for(l = 0, x = w, y = -1; l < w * h && (uint32_t)m < logo_size;) {\n        k = logo_buf[m++];\n        if(k > 127) { p = 0; k -= 127; j = logo_buf[m++] * (logo_buf[7] >> 3) + 18; } else { p = 1; k++; }\n        l += k;\n        while(k--) {\n            if(p) j = logo_buf[m++] * (logo_buf[7] >> 3) + 18;\n            if(x == w) { x = 0; i = ((py + (!o ? h - y - 1 : y)) * (int)vidmode.framebuffer_pitch + (px + x) * b); y++; }\n            if(py + y > 0 && py + y < (int)vidmode.framebuffer_height - 1) {\n                if(px + x > 0 && px + x < (int)vidmode.framebuffer_width - 1) {\n                    c = FB_COLOR(logo_buf[j + 2], logo_buf[j + 1], logo_buf[j + 0]);\n                    if(b == 2) *((uint16_t*)(fb + i)) = (uint16_t)c; else *((uint32_t*)(fb + i)) = c;\n                }\n                i += b;\n            }\n            x++;\n        }\n    }\n}\n\n/**\n * Open a file\n */\nint fw_open(char *fn)\n{\n    uint64_t lba;\n    uint32_t clu = bpb->rc;\n    int i, n = 0, m = 0;\n    uint8_t secleft = 0, *dir = data + sizeof(data);\n    uint16_t *u, *s = wcname, a, b, c, *d;\n    char *e;\n\n    if(!root_dir || !fn || !*fn) return 0;\n    /* UTF-8 to WCHAR */\n    for(e = fn, d = wcname; *e && *e != ' ' && *e != '\\r' && *e != '\\n' && d < &wcname[PATH_MAX - 2]; d++) {\n        if((*e & 128) != 0) {\n            if(!(*e & 32)) { c = ((*e & 0x1F)<<6)|(*(e+1) & 0x3F); e++; } else\n            if(!(*e & 16)) { c = ((*e & 0xF)<<12)|((*(e+1) & 0x3F)<<6)|(*(e+2) & 0x3F); e += 2; } else\n            if(!(*e & 8)) { c = ((*e & 0x7)<<18)|((*(e+1) & 0x3F)<<12)|((*(e+2) & 0x3F)<<6)|(*(e+3) & 0x3F); *e += 3; }\n            else c = 0;\n        } else c = *e;\n        e++; if(c == '\\\\' && *e == ' ') { c = ' '; e++; }\n        *d = c;\n    }\n    *d = 0;\n\n    file_size = file_clu = 0;\n    memset(lfn, 0, sizeof(lfn));\n    while(1) {\n        /* have we reached the end of the sector? */\n        if(dir >= data + sizeof(data)) {\n            if(secleft) { secleft--; lba++; }\n            else {\n                if(clu < 2 || clu >= 0x0FFFFFF8) return 0;\n                secleft = bpb->spc - 1;\n                lba = clu * bpb->spc + data_lba;\n                clu = nextclu(clu);\n            }\n            loadsec(lba, &data);\n            dir = data;\n        }\n        /* empty space? End of directory then */\n        if(!dir[0]) return 0;\n        /* not a deleted entry or current and parent entries? */\n        if(dir[0] != 5 && dir[0] != 0xE5 && (dir[0] != '.' || (dir[1] != '.' && dir[1] != ' '))) {\n            /* is this an LFN block? */\n            if(dir[0xB] == 0xF) {\n                /* first LFN block? */\n                if(!n || (dir[0] & 0x40)) {\n                    memset(lfn, 0, sizeof(lfn));\n                    n = dir[0] & 0x1F;\n                    /* bad record, not sure what to do. Let's reset state and continue with next entry */\n                    if(n < 1 || n > 20) { n = m = 0; dir += 32; continue; }\n                    u = lfn + (n - 1) * 13;\n                }\n                /* get the next part of UCS-2 characters */\n                for(i = 0; i < 5; i++)\n                    u[i] = dir[i*2+2] << 8 | dir[i*2+1];\n                for(i = 0; i < 6; i++)\n                    u[i+5] = dir[i*2+0xF] << 8 | dir[i*2+0xE];\n                u[11] = dir[0x1D] << 8 | dir[0x1C];\n                u[12] = dir[0x1F] << 8 | dir[0x1E];\n                u -= 13;\n                n--;\n                /* indicate that the next directory entry belongs to an LFN */\n                m = (!n && u < lfn);\n            } else\n            if(!(dir[0xB] & 8)) {\n                /* if we don't have an LFN already, generate it from the 8.3 name in this entry */\n                if(!m) {\n                    for(i = 0; i < 8; i++) lfn[i] = dir[i];\n                    while(i && lfn[i - 1] == ' ') i--;\n                    if(dir[8] != ' ') {\n                        lfn[i++] = '.'; lfn[i++] = dir[8];\n                        if(dir[9] != ' ') {\n                            lfn[i++] = dir[9];\n                            if(dir[10] != ' ') { lfn[i++] = dir[10]; }\n                        }\n                    }\n                    lfn[i] = 0;\n                } else m = 0;\n                /* filename match? */\n                if(*s == '/') s++;\n                for(i = 0; lfn[i] && s[i] && s[i] != '/'; i++) {\n                    a = lfn[i]; if(a >= 'A' && a <= 'Z') a += 'a' - 'A';\n                    b = s[i]; if(b >= 'A' && b <= 'Z') b += 'a' - 'A';\n                    if(a != b) break;\n                }\n                if(!lfn[i]) {\n                    clu = (dir[0x15] << 24) | (dir[0x14] << 16) | (dir[0x1B] << 8) | dir[0x1A];\n                    /* is this a directory? */\n                    if(dir[0xB] & 0x10) {\n                        if(s[i] != '/') return 0;\n                        /* go to subdirectory */\n                        s += i + 1; n = m = secleft = 0; dir = data + sizeof(data);\n                        continue;\n                    } else {\n                        /* no, it's a file, then we have located what we were looking for */\n                        if(clu < 2 || clu >= 0x0FFFFFF8) return 0;\n                        file_clu = clu;\n                        file_size = (dir[0x1F] << 24) | (dir[0x1E] << 16) | (dir[0x1D] << 8) | dir[0x1C];\n                        break;\n                    }\n                }\n            }\n        }\n        dir += 32;\n    }\n    return 1;\n}\n\n/**\n * Read data from file\n */\nuint64_t fw_read(uint64_t offs, uint64_t size, void *buf)\n{\n    uint64_t lba = 0, rem, o;\n    uint32_t clu = file_clu, nc, ns = 0, os = 0, rs = 512;\n    uint8_t secleft = 0;\n\n    if(!root_dir || file_clu < 2 || offs >= file_size || !size || !buf) return 0;\n    if(offs + size > file_size) size = file_size - offs;\n    rem = size;\n\n    pb_init(size);\n    if(offs) {\n        nc = offs / (bpb->spc << 9); o = offs % (bpb->spc << 9);\n        ns = o >> 9; os = o & 0x1ff; rs = 512 - os;\n        if(nc) { while(nc-- && clu) { clu = nextclu(clu); } if(!clu) return 0; }\n        secleft = bpb->spc - ns - 1;\n        lba = clu * bpb->spc + ns - 1 + data_lba;\n    }\n    while(rem && !rq) {\n        if(secleft) { secleft--; lba++; }\n        else {\n            if(!clu) break;\n            secleft = bpb->spc - 1;\n            lba = clu * bpb->spc + data_lba;\n            clu = nextclu(clu);\n        }\n        if(rs > rem) rs = rem;\n        if(rs < 512) {\n            loadsec(lba, data);\n            memcpy(buf, data + os, rs); os = 0;\n        } else {\n            loadsec(lba, buf);\n            if(os) { memcpy(buf, buf + os, rs); os = 0; }\n        }\n        buf += rs; rem -= rs; rs = 512;\n        pb_draw(size - rem);\n    }\n    pb_fini();\n    return (size - rem);\n}\n\n/**\n * Close file\n */\nvoid fw_close(void)\n{\n    file_clu = 0;\n}\n\n/**\n * Load and parse config (everything except modules)\n */\nvoid fw_loadconfig(void)\n{\n    char *s, *e, *a;\n    uint32_t r, g, b;\n    int l, m = 0;\n\n    if(bkp) { fw_bootsplash(); printf(\"Aborted, loading backup configuration...\\r\\n\"); }\n\n    kernel = cmdline = NULL;\n    tags_buf = (uint8_t*)0x20000;\n    logo_size = 0;\n    if(!conf_buf) {\n        file_size = 0;\n        /* first check if there's a config in the ROM */\n        r = cbfs_get_size(\"simpleboot.cfg\");\n        if(r) file_size = cbfs_load(\"simpleboot.cfg\", tags_buf, r);\n        /* as a fallback, we try to load the first menuentry from easyboot's configuration */\n        else if(fw_open(\"simpleboot.cfg\") || (!bkp && fw_open(\"easyboot/menu.cfg\"))) {\n            fw_read(0, file_size, tags_buf);\n            fw_close();\n        }\n        tags_buf[file_size] = 0;\n        if(file_size) {\n            conf_buf = (char*)tags_buf;\n            tags_buf += (file_size + 7) & ~7;\n        }\n    }\n    if(conf_buf) {\n        fb_bg = 0; smp = 0;\n        for(s = conf_buf; *s;) {\n            /* find beginning of a line */\n            while(*s && (*s == '\\r' || *s == '\\n' || *s == ' ' || *s == '\\t')) s++;\n            for(a = s; *a && *a != ' ' && *a != '\\r' && *a != '\\n'; a++);\n            for(e = a; *e && *e != '\\r' && *e != '\\n'; e++);\n            for(; a < e && *a == ' '; a++);\n            /* 's' points to the start of the command,\n             * 'a' to the first argument,\n             * 'e' to the end of the line */\n            l = !memcmp(s, \"backup\", 6);\n            if(bkp ^ l) { s = e; continue; } else if(bkp & l) s += 6;\n            if(!memcmp(s, \"multicore\", 9)) smp = 1;\n            if(a >= e) { s = e; continue; }\n            if(!memcmp(s, \"menuentry\", 9)) {\n                if(++m > 1) break;\n            } else\n            if(!memcmp(s, \"verbose\", 7)) {\n                a = getint(a, &verbose);\n            } else\n            if(!memcmp(s, \"framebuffer\", 11)) {\n                /* we can't change resolution with libpayload */\n            } else\n            if(!memcmp(s, \"bootsplash\", 10)) {\n                if(*a == '#') {\n                    a++; a = gethex(a, &r); a = gethex(a, &g); a = gethex(a, &b);\n                    fb_bg = FB_COLOR(r, g, b);\n                    while(a < e && *a == ' ') a++;\n                }\n                if(a < e) {\n                    if(fw_open(a)) {\n                        logo_buf = tags_buf;\n                        tags_buf += (file_size + 7) & ~7;\n                        if(verbose) printf(\"Loading logo (%llu bytes)...\\r\\n\", file_size);\n                        logo_size = file_size;\n                        fw_read(0, file_size, logo_buf);\n                        fw_close();\n                    } else logo_size = 0;\n                }\n                fw_bootsplash();\n            } else\n            if(a < e && !memcmp(s, \"kernel\", 6)) {\n                kernel = a;\n                for(; a < e && *a && *a != ' ' && *a != '\\r' && *a != '\\n'; a++)\n                    if(*a == '\\\\' && a[1] == ' ') a++;\n                while(a < e && *a == ' ') a++;\n                if(*a && *a != '\\r' && *a != '\\n') cmdline = a;\n            }\n            /* go to the next line */\n            s = e;\n        }\n    }\n    if(!logo_size && (r = cbfs_get_size(\"logo.tga\"))) {\n        logo_size = cbfs_load(\"logo.tga\", tags_buf, r);\n        logo_buf = tags_buf;\n        tags_buf += (logo_size + 7) & ~7;\n        fw_bootsplash();\n    }\n}\n\n/**\n * Detect config file independent configuration and generate tags for them\n */\nvoid fw_loadsetup()\n{\n    multiboot_tag_loader_t *stag;\n    multiboot_tag_mmap_t *mtag;\n    multiboot_mmap_entry_t tmp;\n    uint64_t srt, end;\n    uint32_t i, j;\n    char *c;\n\n    file_buf = 0x100000;\n    tags_ptr = tags_buf;\n    memmap = NULL;\n    if(tags_ptr) {\n        /* MBI header */\n        ((multiboot_info_t*)tags_buf)->total_size = ((multiboot_info_t*)tags_buf)->reserved = 0;\n        tags_ptr += sizeof(multiboot_info_t);\n        /* loader tag */\n        stag = (multiboot_tag_loader_t*)tags_ptr;\n        stag->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME;\n        stag->size = bkp ? 28 : 19;\n        memcpy(stag->string, SIMPLEBOOT_MAGIC, 11);\n        if(bkp) memcpy(stag->string + 10, \" (backup)\", 10);\n        tags_ptr += (stag->size + 7) & ~7;\n        /* commandline tag */\n        if(cmdline) {\n            for(c = cmdline; *c && *c != '\\r' && *c != '\\n'; c++);\n            stag = (multiboot_tag_loader_t*)tags_ptr;\n            stag->type = MULTIBOOT_TAG_TYPE_CMDLINE;\n            stag->size = 9 + c - cmdline;\n            memcpy(stag->string, cmdline, c - cmdline); stag->string[c - cmdline] = 0;\n            tags_ptr += (stag->size + 7) & ~7;\n            /* overwrite the cmdline pointer with this new, zero terminated string */\n            cmdline = stag->string;\n        }\n        /* get system tables and generate tags for them */\n        if((c = (char*)lib_sysinfo.smbios)) {\n            memset(tags_ptr, 0, sizeof(multiboot_tag_smbios_t));\n            ((multiboot_tag_smbios_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_SMBIOS;\n            ((multiboot_tag_smbios_t*)tags_ptr)->size = sizeof(multiboot_tag_smbios_t) + (uint32_t)c[5];\n            ((multiboot_tag_smbios_t*)tags_ptr)->major = c[7];\n            ((multiboot_tag_smbios_t*)tags_ptr)->minor = c[8];\n            memcpy(((multiboot_tag_smbios_t*)tags_ptr)->tables, c, (uint32_t)c[5]);\n            tags_ptr += (((multiboot_tag_smbios_t*)tags_ptr)->size + 7) & ~7;\n        }\n        if((c = (char*)lib_sysinfo.acpi_rsdp)) {\n            if(c[15] < 2) {\n                ((multiboot_tag_old_acpi_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_ACPI_OLD;\n                ((multiboot_tag_old_acpi_t*)tags_ptr)->size = sizeof(multiboot_tag_old_acpi_t) + 24;\n                memcpy(((multiboot_tag_old_acpi_t*)tags_ptr)->rsdp, c, 24);\n                tags_ptr += (((multiboot_tag_old_acpi_t*)tags_ptr)->size + 7) & ~7;\n            } else {\n                ((multiboot_tag_new_acpi_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_ACPI_NEW;\n                ((multiboot_tag_new_acpi_t*)tags_ptr)->size = sizeof(multiboot_tag_new_acpi_t) + 36;\n                memcpy(((multiboot_tag_new_acpi_t*)tags_ptr)->rsdp, c, 36);\n                tags_ptr += (((multiboot_tag_new_acpi_t*)tags_ptr)->size + 7) & ~7;\n            }\n            rsdp_ptr = (uintptr_t)c;\n        }\n        /* generate memory map tag */\n        mtag = (multiboot_tag_mmap_t*)tags_ptr;\n        mtag->type = MULTIBOOT_TAG_TYPE_MMAP;\n        mtag->entry_size = sizeof(multiboot_mmap_entry_t);\n        mtag->entry_version = 0;\n        for(ram = num_memmap = i = 0; (int)i < lib_sysinfo.n_memranges; i++) {\n            srt = lib_sysinfo.memrange[i].base;\n            end = srt + lib_sysinfo.memrange[i].size;\n            srt = (srt + 4095) & ~4095; end &= ~4095;\n            if(srt < end) {\n                mtag->entries[num_memmap].base_addr = srt;\n                mtag->entries[num_memmap].length = end - srt;\n                mtag->entries[num_memmap].reserved = lib_sysinfo.memrange[i].type << 16;\n                mtag->entries[num_memmap].type =\n                    lib_sysinfo.memrange[i].type == CB_MEM_RAM || lib_sysinfo.memrange[i].type == CB_MEM_TABLE ? MULTIBOOT_MEMORY_AVAILABLE : (\n                    lib_sysinfo.memrange[i].type == CB_MEM_ACPI ? MULTIBOOT_MEMORY_ACPI_RECLAIMABLE : (\n                    lib_sysinfo.memrange[i].type == CB_MEM_NVS ? MULTIBOOT_MEMORY_NVS : MULTIBOOT_MEMORY_RESERVED));\n                if(mtag->entries[num_memmap].type == MULTIBOOT_MEMORY_AVAILABLE && end - 1 > ram) ram = end - 1;\n                num_memmap++;\n            }\n        }\n        if(num_memmap > 0) {\n            /* make sure of it that the memory map is sorted. Should be, so bubble-sort is affordable here */\n            for(i = 1; i < num_memmap; i++)\n                for(j = i; j > 0 && mtag->entries[j].base_addr < mtag->entries[j - 1].base_addr; j--) {\n                    memcpy(&tmp, &mtag->entries[j - 1], sizeof(multiboot_mmap_entry_t));\n                    memcpy(&mtag->entries[j - 1], &mtag->entries[j], sizeof(multiboot_mmap_entry_t));\n                    memcpy(&mtag->entries[j], &tmp, sizeof(multiboot_mmap_entry_t));\n                }\n            memmap = mtag->entries;\n            mtag->size = sizeof(multiboot_tag_mmap_t) + num_memmap * sizeof(multiboot_mmap_entry_t);\n            tags_ptr += (mtag->size + 7) & ~7;\n        }\n        ram &= ~(2 * 1024 * 1024 - 1);\n    }\n}\n\n/**\n * Parse config for modules and load them\n */\nvoid fw_loadmodules(void)\n{\n    uint32_t uncomp;\n    uint8_t *ptr, tmp[16];\n    int n = 0, f = 0, l;\n    multiboot_tag_module_t *tag;\n    char *s, *e, *a;\n\n    if(conf_buf) {\n        for(s = conf_buf; !rq && !f && *s;) {\n            /* find beginning of a line */\n            while(*s && (*s == '\\r' || *s == '\\n' || *s == ' ' || *s == '\\t')) s++;\n            for(a = s; *a && *a != ' ' && *a != '\\r' && *a != '\\n'; a++);\n            for(e = a; *e && *e != '\\r' && *e != '\\n'; e++);\n            for(; a < e && *a == ' '; a++);\n            /* 's' points to the start of the command,\n             * 'a' to the first argument,\n             * 'e' to the end of the line */\n            l = !memcmp(s, \"backup\", 6);\n            if(a >= e || bkp ^ l) { s = e; continue; } else if(bkp & l) s += 6;\n            if(!memcmp(s, \"module\", 6)) {\nldinitrd:       if(fw_open(a)) {\n                    fw_read(0, 16, (void*)tmp);\n                    /* if it's a gzip compressed module, then load it after bss, and uncompress to position */\n                    uncomp = 0;\n                    if(tmp[0] == 0x1f && tmp[1] == 0x8b)\n                        fw_read(file_size - 4, 4, (void*)&uncomp);\n                    else\n                    if(tmp[0] == 'G' && tmp[1] == 'U' && tmp[2] == 'D' && tmp[8] == 0x78)\n                        uncomp = (((tmp[4] | (tmp[5] << 8)) + 7) & ~7) + ((tmp[6] | (tmp[7] << 8)) << 4);\n                    ptr = (uint8_t*)(uintptr_t)file_buf;\n                    if(verbose) printf(\"Loading module (%llu bytes)...\\r\\n\", file_size);\n                    fw_read(0, file_size, (void*)(uncomp ? (uintptr_t)&_end : (uintptr_t)file_buf));\n                    if(uncomp) {\n                        if(verbose) printf(\"Uncompressing (%u bytes)...\\r\\n\", uncomp);\n                        uncompress((uint8_t*)&_end, (uint8_t*)(uintptr_t)file_buf, uncomp);\n                        file_size = uncomp;\n                    }\n                    file_buf += (file_size + 4095) & ~4095;\n                    /* if it's a DTB or a DSDT, don't add it to the modules list, add it to the ACPI tables */\n                    if(ptr[0] == 0xD0 && ptr[1] == 0x0D && ptr[2] == 0xFE && ptr[3] == 0xED) {\n                        if(verbose) printf(\"DTB detected...\\r\\n\");\n                        dsdt_ptr = (uint64_t)(uintptr_t)ptr;\n                    } else\n                    if(((ptr[0] == 'D' && ptr[1] == 'S') || (ptr[0] == 'G' && ptr[1] == 'U')) && ptr[2] == 'D' && ptr[3] == 'T') {\n                        if(verbose) printf(\"%c%cDT detected...\\n\", ptr[0], ptr[1]);\n                        dsdt_ptr = (uint64_t)(uintptr_t)ptr;\n                    } else {\n                        if(tags_ptr) {\n                            tag = (multiboot_tag_module_t*)tags_ptr;\n                            tag->type = MULTIBOOT_TAG_TYPE_MODULE;\n                            tag->size = sizeof(multiboot_tag_module_t) + e - a + 1;\n                            tag->mod_start = (uint32_t)(uintptr_t)ptr;\n                            tag->mod_end = file_buf;\n                            memcpy(tag->string, a, e - a); tag->string[e - a] = 0;\n                            if(verbose > 2) hexdump(ptr, 1);\n                            tags_ptr += (tag->size + 7) & ~7;\n                            if(!initrd) initrd = tag;\n                        }\n                        n++;\n                    }\n                    fw_close();\n                }\n            }\n            /* go to the next line */\n            s = e;\n        }\n    }\n    /* if no modules were loaded, but we have a default initrd name, try to add that */\n    if(!n && !f) { f = 1; a = bkp ? \"initramfs-linux-fallback.img\" : \"initramfs-linux.img\"; for(e = a; *e; e++){} goto ldinitrd; }\n#if CONFIG(LP_ARCH_X86)\n    if(!n && f == 1) { f = 2; a = bkp ? \"ibmpc/initrd.bak\" : \"ibmpc/initrd\"; e = a + (bkp ? 16 : 12); goto ldinitrd; }\n#endif\n    /* if still no modules were loaded, but we have a default initrd embedded, try to add that */\n    if(!n && f > 0 && !initrd && tags_ptr && (file_size = cbfs_get_size(\"initrd\"))) {\n        if(verbose) printf(\"Loading module (%llu bytes)...\\r\\n\", file_size);\n        ptr = (uint8_t*)(uintptr_t)file_buf;\n        file_size = cbfs_load(\"initrd\", ptr, file_size);\n        if(ptr[0] == 0x1f && ptr[1] == 0x8b) {\n            memcpy(&uncomp, ptr + file_size - 4, 4);\n            memcpy(ptr + uncomp + 4096, ptr, file_size);\n            if(verbose) printf(\"Uncompressing (%u bytes)...\\r\\n\", uncomp);\n            uncompress(ptr + uncomp + 4096, ptr, uncomp);\n            file_size = uncomp;\n        }\n        file_buf = (file_buf + file_size + 4095) & ~4095;\n        tag = initrd = (multiboot_tag_module_t*)tags_ptr;\n        tag->type = MULTIBOOT_TAG_TYPE_MODULE;\n        tag->size = sizeof(multiboot_tag_module_t) + 7 + 1;\n        tag->mod_start = (uint32_t)(uintptr_t)ptr;\n        tag->mod_end = file_buf;\n        memcpy(tag->string, \"initrd\", 7);\n        if(verbose > 2) hexdump(ptr, 1);\n        tags_ptr += (tag->size + 7) & ~7;\n    }\n}\n\n/**\n * Map virtual memory\n */\nint fw_map(uint64_t phys, uint64_t virt, uint32_t size)\n{\n    uint64_t end = virt + size, *ptr, *next = NULL, orig = page_buf;\n\n    /* is this a canonical address? We handle virtual memory up to 256TB */\n    if(!pt || ((virt >> 48L) != 0x0000 && (virt >> 48L) != 0xffff)) return 0;\n\n    /* walk the page tables and add the missing pieces */\n    for(virt &= ~4095, phys &= ~4095; virt < end; virt += 4096) {\n        /* 512G */\n        ptr = &pt[(virt >> 39L) & 511];\n        if(!*ptr) { if(!(*ptr = page_alloc())) return 0; else *ptr |= 3; }\n        /* 1G */\n        ptr = (uint64_t*)(uintptr_t)(*ptr & ~4095); ptr = &ptr[(virt >> 30L) & 511];\n        if(!*ptr) { if(!(*ptr = page_alloc())) return 0; else *ptr |= 3; }\n        /* 2M if we previously had a large page here, split it into 4K pages */\n        ptr = (uint64_t*)(uintptr_t)(*ptr & ~4095); ptr = &ptr[(virt >> 21L) & 511];\n        if(!*ptr || *ptr & 0x80) { if(!(*ptr = page_alloc())) return 0; else *ptr |= 3; }\n        /* 4K */\n        ptr = (uint64_t*)(uintptr_t)(*ptr & ~4095); ptr = &ptr[(virt >> 12L) & 511];\n        /* if this page is already mapped, that means the kernel has invalid, overlapping segments */\n        if(!*ptr) { *ptr = (uint64_t)(uintptr_t)next; next = ptr; }\n    }\n    /* resolve the linked list */\n    for(end = ((phys == orig ? page_buf : phys) + size - 1) & ~4095; next; end -= 4096, next = ptr) {\n        ptr = (uint64_t*)(uintptr_t)*next; *next = end | 3;\n    }\n    return 1;\n}\n\n/**\n * Load a kernel segment\n */\nint fw_loadseg(uint32_t offs, uint32_t filesz, uint64_t vaddr, uint32_t memsz)\n{\n    uint64_t top;\n    uint8_t *buf = (uint8_t*)(uintptr_t)vaddr;\n    uint32_t size, i;\n\n    if(!memsz || !file_size) return 1;\n    if(verbose > 1) printf(\"  segment %08x[%08x] -> %08llx[%08x]\\r\\n\", offs, filesz, vaddr, memsz);\n    size = (memsz + (vaddr & 4095) + 4095) & ~4095;\n    /* no overwriting of the loader data */\n    if(vaddr < 0x20000 + (TAGS_MAX + 2) * 4096 || (vaddr > 0x300000 && vaddr < 0x400000)) goto err;\n    if(vaddr > ram) {\n        /* possibly a higher-half kernel's segment, we must map it */\n        if(!fw_map(file_buf, vaddr, size)) goto err;\n        buf = (void*)(uintptr_t)file_buf; file_buf += size;\n    } else {\n        /* make sure we load modules after the kernel to avoid any conflict */\n        top = ((uintptr_t)buf + size + 4095) & ~4095; if(file_buf < top) file_buf = top;\n        /* let's see if the memory where the segment wants to be loaded is free or not */\n        for(i = 0; memmap && i < num_memmap; i++)\n            /* find which memory slot it fits */\n            if(memmap[i].base_addr <= vaddr && memmap[i].base_addr + memmap[i].length > vaddr) {\n                /* if that slot isn't free or the end doesn't fit in the slot too, then that's a problem */\n                if(memmap[i].type != MULTIBOOT_MEMORY_AVAILABLE ||\n                  memmap[i].base_addr + memmap[i].length < (vaddr & ~4095) + size)\n                    goto err;\n                break;\n            }\n        /* if no memory slots found, that's a dunno. Not used memory for sure, so let's try to load it, maybe works... */\n    }\n    if(filesz) {\n        if(kernel_mem) memcpy(buf, kernel_mem + offs, filesz);\n        else fw_read(offs, filesz, buf);\n    }\n    if(memsz > filesz) memset(buf + filesz, 0, memsz - filesz);\n    return 1;\nerr:printf(\"ERROR: unable to load segment %08llx[%x], memory already in use\\r\\n\", vaddr, memsz);\n    return 0;\n}\n\n/**\n * Load the kernel\n */\nint fw_loadkernel(void)\n{\n    void *p = (void*)kernel_buf;\n    linux_boot_t *hdr = (linux_boot_t*)(kernel_buf + 0x1f1);\n    pe_hdr *pe;\n    pe_sec *sec;\n    uint8_t *ptr;\n    uint64_t offs;\n    int i;\n\n    kernel_mem = NULL; file_buf = 0x100000;\n    /* do some heuristic on kernel name to allow multiple configurations */\n    if((!kernel || !*kernel || !memcmp(kernel, \"kernel\", 6)) && (offs = cbfs_get_size(\"kernel\"))) {\n        kernel_mem = (uint8_t*)(uintptr_t)file_buf;\n        file_size = cbfs_load(\"kernel\", kernel_mem, offs);\n        file_buf = (file_buf + file_size + 4095) & ~4095;\n        memcpy(kernel_buf, kernel_mem, sizeof(kernel_buf));\n    }\n    if(!kernel_mem && (!kernel || !*kernel || !fw_open(kernel))) {\n        if((!bkp || !fw_open(\"vmlinuz-fallback\")) && !fw_open(\"vmlinuz-linux\") && !fw_open(\"bzImage\") && !fw_open(\"kernel\")\n#if CONFIG(LP_ARCH_X86)\n          && !fw_open(\"ibmpc/core\")\n#endif\n          )\n            file_size = 0;\n    }\n    if(!file_size) {\n        printf(\"ERROR: kernel not found\\r\\n\");\n        smp = 0;\n        return 0;\n    } else\n    if(!kernel_mem)\n        fw_read(0, sizeof(kernel_buf), p);\n    /* we must check Linux before COFF/PE, because it might disguise itself as an EFI app */\n#if CONFIG(LP_ARCH_X86)\n    if(hdr->boot_flag == 0xAA55 && !memcmp(&hdr->header, HDRSMAG, 4)) {\n        if(hdr->version < 0x20c || ((hdr->pref_address + file_size) >> 32L)) {\n            printf(\"ERROR: unsupported Linux boot protocol version\\r\\n\"); goto err;\n        }\n        /* it's a Linux kernel */\n        kernel_mode = MODE_LIN; smp = 0;\n        if(verbose) printf(\"Loading Linux kernel...\\r\\n\");\n        zero_page = (linux_boot_params_t*)0x90000;\n        if(!hdr->setup_sects) hdr->setup_sects = 4;\n        memset(zero_page, 0, sizeof(linux_boot_params_t));\n        memcpy(&zero_page->hdr, hdr, 0x202 - 0x1f1 + kernel_buf[0x201]);\n        zero_page->hdr.root_dev = 0x100; zero_page->hdr.root_flags = 1; zero_page->hdr.vid_mode = 0xffff;\n        zero_page->hdr.type_of_loader = 0xff;\n        /*zero_page->hdr.type_of_loader = 0xe0; zero_page->hdr.ext_loader_type = 0x14;*/\n        if(cmdline) {\n            ptr = (uint8_t*)zero_page + sizeof(linux_boot_params_t);\n            zero_page->hdr.cmd_line_ptr = (uint32_t)(uintptr_t)ptr;\n            for(i = 0; i < 32767 && cmdline[i] && cmdline[i] != '\\r' && cmdline[i] != '\\n'; i++) ptr[i] = cmdline[i];\n            ptr[i] = 0;\n        }\n        if(!fw_loadseg((hdr->setup_sects + 1) * 512, hdr->init_size, hdr->pref_address, hdr->init_size)) goto err;\n        kernel_entry = (uint8_t*)(uintptr_t)hdr->pref_address + 512;\n    } else\n    if(!memcmp(((Elf32_Ehdr*)p)->e_ident, ELFMAG, 4) &&\n      (((Elf32_Ehdr*)p)->e_machine == EM_386 || ((Elf32_Ehdr*)p)->e_machine == EM_X86_64)) {\n        /* it's a Multiboot2 ELF kernel */\n        kernel_mode = ((Elf32_Ehdr*)p)->e_ident[EI_CLASS] == ELFCLASS64 ? MODE_MB64 : MODE_MB32;\n        if(verbose) printf(\"Loading Multiboot2 ELF%d kernel...\\r\\n\", kernel_mode == MODE_MB64 ? 64 : 32);\n        if(kernel_mode == MODE_MB64) {\n            kernel_entry = (uint8_t*)(uintptr_t)((Elf64_Ehdr*)p)->e_entry;\n            ptr = p + ((Elf64_Ehdr*)p)->e_phoff;\n            for(i = 0; !rq && i < ((Elf64_Ehdr*)p)->e_phnum && ptr + ((Elf64_Ehdr*)p)->e_phentsize < kernel_buf + sizeof(kernel_buf);\n              i++, ptr += ((Elf64_Ehdr*)p)->e_phentsize)\n                if(((Elf64_Phdr*)ptr)->p_type == PT_LOAD && !fw_loadseg(\n                    (((Elf64_Phdr*)ptr)->p_offset), (((Elf64_Phdr*)ptr)->p_filesz),\n                    (((Elf64_Phdr*)ptr)->p_vaddr), (((Elf64_Phdr*)ptr)->p_memsz))) goto err;\n        } else {\n            kernel_entry = (uint8_t*)(uintptr_t)((Elf32_Ehdr*)p)->e_entry;\n            ptr = p + ((Elf32_Ehdr*)p)->e_phoff;\n            for(i = 0; !rq && i < ((Elf32_Ehdr*)p)->e_phnum && ptr + ((Elf32_Ehdr*)p)->e_phentsize < kernel_buf + sizeof(kernel_buf);\n              i++, ptr += ((Elf32_Ehdr*)p)->e_phentsize)\n                if(((Elf32_Phdr*)ptr)->p_type == PT_LOAD && !fw_loadseg(\n                    ((Elf32_Phdr*)ptr)->p_offset, ((Elf32_Phdr*)ptr)->p_filesz,\n                    (uint64_t)((Elf32_Phdr*)ptr)->p_vaddr, ((Elf32_Phdr*)ptr)->p_memsz)) goto err;\n        }\n    } else\n    if(((mz_hdr*)p)->magic == MZ_MAGIC && ((pe_hdr*)(p + ((mz_hdr*)p)->peaddr))->magic == PE_MAGIC &&\n      (((pe_hdr*)(p + ((mz_hdr*)p)->peaddr))->machine == IMAGE_FILE_MACHINE_I386 ||\n       ((pe_hdr*)(p + ((mz_hdr*)p)->peaddr))->machine == IMAGE_FILE_MACHINE_AMD64)) {\n        /* it's a Multiboot2 COFF/PE kernel */\n        pe = (pe_hdr*)(p + ((mz_hdr*)p)->peaddr);\n        kernel_mode = pe->file_type == PE_OPT_MAGIC_PE32PLUS ? MODE_MB64 : MODE_MB32;\n        offs = kernel_mode == MODE_MB64 ? (uint32_t)pe->data.pe64.img_base : pe->data.pe32.img_base;\n        kernel_entry = offs + (uint8_t*)(uintptr_t)pe->entry_point;\n        if(verbose) printf(\"Loading Multiboot2 PE%d kernel...\\r\\n\", kernel_mode == MODE_MB64 ? 64 : 32);\n        sec = (pe_sec*)((uint8_t*)pe + pe->opt_hdr_size + 24);\n        for(i = 0; !rq && i < pe->sections && (uint8_t*)&sec[1] < kernel_buf + sizeof(kernel_buf); i++, sec++)\n            if(!fw_loadseg(sec->raddr, sec->rsiz,\n                /* the PE section vaddr field is only 32 bits, we must make sure that it properly sign extended to 64 bit */\n                offs + (pe->file_type == PE_OPT_MAGIC_PE32PLUS ? (int64_t)(int32_t)sec->vaddr : sec->vaddr), sec->vsiz)) goto err;\n    } else\n#endif\n#if CONFIG(LP_ARCH_ARM64)\n    if(!memcmp(kernel_buf, \"MZ\", 2) && !memcmp(kernel_buf + 0x38, \"ARM\", 3) && kernel_buf[0x3b] == 64) {\n        /* it's a Linux kernel */\n        kernel_mode = MODE_LIN; smp = 0;\n        if(verbose) printf(\"Loading Linux kernel...\\r\\n\");\n        if(!fw_loadseg(0, file_size, 0x80000, file_size)) goto err;\n    } else\n    if(!memcmp(((Elf64_Ehdr*)p)->e_ident, ELFMAG, 4) && ((Elf64_Ehdr*)p)->e_ident[EI_CLASS] == ELFCLASS64 &&\n      ((Elf64_Ehdr*)p)->e_machine == EM_AARCH64) {\n        /* it's a Multiboot2 ELF kernel */\n        kernel_mode = MODE_MB64;\n        kernel_entry = (uint8_t*)(uintptr_t)((Elf64_Ehdr*)p)->e_entry;\n        if(verbose) printf(\"Loading Multiboot2 ELF64 kernel...\\r\\n\");\n        ptr = p + ((Elf64_Ehdr*)p)->e_phoff;\n        for(i = 0; !rq && i < ((Elf64_Ehdr*)p)->e_phnum && ptr + ((Elf64_Ehdr*)p)->e_phentsize < kernel_buf + sizeof(kernel_buf);\n          i++, ptr += ((Elf64_Ehdr*)p)->e_phentsize)\n            if(((Elf64_Phdr*)ptr)->p_type == PT_LOAD && !fw_loadseg(\n                (((Elf64_Phdr*)ptr)->p_offset), (((Elf64_Phdr*)ptr)->p_filesz),\n                (((Elf64_Phdr*)ptr)->p_vaddr), (((Elf64_Phdr*)ptr)->p_memsz))) goto err;\n    } else\n    if(((mz_hdr*)p)->magic == MZ_MAGIC && ((pe_hdr*)(p + ((mz_hdr*)p)->peaddr))->magic == PE_MAGIC &&\n       ((pe_hdr*)(p + ((mz_hdr*)p)->peaddr))->file_type == PE_OPT_MAGIC_PE32PLUS &&\n       ((pe_hdr*)(p + ((mz_hdr*)p)->peaddr))->machine == IMAGE_FILE_MACHINE_ARM64) {\n        /* it's a Multiboot2 COFF/PE kernel */\n        pe = (pe_hdr*)(p + ((mz_hdr*)p)->peaddr);\n        offs = (uint32_t)pe->data.pe64.img_base;\n        kernel_mode = MODE_MB64;\n        kernel_entry = offs + (uint8_t*)(uintptr_t)pe->entry_point;\n        if(verbose) printf(\"Loading Multiboot2 PE64 kernel...\\r\\n\");\n        sec = (pe_sec*)((uint8_t*)pe + pe->opt_hdr_size + 24);\n        for(i = 0; !rq && i < pe->sections && (uint8_t*)&sec[1] < kernel_buf + sizeof(kernel_buf); i++, sec++)\n            /* the PE section vaddr field is only 32 bits, we must make sure that it properly sign extended to 64 bit */\n            if(!fw_loadseg(sec->raddr, sec->rsiz, offs + (int64_t)(int32_t)sec->vaddr, sec->vsiz)) goto err;\n    } else\n#endif\n    {\n        printf(\"ERROR: unknown kernel format\\r\\n\");\nerr:    fw_close();\n        smp = 0;\n        return 0;\n    }\n    fw_close();\n    if(kernel_mode != MODE_MB64) smp = 0;\n    return 1;\n}\n\n/**\n * Finish up MBI tags\n */\nvoid fw_fini(void)\n{\n    int i, n = 0;\n    fadt_t *fadt;\n    multiboot_tag_t *t;\n    multiboot_tag_smp_t *st = NULL;\n    uint8_t *rsdt = NULL, *lapic = NULL, *p, *q, *e, *ptr, *end, s;\n    static uint8_t ids[256];\n#if CONFIG(LP_ARCH_X86)\n    uint32_t a;\n#endif\n#if CONFIG(LP_ARCH_ARM64)\n    register uint64_t reg;\n#endif\n\n    if(tags_ptr && vidmode.framebuffer_addr) {\n        vidmode.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;\n        vidmode.size = sizeof(vidmode);\n        vidmode.framebuffer_type = 1;\n        vidmode.reserved = 0;\n        memcpy(tags_ptr, &vidmode, vidmode.size);\n        tags_ptr += (vidmode.size + 7) & ~7;\n    }\n    if(tags_ptr) {\n        if(dsdt_ptr && !(\n          (((uint8_t*)(uintptr_t)dsdt_ptr)[0] == 0xD0 && ((uint8_t*)(uintptr_t)dsdt_ptr)[1] == 0x0D &&\n          ((uint8_t*)(uintptr_t)dsdt_ptr)[2] == 0xFE && ((uint8_t*)(uintptr_t)dsdt_ptr)[3] == 0xED) ||\n          (((((uint8_t*)(uintptr_t)dsdt_ptr)[0] == 'D' && ((uint8_t*)(uintptr_t)dsdt_ptr)[1] == 'S') ||\n          (((uint8_t*)(uintptr_t)dsdt_ptr)[0] == 'G' && ((uint8_t*)(uintptr_t)dsdt_ptr)[1] == 'U')) &&\n          ((uint8_t*)(uintptr_t)dsdt_ptr)[2] == 'D' && ((uint8_t*)(uintptr_t)dsdt_ptr)[3] == 'T'))) dsdt_ptr = 0;\n        /* look for the RSD PTR */\n        for(t = (multiboot_tag_t*)(tags_buf + sizeof(multiboot_info_t)); (uint8_t*)t < tags_ptr;\n          t = (multiboot_tag_t*)((uint8_t*)t + ((t->size + 7) & ~7))) {\n            if(t->type == MULTIBOOT_TAG_TYPE_ACPI_OLD || t->type == MULTIBOOT_TAG_TYPE_ACPI_NEW) {\n                rsdt = t->type == MULTIBOOT_TAG_TYPE_ACPI_OLD ?\n                    (uint8_t*)(uintptr_t)*((uint32_t*)&((multiboot_tag_old_acpi_t*)t)->rsdp[16]) :\n                    (uint8_t*)(uintptr_t)*((uint64_t*)&((multiboot_tag_new_acpi_t*)t)->rsdp[24]);\n                /* found RSDP, iterate on ACPI tables */\n                if((rsdt[0] == 'R' || rsdt[0] == 'X') && !memcmp(rsdt + 1, \"SDT\", 3))\n                    for(ptr = rsdt + 36, end = (uint8_t*)(rsdt + ((fadt_t*)rsdt)->hdr.size); ptr < end;\n                      ptr += rsdt[0] == 'X' ? 8 : 4) {\n                        p = rsdt[0] == 'X' ? (uint8_t*)((uintptr_t)*((uint64_t*)ptr)) : (uint8_t*)((uintptr_t)*((uint32_t*)ptr));\n                        fadt = (fadt_t*)p;\n                        /* found FADT, patch DSDT addresses and recalculate checksum */\n                        if(dsdt_ptr && !memcmp(&fadt->hdr.magic, \"FACP\", 4)) {\n                            fadt->dsdt = (uint32_t)dsdt_ptr;\n                            if(fadt->hdr.rev >= 2 && fadt->hdr.size > sizeof(fadt_t)) fadt->x_dsdt = dsdt_ptr;\n                            fadt->hdr.chksum = 0;\n                            for(s = 0, i = 0; i < (int)fadt->hdr.size; i++) { s += *(((uint8_t*)fadt) + i); }\n                            fadt->hdr.chksum = 0x100 - s;\n                        } else\n                        if(smp && !memcmp(p, \"APIC\", 4)) {\n                            if(!lapic) lapic = (uint8_t*)(uintptr_t)(*((uint32_t*)(p + 0x24)));\n                            for(n = 0, q = p + 44, e = p + *((uint32_t*)(p + 4)); q < e && q[1]; q += q[1])\n                                switch(q[0]) {\n                                    case 0: if((q[4] & 1) && q[3] != 0xFF) ids[n++] = q[3]; break;\n                                    case 5: lapic = (uint8_t*)(uintptr_t)*((uint64_t*)(q + 4)); break;\n                                }\n                        }\n                    }\n            }\n        }\n        /* multicore */\n        if(smp) {\n            ((multiboot_tag_smp_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_SMP;\n            ((multiboot_tag_smp_t*)tags_ptr)->size = sizeof(multiboot_tag_smp_t);\n            st = (multiboot_tag_smp_t*)tags_ptr;\n            st->numcores = st->running = st->bspid = 0;\n#if CONFIG(LP_ARCH_X86)\n            st->numcores = n; st->running = 1;\n            __asm__ __volatile__ (\"movl $1, %%eax; cpuid; shrl $24, %%ebx;\" : \"=b\"(a) : : );\n            st->bspid = a; *((uint64_t*)0x8fff8) = a;\n#endif\n#if CONFIG(LP_ARCH_ARM64)\n            ((multiboot_tag_smp_t*)tags_ptr)->numcores = ((multiboot_tag_smp_t*)tags_ptr)->running = n = 4;\n#endif\n            tags_ptr += (((multiboot_tag_smp_t*)tags_ptr)->size + 7) & ~7;\n        }\n        /* partition UUIDs */\n        ((multiboot_tag_partuuid_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_PARTUUID;\n        ((multiboot_tag_partuuid_t*)tags_ptr)->size = 24;\n        memcpy(((multiboot_tag_partuuid_t*)tags_ptr)->bootuuid, &bootuuid, sizeof(guid_t));\n        tags_ptr += (((multiboot_tag_partuuid_t*)tags_ptr)->size + 7) & ~7;\n        /* terminator tag */\n        ((multiboot_tag_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_END;\n        ((multiboot_tag_t*)tags_ptr)->size = 8;\n        tags_ptr += (((multiboot_tag_t*)tags_ptr)->size + 7) & ~7;\n        ((multiboot_info_t*)tags_buf)->total_size = tags_ptr - tags_buf;\n    } else tags_buf = NULL;\n\n    if(kernel_mode == MODE_LIN && zero_page) {\n        if(memmap && num_memmap) {\n            for(i = 0; (uint32_t)i < num_memmap && i < E820_MAX_ENTRIES_ZEROPAGE; i++) {\n                zero_page->e820_table[i].addr = memmap[i].base_addr;\n                zero_page->e820_table[i].size = memmap[i].length;\n                zero_page->e820_table[i].type = memmap[i].type;\n            }\n            zero_page->e820_entries = i;\n        }\n        if(vidmode.framebuffer_addr) {\n            zero_page->lfb_width = vidmode.framebuffer_width;\n            zero_page->lfb_height = vidmode.framebuffer_height;\n            zero_page->lfb_depth = vidmode.framebuffer_bpp;\n            zero_page->lfb_base = vidmode.framebuffer_addr;\n            zero_page->lfb_size = (vidmode.framebuffer_pitch * vidmode.framebuffer_height * vidmode.framebuffer_bpp) >> 3;\n            zero_page->lfb_linelength = vidmode.framebuffer_pitch;\n            zero_page->red_size = vidmode.framebuffer_red_mask_size;\n            zero_page->red_pos = vidmode.framebuffer_red_field_position;\n            zero_page->green_size = vidmode.framebuffer_green_mask_size;\n            zero_page->green_pos = vidmode.framebuffer_green_field_position;\n            zero_page->blue_size = vidmode.framebuffer_blue_mask_size;\n            zero_page->blue_pos = vidmode.framebuffer_blue_field_position;\n            zero_page->orig_video_isVGA = VIDEO_TYPE_VLFB;\n            zero_page->hdr.vid_mode = VIDEO_MODE_CUR;\n        }\n        zero_page->acpi_rsdp_addr = rsdp_ptr;\n        if(initrd) {\n            zero_page->hdr.ramdisk_image = initrd->mod_start;\n            zero_page->hdr.ramdisk_size = initrd->mod_end - initrd->mod_start;\n        }\n    }\n#if CONFIG(LP_ARCH_X86)\n    /* new GDT (this must be below 1M because we need it in real mode) */\n    __asm__ __volatile__(\"repnz stosb\"::\"D\"(0x500),\"a\"(0),\"c\"(256):);\n    *((uint16_t*)0x510) = 0x3F; *((uint32_t*)0x512) = 0x560;            /* value */\n    *((uint32_t*)0x568) = 0x0000FFFF; *((uint32_t*)0x56C) = 0x00009800; /*   8 - legacy real cs */\n    *((uint32_t*)0x570) = 0x0000FFFF; *((uint32_t*)0x574) = 0x00CF9A00; /*  16 - prot mode cs */\n    *((uint32_t*)0x578) = 0x0000FFFF; *((uint32_t*)0x57C) = 0x00CF9200; /*  24 - prot mode ds */\n    *((uint32_t*)0x580) = 0x0000FFFF; *((uint32_t*)0x584) = 0x00AF9A00; /*  32 - long mode cs */\n    *((uint32_t*)0x588) = 0x0000FFFF; *((uint32_t*)0x58C) = 0x00CF9200; /*  40 - long mode ds */\n    *((uint32_t*)0x590) = 0x00000068; *((uint32_t*)0x594) = 0x00008900; /*  48 - long mode tss descriptor */\n    *((uint32_t*)0x598) = 0x00000000; *((uint32_t*)0x59C) = 0x00000000; /*       cont. */\n    if(smp && n > 1 && lapic && st) {\n/* Memory layout (only valid when kernel entry isn't zero)\n *    0x510 -   0x520   GDT value\n *    0x520 -   0x530   IDT value (not used)\n *    0x530 -   0x538   page table root\n *    0x538 -   0x540   kernel entry point (also SMP semaphor)\n *    0x540 -   0x548   tags_buf\n *    0x548 -   0x550   CPU clockcycles in 1 msec\n *    0x550 -   0x558   lapic address\n *    0x558 -   0x559   AP is running flag\n *    0x560 -   0x590   GDT table\n */\n        if(verbose) printf(\"Initializing SMP (%d cores)...\\n\", n);\n        *((volatile uint64_t*)0x530) = (uint64_t)(uintptr_t)pt;\n        *((volatile uint64_t*)0x538) = (uint64_t)0;\n        *((volatile uint64_t*)0x540) = (uintptr_t)tags_buf;\n        *((volatile uint64_t*)0x550) = (uint64_t)(uintptr_t)lapic;\n        /* relocate AP startup code to 0x8000 */\n        __asm__ __volatile__(\n        /* relocate code */\n        \".byte 0xe8;.long 0;\"\n        \"1:popl %%esi;addl $1f - 1b, %%esi;movl $0x8000, %%edi;movl $99f - 1f, %%ecx;repnz movsb;jmp 99f;\"\n        /* do the real mode -> prot mode -> long mode trampoline */\n        \"1:.code16;cli;cld;xorw %%ax, %%ax;movw %%ax, %%ds;incb (0x558);\"\n        /* spinlock waiting for the kernel entry address */\n        \"2:pause;cmpl $0, (0x538);jnz 3f;cmpl $0, (0x53C);jz 2b;3:;\"\n        /* initialize AP */\n        \"lgdt (0x510);movl %%cr0, %%eax;orb $1, %%al;movl %%eax, %%cr0;\"\n        \".code32;ljmp $16,$2f-1b+0x108000;2:;\"\n        \"movw $24, %%ax;movw %%ax, %%ds;\"\n        \"movl (0x530), %%eax;movl %%eax, %%cr3;\"\n        \"movl $0xE0, %%eax;movl %%eax, %%cr4;\"\n        \"movl $0x0C0000080, %%ecx;rdmsr;btsl $8, %%eax;wrmsr;\"\n        \"movl %%cr0, %%eax;xorb %%cl, %%cl;orl %%ecx, %%eax;btcl $16, %%eax;btsl $31, %%eax;movl %%eax, %%cr0;\"\n        \"lgdt (0x510);ljmp $32,$1f-1b+0x8000;\"\n        \".code64;1:;lgdt (0x510);movw $40, %%ax;movw %%ax, %%ds;movw %%ax, %%es;movw %%ax, %%ss;\"\n        \"xorq %%rax, %%rax;lidt (%%rax);movq (0x550), %%rbx;\"\n        /* enable lapic */\n        \"movl $0x1000000, 0xD0(%%rbx);movl $0xFFFFFFFF, 0xE0(%%rbx);\"\n        \"movl 0xF0(%%rbx), %%eax;orl $0x100, %%eax;movl %%eax,0xF0(%%rbx);\"\n        \"movl $0, 0x80(%%rbx);movl $0, 0x280(%%rbx);movl 0x280(%%rbx), %%eax;movl 0x20(%%rbx), %%eax;\"\n        \"shrl $24, %%eax;andq $0xff, %%rax;movq %%rax, %%rbx;shll $10, %%eax;\"\n        /* execute 64-bit kernel */\n        \"movq $0x90000, %%rsp;subq %%rax, %%rsp;movq %%rsp, %%rbp;pushq %%rbx;\"             /* stack = 0x90000 - coreid * 1024 */\n        \"movq (0x530), %%rax;movq %%rax, %%cr3;\"                                            /* kick the MMU to flush cache */\n        \"xorq %%rax, %%rax;movl $0x36d76289, %%eax;movq %%rax, %%rcx;movq %%rax, %%rdi;\"    /* set arguments */\n        \"movq (0x540), %%rbx;movq %%rbx, %%rdx;movq %%rbx, %%rsi;\"\n        /* execute 64-bit kernel (stack: 8 byte aligned, and contains the core's id) */\n        /* note: the entry point's function prologue will push rbp, and after that the stack becomes 16 byte aligned as expected */\n        \"movq (0x538), %%r8;jmp *%%r8;\"                                                     /* jump to kernel entry */\n        \"99:;.code32;\":::);\n\n        /* enable Local APIC */\n        *((volatile uint32_t*)(lapic + 0x0D0)) = (1 << 24);\n        *((volatile uint32_t*)(lapic + 0x0E0)) = 0xFFFFFFFF;\n        *((volatile uint32_t*)(lapic + 0x0F0)) = *((volatile uint32_t*)(lapic + 0x0F0)) | 0x1FF;\n        *((volatile uint32_t*)(lapic + 0x080)) = 0;\n        st->bspid = *((volatile uint32_t*)(lapic + 0x20)) >> 24; *((uint64_t*)0x8fff8) =  st->bspid;\n        /* initialize APs */\n        for(i = 0; i < n; i++) {\n            if(ids[i] == st->bspid) continue;\n            *((volatile uint32_t*)(lapic + 0x280)) = 0;                 /* clear APIC errors */\n            a = *((volatile uint32_t*)(lapic + 0x280));\n            send_ipi(ids[i], 0xfff00000, 0x00C500);                     /* trigger INIT IPI */\n            sleep(1);\n            send_ipi(ids[i], 0xfff00000, 0x008500);                     /* deassert INIT IPI */\n        }\n        sleep(10);                                                      /* wait 10 msec */\n        /* start APs */\n        for(i = 0; i < n; i++) {\n            if(ids[i] == st->bspid) continue;\n            *((volatile uint8_t*)0x558) = 0;\n            send_ipi(ids[i], 0xfff0f800, 0x004608);                     /* trigger SIPI, start at 0800:0000h */\n            for(a = 250; !*((volatile uint8_t*)0x558) && a > 0; a--)    /* wait for AP with 250 msec timeout */\n                sleep(1);\n            if(!*((volatile uint8_t*)0x558)) {\n                send_ipi(ids[i], 0xfff0f800, 0x004608);\n                sleep(250);\n            }\n            if(*((volatile uint8_t*)0x558)) st->running++;\n        }\n    } else smp = 0;\n#endif\n#if CONFIG(LP_ARCH_ARM64)\n    /* enable paging */\n    reg=(0xFF << 0) |    /* Attr=0: normal, IWBWA, OWBWA, NTR */\n        (0x04 << 8) |    /* Attr=1: device, nGnRE (must be OSH too) */\n        (0x44 <<16);     /* Attr=2: non cacheable */\n    __asm__ __volatile__(\"msr mair_el1, %0\" ::\"r\"(reg):);\n    *((uint64_t*)0x518) = reg;\n    __asm__ __volatile__(\"mrs %0, id_aa64mmfr0_el1\" :\"=r\"(reg)::);\n    reg = (reg & 0xF) << 32L; /* IPS=autodetected */\n    reg=(0x00LL << 37) | /* TBI=0, no tagging */\n        (0x02LL << 30) | /* TG1=4k */\n        (0x03LL << 28) | /* SH1=3 inner */\n        (0x01LL << 26) | /* ORGN1=1 write back */\n        (0x01LL << 24) | /* IRGN1=1 write back */\n        (0x00LL << 23) | /* EPD1 undocumented by ARM DEN0024A Fig 12-5, 12-6 */\n        (25LL   << 16) | /* T1SZ=25, 3 levels (512G) */\n        (0x00LL << 14) | /* TG0=4k */\n        (0x03LL << 12) | /* SH0=3 inner */\n        (0x01LL << 10) | /* ORGN0=1 write back */\n        (0x01LL << 8) |  /* IRGN0=1 write back */\n        (0x00LL << 7) |  /* EPD0 undocumented by ARM DEN0024A Fig 12-5, 12-6 */\n        (25LL   << 0);   /* T0SZ=25, 3 levels (512G) */\n    __asm__ __volatile__(\"msr tcr_el1, %0; isb\" ::\"r\" (reg):);\n    *((uint64_t*)0x520) = reg;\n    __asm__ __volatile__(\"msr ttbr0_el1, %0\" ::\"r\"((uintptr_t)pt + 1):);\n    *((uint64_t*)0x528) = (uintptr_t)pt + 1;\n    __asm__ __volatile__(\"msr ttbr1_el1, %0\" ::\"r\"((uintptr_t)pt + 1 + 4096):);\n    *((uint64_t*)0x530) = (uintptr_t)pt + 1 + 4096;\n    /* set mandatory reserved bits */\n    __asm__ __volatile__(\"dsb ish; isb; mrs %0, sctlr_el1\" :\"=r\"(reg)::);\n    reg |= 0xC00801;\n    reg&=~( (1<<25) |   /* clear EE, little endian translation tables */\n            (1<<24) |   /* clear E0E */\n            (1<<19) |   /* clear WXN */\n            (1<<12) |   /* clear I, no instruction cache */\n            (1<<4) |    /* clear SA0 */\n            (1<<3) |    /* clear SA */\n            (1<<2) |    /* clear C, no cache at all */\n            (1<<1));    /* clear A, no aligment check */\n    __asm__ __volatile__(\"msr sctlr_el1, %0; isb\" ::\"r\"(reg):);\n    *((uint64_t*)0x508) = reg;\n    if(smp) {\n        if(verbose) printf(\"Initializing SMP (%d cores)...\\n\", n);\n        *((uint64_t*)0x540) = (uintptr_t)tags_buf;\n        *((uint64_t*)0x538) = 0;\n/* Memory layout (only valid when kernel entry isn't zero)\n *    0x508 -   0x510   sctlr\n *    0x510 -   0x518   vbar\n *    0x518 -   0x520   mair\n *    0x520 -   0x528   tcr\n *    0x528 -   0x530   ttbr0\n *    0x530 -   0x538   ttbr1\n *    0x538 -   0x540   kernel entry point (also SMP semaphor)\n *    0x540 -   0x548   tags_buf\n */\n        __asm__ __volatile__(\n        \"mov w2, %w0; mov x1, x30; bl 1f;1:mov x0, x30;mov x30, x1;add x0, x0, #2f-1b;\"\n        \"mov x1, #0xE0; 9:str x0, [x1], #0;add x1, x1, #8;sub w2, w2, #1;cbnz w2, 9b; b 99f;\"\n        \"2:mov x1, #0x1000;\"\n        \"mrs x0, CurrentEL;and x0, x0, #12;\"\n        \"cmp x0, #12;bne 1f;\"                           /* are we running at EL3? */\n        \"mov x0, #0x5b1;msr scr_el3, x0;mov x0, #0x3c9;msr spsr_el3, x0;adr x0, 1f;msr elr_el3, x0;mov x0, #4;msr sp_el2, x1;eret;\"\n        \"1:cmp x0, #4;beq 1f;\"                          /* are we running at EL2? */\n        \"mrs x0,cnthctl_el2;orr x0,x0,#3;msr cnthctl_el2,x0;msr cnthp_ctl_el2,xzr;\"         /* enable CNTP */\n        \"mov x0,#(1 << 31);orr x0,x0,#2;msr hcr_el2,x0;mrs x0,hcr_el2;\"                     /* enable Aarch64 at EL1 */\n        \"mrs x0,midr_el1;mrs x2,mpidr_el1;msr vpidr_el2,x0;msr vmpidr_el2,x2;\"              /* initialize virtual MPIDR */\n        \"mov x0,#0x33FF;msr cptr_el2,x0;msr hstr_el2,xzr;mov x0,#(3<<20);msr cpacr_el1,x0;\" /* disable coprocessor traps */\n        \"mov x2,#0x0800;movk x2,#0x30d0,lsl #16;msr sctlr_el1, x2;\"                         /* setup SCTLR access */\n        \"mov x2,#0x3c5;msr spsr_el2,x2;adr x2, 1f;msr elr_el2, x2;mov sp, x1;msr sp_el1, x1;eret;\"/* switch to EL1 */\n        \"1:mov sp, x1;mov x2, #0x500;ldr x0, [x2], #0x10;msr vbar_el1,x0;msr SPSel,#0;\"     /* set up exception handlers */\n        /* spinlock waiting for the kernel entry address */\n        \"1:ldr x30, [x2], #0x38;nop;nop;nop;nop;cbz x30, 1b;\"\n        /* initialize AP */\n        \"ldr x0, [x2], #0x18;msr mair_el1,x0;\"\n        \"ldr x0, [x2], #0x20;msr tcr_el1,x0;\"\n        \"ldr x0, [x2], #0x28;msr ttbr0_el1,x0;\"\n        \"ldr x0, [x2], #0x30;msr ttbr1_el1,x0;\"\n        \"ldr x0, [x2], #0x08;dsb ish;msr sctlr_el1,x0;isb;\"\n        /* execute 64-bit kernel (stack: 16 byte aligned, and contains the core's id) */\n        \"mov sp, #0x80000;mrs x0, mpidr_el1;and x0, x0, #3;lsl x1,x0,#10;sub sp,sp,x1;\"     /* stack = 0x80000 - coreid * 1024 */\n        \"str x0, [sp, #-16]!;ldr x0, =0x36d76289;ldr x1, [x2], #0x40;ret;\"                  /* jump to kernel entry */\n        \"99:\"::\"r\"(n - 1):);\n    }\n#endif\n    *((uint64_t*)0x558) = 0;\n}\n\n/*****************************************\n *     Simpleboot loader entry point     *\n *****************************************/\nint main(void)\n{\n    fw_init();\n    printf(\"Simpleboot loader, Copyright (c) 2023 bzt, MIT license\\r\\n\");\n    /* now that we can display error messages, let's see if we got everything we need */\n    if(!pt) { printf(\"ERROR: unable to allocate memory\\r\\n\"); goto err; }\n    if(!root_dir) { printf(\"ERROR: unable to locate boot partition\\r\\n\"); }\n\n    /* load and parse simpleboot.cfg */\nagain:\n    fw_loadconfig();\n    fw_loadsetup();\n    if(ram < 64) { printf(\"ERROR: unable to determine the amount of RAM\\r\\n\"); goto err; }\n    else if(verbose && !bkp) printf(\"Physical RAM %llu Megabytes\\r\\n\", ram / 1024 / 1024 + 2);\n\n    /* now we have the kernel's filename, try to load that, it's a critical error if fails */\n    if(!fw_loadkernel()) goto err;\n    /* last step, load modules too */\n    fw_loadmodules();\n    /* if the user pressed a key during loading, fallback to backup and do over */\n    if(!bkp && rq) { bkp++; rq = 0; goto again; }\n\n    /* finish up things, finalize tags list */\n    fw_fini();\n\n    /* transfer control to kernel. Should never return */\n    if(!kernel_entry) { printf(\"ERROR: no kernel entry point\\r\\n\"); goto err; }\n    if(verbose > 2) { printf(\"Kernel entry:\\r\\n\"); hexdump(kernel_entry, 4); }\n\n    switch(kernel_mode) {\n#if CONFIG(LP_ARCH_X86)\n        case MODE_MB32:\n            if(verbose > 1)\n                printf(\"Transfering prot mode control to %08lx(%08x, %08lx[%lx])\\r\\n\", (uintptr_t)kernel_entry,\n                    MULTIBOOT2_BOOTLOADER_MAGIC, (uintptr_t)tags_buf, (uintptr_t)(tags_ptr - tags_buf));\n            /* execute 32-bit kernels in protected mode */\n            *((uint32_t*)0x8fffc) = (uint32_t)(uintptr_t)tags_buf;\n            *((uint32_t*)0x8fff8) = MULTIBOOT2_BOOTLOADER_MAGIC;\n            *((uint32_t*)0x8fff4) = 0xDEADBEEF;\n            __asm__ __volatile__(\n            \"xorl %%eax, %%eax;lidt (%%eax);\"           /* disable IDT */\n            /* CDECL uses the stack for arguments, but fastcall uses %ecx, %edx */\n            \"movl $0x8fff4, %%esp; movl %%esp, %%ebp;\"\n            \"movl 8(%%esp), %%edx;movl %%edx, %%ebx;movl 4(%%esp), %%eax; movl %%eax, %%ecx;\"\n            \"cli;cld;jmp *%%esi;\"\n            ::\"S\"(kernel_entry):);\n        break;\n        case MODE_MB64:\n            if(verbose > 1)\n                printf(\"Transfering long mode control to %08lx(%08x, %08lx[%lx])\\r\\n\", (uintptr_t)kernel_entry,\n                    MULTIBOOT2_BOOTLOADER_MAGIC, (uintptr_t)tags_buf, (uintptr_t)(tags_ptr - tags_buf));\n            /* tell APs to execute kernel */\n            if(smp) { *((volatile uint64_t*)0x538) = (uintptr_t)kernel_entry; __asm__ __volatile__(\"pause\":::\"memory\"); }\n            /* execute 64-bit kernels in long mode */\n            __asm__ __volatile__(\n            \"movl $0x1000, %%eax; movl %%eax, %%cr3;\"   /* page tables */\n            \"movl $0x00E0, %%eax; movl %%eax, %%cr4;\"   /* set PAE, MCE, PGE; clear everything else */\n            \"movl $0xC0000080, %%ecx;\"\n            \"rdmsr; btsl $8, %%eax; wrmsr;\"             /* EFER MSR */\n            \"movl $0xC0000011, %%eax;movl %%eax, %%cr0;\"/* clear EM, MP, WP, enable paging with cache disabled (set PE, CD) */\n            \"lgdt (0x510);ljmp $32, $1f;.code64;1:;\"    /* set segments */\n            \"movw $40, %%ax;movw %%ax, %%ds;movw %%ax, %%es;movw %%ax, %%ss;\"\n            \"xorq %%rax, %%rax;lidt (%%rax);\"           /* disable IDT */\n            \"movq $0x90000, %%rsp; movq %%rsp, %%rbp; subl $8, %%esp;\"\n            \"movq %%rbx, %%r8;\"\n            \"movq %%rdi, %%rcx; movq %%rdi, %%rax;\"\n            \"movq %%rsi, %%rdx; movq %%rsi, %%rbx;\"\n            \"cli;cld;jmp *%%r8;.code32;\"\n            ::\"D\"(MULTIBOOT2_BOOTLOADER_MAGIC),\"S\"(tags_buf),\"b\"(kernel_entry):);\n        break;\n        case MODE_LIN:\n            if(verbose > 1)\n                printf(\"Transfering long mode control to %08lx(%08lx)\\r\\n\", (uintptr_t)kernel_entry, (uintptr_t)zero_page);\n            /* execute Linux kernel in 64 bit mode */\n            __asm__ __volatile__(\n            \"movl $0x1000, %%eax; movl %%eax, %%cr3;\"   /* page tables */\n            \"movl $0x00E0, %%eax; movl %%eax, %%cr4;\"   /* set PAE, MCE, PGE; clear everything else */\n            \"movl $0xC0000080, %%ecx;\"\n            \"rdmsr; btsl $8, %%eax; wrmsr;\"             /* EFER MSR */\n            \"movl $0xC0000011, %%eax;movl %%eax, %%cr0;\"/* clear EM, MP, WP, enable paging with cache disabled (set PE, CD) */\n            \"lgdt (0x510);ljmp $32, $1f;.code64;1:;\"    /* set segments */\n            \"movw $40, %%ax;movw %%ax, %%ds;movw %%ax, %%es;movw %%ax, %%ss;\"\n            \"xorq %%rax, %%rax;lidt (%%rax);\"           /* disable IDT */\n            \"movq $0x90000, %%rsp; movq %%rsp, %%rbp;\"\n            \"cli;cld;jmp *%%rbx;.code32;\"\n            ::\"S\"(zero_page),\"b\"(kernel_entry):);\n        break;\n#endif\n#if CONFIG(LP_ARCH_ARM64)\n        case MODE_MB64:\n            if(verbose > 1)\n                printf(\"Transfering control to %08x(%08x, %08x[%x])\\r\\n\", kernel_entry,\n                    MULTIBOOT2_BOOTLOADER_MAGIC, tags_buf, tags_ptr - tags_buf);\n            if(smp) {\n                /* tell APs to execute kernel */\n                *((volatile uint64_t*)0x538) = (uintptr_t)kernel_entry; __asm__ __volatile__(\"dsb ish\":::\"memory\");\n                /* execute 64-bit kernels in long mode */\n                __asm__ __volatile__(\n                \"ldr x0, =tags_buf; ldr x1, [x0], #0;\"  /* MBI tags pointer */\n                \"ldr x0, =0x36d76289;\"                  /* magic */\n                \"mov sp, #0x80000;str xzr, [sp, #-16]!;\"/* stack, bsp id on top */\n                \"mov x30, %0; ret\"                      /* jump to entry point */\n                ::\"r\"(kernel_entry):);\n            } else {\n                __asm__ __volatile__(\n                \"ldr x0, =tags_buf; ldr x1, [x0], #0;\"  /* MBI tags pointer */\n                \"ldr x0, =0x36d76289;\"                  /* magic */\n                \"mov sp, #0x80000; mov x30, %0; ret\"    /* stack and jump to entry point */\n                ::\"r\"(kernel_entry):);\n            }\n        break;\n        case MODE_LIN:\n            if(verbose > 1)\n                printf(\"Transfering control to 80000\\r\\n\");\n            __asm__ __volatile__(\n            \"mov x0, %0; mov x1, xzr; mov x2, xzr; mov x3, xzr;\"\n            \"mov x30,#0x80000; mov sp, x30; ret\"\n            ::\"r\"(dsdt_ptr):);\n        break;\n#endif\n    }\n    printf(\"ERROR: kernel should not have returned\\r\\n\");\n\n    /* there's nowhere to return to, halt machine */\nerr:if(!bkp) { getchar(); bkp++; goto again; }\n    halt();\n    return 0;\n}\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/loader_rpi.c",
    "content": "/*\n * src/loader_rpi.c\n * https://gitlab.com/bztsrc/simpleboot\n *\n * Copyright (C) 2023 bzt (bztsrc@gitlab), MIT license\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * @brief The main Simpleboot loader program on Raspberry Pi\n *\n * Memory layout when booted on Raspberry Pi:\n *      0x0 -    0x400  reserved by firmware\n *    0x400 -   0x1000  stack (3072 bytes)\n *   0x1000 -  0x20000  paging tables\n *  0x20000 -  0x80000  config + logo + tags; from the top to bottom: kernel's stack\n *  0x80000 - _bss_end  our sections\n * _bss_end -        x  kernel segments, followed by the modules, each page aligned\n */\n\n/**\n * The longest path we can handle\n */\n#define PATH_MAX 1024\n/**\n * Maximum size of MBI tags in pages (30 * 4096 = 122k)\n */\n#define TAGS_MAX 30\n\n/**\n * Specify where the boot messages should appear, make it a comment to disable\n */\n#define CONSOLE_SERIAL                              /* default serial, UART0 */\n#define CONSOLE_FB                                  /* on screen too */\n\n/* it is VERY important that these two variables must be the first in the\n * read-only data segment, because the disk generator might alter them */\nconst char __attribute__((aligned(16))) defkernel[64] = \"kernel\", definitrd[64] = \"\";\n/* patched by bin2h.c, must be right after the default names. Must use volatile otherwise Clang optimizes memread away */\nconst volatile unsigned int _bss_start = 0xffffffff, _bss_end = 0xffffffff;\n\n/**\n * Assembly preambule to C\n * must be the very first function; it can't use any local variables and can't have a stack frame\n */\nvoid __attribute__((noreturn)) /*__attribute__((naked))*/ _preambule(void)\n{\n    /* make sure we run on BSP only, set up EL1 and a stack */\n    __asm__ __volatile__(\n    \"movk x0,#0,lsl #32;adr x1,dtb_base;str x0,[x1];\"/* save device tree base */\n    \"mrs x1, mpidr_el1;and x1, x1, #3;cbz x1, 2f;\"  /* get core id and branch if BSP */\n    \"1:wfe; b 1b;\"                                  /* neverending loop for APs */\n    \".balign 64;.asciz \\\"Simpleboot https://codeberg.org/bzt/simpleboot\\\";.asciz \\\"aarch64\\\";.balign 4;\"\n    \"2:mov x1, #0x1000;\"\n    \"mrs x0, CurrentEL;and x0, x0, #12;\"\n    \"cmp x0, #12;bne 1f;\"                           /* are we running at EL3? */\n    \"mov x0, #0x5b1;msr scr_el3, x0;mov x0, #0x3c9;msr spsr_el3, x0;adr x0, 1f;msr elr_el3, x0;mov x0, #4;msr sp_el2, x1;eret;\"\n    \"1:cmp x0, #4;beq 1f;\"                          /* are we running at EL2? */\n    \"mrs x0,cnthctl_el2;orr x0,x0,#3;msr cnthctl_el2,x0;msr cnthp_ctl_el2,xzr;\"         /* enable CNTP */\n    \"mov x0,#(1 << 31);orr x0,x0,#2;msr hcr_el2,x0;mrs x0,hcr_el2;\"                     /* enable Aarch64 at EL1 */\n    \"mrs x0,midr_el1;mrs x2,mpidr_el1;msr vpidr_el2,x0;msr vmpidr_el2,x2;\"              /* initialize virtual MPIDR */\n    \"mov x0,#0x33FF;msr cptr_el2,x0;msr hstr_el2,xzr;mov x0,#(3<<20);msr cpacr_el1,x0;\" /* disable coprocessor traps */\n    \"mov x2,#0x0800;movk x2,#0x30d0,lsl #16;msr sctlr_el1, x2;\"                         /* setup SCTLR access */\n    \"mov x2,#0x3c5;msr spsr_el2,x2;adr x2, 1f;msr elr_el2, x2;mov sp, x1;msr sp_el1, x1;eret;\"/* switch to EL1 */\n    \"1:adr x0,1f;msr vbar_el1,x0;msr SPSel,#0;\"                                         /* set up exception handlers */\n    \"mov sp, x1;b _start;\"                        /* set up stack and jump to C function in EL1 */\n    /* exception handlers */\n    \".balign 128;1:mov x0,#0;mrs x1,esr_el1;mrs x2,elr_el1;mrs x3,spsr_el1;mrs x4,far_el1;mrs x5,sctlr_el1;mrs x6,tcr_el1;b fw_exc;\"\n    \".balign 128;mov x0,#1;mrs x1,esr_el1;mrs x2,elr_el1;mrs x3,spsr_el1;mrs x4,far_el1;mrs x5,sctlr_el1;mrs x6,tcr_el1;b fw_exc;\"\n    \".balign 128;mov x0,#2;mrs x1,esr_el1;mrs x2,elr_el1;mrs x3,spsr_el1;mrs x4,far_el1;mrs x5,sctlr_el1;mrs x6,tcr_el1;b fw_exc;\"\n    \".balign 128;mov x0,#3;mrs x1,esr_el1;mrs x2,elr_el1;mrs x3,spsr_el1;mrs x4,far_el1;mrs x5,sctlr_el1;mrs x6,tcr_el1;b fw_exc;\"\n    :::\"x0\",\"x1\",\"x2\");\n    /* naked not supported, so noreturn and unreachable needed to make the compiler omit the stack frame prologue / epilogue */\n    __builtin_unreachable();\n}\n\n#include \"../simpleboot.h\"\n#include \"loader.h\"\n\n/* IMPORTANT: don't assume .bss is zeroed out like in a hosted environment, because it's not */\nvolatile uint32_t  __attribute__((aligned(16))) mbox[40];\nuint8_t __attribute__((aligned(16))) vbr[512], data[512];\nuint32_t fat[1024], fat_cache, file_clu;\nuint16_t lfn[272], wcname[PATH_MAX];\nuint64_t mmio_base, emmc_base;\nuint64_t file_size, rsdp_ptr, file_base, file_buf, mod_buf, ram, *pt;\nuint32_t fb_w, fb_h, fb_bpp, fb_bg, logo_size, verbose, num_memmap, pb_b, pb_m, pb_l, rq, bkp;\nuint8_t rpi, *tags_buf, *tags_ptr, *logo_buf, *dtb_base, *kernel_entry, kernel_mode, kernel_buf[4096], *pb_fb, in_exc, smp;\nuint64_t root_dir, data_lba, fat_lba;\nguid_t espGuid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID, bootuuid;\nesp_bpb_t *bpb;\nmultiboot_tag_framebuffer_t vidmode;\nmultiboot_tag_module_t *initrd;\nchar *conf_buf, *kernel, *cmdline;\n\napic_t __attribute__((aligned(16))) apic;\nrsdt_t __attribute__((aligned(16))) rsdt;\nrsdp_t __attribute__((aligned(16))) rsdp;\nfadt_t __attribute__((aligned(16))) fadt;\n\n/**************** Mandatory functions, Clang generates calls to them ****************/\n\nvoid memcpy(void *dst, const void *src, uint32_t n){uint8_t *a=(uint8_t*)dst,*b=(uint8_t*)src;while(n--) *a++=*b++; }\nvoid memset(void *dst, uint8_t c, uint32_t n){uint8_t *a=dst;while(n--) *a++=c; }\nint  memcmp(const void *s1, const void *s2, uint32_t n){\n    uint8_t *a=(uint8_t*)s1,*b=(uint8_t*)s2;while(n--){if(*a!=*b){return *a-*b;}a++;b++;} return 0;\n}\n\n#include \"inflate.h\"\n\n/**\n * Convert hex string into integer\n */\nchar *gethex(char *ptr, uint32_t *ret)\n{\n    int len = 2;\n    *ret = 0;\n    for(;len--;ptr++) {\n        if(*ptr>='0' && *ptr<='9') {          *ret <<= 4; *ret += (uint32_t)(*ptr - '0'); }\n        else if(*ptr >= 'a' && *ptr <= 'f') { *ret <<= 4; *ret += (uint32_t)(*ptr - 'a' + 10); }\n        else if(*ptr >= 'A' && *ptr <= 'F') { *ret <<= 4; *ret += (uint32_t)(*ptr - 'A' + 10); }\n        else break;\n    }\n    return ptr;\n}\n\n/**\n * Convert decimal string to integer\n */\nchar *getint(char *ptr, uint32_t *ret)\n{\n    for(*ret = 0; *ptr >= '0' && *ptr <= '9'; ptr++) { *ret *= 10; *ret += (uint32_t)(*ptr - '0'); }\n    return ptr;\n}\n\n/**************** GPU MailBox interface ****************/\n\n#define VIDEOCORE_MBOX  (mmio_base+0x0000B880)\n#define MBOX_READ       ((volatile uint32_t*)(VIDEOCORE_MBOX+0x0))\n#define MBOX_POLL       ((volatile uint32_t*)(VIDEOCORE_MBOX+0x10))\n#define MBOX_SENDER     ((volatile uint32_t*)(VIDEOCORE_MBOX+0x14))\n#define MBOX_STATUS     ((volatile uint32_t*)(VIDEOCORE_MBOX+0x18))\n#define MBOX_CONFIG     ((volatile uint32_t*)(VIDEOCORE_MBOX+0x1C))\n#define MBOX_WRITE      ((volatile uint32_t*)(VIDEOCORE_MBOX+0x20))\n#define MBOX_REQUEST    0\n#define MBOX_RESPONSE   0x80000000\n#define MBOX_FULL       0x80000000\n#define MBOX_EMPTY      0x40000000\n#define MBOX_CH_POWER   0\n#define MBOX_CH_FB      1\n#define MBOX_CH_VUART   2\n#define MBOX_CH_VCHIQ   3\n#define MBOX_CH_LEDS    4\n#define MBOX_CH_BTNS    5\n#define MBOX_CH_TOUCH   6\n#define MBOX_CH_COUNT   7\n#define MBOX_CH_PROP    8\n\nuint8_t mbox_call(uint8_t ch)\n{\n    uint32_t r;\n\n    /* mailbox write */\n    do{ __asm__ __volatile__(\"nop\"); } while(*MBOX_STATUS & MBOX_FULL);\n    *MBOX_WRITE = (((uint32_t)((uint64_t)mbox) & ~0xF) | (ch & 0xF));\n    /* mailbox read */\n    do {\n        do{ __asm__ __volatile__(\"nop\");} while(*MBOX_STATUS & MBOX_EMPTY);\n        r = *MBOX_READ;\n    } while((uint8_t)(r & 0xF) != ch);\n    return (r & ~0xF) == (uint32_t)((uint64_t)mbox) && mbox[1] == MBOX_RESPONSE;\n}\n\n/**\n * Set up framebuffer with VideoCore\n */\nvoid mbox_lfb(uint32_t width, uint32_t height, uint32_t bpp)\n{\n    /* query natural width, height if not given */\n    if(!width || !height) {\n        mbox[0] = 12*4;\n        mbox[1] = MBOX_REQUEST;\n        mbox[2] = 0x40003;  /* get phy wh */\n        mbox[3] = 8;\n        mbox[4] = 8;\n        mbox[5] = 0;\n        mbox[6] = 0;\n        mbox[7] = 0x40005;  /* get depth */\n        mbox[8] = 4;\n        mbox[9] = 4;\n        mbox[10] = 0;\n        mbox[11] = 0;\n        if(mbox_call(MBOX_CH_PROP) && mbox[5] && mbox[10]) {\n            width = mbox[5];\n            height = mbox[6];\n            if(width < 800) width = 800;\n            if(height < 600) height = 600;\n            bpp = 32;\n        }\n    }\n    /* if we already have a framebuffer, release it */\n    if(vidmode.framebuffer_addr) {\n        mbox[0] = 8*4;\n        mbox[1] = MBOX_REQUEST;\n        mbox[2] = 0x48001;  /* release buffer */\n        mbox[3] = 8;\n        mbox[4] = 8;\n        mbox[5] = (uint32_t)vidmode.framebuffer_addr;\n        mbox[6] = 0;\n        mbox[7] = 0;\n        mbox_call(MBOX_CH_PROP);\n        vidmode.framebuffer_addr = 0;\n    }\n    /* check minimum resolution */\n    if(width < 320) width = 320;\n    if(height < 200) height = 200;\n    if(bpp != 15 && bpp != 16 && bpp != 24) bpp = 32;\n\n    mbox[0] = 35*4;\n    mbox[1] = MBOX_REQUEST;\n\n    mbox[2] = 0x48003;  /* set phy wh */\n    mbox[3] = 8;\n    mbox[4] = 8;\n    mbox[5] = width;\n    mbox[6] = height;\n\n    mbox[7] = 0x48004;  /* set virt wh */\n    mbox[8] = 8;\n    mbox[9] = 8;\n    mbox[10] = width;\n    mbox[11] = height;\n\n    mbox[12] = 0x48009; /* set virt offset */\n    mbox[13] = 8;\n    mbox[14] = 8;\n    mbox[15] = 0;\n    mbox[16] = 0;\n\n    mbox[17] = 0x48005; /* set depth */\n    mbox[18] = 4;\n    mbox[19] = 4;\n    mbox[20] = bpp;\n\n    mbox[21] = 0x48006; /* set pixel order */\n    mbox[22] = 4;\n    mbox[23] = 4;\n    mbox[24] = 1;       /* RGB, not BGR preferably */\n\n    mbox[25] = 0x40001; /* get framebuffer, gets alignment on request */\n    mbox[26] = 8;\n    mbox[27] = 8;\n    mbox[28] = 4096;\n    mbox[29] = 0;\n\n    mbox[30] = 0x40008; /* get pitch */\n    mbox[31] = 4;\n    mbox[32] = 4;\n    mbox[33] = 0;\n\n    mbox[34] = 0;\n\n    if(mbox_call(MBOX_CH_PROP) && mbox[20] == bpp && mbox[27] == (MBOX_RESPONSE|8) && mbox[28]) {\n        vidmode.framebuffer_addr = (uint64_t)(mbox[28] & 0x3FFFFFFF);\n        vidmode.framebuffer_pitch = mbox[33];\n        vidmode.framebuffer_width = mbox[5];\n        vidmode.framebuffer_height = mbox[6];\n        vidmode.framebuffer_bpp = mbox[20];\n        vidmode.framebuffer_type = 1;\n        if(mbox[24]) {\n            /* red is the least significant channel */\n            switch(mbox[20]) {\n                case 15:\n                    vidmode.framebuffer_red_mask_size = vidmode.framebuffer_green_mask_size =\n                        vidmode.framebuffer_blue_mask_size = 5;\n                    vidmode.framebuffer_red_field_position = 0;\n                    vidmode.framebuffer_green_field_position = 5;\n                    vidmode.framebuffer_blue_field_position = 10;\n                break;\n                case 16:\n                    vidmode.framebuffer_red_mask_size = vidmode.framebuffer_blue_mask_size = 5;\n                    vidmode.framebuffer_green_mask_size = 6;\n                    vidmode.framebuffer_red_field_position = 0;\n                    vidmode.framebuffer_green_field_position = 5;\n                    vidmode.framebuffer_blue_field_position = 11;\n                break;\n                default:\n                    vidmode.framebuffer_red_mask_size = vidmode.framebuffer_green_mask_size =\n                        vidmode.framebuffer_blue_mask_size = 8;\n                    vidmode.framebuffer_red_field_position = 0;\n                    vidmode.framebuffer_green_field_position = 8;\n                    vidmode.framebuffer_blue_field_position = 16;\n                break;\n            }\n        } else {\n            /* blue is the least significant channel */\n            switch(mbox[20]) {\n                case 15:\n                    vidmode.framebuffer_red_mask_size = vidmode.framebuffer_green_mask_size =\n                        vidmode.framebuffer_blue_mask_size = 5;\n                    vidmode.framebuffer_red_field_position = 10;\n                    vidmode.framebuffer_green_field_position = 5;\n                    vidmode.framebuffer_blue_field_position = 0;\n                break;\n                case 16:\n                    vidmode.framebuffer_red_mask_size = vidmode.framebuffer_blue_mask_size = 5;\n                    vidmode.framebuffer_green_mask_size = 6;\n                    vidmode.framebuffer_red_field_position = 11;\n                    vidmode.framebuffer_green_field_position = 5;\n                    vidmode.framebuffer_blue_field_position = 0;\n                break;\n                default:\n                    vidmode.framebuffer_red_mask_size = vidmode.framebuffer_green_mask_size =\n                        vidmode.framebuffer_blue_mask_size = 8;\n                    vidmode.framebuffer_red_field_position = 16;\n                    vidmode.framebuffer_green_field_position = 8;\n                    vidmode.framebuffer_blue_field_position = 0;\n                break;\n            }\n        }\n    } else {\n        if(vidmode.framebuffer_addr) {\n            mbox[0] = 8*4;\n            mbox[1] = MBOX_REQUEST;\n            mbox[2] = 0x48001;  /* release buffer */\n            mbox[3] = 8;\n            mbox[4] = 8;\n            mbox[5] = (uint32_t)vidmode.framebuffer_addr;\n            mbox[6] = 0;\n            mbox[7] = 0;\n            mbox_call(MBOX_CH_PROP);\n            vidmode.framebuffer_addr = 0;\n        }\n        vidmode.framebuffer_width = vidmode.framebuffer_height = vidmode.framebuffer_bpp = 0;\n    }\n}\n\n/**************** Early boot console ****************/\n\n#define GPFSEL0         ((volatile uint32_t*)(mmio_base+0x00200000))\n#define GPFSEL1         ((volatile uint32_t*)(mmio_base+0x00200004))\n#define GPFSEL2         ((volatile uint32_t*)(mmio_base+0x00200008))\n#define GPFSEL3         ((volatile uint32_t*)(mmio_base+0x0020000C))\n#define GPFSEL4         ((volatile uint32_t*)(mmio_base+0x00200010))\n#define GPFSEL5         ((volatile uint32_t*)(mmio_base+0x00200014))\n#define GPSET0          ((volatile uint32_t*)(mmio_base+0x0020001C))\n#define GPSET1          ((volatile uint32_t*)(mmio_base+0x00200020))\n#define GPCLR0          ((volatile uint32_t*)(mmio_base+0x00200028))\n#define GPLEV0          ((volatile uint32_t*)(mmio_base+0x00200034))\n#define GPLEV1          ((volatile uint32_t*)(mmio_base+0x00200038))\n#define GPEDS0          ((volatile uint32_t*)(mmio_base+0x00200040))\n#define GPEDS1          ((volatile uint32_t*)(mmio_base+0x00200044))\n#define GPHEN0          ((volatile uint32_t*)(mmio_base+0x00200064))\n#define GPHEN1          ((volatile uint32_t*)(mmio_base+0x00200068))\n#define GPPUD           ((volatile uint32_t*)(mmio_base+0x00200094))\n#define GPPUDCLK0       ((volatile uint32_t*)(mmio_base+0x00200098))\n#define GPPUDCLK1       ((volatile uint32_t*)(mmio_base+0x0020009C))\n\n#define UART0_DR        ((volatile uint32_t*)(mmio_base+0x00201000))\n#define UART0_FR        ((volatile uint32_t*)(mmio_base+0x00201018))\n#define UART0_IBRD      ((volatile uint32_t*)(mmio_base+0x00201024))\n#define UART0_FBRD      ((volatile uint32_t*)(mmio_base+0x00201028))\n#define UART0_LCRH      ((volatile uint32_t*)(mmio_base+0x0020102C))\n#define UART0_CR        ((volatile uint32_t*)(mmio_base+0x00201030))\n#define UART0_IMSC      ((volatile uint32_t*)(mmio_base+0x00201038))\n#define UART0_ICR       ((volatile uint32_t*)(mmio_base+0x00201044))\n\n#ifdef CONSOLE_FB\ntypedef struct { uint32_t magic, version, headersize, flags, numglyph, bytesperglyph, height, width; } __attribute__((packed)) psf2_t;\nuint8_t font_psf[2080] = { 114,181,74,134,0,0,0,0,32,0,0,0,0,0,12,0,128,0,0,0,16,0,0,0,16,0,0,0,8,0,0,0,0,0,218,2,128,130,2,128,130,2,128,182,0,0,0,0,0,0,126,129,165,129,129,189,153,129,129,126,0,0,0,0,0,0,126,255,219,255,255,195,231,255,255,126,0,0,0,0,0,0,0,0,108,254,254,254,254,124,56,16,0,0,0,0,0,0,0,0,16,56,124,254,124,56,16,0,0,0,0,0,0,0,0,24,60,60,231,231,231,24,24,60,0,0,0,0,0,0,0,24,60,126,255,255,126,24,24,60,0,0,0,0,0,0,0,0,0,0,24,60,60,24,0,0,0,0,0,0,255,255,255,255,255,255,231,195,195,231,255,255,255,255,255,255,0,0,0,0,0,60,102,66,66,102,60,0,0,0,0,0,255,255,255,255,255,195,153,189,189,153,195,255,255,255,255,255,0,0,30,14,26,50,120,204,204,204,204,120,0,0,0,0,0,0,60,102,102,102,102,60,24,126,24,24,0,0,0,0,0,0,63,51,63,48,48,48,48,112,240,224,0,0,0,0,0,0,127,99,127,99,99,99,99,103,231,230,192,0,0,0,0,0,0,24,24,219,60,231,60,219,24,24,0,0,0,0,0,128,192,224,240,248,254,248,240,224,192,128,0,0,0,0,0,2,6,14,30,62,254,62,30,14,6,2,0,0,0,0,0,0,24,60,126,24,24,24,126,60,24,0,0,0,0,0,0,0,102,102,102,102,102,102,102,0,102,102,0,0,0,0,0,0,127,219,219,219,123,27,27,27,27,27,0,0,0,0,0,124,198,96,56,108,198,198,108,56,12,198,124,0,0,0,0,0,0,0,0,0,0,0,254,254,254,254,0,0,0,0,0,0,24,60,126,24,24,24,126,60,24,126,0,0,0,0,0,0,24,60,126,24,24,24,24,24,24,24,0,0,0,0,0,0,24,24,24,24,24,24,24,126,60,24,0,0,0,0,0,0,0,0,0,24,12,254,12,24,0,0,0,0,0,0,0,0,0,0,0,48,96,254,96,48,0,0,0,0,0,0,0,0,0,0,0,0,192,192,192,254,0,0,0,0,0,0,0,0,0,0,0,40,108,254,108,40,0,0,0,0,0,0,0,0,0,0,16,56,56,124,124,254,254,0,0,0,0,0,0,0,0,0,254,254,124,124,56,56,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,60,60,60,24,24,24,0,24,24,0,0,0,0,0,102,102,102,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,108,108,254,108,108,108,254,108,108,0,0,0,0,24,24,124,198,194,192,124,6,6,134,198,124,24,24,0,0,0,0,0,0,194,198,12,24,48,96,198,134,0,0,0,0,0,0,56,108,108,56,118,220,204,204,204,118,0,0,0,0,0,48,48,48,32,0,0,0,0,0,0,0,0,0,0,0,0,0,12,24,48,48,48,48,48,48,24,12,0,0,0,0,0,0,48,24,12,12,12,12,12,12,24,48,0,0,0,0,0,0,0,0,0,102,60,255,60,102,0,0,0,0,0,0,0,0,0,0,0,24,24,126,24,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,24,24,48,0,0,0,0,0,0,0,0,0,0,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,24,0,0,0,0,0,0,0,0,2,6,12,24,48,96,192,128,0,0,0,0,0,0,56,108,198,198,214,214,198,198,108,56,0,0,0,0,0,0,24,56,120,24,24,24,24,24,24,126,0,0,0,0,0,0,124,198,6,12,24,48,96,192,198,254,0,0,0,0,0,0,124,198,6,6,60,6,6,6,198,124,0,0,0,0,0,0,12,28,60,108,204,254,12,12,12,30,0,0,0,0,0,0,254,192,192,192,252,6,6,6,198,124,0,0,0,0,0,0,56,96,192,192,252,198,198,198,198,124,0,0,0,0,0,0,254,198,6,6,12,24,48,48,48,48,0,0,0,0,0,0,124,198,198,198,124,198,198,198,198,124,0,0,0,0,0,0,124,198,198,198,126,6,6,6,12,120,0,0,0,0,0,0,0,0,24,24,0,0,0,24,24,0,0,0,0,0,0,0,0,0,24,24,0,0,0,24,24,48,0,0,0,0,0,0,0,6,12,24,48,96,48,24,12,6,0,0,0,0,0,0,0,0,0,126,0,0,126,0,0,0,0,0,0,0,0,0,0,96,48,24,12,6,12,24,48,96,0,0,0,0,0,0,124,198,198,12,24,24,24,0,24,24,0,0,0,0,0,0,0,124,198,198,222,222,222,220,192,124,0,0,0,0,0,0,16,56,108,198,198,254,198,198,198,198,0,0,0,0,0,0,252,102,102,102,124,102,102,102,102,252,0,0,0,0,0,0,60,102,194,192,192,192,192,194,102,60,0,0,0,0,0,0,248,108,102,102,102,102,102,102,108,248,0,0,0,0,0,0,254,102,98,104,120,104,96,98,102,254,0,0,0,0,0,0,254,102,98,104,120,104,96,96,96,240,0,0,0,0,0,0,60,102,194,192,192,222,198,198,102,58,0,0,0,0,0,0,198,198,198,198,254,198,198,198,198,198,0,0,0,0,0,0,60,24,24,24,24,24,24,24,24,60,0,0,0,0,0,0,30,12,12,12,12,12,204,204,204,120,0,0,0,0,0,0,230,102,102,108,120,120,108,102,102,230,0,0,0,0,0,0,240,96,96,96,96,96,96,98,102,254,0,0,0,0,0,0,198,238,254,254,214,198,198,198,198,198,0,0,0,0,0,0,198,230,246,254,222,206,198,198,198,198,0,0,0,0,0,0,124,198,198,198,198,198,198,198,198,124,0,0,0,0,0,0,252,102,102,102,124,96,96,96,96,240,0,0,0,0,0,0,124,198,198,198,198,198,198,214,222,124,12,14,0,0,0,0,252,102,102,102,124,108,102,102,102,230,0,0,0,0,0,0,124,198,198,96,56,12,6,198,198,124,0,0,0,0,0,0,126,126,90,24,24,24,24,24,24,60,0,0,0,0,0,0,198,198,198,198,198,198,198,198,198,124,0,0,0,0,0,0,198,198,198,198,198,198,198,108,56,16,0,0,0,0,0,0,198,198,198,198,214,214,214,254,238,108,0,0,0,0,0,0,198,198,108,124,56,56,124,108,198,198,0,0,0,0,0,0,102,102,102,102,60,24,24,24,24,60,0,0,0,0,0,0,254,198,134,12,24,48,96,194,198,254,0,0,0,0,0,0,60,48,48,48,48,48,48,48,48,60,0,0,0,0,0,0,0,128,192,224,112,56,28,14,6,2,0,0,0,0,0,0,60,12,12,12,12,12,12,12,12,60,0,0,0,0,16,56,108,198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,48,48,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,120,12,124,204,204,204,118,0,0,0,0,0,0,224,96,96,120,108,102,102,102,102,124,0,0,0,0,0,0,0,0,0,124,198,192,192,192,198,124,0,0,0,0,0,0,28,12,12,60,108,204,204,204,204,118,0,0,0,0,0,0,0,0,0,124,198,254,192,192,198,124,0,0,0,0,0,0,56,108,100,96,240,96,96,96,96,240,0,0,0,0,0,0,0,0,0,118,204,204,204,204,204,124,12,204,120,0,0,0,224,96,96,108,118,102,102,102,102,230,0,0,0,0,0,0,24,24,0,56,24,24,24,24,24,60,0,0,0,0,0,0,6,6,0,14,6,6,6,6,6,6,102,102,60,0,0,0,224,96,96,102,108,120,120,108,102,230,0,0,0,0,0,0,56,24,24,24,24,24,24,24,24,60,0,0,0,0,0,0,0,0,0,236,254,214,214,214,214,198,0,0,0,0,0,0,0,0,0,220,102,102,102,102,102,102,0,0,0,0,0,0,0,0,0,124,198,198,198,198,198,124,0,0,0,0,0,0,0,0,0,220,102,102,102,102,102,124,96,96,240,0,0,0,0,0,0,118,204,204,204,204,204,124,12,12,30,0,0,0,0,0,0,220,118,102,96,96,96,240,0,0,0,0,0,0,0,0,0,124,198,96,56,12,198,124,0,0,0,0,0,0,16,48,48,252,48,48,48,48,54,28,0,0,0,0,0,0,0,0,0,204,204,204,204,204,204,118,0,0,0,0,0,0,0,0,0,102,102,102,102,102,60,24,0,0,0,0,0,0,0,0,0,198,198,214,214,214,254,108,0,0,0,0,0,0,0,0,0,198,108,56,56,56,108,198,0,0,0,0,0,0,0,0,0,198,198,198,198,198,198,126,6,12,248,0,0,0,0,0,0,254,204,24,48,96,198,254,0,0,0,0,0,0,14,24,24,24,112,24,24,24,24,14,0,0,0,0,0,0,24,24,24,24,24,24,24,24,24,24,24,24,0,0,0,0,112,24,24,24,14,24,24,24,24,112,0,0,0,0,0,0,118,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,56,108,198,198,198,254,0,0,0,0,0 };\nuint32_t fb_x, fb_y;\n#endif\n\n/**\n * Initialize the console\n */\nvoid console_init(void)\n{\n    uint32_t r;\n\n    /* initialize UART */\n    *UART0_CR = 0;          /* turn off UART0 */\n#ifdef CONSOLE_SERIAL\n    /* set up clock for consistent divisor values */\n    mbox[0] = 8*4;\n    mbox[1] = MBOX_REQUEST;\n    mbox[2] = 0x38002;      /* set clock rate */\n    mbox[3] = 12;\n    mbox[4] = 8;\n    mbox[5] = 2;            /* UART clock */\n    mbox[6] = 4000000;      /* 4Mhz */\n    mbox[7] = 0;            /* set turbo */\n    mbox_call(MBOX_CH_PROP);\n    r = *GPFSEL1;\n    r &= ~((7<<12)|(7<<15));/* gpio14, gpio15 */\n    r |= (4<<12)|(4<<15);   /* alt0 */\n    *GPFSEL1 = r;\n    *GPPUD = 0;             /* enable pins 14 and 15 */\n    for(r = 0; r < 150; r++) __asm__ __volatile__(\"nop\");\n    *GPPUDCLK0 = (1<<14)|(1<<15);\n    for(r = 0; r < 150; r++) __asm__ __volatile__(\"nop\");\n    *GPPUDCLK0 = 0;         /* flush GPIO setup */\n    *UART0_ICR = 0x7FF;     /* clear interrupts */\n    *UART0_IBRD = 2;        /* 115200 baud */\n    *UART0_FBRD = 0xB;\n    *UART0_LCRH = 0x03<<5;  /* 8n1 */\n    *UART0_CR = 0x301;      /* enable Tx, Rx, FIFO */\n#endif\n#ifdef CONSOLE_FB\n    fb_x = fb_y = 4;\n#endif\n}\n\n/**\n * Display a character on boot console\n */\nvoid console_putc(uint8_t c)\n{\n#ifdef CONSOLE_UEFI\n    uint16_t tmp[2];\n#endif\n#ifdef CONSOLE_FB\n    psf2_t *font = (psf2_t*)font_psf;\n    uint32_t x, y, line, mask, offs, bpl = (font->width + 7) >> 3;\n    uint8_t *glyph, *fb = (uint8_t*)vidmode.framebuffer_addr;\n\n    if(fb)\n        switch(c) {\n            case '\\r': fb_x = 4; break;\n            case '\\n': fb_x = 4; fb_y += font->height; break;\n            default:\n                if(fb_x + font->width + 5 >= vidmode.framebuffer_width) { fb_x = 4; fb_y += font->height; }\n                if(fb_y + font->height + 5 > vidmode.framebuffer_height) {\n                    x = fb_y; fb_y = vidmode.framebuffer_height - font->height - 5; x -= fb_y;\n                    offs = 0; line = x * vidmode.framebuffer_pitch;\n                    for(y = x; y < vidmode.framebuffer_height; y++,\n                      offs += vidmode.framebuffer_pitch, line += vidmode.framebuffer_pitch)\n                        memcpy(fb + offs, fb + line, vidmode.framebuffer_pitch);\n                    for(y = fb_y, offs = fb_y * vidmode.framebuffer_pitch; y < vidmode.framebuffer_height; y++,\n                      offs += vidmode.framebuffer_pitch)\n                        memset(fb + offs, 0, vidmode.framebuffer_pitch);\n                }\n                glyph = font_psf + font->headersize + (c > 0 && c < font->numglyph ? c : 0) * font->bytesperglyph;\n                offs = fb_y * vidmode.framebuffer_pitch + fb_x * ((vidmode.framebuffer_bpp + 7) >> 3); fb_x += (font->width + 1);\n                for(y = 0; y < font->height; y++, glyph += bpl, offs += vidmode.framebuffer_pitch) {\n                    line = offs; mask = 1 << (font->width - 1);\n                    for(x = 0; x < font->width && mask; x++, mask >>= 1) {\n                        switch(vidmode.framebuffer_bpp) {\n                            case 15: case 16: *((uint16_t*)(fb + line)) = ((int)*glyph) & mask ? 0xFFFF : fb_bg; line += 2; break;\n                            case 24: *((uint32_t*)(fb + line)) = ((int)*glyph) & mask ? 0xFFFFFF : fb_bg; line += 3; break;\n                            case 32: *((uint32_t*)(fb + line)) = ((int)*glyph) & mask ? 0xFFFFFFFF : fb_bg; line += 4; break;\n                        }\n                    }\n                    *((uint32_t*)(fb + line)) = fb_bg;\n                }\n            break;\n        }\n#endif\n#ifdef CONSOLE_SERIAL\n    do{ __asm__ __volatile__(\"nop\");} while(*UART0_FR&0x20); *UART0_DR=c;\n#endif\n}\n\n/**\n * Display (extremely minimal) formated message on console\n * %c: an ASCII character\n * %d: a decimal number\n * %x: a hexadecimal number\n * %p: a pointer\n * %s: a zero terminated ASCII string (8 bit)\n * %S: a zero terminated WCHAR string (16 bit characters, truncated to 8 bit)\n * %D: dump 16 bytes from given address\n */\nvoid printf(char *fmt, ...)\n{\n    __builtin_va_list args;\n    uint8_t *ptr;\n    int64_t arg;\n    uint16_t *u;\n    int len, sign, i, l;\n    char *p, tmpstr[19], n;\n\n    __builtin_va_start(args, fmt);\n    arg = 0;\n    while(*fmt) {\n        if(*fmt == '%') {\n            fmt++;\n            if(*fmt == '%') goto put;\n            len=l=0; while(*fmt >= '0' && *fmt <= '9') { len *= 10; len += *fmt - '0'; fmt++; }\n            if(*fmt == 'l') { l++; fmt++; }\n            if(*fmt == 'c') { arg = __builtin_va_arg(args, int); console_putc((uint8_t)arg); fmt++; continue; } else\n            if(*fmt == 'd') {\n                if(!l) arg = (int32_t)__builtin_va_arg(args, int32_t);\n                else arg = __builtin_va_arg(args, int64_t);\n                sign = 0; if((int)arg < 0) { arg = -arg; sign++; }\n                i = 18; tmpstr[i] = 0;\n                do { tmpstr[--i] = '0' + (arg % 10); arg /= 10; } while(arg != 0 && i > 0);\n                if(sign) tmpstr[--i] = '-';\n                if(len > 0 && len < 18) { while(i > 18 - len) tmpstr[--i] = ' '; }\n                p = &tmpstr[i];\n                goto putstring;\n            } else\n            if(*fmt == 'x' || *fmt == 'p') {\n                if(*fmt == 'x' && !l) arg = (int32_t)__builtin_va_arg(args, int32_t);\n                else arg = __builtin_va_arg(args, int64_t);\n                i = 16; tmpstr[i] = 0; if(*fmt == 'p') len = 16;\n                do { n = arg & 0xf; tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); arg >>= 4; } while(arg != 0 && i > 0);\n                if(len > 0 && len <= 16) { while(i > 16 - len) tmpstr[--i] = '0'; }\n                p = &tmpstr[i];\n                goto putstring;\n            } else\n            if(*fmt == 's') {\n                p = __builtin_va_arg(args, char*);\nputstring:      if(p == (void*)0) p = \"(null)\";\n                while(*p) console_putc(*p++);\n            }\n            if(*fmt == 'S') {\n                u = __builtin_va_arg(args, uint16_t*);\n                if(u == (void*)0) u = L\"(null)\";\n                while(*u) console_putc(*u++);\n            } else\n            if(*fmt == 'D') {\n                arg = __builtin_va_arg(args, int64_t);\n                if(len < 1) len = 1;\n                do {\n                    for(i = 28; i >= 0; i -= 4) { n = (arg >> i) & 15; n += (n>9?0x37:0x30); console_putc(n); }\n                    console_putc(':'); console_putc(' ');\n                    ptr = (uint8_t*)(uintptr_t)arg;\n                    for(i = 0; i < 16; i++) {\n                        n = (ptr[i] >> 4) & 15; n += (n>9?0x37:0x30); console_putc(n);\n                        n = ptr[i] & 15; n += (n>9?0x37:0x30); console_putc(n);\n                        console_putc(' ');\n                    }\n                    console_putc(' ');\n                    for(i = 0; i < 16; i++)\n                        console_putc(ptr[i] < 32 || ptr[i] >= 127 ? '.' : ptr[i]);\n                    console_putc('\\r'); console_putc('\\n');\n                    arg += 16;\n                } while(--len);\n            }\n        } else {\nput:        console_putc(*fmt);\n        }\n        fmt++;\n    }\n    __builtin_va_end(args);\n}\n\n/**************** Progress bar ****************/\n\n/**\n * Initialize the progress bar\n */\nuint64_t pb_init(uint64_t size)\n{\n    uint32_t c, i, x;\n\n    pb_fb = NULL; pb_m = (size >> 9) + 1; pb_l = 0;\n    if(!vidmode.framebuffer_addr || !size || pb_m < vidmode.framebuffer_width - 4) return 0;\n    pb_b = (vidmode.framebuffer_bpp + 7) >> 3;\n    pb_fb = (uint8_t*)vidmode.framebuffer_addr + (vidmode.framebuffer_height - 4) * vidmode.framebuffer_pitch + 2 * pb_b;\n    c = FB_COLOR(32, 32, 32);\n    for(i = x = 0; x < vidmode.framebuffer_width - 4; x++, i += pb_b)\n        switch(vidmode.framebuffer_bpp) {\n            case 15: case 16: *((uint16_t*)(pb_fb + i)) = *((uint16_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = c; break;\n            case 24: case 32: *((uint32_t*)(pb_fb + i)) = *((uint32_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = c; break;\n        }\n    return size / (vidmode.framebuffer_width - 4);\n}\n\n/**\n * Draw the progress bar\n */\nvoid pb_draw(uint64_t curr)\n{\n    uint32_t i;\n\n    if(pb_fb) {\n        i = pb_l; pb_l = ((curr >> 9) * (vidmode.framebuffer_width - 4) / pb_m) * pb_b;\n        for(; i < pb_l; i++)\n            switch(vidmode.framebuffer_bpp) {\n                case 15: case 16: *((uint16_t*)(pb_fb + i)) = *((uint16_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = 0xFFFF; break;\n                case 24: case 32: *((uint32_t*)(pb_fb + i)) = *((uint32_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = 0xFFFFFF; break;\n            }\n    }\n}\n\n/**\n * Close the progress bar\n */\nvoid pb_fini(void)\n{\n    uint32_t i, x;\n\n    if(pb_fb)\n        for(i = x = 0; x < vidmode.framebuffer_width - 2; x++, i += pb_b)\n            switch(vidmode.framebuffer_bpp) {\n                case 15: case 16: *((uint16_t*)(pb_fb + i)) = *((uint16_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = fb_bg; break;\n                case 24: case 32: *((uint32_t*)(pb_fb + i)) = *((uint32_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = fb_bg; break;\n            }\n    pb_fb = NULL;\n}\n\n/**************** EMMC SDCard functions ****************/\n\n#define EMMC_ARG2           ((volatile uint32_t*)(emmc_base+0x00000000))\n#define EMMC_BLKSIZECNT     ((volatile uint32_t*)(emmc_base+0x00000004))\n#define EMMC_ARG1           ((volatile uint32_t*)(emmc_base+0x00000008))\n#define EMMC_CMDTM          ((volatile uint32_t*)(emmc_base+0x0000000C))\n#define EMMC_RESP0          ((volatile uint32_t*)(emmc_base+0x00000010))\n#define EMMC_RESP1          ((volatile uint32_t*)(emmc_base+0x00000014))\n#define EMMC_RESP2          ((volatile uint32_t*)(emmc_base+0x00000018))\n#define EMMC_RESP3          ((volatile uint32_t*)(emmc_base+0x0000001C))\n#define EMMC_DATA           ((volatile uint32_t*)(emmc_base+0x00000020))\n#define EMMC_STATUS         ((volatile uint32_t*)(emmc_base+0x00000024))\n#define EMMC_CONTROL0       ((volatile uint32_t*)(emmc_base+0x00000028))\n#define EMMC_CONTROL1       ((volatile uint32_t*)(emmc_base+0x0000002C))\n#define EMMC_INTERRUPT      ((volatile uint32_t*)(emmc_base+0x00000030))\n#define EMMC_INT_MASK       ((volatile uint32_t*)(emmc_base+0x00000034))\n#define EMMC_INT_EN         ((volatile uint32_t*)(emmc_base+0x00000038))\n#define EMMC_CONTROL2       ((volatile uint32_t*)(emmc_base+0x0000003C))\n#define EMMC_SLOTISR_VER    ((volatile uint32_t*)(emmc_base+0x000000FC))\n#define CMD_NEED_APP        0x80000000\n#define CMD_RSPNS_48        0x00020000\n#define CMD_ERRORS_MASK     0xfff9c004\n#define CMD_RCA_MASK        0xffff0000\n#define CMD_GO_IDLE         0x00000000\n#define CMD_ALL_SEND_CID    0x02010000\n#define CMD_SEND_REL_ADDR   0x03020000\n#define CMD_CARD_SELECT     0x07030000\n#define CMD_SEND_IF_COND    0x08020000\n#define CMD_STOP_TRANS      0x0C030000\n#define CMD_READ_SINGLE     0x11220010\n#define CMD_READ_MULTI      0x12220032\n#define CMD_SET_BLOCKCNT    0x17020000\n#define CMD_APP_CMD         0x37000000\n#define CMD_SET_BUS_WIDTH   (0x06020000|CMD_NEED_APP)\n#define CMD_SEND_OP_COND    (0x29020000|CMD_NEED_APP)\n#define CMD_SEND_SCR        (0x33220010|CMD_NEED_APP)\n#define SR_READ_AVAILABLE   0x00000800\n#define SR_DAT_INHIBIT      0x00000002\n#define SR_CMD_INHIBIT      0x00000001\n#define SR_APP_CMD          0x00000020\n#define INT_DATA_TIMEOUT    0x00100000\n#define INT_CMD_TIMEOUT     0x00010000\n#define INT_READ_RDY        0x00000020\n#define INT_CMD_DONE        0x00000001\n#define INT_ERROR_MASK      0x017E8000\n#define C0_SPI_MODE_EN      0x00100000\n#define C0_HCTL_HS_EN       0x00000004\n#define C0_HCTL_DWITDH      0x00000002\n#define C1_SRST             0x07000000\n#define C1_SRST_DATA        0x04000000\n#define C1_SRST_CMD         0x02000000\n#define C1_SRST_HC          0x01000000\n#define C1_TOUNIT_DIS       0x000f0000\n#define C1_TOUNIT_MAX       0x000e0000\n#define C1_CLK_GENSEL       0x00000020\n#define C1_CLK_EN           0x00000004\n#define C1_CLK_STABLE       0x00000002\n#define C1_CLK_INTLEN       0x00000001\n#define HOST_SPEC_NUM       0x00ff0000\n#define HOST_SPEC_NUM_SHIFT 16\n#define HOST_SPEC_V3        2\n#define HOST_SPEC_V2        1\n#define HOST_SPEC_V1        0\n#define SCR_SD_BUS_WIDTH_4  0x00000400\n#define SCR_SUPP_SET_BLKCNT 0x02000000\n#define SCR_SUPP_CCS        0x00000001\n#define ACMD41_VOLTAGE      0x00ff8000\n#define ACMD41_CMD_COMPLETE 0x80000000\n#define ACMD41_CMD_CCS      0x40000000\n#define ACMD41_ARG_HC       0x51ff8000\n#define SD_OK                0\n#define SD_TIMEOUT          -1\n#define SD_ERROR            -2\n\nuint32_t sd_scr[2], sd_ocr, sd_rca, sd_hv;\nint sd_err;\n\nuint64_t cntfrq;\n/* delay cnt microsec */\nvoid delayms(uint32_t cnt) {\n    uint64_t t,r;\n    if(!cntfrq) __asm__ __volatile__ (\"mrs %0, cntfrq_el0\" : \"=r\" (cntfrq));\n    __asm__ __volatile__ (\"mrs %0, cntpct_el0\" : \"=r\" (t));\n    t+=((cntfrq/1000)*cnt)/1000;do{__asm__ __volatile__ (\"mrs %0, cntpct_el0\" : \"=r\" (r));}while(r<t);\n}\n\n/**\n * Wait for data or command ready\n */\nint sd_status(uint32_t mask)\n{\n    int cnt = 500000; while((*EMMC_STATUS & mask) && !(*EMMC_INTERRUPT & INT_ERROR_MASK) && cnt--) delayms(1);\n    return (cnt <= 0 || (*EMMC_INTERRUPT & INT_ERROR_MASK)) ? SD_ERROR : SD_OK;\n}\n\n/**\n * Wait for interrupt\n */\nint sd_int(uint32_t mask)\n{\n    uint32_t r, m=mask | INT_ERROR_MASK;\n    int cnt = 1000000; while(!(*EMMC_INTERRUPT & m) && cnt--) delayms(1);\n    r=*EMMC_INTERRUPT;\n    if(cnt<=0 || (r & INT_CMD_TIMEOUT) || (r & INT_DATA_TIMEOUT) ) { *EMMC_INTERRUPT=r; return SD_TIMEOUT; } else\n    if(r & INT_ERROR_MASK) { *EMMC_INTERRUPT=r; return SD_ERROR; }\n    *EMMC_INTERRUPT=mask;\n    return 0;\n}\n\n/**\n * Send a command\n */\nint sd_cmd(uint32_t code, uint32_t arg)\n{\n    uint32_t r=0;\n    sd_err=SD_OK;\n    if(code&CMD_NEED_APP) {\n        r=sd_cmd(CMD_APP_CMD|(sd_rca?CMD_RSPNS_48:0),sd_rca);\n        if(sd_rca && !r) { printf(\"EMMC: failed to send SD APP command\\r\\n\"); sd_err=SD_ERROR;return 0;}\n        code &= ~CMD_NEED_APP;\n    }\n    if(sd_status(SR_CMD_INHIBIT)) { printf(\"EMMC: busy, timed out\\r\\n\"); sd_err= SD_TIMEOUT;return 0;}\n    *EMMC_INTERRUPT=*EMMC_INTERRUPT; *EMMC_ARG1=arg; *EMMC_CMDTM=code;\n    if(code==CMD_SEND_OP_COND) delayms(1000); else\n    if(code==CMD_SEND_IF_COND || code==CMD_APP_CMD) delayms(100);\n    if((r=sd_int(INT_CMD_DONE))) {printf(\"EMMC: failed to send command\\r\\n\");sd_err=r;return 0;}\n    r=*EMMC_RESP0;\n    if(code==CMD_GO_IDLE || code==CMD_APP_CMD) return 0; else\n    if(code==(CMD_APP_CMD|CMD_RSPNS_48)) return r&SR_APP_CMD; else\n    if(code==CMD_SEND_OP_COND) return r; else\n    if(code==CMD_SEND_IF_COND) return r==arg? SD_OK : SD_ERROR; else\n    if(code==CMD_ALL_SEND_CID) {r|=*EMMC_RESP3; r|=*EMMC_RESP2; r|=*EMMC_RESP1; return r; } else\n    if(code==CMD_SEND_REL_ADDR) {\n        sd_err=(((r&0x1fff))|((r&0x2000)<<6)|((r&0x4000)<<8)|((r&0x8000)<<8))&CMD_ERRORS_MASK;\n        return r&CMD_RCA_MASK;\n    }\n    return r&CMD_ERRORS_MASK;\n}\n\n/**\n * Load a sector from boot drive using EMMC\n */\nint sd_loadsec(uint64_t lba, void *dst)\n{\n    int r,d;\n    uint32_t *buf=(uint32_t *)dst;\n\n#ifdef SD_DEBUG\n    printf(\"EMMC: sd_loadsec lba %d dst %lx\\r\\n\", lba, dst);\n#endif\n    if(sd_status(SR_DAT_INHIBIT)) {sd_err=SD_TIMEOUT; return 0;}\n    *EMMC_BLKSIZECNT = (1 << 16) | 512;\n    sd_cmd(CMD_READ_SINGLE, sd_scr[0] & SCR_SUPP_CCS ? lba : lba << 9);\n    if(sd_err) return 0;\n    if((r=sd_int(INT_READ_RDY))){printf(\"\\rEMMC: timeout waiting for ready to read\\n\");sd_err=r;return 0;}\n    for(d=0;d<128;d++) buf[d] = *EMMC_DATA;\n    return sd_err!=SD_OK;\n}\n\n/**\n * set SD clock to frequency in Hz\n */\nint sd_clk(uint32_t f)\n{\n    uint32_t d,c=41666666/f,x,s=32,h=0;\n    int cnt = 100000;\n    while((*EMMC_STATUS & (SR_CMD_INHIBIT|SR_DAT_INHIBIT)) && cnt--) delayms(1);\n    if(cnt<=0) {printf(\"EMMC: timeout waiting for inhibit flag\\r\\n\"); return SD_ERROR; }\n\n    *EMMC_CONTROL1 &= ~C1_CLK_EN; delayms(10);\n    x=c-1; if(!x) s=0; else {\n        if(!(x & 0xffff0000u)) { x <<= 16; s -= 16; }\n        if(!(x & 0xff000000u)) { x <<= 8;  s -= 8; }\n        if(!(x & 0xf0000000u)) { x <<= 4;  s -= 4; }\n        if(!(x & 0xc0000000u)) { x <<= 2;  s -= 2; }\n        if(!(x & 0x80000000u)) { x <<= 1;  s -= 1; }\n        if(s>0) s--;\n        if(s>7) s=7;\n    }\n    if(sd_hv>HOST_SPEC_V2) d=c; else d=(1<<s);\n    if(d<=2) {d=2;s=0;}\n#ifdef SD_DEBUG\n    printf(\"sd_clk divisor %x, shift %x\\r\\n\", d, s);\n#endif\n    if(sd_hv>HOST_SPEC_V2) h=(d&0x300)>>2;\n    d=(((d&0x0ff)<<8)|h);\n    *EMMC_CONTROL1=(*EMMC_CONTROL1&0xffff003f)|d; delayms(10);\n    *EMMC_CONTROL1 |= C1_CLK_EN; delayms(10);\n    cnt=10000; while(!(*EMMC_CONTROL1 & C1_CLK_STABLE) && cnt--) delayms(10);\n    if(cnt<=0) {printf(\"EMMC: failed to get stable clock\\r\\n\");return SD_ERROR;}\n    return SD_OK;\n}\n\n/**\n * initialize EMMC to read SDHC card\n */\nint sd_init()\n{\n    long r,cnt,ccs=0;\n    sd_hv = (*EMMC_SLOTISR_VER & HOST_SPEC_NUM) >> HOST_SPEC_NUM_SHIFT;\n#ifdef SD_DEBUG\n    printf(\"EMMC: GPIO set up hcl ver %d\\r\\n\", sd_hv);\n#endif\n    if(sd_hv<HOST_SPEC_V2) {printf(\"EMMC: SDHCI version too old\\r\\n\"); return SD_ERROR;}\n    /* Reset the card. */\n    *EMMC_CONTROL0 = 0;\n    r = *EMMC_CONTROL1; r |= C1_SRST_HC; r &= ~(C1_CLK_EN | C1_CLK_INTLEN); *EMMC_CONTROL1 = r;\n    cnt=10000; do{delayms(10);} while( (*EMMC_CONTROL1 & C1_SRST) && cnt-- );\n    if(cnt<=0) {printf(\"EMMC: failed to reset EMMC\\r\\n\"); return SD_ERROR;}\n#ifdef SD_DEBUG\n    printf(\"EMMC: reset OK\\n\");\n#endif\n    *EMMC_CONTROL0 = 0xF << 8; /* set voltage to 3.3 */\n    *EMMC_CONTROL1 |= C1_CLK_INTLEN | C1_TOUNIT_MAX;\n    delayms(10);\n    /* Set clock to setup frequency. */\n    if((r=sd_clk(400000))) return r;\n    *EMMC_INT_EN   = 0xffffffff;\n    *EMMC_INT_MASK = 0xffffffff;\n    sd_scr[0]=sd_scr[1]=sd_rca=sd_err=0;\n    sd_cmd(CMD_GO_IDLE,0);\n    if(sd_err) return sd_err;\n\n    sd_cmd(CMD_SEND_IF_COND,0x000001AA);\n    if(sd_err) return sd_err;\n    cnt=6; r=0; while(!(r&ACMD41_CMD_COMPLETE) && cnt--) {\n        delayms(1);\n        r=sd_cmd(CMD_SEND_OP_COND,ACMD41_ARG_HC);\n#ifdef SD_DEBUG\n        printf(\"EMMC: CMD_SEND_OP_COND returned \");\n        if(r&ACMD41_CMD_COMPLETE) printf(\"COMPLETE \");\n        if(r&ACMD41_VOLTAGE) printf(\"VOLTAGE \");\n        if(r&ACMD41_CMD_CCS) printf(\"CCS \");\n        printf(\"%x\\r\\n\", r);\n#endif\n        if(sd_err!=SD_TIMEOUT && sd_err!=SD_OK ) {printf(\"EMMC: EMMC ACMD41 returned error\\r\\n\"); return sd_err;}\n    }\n    if(!(r&ACMD41_CMD_COMPLETE) || !cnt ) return SD_TIMEOUT;\n    if(!(r&ACMD41_VOLTAGE)) return SD_ERROR;\n    if(r&ACMD41_CMD_CCS) ccs=SCR_SUPP_CCS;\n\n    sd_cmd(CMD_ALL_SEND_CID,0);\n\n    sd_rca = sd_cmd(CMD_SEND_REL_ADDR,0);\n#ifdef SD_DEBUG\n    printf(\"EMMC: CMD_SEND_REL_ADDR returned %x\\r\\n\", sd_rca);\n#endif\n    if(sd_err) return sd_err;\n\n    if((r=sd_clk(25000000))) return r;\n\n    sd_cmd(CMD_CARD_SELECT,sd_rca);\n    if(sd_err) return sd_err;\n\n    if(sd_status(SR_DAT_INHIBIT)) return SD_TIMEOUT;\n    *EMMC_BLKSIZECNT = (1<<16) | 8;\n    sd_cmd(CMD_SEND_SCR,0);\n    if(sd_err) return sd_err;\n    if(sd_int(INT_READ_RDY)) return SD_TIMEOUT;\n\n    r=0; cnt=100000; while(r<2 && cnt) {\n        if( *EMMC_STATUS & SR_READ_AVAILABLE )\n            sd_scr[r++] = *EMMC_DATA;\n        else\n            delayms(1);\n    }\n    if(r!=2) return SD_TIMEOUT;\n    if(sd_scr[0] & SCR_SD_BUS_WIDTH_4) {\n        sd_cmd(CMD_SET_BUS_WIDTH,sd_rca|2);\n        if(sd_err) return sd_err;\n        *EMMC_CONTROL0 |= C0_HCTL_DWITDH;\n    }\n    /* add software flag */\n#ifdef SD_DEBUG\n    printf(\"EMMC: supports \");\n    if(sd_scr[0] & SCR_SUPP_SET_BLKCNT) printf(\"SET_BLKCNT \");\n    if(ccs) printf(\"CCS \");\n    printf(\"\\r\\n\");\n#endif\n    sd_scr[0]&=~SCR_SUPP_CCS;\n    sd_scr[0]|=ccs;\n    return SD_OK;\n}\n\n/**************** Common functions ****************/\n\n/**\n * Load a sector from boot drive using EMMC\n */\nint fw_loadsec(uint64_t lba, void *dst)\n{\n    return sd_loadsec(lba, dst);\n}\n\n/**\n * Allocate and zero out a page\n */\nuint64_t fw_alloc(void)\n{\n    uint64_t page = file_buf;\n    file_buf += 4096;\n    memset((void*)page, 0, 4096);\n    return page;\n}\n\n/**\n * Map virtual memory\n */\nint fw_map(uint64_t phys, uint64_t virt, uint32_t size)\n{\n    uint64_t end = virt + size, *ptr, *next = NULL, orig = file_buf, type;\n\n    /* is this a canonical address? We handle virtual memory up to 256TB */\n    if(!pt || ((virt >> 48L) != 0x0000 && (virt >> 48L) != 0xffff)) return 0;\n    /* if we're mapping the framebuffer, use device SH=2 memory type */\n    type = 0x03 | (1<<10) | (file_buf < 0x20000 ? (2<<8) | (1<<2) | (1L<<54) : (3<<8));\n\n    /* walk the page tables and add the missing pieces */\n    for(virt &= ~4095, phys &= ~4095; virt < end; virt += 4096) {\n        /* 1G */\n        ptr = &pt[((virt >> 48L) ? 512 : 0) + ((virt >> 30L) & 511)];\n        if(!*ptr) { if(!(*ptr = fw_alloc())) return 0; else *ptr |= 3|(3<<8)|(1<<10); }\n        /* 2M if we previously had a large page here, split it into 4K pages */\n        ptr = (uint64_t*)(*ptr & ~4095); ptr = &ptr[(virt >> 21L) & 511];\n        if(!(*ptr & 0x2)) { if(!(*ptr = fw_alloc())) return 0; else *ptr |= 3|(3<<8)|(1<<10); }\n        /* 4K */\n        ptr = (uint64_t*)(*ptr & ~4095); ptr = &ptr[(virt >> 12L) & 511];\n        /* if this page is already mapped, that means the kernel has invalid, overlapping segments */\n        if(!*ptr) { *ptr = (uint64_t)next; next = ptr; }\n    }\n    /* resolve the linked list */\n    for(end = ((phys == orig ? file_buf : phys) + size - 1) & ~4095; next; end -= 4096, next = ptr) {\n        ptr = (uint64_t*)*next; *next = end | type;\n    }\n    return 1;\n}\n\n/**\n * Initialize firmware related stuff\n */\nvoid fw_init(void)\n{\n    uint64_t i=0, ms, me;\n\n    /* get the base address */\n    __asm__ __volatile__(\"mrs %0, midr_el1;\":\"=r\"(mmio_base)::);\n    switch(mmio_base & 0xFFF0) {\n        case 0xD030: rpi = 3; mmio_base = 0x3F000000; emmc_base = 0x3F300000; break;     /* Raspberry Pi 3 */\n        default:     rpi = 4; mmio_base = 0xFE000000; emmc_base = 0xFE340000; break;     /* Raspberry Pi 4 */\n    }\n    file_base = (uint64_t)_bss_end;\n    /* if we got a DTB from the firmware, move it out of the way */\n    if(dtb_base && (uintptr_t)dtb_base < 2*1024*1024 && dtb_base[0] == 0xD0 && dtb_base[1] == 0x0D &&\n      dtb_base[2] == 0xFE && dtb_base[3] == 0xED) {\n        i = dtb_base[7] | (dtb_base[6] << 8) | (dtb_base[5] << 16);\n        memcpy((void*)file_base, dtb_base, i);\n        dtb_base = (uint8_t*)(uintptr_t)file_base; file_base += 4096 + ((i + 4095) & ~4095);\n    } else dtb_base = 0;\n    /* initialize screen and console */\n    mbox_lfb(0, 0, 0);\n    fb_w = vidmode.framebuffer_width; fb_h = vidmode.framebuffer_height; fb_bpp = vidmode.framebuffer_bpp;\n    console_init();\n    /* set up paging */\n    ms = mmio_base >> 21; me = (mmio_base + 0x800000) >> 21;\n    pt = (uint64_t*)0x1000;\n    memset(pt, 0, 8 * 4096);\n    /* TTBR0 */\n    for(i = 0; i < 4; i++)\n        pt[i] = (uintptr_t)pt + ((i + 2) * 4096) + (3|(3<<8)|(1<<10));\n    for(i = 0; i < 4 * 512; i++) pt[1024 + i] = (uintptr_t)i * 2 * 1024 * 1024 +\n        /* if we're mapping the mmio area, use device SH=2 memory type */\n        (1 | (1<<10) | (i >= ms && i < me ? (2<<8) | (1<<2) | (1L<<54) : (3<<8)));\n    /* dynamically map framebuffer */\n    if(vidmode.framebuffer_addr) {\n        /* map new pages from the page table area */\n        file_buf = 0x7000;\n        fw_map(vidmode.framebuffer_addr, vidmode.framebuffer_addr,\n            (vidmode.framebuffer_pitch * vidmode.framebuffer_height + 4095) & ~4095);\n    }\n    file_buf = file_base;\n    /* TTBR1 */\n    /* pt[512] = nothing for now; */\n}\n\n/**\n * Initialize root file system\n */\nvoid fw_fsinit(void)\n{\n    uint32_t i, j, n;\n    uint64_t k, l;\n\n    /* initialize SDCard */\n    sd_init();\n    /* get boot partition's root directory */\n    fw_loadsec(1, &vbr);\n    root_dir = 0;\n    if(!memcmp(&vbr, EFI_PTAB_HEADER_ID, 8)) {\n        /* found GPT */\n        j = ((gpt_header_t*)&vbr)->SizeOfPartitionEntry;\n        n = ((gpt_header_t*)&vbr)->NumberOfPartitionEntries;\n        l = ((gpt_header_t*)&vbr)->PartitionEntryLBA;\n        /* look for ESP */\n        for(k = 0; n && !root_dir; k++) {\n            fw_loadsec(l + k, &vbr);\n            for(i = 0; n && i + j <= 512; i += j, n--) {\n                /* does ESP type match? */\n                if(!memcmp(&((gpt_entry_t*)&vbr[i])->PartitionTypeGUID, &espGuid, sizeof(guid_t))) {\n                    root_dir = ((gpt_entry_t*)&vbr[i])->StartingLBA;\n                    memcpy(&bootuuid, &(((gpt_entry_t*)&vbr[i])->UniquePartitionGUID), sizeof(guid_t));\n                    break;\n                }\n            }\n        }\n    } else {\n        /* fallback to MBR partitioning scheme */\n        fw_loadsec(0, &vbr);\n        if(vbr[510] == 0x55 && vbr[511] == 0xAA)\n            for(i = 0x1c0; i < 510; i += 16)\n                if(vbr[i - 2] == 0x80/*active*/ && (vbr[i + 2] == 0xC/*FAT32*/ || vbr[i + 2] == 0xEF/*ESP*/)) {\n                    root_dir = (uint64_t)(*((uint32_t*)&vbr[i + 6]));\n                    memcpy(&bootuuid.Data1, \"PART\", 4); memcpy(bootuuid.Data4, \"boot\", 4);\n                    bootuuid.Data3 = (i - 0x1c0) / 16;\n                    break;\n                }\n    }\n    if(root_dir) {\n        fw_loadsec(root_dir, &vbr);\n        bpb = (esp_bpb_t*)&vbr;\n        if(vbr[510] != 0x55 || vbr[511] != 0xAA || vbr[11] || vbr[12] != 2 || !bpb->spc || bpb->spf16 || !bpb->spf32)\n            root_dir = 0;\n        else {\n            /* calculate the LBA address of the FAT and the first data sector */\n            fat_lba = bpb->rsc + (uint64_t)root_dir;\n            data_lba = bpb->spf32 * bpb->nf + bpb->rsc - 2 * bpb->spc + (uint64_t)root_dir;\n            /* load the beginning of the FAT into the cache */\n            for(i = 0; i < 8; i++) fw_loadsec(fat_lba + i, &fat[i << 7]);\n            fat_cache = 0;\n        }\n    }\n}\n\n/**\n * Display a boot splash\n */\nvoid fw_bootsplash(void)\n{\n    uint32_t c;\n    uint8_t *fb = (uint8_t*)vidmode.framebuffer_addr;\n    int i, j, k, l, x, y, w, h, o, m, p, px, py, b = (vidmode.framebuffer_bpp + 7) >> 3;\n\n    /* clear screen */\n    if(!fb) return;\n    for(j = y = 0; y < (int)vidmode.framebuffer_height; y++, j += vidmode.framebuffer_pitch)\n        for(i = j, x = 0; x < (int)vidmode.framebuffer_width; x++, i += b)\n            if(b == 2) *((uint16_t*)(fb + i)) = (uint16_t)fb_bg; else *((uint32_t*)(fb + i)) = fb_bg;\n#ifdef CONSOLE_FB\n    fb_x = fb_y = 4;\n#endif\n    /* only indexed RLE compressed TGA images supported */\n    if(!logo_buf || logo_buf[0] || logo_buf[1] != 1 || logo_buf[2] != 9 || logo_buf[3] || logo_buf[4] ||\n        (logo_buf[7] != 24 && logo_buf[7] != 32)) return;\n    /* uncompress image */\n    o = (logo_buf[17] & 0x20); w = (logo_buf[13] << 8) + logo_buf[12]; h = (logo_buf[15] << 8) + logo_buf[14];\n    if(w < 1 || h < 1) return;\n    px = ((int)vidmode.framebuffer_width - w) / 2; py = ((int)vidmode.framebuffer_height - h) / 2;\n    m = ((logo_buf[7] >> 3) * ((logo_buf[6] << 8) | logo_buf[5])) + 18; y = i = 0;\n    for(l = 0, x = w, y = -1; l < w * h && (uint32_t)m < logo_size;) {\n        k = logo_buf[m++];\n        if(k > 127) { p = 0; k -= 127; j = logo_buf[m++] * (logo_buf[7] >> 3) + 18; } else { p = 1; k++; }\n        l += k;\n        while(k--) {\n            if(p) j = logo_buf[m++] * (logo_buf[7] >> 3) + 18;\n            if(x == w) { x = 0; i = ((py + (!o ? h - y - 1 : y)) * (int)vidmode.framebuffer_pitch + (px + x) * b); y++; }\n            if(py + y > 0 && py + y < (int)vidmode.framebuffer_height - 1) {\n                if(px + x > 0 && px + x < (int)vidmode.framebuffer_width - 1) {\n                    c = FB_COLOR(logo_buf[j + 2], logo_buf[j + 1], logo_buf[j + 0]);\n                    if(b == 2) *((uint16_t*)(fb + i)) = (uint16_t)c; else *((uint32_t*)(fb + i)) = c;\n                }\n                i += b;\n            }\n            x++;\n        }\n    }\n}\n\n/**\n * Get the next cluster from FAT\n */\nuint32_t fw_nextclu(uint32_t clu)\n{\n    uint64_t i;\n\n    if(clu < 2 || clu >= 0x0FFFFFF8) return 0;\n    if(clu < fat_cache || clu > fat_cache + 1023) {\n        fat_cache = clu & ~1023;\n        for(i = 0; i < 8; i++) fw_loadsec(fat_lba + (fat_cache >> 7) + i, &fat[i << 7]);\n    }\n    clu = fat[clu - fat_cache];\n    return clu < 2 || clu >= 0x0FFFFFF8 ? 0 : clu;\n}\n\n/**\n * Open a file\n */\nint fw_open(char *fn)\n{\n    uint64_t lba;\n    uint32_t clu = bpb->rc;\n    int i, n = 0, m = 0;\n    uint8_t secleft = 0, *dir = data + sizeof(data);\n    uint16_t *u, *s = wcname, a, b, c, *d;\n    char *S;\n\n    if(!fn || !*fn) return 0;\n    /* UTF-8 to WCHAR */\n    for(S = fn, d = wcname; *S && *S != ' ' && *S != '\\r' && *S != '\\n' && d < &wcname[PATH_MAX - 2]; d++) {\n        if((*S & 128) != 0) {\n            if(!(*S & 32)) { c = ((*S & 0x1F)<<6)|(*(S+1) & 0x3F); S++; } else\n            if(!(*S & 16)) { c = ((*S & 0xF)<<12)|((*(S+1) & 0x3F)<<6)|(*(S+2) & 0x3F); S += 2; } else\n            if(!(*S & 8)) { c = ((*S & 0x7)<<18)|((*(S+1) & 0x3F)<<12)|((*(S+2) & 0x3F)<<6)|(*(S+3) & 0x3F); *S += 3; }\n            else c = 0;\n        } else c = *S;\n        S++; if(c == '\\\\' && *S == ' ') { c = ' '; S++; }\n        *d = c;\n    }\n    *d = 0;\n\n    file_size = file_clu = 0;\n    memset(lfn, 0, sizeof(lfn));\n    while(1) {\n        /* have we reached the end of the sector? */\n        if(dir >= data + sizeof(data)) {\n            if(secleft) { secleft--; lba++; }\n            else {\n                if(clu < 2 || clu >= 0x0FFFFFF8) return 0;\n                secleft = bpb->spc - 1;\n                lba = clu * bpb->spc + data_lba;\n                clu = fw_nextclu(clu);\n            }\n            fw_loadsec(lba, &data);\n            dir = data;\n        }\n        /* empty space? End of directory then */\n        if(!dir[0]) return 0;\n        /* not a deleted entry or current and parent entries? */\n        if(dir[0] != 5 && dir[0] != 0xE5 && (dir[0] != '.' || (dir[1] != '.' && dir[1] != ' '))) {\n            /* is this an LFN block? */\n            if(dir[0xB] == 0xF) {\n                /* first LFN block? */\n                if(!n || (dir[0] & 0x40)) {\n                    memset(lfn, 0, sizeof(lfn));\n                    n = dir[0] & 0x1F;\n                    /* bad record, not sure what to do. Let's reset state and continue with next entry */\n                    if(n < 1 || n > 20) { n = m = 0; dir += 32; continue; }\n                    u = lfn + (n - 1) * 13;\n                }\n                /* get the next part of UCS-2 characters */\n                for(i = 0; i < 5; i++)\n                    u[i] = dir[i*2+2] << 8 | dir[i*2+1];\n                for(i = 0; i < 6; i++)\n                    u[i+5] = dir[i*2+0xF] << 8 | dir[i*2+0xE];\n                u[11] = dir[0x1D] << 8 | dir[0x1C];\n                u[12] = dir[0x1F] << 8 | dir[0x1E];\n                u -= 13;\n                n--;\n                /* indicate that the next directory entry belongs to an LFN */\n                m = (!n && u < lfn);\n            } else\n            if(!(dir[0xB] & 8)) {\n                /* if we don't have an LFN already, generate it from the 8.3 name in this entry */\n                if(!m) {\n                    for(i = 0; i < 8; i++) lfn[i] = dir[i];\n                    while(i && lfn[i - 1] == ' ') i--;\n                    if(dir[8] != ' ') {\n                        lfn[i++] = '.'; lfn[i++] = dir[8];\n                        if(dir[9] != ' ') {\n                            lfn[i++] = dir[9];\n                            if(dir[10] != ' ') { lfn[i++] = dir[10]; }\n                        }\n                    }\n                    lfn[i] = 0;\n                } else m = 0;\n                /* filename match? */\n                if(*s == '/') s++;\n                for(i = 0; lfn[i] && s[i] && s[i] != '/'; i++) {\n                    a = lfn[i]; if(a >= 'A' && a <= 'Z') a += 'a' - 'A';\n                    b = s[i]; if(b >= 'A' && b <= 'Z') b += 'a' - 'A';\n                    if(a != b) break;\n                }\n                if(!lfn[i]) {\n                    clu = (dir[0x15] << 24) | (dir[0x14] << 16) | (dir[0x1B] << 8) | dir[0x1A];\n                    /* is this a directory? */\n                    if(dir[0xB] & 0x10) {\n                        if(s[i] != '/') return 0;\n                        /* go to subdirectory */\n                        s += i + 1; n = m = secleft = 0; dir = data + sizeof(data);\n                        continue;\n                    } else {\n                        /* no, it's a file, then we have located what we were looking for */\n                        if(clu < 2 || clu >= 0x0FFFFFF8) return 0;\n                        file_clu = clu;\n                        file_size = (dir[0x1F] << 24) | (dir[0x1E] << 16) | (dir[0x1D] << 8) | dir[0x1C];\n                        break;\n                    }\n                }\n            }\n        }\n        dir += 32;\n    }\n    return 1;\n}\n\n/**\n * Read data from file\n */\nuint64_t fw_read(uint64_t offs, uint64_t size, void *buf)\n{\n    uint64_t lba = 0, rem, o;\n    uint32_t clu = file_clu, nc, ns = 0, os = 0, rs = 512;\n    uint8_t secleft = 0;\n\n    if(file_clu < 2 || offs >= file_size || !size || !buf) return 0;\n    if(offs + size > file_size) size = file_size - offs;\n    rem = size;\n\n    pb_init(size);\n    if(offs) {\n        nc = offs / (bpb->spc << 9); o = offs % (bpb->spc << 9);\n        ns = o >> 9; os = o & 0x1ff; rs = 512 - os;\n        if(nc) { while(nc-- && clu) { clu = fw_nextclu(clu); } if(!clu) return 0; }\n        secleft = bpb->spc - ns - 1;\n        lba = clu * bpb->spc + ns - 1 + data_lba;\n    }\n    while(rem && !rq) {\n        /* check for user interruption */\n        if(!bkp && !rq && !(*UART0_FR & 0x10)) { rq = 1; break; }\n        if(secleft) { secleft--; lba++; }\n        else {\n            if(!clu) break;\n            secleft = bpb->spc - 1;\n            lba = clu * bpb->spc + data_lba;\n            clu = fw_nextclu(clu);\n        }\n        if(rs > rem) rs = rem;\n        if(rs < 512) {\n            fw_loadsec(lba, data);\n            memcpy(buf, data + os, rs); os = 0;\n        } else {\n            fw_loadsec(lba, buf);\n            if(os) { memcpy(buf, buf + os, rs); os = 0; }\n        }\n        buf += rs; rem -= rs; rs = 512;\n        pb_draw(size - rem);\n    }\n    pb_fini();\n    return (size - rem);\n}\n\n/**\n * Close file\n */\nvoid fw_close(void)\n{\n    file_clu = file_size = 0;\n}\n\n/**\n * Load and parse config (everything except modules)\n */\nvoid fw_loadconfig(void)\n{\n    char *s, *e, *a;\n    uint32_t r, g, b;\n    int l, m = 0;\n\n    if(bkp) { fw_bootsplash(); printf(\"Aborted, loading backup configuration...\\r\\n\"); }\n\n    kernel = NULL;\n    tags_buf = (uint8_t*)(uintptr_t)0x20000;\n    /* as a fallback, we try to load the first menuentry from easyboot's configuration */\n    if(fw_open(\"simpleboot.cfg\") || (!bkp && fw_open(\"easyboot/menu.cfg\"))) {\n        conf_buf = (char*)tags_buf;\n        tags_buf += (file_size + 7) & ~7;\n        fw_read(0, file_size, conf_buf);\n        conf_buf[file_size] = 0;\n        fw_close();\n        fb_w = vidmode.framebuffer_width; fb_h = vidmode.framebuffer_height; fb_bpp = vidmode.framebuffer_bpp; fb_bg = 0; smp = 0;\n        for(s = conf_buf; *s;) {\n            /* find beginning of a line */\n            while(*s && (*s == '\\r' || *s == '\\n' || *s == ' ' || *s == '\\t')) s++;\n            for(a = s; *a && *a != ' ' && *a != '\\r' && *a != '\\n'; a++);\n            for(e = a; *e && *e != '\\r' && *e != '\\n'; e++);\n            for(; a < e && *a == ' '; a++);\n            /* 's' points to the start of the command,\n             * 'a' to the first argument,\n             * 'e' to the end of the line */\n            l = !memcmp(s, \"backup\", 6);\n            if(bkp ^ l) { s = e; continue; } else if(bkp & l) s += 6;\n            if(!memcmp(s, \"multicore\", 9)) smp = 1;\n            if(a >= e) { s = e; continue; }\n            if(!memcmp(s, \"menuentry\", 9)) {\n                if(++m > 1) break;\n            } else\n            if(!memcmp(s, \"verbose\", 7)) {\n                a = getint(a, &verbose);\n            } else\n            if(!memcmp(s, \"framebuffer\", 11)) {\n                a = getint(a, &fb_w); while(a < e && *a == ' ') a++;\n                a = getint(a, &fb_h); while(a < e && *a == ' ') a++;\n                a = getint(a, &fb_bpp);\n                if(fb_w < 320 || fb_w > 65536 || fb_h < 200 || fb_h > 65536 || fb_bpp < 15 || fb_bpp > 32) {\n                    fb_w = vidmode.framebuffer_width; fb_h = vidmode.framebuffer_height; fb_bpp = vidmode.framebuffer_bpp;\n                }\n            } else\n            if(!memcmp(s, \"bootsplash\", 10)) {\n                if(*a == '#') {\n                    a++; a = gethex(a, &r); a = gethex(a, &g); a = gethex(a, &b);\n                    fb_bg = FB_COLOR(r, g, b);\n                    while(a < e && *a == ' ') a++;\n                }\n                if(a < e) {\n                    if(fw_open(a)) {\n                        logo_buf = tags_buf;\n                        tags_buf += (file_size + 7) & ~7;\n                        if(verbose) printf(\"Loading logo '%S' (%ld bytes)...\\r\\n\", wcname, file_size);\n                        logo_size = file_size;\n                        fw_read(0, file_size, logo_buf);\n                        fw_close();\n                    } else if(verbose) printf(\"WARNING: unable to load '%S'\\r\\n\", wcname);\n                }\n                fw_bootsplash();\n            } else\n            if(a < e && !memcmp(s, \"kernel\", 6)) {\n                kernel = a;\n                for(; a < e && *a && *a != ' ' && *a != '\\r' && *a != '\\n'; a++)\n                    if(*a == '\\\\' && a[1] == ' ') a++;\n                while(a < e && *a == ' ') a++;\n                if(*a && *a != '\\r' && *a != '\\n') cmdline = a;\n            }\n            /* go to the next line */\n            s = e;\n        }\n    }\n    if(!kernel) kernel = (char*)defkernel;\n    if(!bkp && (volatile char)definitrd[63] == 1) smp = 1;\n}\n\n/**\n * Detect config file independent configuration and generate tags for them\n */\nvoid fw_loadsetup()\n{\n    multiboot_tag_loader_t *stag;\n    multiboot_tag_mmap_t *mtag;\n    char *c;\n\n    mod_buf = 0;\n    file_buf = file_base;\n    tags_ptr = tags_buf;\n    if(tags_ptr) {\n        /* MBI header */\n        ((multiboot_info_t*)tags_buf)->total_size = ((multiboot_info_t*)tags_buf)->reserved = 0;\n        tags_ptr += sizeof(multiboot_info_t);\n        /* loader tag */\n        stag = (multiboot_tag_loader_t*)tags_ptr;\n        stag->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME;\n        stag->size = bkp ? 28 : 19;\n        memcpy(stag->string, SIMPLEBOOT_MAGIC, 11);\n        if(bkp) memcpy(stag->string + 10, \" (backup)\", 10);\n        tags_ptr += (stag->size + 7) & ~7;\n        /* commandline tag */\n        if(cmdline) {\n            for(c = cmdline; *c && *c != '\\r' && *c != '\\n'; c++);\n            stag = (multiboot_tag_loader_t*)tags_ptr;\n            stag->type = MULTIBOOT_TAG_TYPE_CMDLINE;\n            stag->size = 9 + c - cmdline;\n            memcpy(stag->string, cmdline, c - cmdline); stag->string[c - cmdline] = 0;\n            tags_ptr += (stag->size + 7) & ~7;\n            /* overwrite the cmdline pointer with this new, zero terminated string */\n            cmdline = stag->string;\n        }\n        mbox[0]=8*4;\n        mbox[1]=0;\n        mbox[2]=0x10005; /* get memory size */\n        mbox[3]=8;\n        mbox[4]=0;\n        mbox[5]=0;\n        mbox[6]=0;\n        mbox[7]=0;\n        if(mbox_call(MBOX_CH_PROP)) ram = mbox[6];\n        else ram = 64*1024*1024;\n        ram &= ~(2 * 1024 * 1024 - 1);\n        /* generate memory map tag */\n        mtag = (multiboot_tag_mmap_t*)tags_ptr;\n        mtag->type = MULTIBOOT_TAG_TYPE_MMAP;\n        mtag->entry_size = sizeof(multiboot_mmap_entry_t);\n        mtag->entry_version = 0;\n        mtag->entries[0].base_addr = 0;\n        mtag->entries[0].length = 0x400;\n        mtag->entries[0].type = MULTIBOOT_MEMORY_RESERVED;\n        mtag->entries[0].reserved = 0;\n        mtag->entries[1].base_addr = 0x400;\n        mtag->entries[1].length = ram - 0x400;\n        mtag->entries[1].type = MULTIBOOT_MEMORY_AVAILABLE;\n        mtag->entries[1].reserved = 0;\n        mtag->entries[2].base_addr = mmio_base;\n        mtag->entries[2].length = 0x00800000;\n        mtag->entries[2].type = MULTIBOOT_MEMORY_RESERVED;\n        mtag->entries[2].reserved = EfiMemoryMappedIO;\n        mtag->size = sizeof(multiboot_tag_mmap_t) + 3 * sizeof(multiboot_mmap_entry_t);\n        tags_ptr += (mtag->size + 7) & ~7;\n    }\n}\n\n/**\n * Parse config for modules and load them\n */\nvoid fw_loadmodules(void)\n{\n    uint64_t unc_buf;\n    uint32_t uncomp;\n    uint8_t *ptr, tmp[16];\n    int n = 0, f = 0, l;\n    multiboot_tag_module_t *tag;\n    char *s, *e, *a;\n\n    if(conf_buf) {\n        for(s = conf_buf; !rq && !f && *s;) {\n            /* find beginning of a line */\n            while(*s && (*s == '\\r' || *s == '\\n' || *s == ' ' || *s == '\\t')) s++;\n            for(a = s; *a && *a != ' ' && *a != '\\r' && *a != '\\n'; a++);\n            for(e = a; *e && *e != '\\r' && *e != '\\n'; e++);\n            for(; a < e && *a == ' '; a++);\n            /* 's' points to the start of the command,\n             * 'a' to the first argument,\n             * 'e' to the end of the line */\n            l = !memcmp(s, \"backup\", 6);\n            if(a >= e || bkp ^ l) { s = e; continue; } else if(bkp & l) s += 6;\n            if(!memcmp(s, \"module\", 6)) {\nldinitrd:       if(fw_open(a)) {\n                    fw_read(0, 16, (void*)tmp);\n                    /* if it's a gzip compressed module, then load it at position + uncompressed size,\n                     * and uncompress to position. Compressed buffer will be overwritten by the next module. */\n                    uncomp = 0;\n                    if(tmp[0] == 0x1f && tmp[1] == 0x8b)\n                        fw_read(file_size - 4, 4, (void*)&uncomp);\n                    else\n                    if(tmp[0] == 'G' && tmp[1] == 'U' && tmp[2] == 'D' && tmp[8] == 0x78)\n                        uncomp = (((tmp[4] | (tmp[5] << 8)) + 7) & ~7) + ((tmp[6] | (tmp[7] << 8)) << 4);\n                    ptr = (uint8_t*)file_buf;\n                    if(uncomp) {\n                        unc_buf = file_buf;\n                        file_buf += (uncomp + 4095) & ~4095;\n                        mod_buf = file_buf;\n                    } else {\n                        unc_buf = 0;\n                        mod_buf = file_buf;\n                        file_buf += (file_size + 4095) & ~4095;\n                    }\n                    if(verbose) printf(\"Loading module '%S' (%ld bytes)...\\r\\n\", wcname, file_size);\n                    fw_read(0, file_size, (void*)mod_buf);\n                    if(unc_buf) {\n                        if(verbose) printf(\"Uncompressing module '%S' (%d bytes)...\\r\\n\", wcname, uncomp);\n                        uncompress((uint8_t*)mod_buf, (uint8_t*)unc_buf, uncomp);\n                    }\n                    /* if it's a DTB, DSDT or a GUDT, don't add it to the modules list, add it to the ACPI tables */\n                    if(ptr[0] == 0xD0 && ptr[1] == 0x0D && ptr[2] == 0xFE && ptr[3] == 0xED) {\n                        if(verbose) printf(\"DTB detected...\\r\\n\");\n                        dtb_base = ptr;\n                        /* make sure we have enough space after the dtb, because we'll have to patch it */\n                        file_buf += 4096;\n                    } else\n                    if(((ptr[0] == 'D' && ptr[1] == 'S') || (ptr[0] == 'G' && ptr[1] == 'U')) && ptr[2] == 'D' && ptr[3] == 'T') {\n                        if(verbose) printf(\"%c%cDT detected...\\n\", ptr[0], ptr[1]);\n                        dtb_base = ptr;\n                    } else {\n                        if(tags_ptr) {\n                            tag = (multiboot_tag_module_t*)tags_ptr;\n                            tag->type = MULTIBOOT_TAG_TYPE_MODULE;\n                            tag->size = sizeof(multiboot_tag_module_t) + e - a + 1;\n                            tag->mod_start = unc_buf ? (uint32_t)(uintptr_t)unc_buf : (uint32_t)(uintptr_t)mod_buf;\n                            tag->mod_end = unc_buf ? (uint32_t)(uintptr_t)unc_buf + uncomp :\n                                (uint32_t)(uintptr_t)mod_buf + (uint32_t)file_size;\n                            memcpy(tag->string, a, e - a); tag->string[e - a] = 0;\n                            if(verbose > 2) printf(\"%D\\r\\n\", tag->mod_start);\n                            tags_ptr += (tag->size + 7) & ~7;\n                            if(!initrd) initrd = tag;\n                        }\n                        n++;\n                    }\n                    fw_close();\n                } else if(verbose) printf(\"WARNING: unable to load '%S'\\r\\n\", wcname);\n            }\n            /* go to the next line */\n            s = e;\n        }\n    }\n    /* if no modules were loaded, but we have a default initrd name, try to add that */\n    if(!n && !f) { f = 1; if((volatile char)definitrd[0]) { a = (char*)definitrd; for(e = a; *e; e++){} goto ldinitrd; } }\n    if(!n && f == 1) { f = 2; a = bkp ? \"rpi/initrd.bak\" : \"rpi/initrd\"; e = a + (bkp ? 16 : 12); goto ldinitrd; }\n}\n\n/**\n * Load a kernel segment\n */\nint fw_loadseg(uint32_t offs, uint32_t filesz, uint64_t vaddr, uint32_t memsz)\n{\n    uint64_t top;\n    uint8_t *buf = (uint8_t*)(uintptr_t)vaddr;\n    uint32_t size;\n\n    if(!memsz || !file_size) return 1;\n    if(verbose > 1) printf(\"  segment %08x[%08x] -> %08x[%08x]\\r\\n\", offs, filesz, vaddr, memsz);\n    size = (memsz + (vaddr & 4095) + 4095) & ~4095;\n    /* no overwriting of the loader data */\n    if(vaddr < _bss_end) goto err;\n    if(vaddr > ram) {\n        /* possibly a higher-half kernel's segment, we must map it */\n        if(!fw_map(file_buf, vaddr, size)) goto err;\n        buf = (void*)file_buf; file_buf += size;\n    } else {\n        /* make sure we load modules after the kernel to avoid any conflict */\n        top = ((uintptr_t)buf + size + 4095) & ~4095; if(file_buf < top) file_buf = top;\n    }\n    if(filesz) fw_read(offs, filesz, buf);\n    if(memsz > filesz) memset(buf + filesz, 0, memsz - filesz);\n    return 1;\nerr:printf(\"ERROR: unable to load segment %08lx[%x], memory already in use\\r\\n\", vaddr, memsz);\n    return 0;\n}\n\n/**\n * Load the kernel\n */\nint fw_loadkernel(void)\n{\n    void *p = (void*)kernel_buf;\n    pe_hdr *pe;\n    pe_sec *sec;\n    uint8_t *ptr;\n    uint64_t offs;\n    int i;\n\n    wcname[0] = 0;\n    if(!((kernel && *kernel && fw_open(kernel)) || fw_open(\"rpi/core\"))) {\n        smp = 0;\n        if(wcname[0]) printf(\"ERROR: kernel '%S' not found\\r\\n\", wcname);\n        else printf(\"ERROR: kernel not found\\r\\n\");\n        return 0;\n    }\n    fw_read(0, sizeof(kernel_buf), p);\n    if(!memcmp(kernel_buf, \"MZ\", 2) && !memcmp(kernel_buf + 0x38, \"ARM\", 3) && kernel_buf[0x3b] == 64) {\n        /* it's a Linux kernel */\n        kernel_mode = MODE_LIN; smp = 0;\n        if(verbose) printf(\"Loading Linux kernel...\\r\\n\");\n        if(!fw_loadseg(0, file_size, 0x80000, file_size)) goto err;\n    } else\n    if(!memcmp(((Elf64_Ehdr*)p)->e_ident, ELFMAG, 4) && ((Elf64_Ehdr*)p)->e_ident[EI_CLASS] == ELFCLASS64 &&\n      ((Elf64_Ehdr*)p)->e_machine == EM_AARCH64) {\n        /* it's a Multiboot2 ELF kernel */\n        kernel_mode = MODE_MB64;\n        kernel_entry = (uint8_t*)(uintptr_t)((Elf64_Ehdr*)p)->e_entry;\n        if(verbose) printf(\"Loading Multiboot2 ELF64 kernel '%S'...\\r\\n\", wcname);\n        ptr = p + ((Elf64_Ehdr*)p)->e_phoff;\n        for(i = 0; !rq && i < ((Elf64_Ehdr*)p)->e_phnum && ptr + ((Elf64_Ehdr*)p)->e_phentsize < kernel_buf + sizeof(kernel_buf);\n          i++, ptr += ((Elf64_Ehdr*)p)->e_phentsize)\n            if(((Elf64_Phdr*)ptr)->p_type == PT_LOAD && !fw_loadseg(\n                (((Elf64_Phdr*)ptr)->p_offset), (((Elf64_Phdr*)ptr)->p_filesz),\n                (((Elf64_Phdr*)ptr)->p_vaddr), (((Elf64_Phdr*)ptr)->p_memsz))) goto err;\n    } else\n    if(((mz_hdr*)p)->magic == MZ_MAGIC && ((pe_hdr*)(p + ((mz_hdr*)p)->peaddr))->magic == PE_MAGIC &&\n       ((pe_hdr*)(p + ((mz_hdr*)p)->peaddr))->file_type == PE_OPT_MAGIC_PE32PLUS &&\n       ((pe_hdr*)(p + ((mz_hdr*)p)->peaddr))->machine == IMAGE_FILE_MACHINE_ARM64) {\n        /* it's a Multiboot2 COFF/PE kernel */\n        kernel_mode = MODE_MB64;\n        pe = (pe_hdr*)(p + ((mz_hdr*)p)->peaddr);\n        offs = (uint32_t)pe->data.pe64.img_base;\n        kernel_entry = offs + (uint8_t*)(uintptr_t)pe->entry_point;\n        if(verbose) printf(\"Loading Multiboot2 PE64 kernel '%S'...\\r\\n\", wcname);\n        sec = (pe_sec*)((uint8_t*)pe + pe->opt_hdr_size + 24);\n        for(i = 0; !rq && i < pe->sections && (uint8_t*)&sec[1] < kernel_buf + sizeof(kernel_buf); i++, sec++)\n            /* the PE section vaddr field is only 32 bits, we must make sure that it properly sign extended to 64 bit */\n            if(!fw_loadseg(sec->raddr, sec->rsiz, offs + (int64_t)(int32_t)sec->vaddr, sec->vsiz)) goto err;\n    } else {\n        printf(\"ERROR: unknown kernel format '%S'\\r\\n\", wcname);\nerr:    fw_close();\n        smp = 0;\n        return 0;\n    }\n    fw_close();\n    if(kernel_mode != MODE_MB64) smp = 0;\n    return 1;\n}\n\n/**\n * Finish up MBI tags\n */\nvoid fw_fini(void)\n{\n    rsdp_t *rsdp;\n    register uint64_t reg;\n    uint32_t ow, oh, ob, totalsize, off_dt, off_str, siz_str, siz_dt, tag, sz, ol = 0, nl = 0, cl = 0;\n    uint8_t s, *p, *end, *l = NULL, *cmd = NULL;\n    int i, n = 4;\n\n    /* patch the command line in the dtb, Linux needs this */\n    if(dtb_base && (dtb_base[0] == 0xD0 && dtb_base[1] == 0x0D && dtb_base[2] == 0xFE && dtb_base[3] == 0xED)) {\n        /* proof that Linux developers are incompetent and total morons: where did they put the most likely to change string?\n         * in the string table maybe? Nah, that would be outrageous! They barfed that right in the middle of a binary blob!!! */\n        totalsize = dtb_base[7] | (dtb_base[6] << 8) | (dtb_base[5] << 16);\n        off_dt = dtb_base[11] | (dtb_base[10] << 8) | (dtb_base[9] << 16);\n        off_str = dtb_base[15] | (dtb_base[14] << 8) | (dtb_base[13] << 16);\n        siz_str = dtb_base[35] | (dtb_base[34] << 8) | (dtb_base[33] << 16);\n        siz_dt = dtb_base[39] | (dtb_base[38] << 8) | (dtb_base[37] << 16);\n        p = dtb_base + off_dt; end = dtb_base + off_dt + siz_dt;\n        /* failsafe, we assume that the string table is the last section in the blob */\n        if(off_str >= off_dt + siz_dt) {\n            /* get size of the new command line */\n            if(cmdline && *cmdline) for(; cmdline[cl]; cl++);\n            cl++; nl = (cl + 3) & ~3;\n            /* locate the command line node property */\n            while(p < end) {\n                tag = p[3] | (p[2] << 8) | (p[1] << 16) | (p[0] << 24); p += 4;\n                if(tag == 9) break;\n                if(tag == 1) {\n                    for(l = p; p < end && *p; p++);\n                    p = (uint8_t*)(((uintptr_t)p + 3) & ~3);\n                } else\n                if(tag == 2) l = NULL; else\n                if(tag == 3) {\n                    sz = p[3] | (p[2] << 8) | (p[1] << 16); p += 4; tag = p[3] | (p[2] << 8) | (p[1] << 16); p += 4;\n                    if(tag < siz_str - 1 && l && !memcmp(l, \"chosen\", 7) && !memcmp(dtb_base + off_str + tag, \"bootargs\", 9)) {\n                        cmd = p; ol = (sz + 3) & ~3; break;\n                    }\n                    p = (uint8_t*)(((uintptr_t)p + sz + 3) & ~3);\n                }\n            }\n            /* if we haven't found it */\n            if(!cmd) {\n                /* we need to add the property key to the string table, and a chosen node at the end of the node tree */\n                tag = siz_str; siz_str += 9; totalsize += 9;\n                memcpy(dtb_base + tag, \"bootargs\", 9);\n                cmd = dtb_base + off_dt + siz_dt;\n                for(p = dtb_base + totalsize, l = dtb_base + totalsize + nl + 28; p >= cmd; p++, l++) *l = *p;\n                memcpy(cmd, \"\\0\\0\\0\\1chosen\\0\\0\\0\\0\\0\\3\", 16); cmd += 16;\n                cmd[3] = cl & 0xff; cmd[2] = (cl >> 8) & 0xff; cmd[1] = (cl >> 8) & 0xff; cmd[0] = 0; cmd += 4;\n                cmd[3] = tag & 0xff; cmd[2] = (tag >> 8) & 0xff; cmd[1] = (tag >> 8) & 0xff; cmd[0] = 0; cmd += 4;\n                if(cmdline) memcpy(cmd, cmdline, cl - 1);\n                memset(cmd + cl - 1, 0, nl - cl + 1);\n                memcpy(cmd + nl, \"\\0\\0\\0\\2\", 4);\n                siz_dt += nl + 28; totalsize += nl + 28; off_str += nl + 28;\n            } else {\n                /* update the command line somewhere in the middle... */\n                if(nl < ol) memcpy(cmd + nl, cmd + ol, totalsize - ol); else\n                if(nl > ol) for(p = dtb_base + totalsize, l = dtb_base + totalsize + nl - ol; p >= cmd + ol; p++, l++) *l = *p;\n                cmd[-5] = cl & 0xff; cmd[-6] = (cl >> 8) & 0xff; cmd[-7] = (cl >> 8) & 0xff; cmd[-8] = 0;\n                if(cmdline) memcpy(cmd, cmdline, cl - 1);\n                memset(cmd + cl - 1, 0, nl - cl + 1);\n                siz_dt += nl - ol; totalsize += nl - ol; off_str += nl - ol;\n            }\n            /* write header back with new offset and size values */\n            dtb_base[7] = totalsize & 0xff; dtb_base[6] = (totalsize >> 8) & 0xff; dtb_base[5] = (totalsize >> 16) & 0xff;\n            dtb_base[15] = off_str & 0xff; dtb_base[14] = (off_str >> 8) & 0xff; dtb_base[13] = (off_str >> 16) & 0xff;\n            dtb_base[35] = siz_str & 0xff; dtb_base[34] = (siz_str >> 8) & 0xff; dtb_base[33] = (siz_str >> 16) & 0xff;\n            dtb_base[39] = siz_dt & 0xff; dtb_base[38] = (siz_dt >> 8) & 0xff; dtb_base[37] = (siz_dt >> 16) & 0xff;\n        }\n    }\n\n    if(vidmode.framebuffer_addr) {\n        if(vidmode.framebuffer_width != fb_w || vidmode.framebuffer_height != fb_h || vidmode.framebuffer_bpp != fb_bpp) {\n            ow = vidmode.framebuffer_width; oh = vidmode.framebuffer_height; ob = vidmode.framebuffer_bpp;\n            mbox_lfb(fb_w, fb_h, fb_bpp);\n            if(!vidmode.framebuffer_addr) mbox_lfb(ow, oh, ob);\n            fw_bootsplash();\n        }\n        if(tags_ptr && vidmode.framebuffer_addr) {\n            vidmode.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;\n            vidmode.size = sizeof(vidmode);\n            vidmode.framebuffer_type = 1;\n            vidmode.reserved = 0;\n            memcpy(tags_ptr, &vidmode, vidmode.size);\n            tags_ptr += (vidmode.size + 7) & ~7;\n        }\n    }\n    if(tags_ptr) {\n        /* Get EDID info */\n        mbox[0]=8*4;\n        mbox[1]=0;\n        mbox[2]=0x30020; /* get edid */\n        mbox[3]=4;\n        mbox[4]=0;\n        mbox[5]=0;\n        mbox[6]=0;\n        mbox[7]=0;\n        if(mbox_call(MBOX_CH_PROP) && mbox[3] > 128) {\n            ((multiboot_tag_edid_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_EDID;\n            ((multiboot_tag_edid_t*)tags_ptr)->size = mbox[3];\n            memcpy(tags_ptr + 8, (void*)&mbox[6], mbox[3] - 8);\n            tags_ptr += (mbox[3] + 7) & ~7;\n        }\n        /* create a fake ACPI table */\n        ((multiboot_tag_old_acpi_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_ACPI_OLD;\n        ((multiboot_tag_old_acpi_t*)tags_ptr)->size = sizeof(multiboot_tag_old_acpi_t) + sizeof(rsdp_t);\n        rsdp = (rsdp_t*)&((multiboot_tag_old_acpi_t*)tags_ptr)->rsdp;\n        memset(rsdp, 0, sizeof(rsdp_t));\n        memcpy(&rsdp->magic, \"RSD PTR \", 8);\n        rsdp->rev = 1; rsdp->rsdt = (uint32_t)(uintptr_t)&rsdt;\n        for(s = 0, i = 0; i < (int)sizeof(rsdp_t); i++) { s += *(((uint8_t*)rsdp) + i); } rsdp->chksum = 0x100 - s;\n        memset(&rsdt, 0, sizeof(rsdt_t));\n        memcpy(&rsdt.hdr.magic, \"RSDT\", 4);\n        rsdt.hdr.rev = 1; rsdt.hdr.size = sizeof(sdt_hdr_t) + sizeof(uint32_t); rsdt.table_ptr[0] = (uint32_t)(uintptr_t)&apic;\n        if(dtb_base && (\n          (dtb_base[0] == 0xD0 && dtb_base[1] == 0x0D && dtb_base[2] == 0xFE && dtb_base[3] == 0xED) ||\n          (((dtb_base[0] == 'D' && dtb_base[1] == 'S') || (dtb_base[0] == 'G' && dtb_base[1] == 'U')) &&\n          dtb_base[2] == 'D' && dtb_base[3] == 'T'))) {\n            /* add fake FADT and DSDT tables to the ACPI list with the DTB data */\n            rsdt.hdr.size += sizeof(uint32_t);\n            rsdt.table_ptr[1] = (uint32_t)(uintptr_t)&fadt; /* DSDT is pointed by FADT, not RSDT */\n            memset(&fadt, 0, sizeof(fadt_t));\n            memcpy(&fadt.hdr.magic, \"FACP\", 4);\n            fadt.hdr.rev = 1; fadt.hdr.size = sizeof(fadt_t); fadt.dsdt = (uint32_t)(uintptr_t)dtb_base;\n            for(s = 0, i = 0; i < (int)sizeof(fadt); i++) { s += *(((uint8_t*)&fadt) + i); } fadt.hdr.chksum = 0x100 - s;\n        }\n        for(s = 0, i = 0; i < (int)sizeof(rsdt_t); i++) { s += *(((uint8_t*)&rsdt) + i); } rsdt.hdr.chksum = 0x100 - s;\n        memset(&apic, 0, sizeof(apic_t));\n        memcpy(&apic.hdr.magic, \"APIC\", 4);\n        apic.hdr.rev = 1; apic.hdr.size = sizeof(sdt_hdr_t) + (n + 1) * 8;\n        for(i = 0; i < n; i++) {\n            apic.cpus[i].type = 0; apic.cpus[i].size = sizeof(cpu_entry_t);\n            apic.cpus[i].acpi_id = i; apic.cpus[i].apic_id =  0xd8 + i * 8; apic.cpus[i].flags = i ? 2 : 1;\n        }\n        for(s = 0, i = 0; i < (int)apic.hdr.size; i++) { s += *(((uint8_t*)&apic) + i); } apic.hdr.chksum = 0x100 - s;\n        tags_ptr += (((multiboot_tag_old_acpi_t*)tags_ptr)->size + 7) & ~7;\n        /* multicore */\n        if(smp) {\n            ((multiboot_tag_smp_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_SMP;\n            ((multiboot_tag_smp_t*)tags_ptr)->size = sizeof(multiboot_tag_smp_t);\n            ((multiboot_tag_smp_t*)tags_ptr)->numcores = n;\n            ((multiboot_tag_smp_t*)tags_ptr)->running = n;\n            ((multiboot_tag_smp_t*)tags_ptr)->bspid = 0;\n            tags_ptr += (((multiboot_tag_smp_t*)tags_ptr)->size + 7) & ~7;\n        }\n        /* partition UUIDs */\n        ((multiboot_tag_partuuid_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_PARTUUID;\n        ((multiboot_tag_partuuid_t*)tags_ptr)->size = 24;\n        memcpy(((multiboot_tag_partuuid_t*)tags_ptr)->bootuuid, &bootuuid, sizeof(guid_t));\n        tags_ptr += (((multiboot_tag_partuuid_t*)tags_ptr)->size + 7) & ~7;\n        /* terminator tag */\n        ((multiboot_tag_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_END;\n        ((multiboot_tag_t*)tags_ptr)->size = 8;\n        tags_ptr += (((multiboot_tag_t*)tags_ptr)->size + 7) & ~7;\n        ((multiboot_info_t*)tags_buf)->total_size = tags_ptr - tags_buf;\n    } else tags_buf = NULL;\n\n    /* enable paging */\n    reg=(0xFF << 0) |    /* Attr=0: normal, IWBWA, OWBWA, NTR */\n        (0x04 << 8) |    /* Attr=1: device, nGnRE (must be OSH too) */\n        (0x44 <<16);     /* Attr=2: non cacheable */\n    __asm__ __volatile__(\"msr mair_el1, %0\" ::\"r\"(reg):);\n    *((uint64_t*)0x518) = reg;\n    __asm__ __volatile__(\"mrs %0, id_aa64mmfr0_el1\" :\"=r\"(reg)::);\n    reg = (reg & 0xF) << 32L; /* IPS=autodetected */\n    reg=(0x00LL << 37) | /* TBI=0, no tagging */\n        (0x02LL << 30) | /* TG1=4k */\n        (0x03LL << 28) | /* SH1=3 inner */\n        (0x01LL << 26) | /* ORGN1=1 write back */\n        (0x01LL << 24) | /* IRGN1=1 write back */\n        (0x00LL << 23) | /* EPD1 undocumented by ARM DEN0024A Fig 12-5, 12-6 */\n        (25LL   << 16) | /* T1SZ=25, 3 levels (512G) */\n        (0x00LL << 14) | /* TG0=4k */\n        (0x03LL << 12) | /* SH0=3 inner */\n        (0x01LL << 10) | /* ORGN0=1 write back */\n        (0x01LL << 8) |  /* IRGN0=1 write back */\n        (0x00LL << 7) |  /* EPD0 undocumented by ARM DEN0024A Fig 12-5, 12-6 */\n        (25LL   << 0);   /* T0SZ=25, 3 levels (512G) */\n    __asm__ __volatile__(\"msr tcr_el1, %0; isb\" ::\"r\" (reg):);\n    *((uint64_t*)0x520) = reg;\n    __asm__ __volatile__(\"msr ttbr0_el1, %0\" ::\"r\"((uintptr_t)pt + 1):);\n    *((uint64_t*)0x528) = (uintptr_t)pt + 1;\n    __asm__ __volatile__(\"msr ttbr1_el1, %0\" ::\"r\"((uintptr_t)pt + 1 + 4096):);\n    *((uint64_t*)0x530) = (uintptr_t)pt + 1 + 4096;\n    /* set mandatory reserved bits */\n    __asm__ __volatile__(\"dsb ish; isb; mrs %0, sctlr_el1\" :\"=r\"(reg)::);\n    reg |= 0xC00801;\n    reg&=~( (1<<25) |   /* clear EE, little endian translation tables */\n            (1<<24) |   /* clear E0E */\n            (1<<19) |   /* clear WXN */\n            (1<<12) |   /* clear I, no instruction cache */\n            (1<<4) |    /* clear SA0 */\n            (1<<3) |    /* clear SA */\n            (1<<2) |    /* clear C, no cache at all */\n            (1<<1));    /* clear A, no aligment check */\n    __asm__ __volatile__(\"msr sctlr_el1, %0; isb\" ::\"r\"(reg):);\n    *((uint64_t*)0x508) = reg;\n    if(smp) {\n        if(verbose) printf(\"Initializing SMP (%d cores)...\\n\", n);\n        *((uint64_t*)0x540) = (uintptr_t)tags_buf;\n        *((uint64_t*)0x538) = 0;\n/* Memory layout (only valid when kernel entry isn't zero)\n *    0x508 -   0x510   sctlr\n *    0x510 -   0x518   vbar\n *    0x518 -   0x520   mair\n *    0x520 -   0x528   tcr\n *    0x528 -   0x530   ttbr0\n *    0x530 -   0x538   ttbr1\n *    0x538 -   0x540   kernel entry point (also SMP semaphor)\n *    0x540 -   0x548   tags_buf\n */\n        __asm__ __volatile__(\n        \"mov w2, %w0; mov x1, x30; bl 1f;1:mov x0, x30;mov x30, x1;add x0, x0, #2f-1b;\"\n        \"mov x1, #0xE0; 9:str x0, [x1], #0;add x1, x1, #8;sub w2, w2, #1;cbnz w2, 9b; b 99f;\"\n        \"2:mov x1, #0x1000;\"\n        \"mrs x0, CurrentEL;and x0, x0, #12;\"\n        \"cmp x0, #12;bne 1f;\"                           /* are we running at EL3? */\n        \"mov x0, #0x5b1;msr scr_el3, x0;mov x0, #0x3c9;msr spsr_el3, x0;adr x0, 1f;msr elr_el3, x0;mov x0, #4;msr sp_el2, x1;eret;\"\n        \"1:cmp x0, #4;beq 1f;\"                          /* are we running at EL2? */\n        \"mrs x0,cnthctl_el2;orr x0,x0,#3;msr cnthctl_el2,x0;msr cnthp_ctl_el2,xzr;\"         /* enable CNTP */\n        \"mov x0,#(1 << 31);orr x0,x0,#2;msr hcr_el2,x0;mrs x0,hcr_el2;\"                     /* enable Aarch64 at EL1 */\n        \"mrs x0,midr_el1;mrs x2,mpidr_el1;msr vpidr_el2,x0;msr vmpidr_el2,x2;\"              /* initialize virtual MPIDR */\n        \"mov x0,#0x33FF;msr cptr_el2,x0;msr hstr_el2,xzr;mov x0,#(3<<20);msr cpacr_el1,x0;\" /* disable coprocessor traps */\n        \"mov x2,#0x0800;movk x2,#0x30d0,lsl #16;msr sctlr_el1, x2;\"                         /* setup SCTLR access */\n        \"mov x2,#0x3c5;msr spsr_el2,x2;adr x2, 1f;msr elr_el2, x2;mov sp, x1;msr sp_el1, x1;eret;\"/* switch to EL1 */\n        \"1:mov sp, x1;mov x2, #0x500;ldr x0, [x2], #0x10;msr vbar_el1,x0;msr SPSel,#0;\"     /* set up exception handlers */\n        /* spinlock waiting for the kernel entry address */\n        \"1:ldr x30, [x2], #0x38;nop;nop;nop;nop;cbz x30, 1b;\"\n        /* initialize AP */\n        \"ldr x0, [x2], #0x18;msr mair_el1,x0;\"\n        \"ldr x0, [x2], #0x20;msr tcr_el1,x0;\"\n        \"ldr x0, [x2], #0x28;msr ttbr0_el1,x0;\"\n        \"ldr x0, [x2], #0x30;msr ttbr1_el1,x0;\"\n        \"ldr x0, [x2], #0x08;dsb ish;msr sctlr_el1,x0;isb;\"\n        /* execute 64-bit kernel (stack: 16 byte aligned, and contains the core's id) */\n        \"mov sp, #0x80000;mrs x0, mpidr_el1;and x0, x0, #3;lsl x1,x0,#10;sub sp,sp,x1;\"     /* stack = 0x80000 - coreid * 1024 */\n        \"str x0, [sp, #-16]!;ldr x0, =0x36d76289;ldr x1, [x2], #0x40;ret;\"                  /* jump to kernel entry */\n        \"99:\"::\"r\"(n - 1):);\n    }\n    *((uint64_t*)0x558) = 0;\n}\n\n/**\n * Dummy exception handler\n */\nvoid fw_exc(uint8_t excno, uint64_t esr, uint64_t elr, uint64_t spsr, uint64_t far, uint64_t sctlr, uint64_t tcr)\n{\n    register uint64_t r0, r1, r2, r3;\n#ifdef CONSOLE_FB\n    uint32_t i, j, x, y, b;\n#endif\n    if(!in_exc) {\n        in_exc++;\n        /* only report exceptions for the BSP */\n        __asm__ __volatile__ (\"mrs x8, mpidr_el1; and x8, x8, #3; cbz x8, 2f; 1: wfe; b 1b; 2:;\" :::\"x8\");\n        __asm__ __volatile__ (\"msr ttbr0_el1, %0;tlbi vmalle1\" ::\"r\"((uint64_t)&pt[0] + 1));\n        __asm__ __volatile__ (\"dsb ish; isb; mrs %0, sctlr_el1\" :\"=r\"(r0)::);\n        /* set mandatory reserved bits to disable cache */\n        r0 &= ~((1 << 12) /* clear I */ | (1 << 2) /* clear C */);\n        __asm__ __volatile__ (\"msr sctlr_el1, %0; isb\" ::\"r\"(r0));\n\n#ifdef CONSOLE_FB\n        if(vidmode.framebuffer_addr) {\n            b = (vidmode.framebuffer_bpp + 7) >> 3;\n            fb_x = fb_y = 4; fb_bg = FB_COLOR(255, 0, 0);\n            for(j = y = 0; y < 8 + (((psf2_t*)font_psf)->height << 1); y++, j += vidmode.framebuffer_pitch)\n                for(i = j, x = 0; x < vidmode.framebuffer_width; x++, i += b)\n                    if(b == 2) *((uint16_t*)(vidmode.framebuffer_addr + i)) = (uint16_t)fb_bg;\n                    else *((uint32_t*)(vidmode.framebuffer_addr + i)) = fb_bg;\n        }\n#endif\n        printf(\"Simpleboot Exception Handler\\r\\nException #%02x\\r\\n\\r\\n\", excno);\n#ifdef CONSOLE_FB\n        fb_bg = 0;\n#endif\n        __asm__ __volatile__(\"mrs %0, sp_el0;mov %1, sp;mrs %2, ttbr0_el1;mrs %3, ttbr1_el1\" :\"=r\"(r0),\"=r\"(r1),\"=r\"(r2),\"=r\"(r3)::);\n        printf(\"  ESR %016x   ELR %016x\\n SPSR %016x   FAR %016x\\nSCTLR %016x   TCR %016x\\n  SP0 %016x   SP1 %016x\\n\"\n            \"TTBR0 %016x TTBR1 %016x\\n\\n\", esr, elr, spsr, far, sctlr, tcr, r0, r1, r2, r3);\n        printf(\"Code\\r\\n%D\\r\\nStack\\r\\n%4D\\r\\n\", elr, r0);\n    }\n    __asm__ __volatile__(\"1: wfe; b 1b\");\n}\n\n/*****************************************\n *     Simpleboot loader entry point     *\n *****************************************/\n/* actually almost. We come here from _preambule */\nvoid _start(void)\n{\n    /* initialize everything to zero */\n    memset((void*)(uintptr_t)_bss_start, 0, _bss_end - _bss_start);\n    fw_init();\n    printf(\"Simpleboot loader, Copyright (c) 2023 bzt, MIT license\\r\\n\");\n    /* the emmc driver might print error messages, so call this after we have a console */\n    fw_fsinit();\n\nagain:\n    fw_loadconfig();\n    fw_loadsetup();\n    if(!ram) { printf(\"ERROR: unable to determine the amount of RAM\\r\\n\"); goto err; }\n    else if(verbose && !bkp) printf(\"Physical RAM %ld Megabytes\\r\\n\", ram / 1024 / 1024 + 2);\n\n    /* now we have the kernel's filename, try to load that, it's a critical error if fails */\n    if(!fw_loadkernel()) goto err;\n    /* last step, load modules too */\n    fw_loadmodules();\n    /* if the user pressed a key during loading, fallback to backup and do over */\n    if(!bkp && rq) { bkp++; rq = 0; goto again; }\n\n    /* finish up things, finalize tags list */\n    fw_fini();\n\n    /* transfer control to kernel. Should never return */\n    if(!kernel_entry) { printf(\"ERROR: no kernel entry point\\r\\n\"); goto err; }\n    if(verbose > 2) printf(\"Kernel entry:\\r\\n%4D\", kernel_entry);\n\n    switch(kernel_mode) {\n        case MODE_MB64:\n            if(verbose > 1)\n                printf(\"Transfering control to %08x(%08x, %08x[%x])\\r\\n\", kernel_entry,\n                    MULTIBOOT2_BOOTLOADER_MAGIC, tags_buf, tags_ptr - tags_buf);\n            if(smp) {\n                /* tell APs to execute kernel */\n                *((volatile uint64_t*)0x538) = (uintptr_t)kernel_entry; __asm__ __volatile__(\"dsb ish\":::\"memory\");\n                /* execute 64-bit kernels in long mode */\n                __asm__ __volatile__(\n                \"ldr x0, =tags_buf; ldr x1, [x0], #0;\"  /* MBI tags pointer */\n                \"ldr x0, =0x36d76289;\"                  /* magic */\n                \"mov sp, #0x80000;str xzr, [sp, #-16]!;\"/* stack, bsp id on top */\n                \"mov x30, %0; ret\"                      /* jump to entry point */\n                ::\"r\"(kernel_entry):);\n            } else {\n                __asm__ __volatile__(\n                \"ldr x0, =tags_buf; ldr x1, [x0], #0;\"  /* MBI tags pointer */\n                \"ldr x0, =0x36d76289;\"                  /* magic */\n                \"mov sp, #0x80000; mov x30, %0; ret\"    /* stack and jump to entry point */\n                ::\"r\"(kernel_entry):);\n            }\n        break;\n        case MODE_LIN:\n            if(verbose > 1)\n                printf(\"Transfering control to 80000\\r\\n\");\n            __asm__ __volatile__(\n            \"mov x0, %0; mov x1, xzr; mov x2, xzr; mov x3, xzr;\"\n            \"mov x30,#0x80000; mov sp, x30; ret\"\n            ::\"r\"(dtb_base):);\n        break;\n    }\n    printf(\"ERROR: kernel should not have returned\\r\\n\");\n\n    /* there's nowhere to return to on BIOS, halt machine */\nerr:if(bkp) __asm__ __volatile__(\"1:wfe; b 1b;\");\n    else while(1) { if(!(*UART0_FR & 0x10)) { bkp++; goto again; } }\n}\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/loader_x86.c",
    "content": "/*\n * src/loader_x86.c\n * https://gitlab.com/bztsrc/simpleboot\n *\n * Copyright (C) 2023 bzt (bztsrc@gitlab), MIT license\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * @brief The main Simpleboot loader program on x86_64\n *\n * Memory layout when booted on UEFI:\n *     Arbitrary, uses relocations. Data buffers are allocated through BootServices\n *    0x510 -   0x5A0   AP startup data\n *   0x8000 -  0x80FF   relocated AP startup code\n *\n * Memory layout when booted on BIOS:\n *      0x0 -   0x400   IVT\n *    0x400 -   0x4FF   BDA\n *    0x4FF -   0x500   BIOS boot drive code\n *    0x500 -   0x510   BIOS LBA packet\n *    0x510 -   0x520   GDT value\n *    0x520 -   0x530   IDT value\n *    0x580 -   0x600   EDID info\n *    0x600 -   0x800   temporary disk, E820 or VESA buffer\n *    0x800 -   0xB00   temporary VESA buffer continued\n *    0xB00 -  0x1000   stack (ca. 1280 bytes)\n *   0x1000 -  0x8000   paging tables\n *   0x8000 - 0x20000   our COFF sections (0x8000 - 0x80FF relocated AP startup code)\n *  0x20000 - 0x90000   config + logo + tags; from the top to bottom: kernel's stack\n *  0x90000 - 0x9A000   Linux kernel only: zero page + cmdline\n *  0x9A000 - 0xA0000   EBDA\n *  0xA0000 - 0xFFFFF   VRAM and BIOS ROM\n * 0x100000 -      x    kernel segments, followed by the modules, each page aligned\n */\n\n/**\n * The longest path we can handle\n */\n#define PATH_MAX 1024\n/**\n * Maximum size of MBI tags in pages (30 * 4096 = 122k)\n */\n#define TAGS_MAX 30\n\n/**\n * Specify where the boot messages should appear, make it a comment to disable\n */\n#define CONSOLE_SERIAL  0x3f8                       /* default serial, IO base address of COM1 port */\n#define CONSOLE_FB                                  /* on screen too */\n#define CONSOLE_VGA                                 /* fallback text mode console in BIOS */\n/*#define CONSOLE_BOCHS_E9*/                        /* bochs E9 port hack */\n/*#define CONSOLE_UEFI*/                            /* UEFI ConOut */\n\n/* it is VERY important that these two variables must be the first in the\n * read-only data segment, because the disk generator might alter them */\nconst char defkernel[64] = \"kernel\", definitrd[64] = \"\";\n\n#include \"../simpleboot.h\"\n#include \"loader.h\"\n\n/* IMPORTANT: don't assume .bss is zeroed out like in a hosted environment, because it's not */\nefi_system_table_t *ST;\nesp_bpb_t *bpb;\nfossbios_t *FB;\nmultiboot_mmap_entry_t *memmap;\nmultiboot_tag_module_t *initrd;\nmultiboot_tag_framebuffer_t vidmode;\nuint64_t vbr_lba, vbr_size, file_size, rsdp_ptr, dsdt_ptr, file_buf, mod_buf, ram, *pt, hack_buf;\nuint32_t fb_w, fb_h, fb_bpp, fb_bg, logo_size, verbose, num_memmap, pb_b, pb_m, pb_l, rq, bkp, smp;\nuint16_t bootdev, wcname[PATH_MAX];\nuint8_t *tags_buf, *tags_ptr, *logo_buf, *kernel_entry, kernel_mode, kernel_buf[4096], *pb_fb, in_exc;\nchar *conf_buf, *kernel, *cmdline;\nconst char excstr[32][3] = { \"DE\", \"DB\", \"NI\", \"BP\", \"OF\", \"BR\", \"UD\", \"DF\", \"CO\", \"TS\", \"NP\", \"SS\", \"GP\", \"PF\",\n    \"15\", \"MF\", \"AC\", \"MC\", \"XF\", \"20\", \"CP\", \"22\", \"23\", \"24\", \"25\", \"26\", \"27\", \"HV\", \"VC\", \"SX\", \"31\" };\nlinux_boot_params_t *zero_page;\nrsdt_t __attribute__((aligned(16))) rsdt;\nfadt_t __attribute__((aligned(16))) fadt;\n\n#define sleep(n) do { \\\n        __asm__ __volatile__ ( \"rdtsc\" : \"=a\"(a),\"=d\"(b)); d = (((uint64_t)b << 32UL)|(uint64_t)a) + n*(*((uint64_t*)0x548)); \\\n            do { __asm__ __volatile__ ( \"pause;rdtsc\" : \"=a\"(a),\"=d\"(b)); c = ((uint64_t)b << 32UL)|(uint64_t)a; } while(c < d); \\\n    } while(0)\n#define send_ipi(a,m,v) do { \\\n        while(*((volatile uint32_t*)(lapic + 0x300)) & (1 << 12)) __asm__ __volatile__ (\"pause\" : : : \"memory\"); \\\n        *((volatile uint32_t*)(lapic + 0x310)) = (*((volatile uint32_t*)(lapic + 0x310)) & 0x00ffffff) | (a << 24); \\\n        *((volatile uint32_t*)(lapic + 0x300)) = (*((volatile uint32_t*)(lapic + 0x300)) & m) | v;  \\\n    } while(0)\n\n/**************** These will be overriden by the SMP trampoline code ****************/\n\n/**\n * Convert hex string into integer\n */\nchar *gethex(char *ptr, uint32_t *ret)\n{\n    int len = 2;\n    *ret = 0;\n    for(;len--;ptr++) {\n        if(*ptr>='0' && *ptr<='9') {          *ret <<= 4; *ret += (uint32_t)(*ptr - '0'); }\n        else if(*ptr >= 'a' && *ptr <= 'f') { *ret <<= 4; *ret += (uint32_t)(*ptr - 'a' + 10); }\n        else if(*ptr >= 'A' && *ptr <= 'F') { *ret <<= 4; *ret += (uint32_t)(*ptr - 'A' + 10); }\n        else break;\n    }\n    return ptr;\n}\n\n/**\n * Convert decimal string to integer\n */\nchar *getint(char *ptr, uint32_t *ret)\n{\n    for(*ret = 0; *ptr >= '0' && *ptr <= '9'; ptr++) { *ret *= 10; *ret += (uint32_t)(*ptr - '0'); }\n    return ptr;\n}\n\n/**************** Mandatory functions, Clang generates calls to them ****************/\n\nvoid memcpy(void *dst, const void *src, uint32_t n) { __asm__ __volatile__(\"repnz movsb\"::\"D\"(dst),\"S\"(src),\"c\"(n):); }\nvoid memset(void *dst, uint8_t c, uint32_t n) { __asm__ __volatile__(\"repnz stosb\"::\"D\"(dst),\"a\"(c),\"c\"(n):); }\nint  memcmp(const void *s1, const void *s2, uint32_t n) {\n    int ret;\n    __asm__ __volatile__(\"cld;repe cmpsb;xorl %%eax,%%eax;movb -1(%%rdi), %%al;subb -1(%%rsi), %%al;\"\n    :\"=a\"(ret)\n    :\"D\"(s1),\"S\"(s2),\"c\"(n):);\n    return ret;\n}\n\n/**************** Early boot console ****************/\n\n#ifdef CONSOLE_FB\ntypedef struct { uint32_t magic, version, headersize, flags, numglyph, bytesperglyph, height, width; } __attribute__((packed)) psf2_t;\nuint8_t font_psf[2080] = { 114,181,74,134,0,0,0,0,32,0,0,0,0,0,12,0,128,0,0,0,16,0,0,0,16,0,0,0,8,0,0,0,0,0,218,2,128,130,2,128,130,2,128,182,0,0,0,0,0,0,126,129,165,129,129,189,153,129,129,126,0,0,0,0,0,0,126,255,219,255,255,195,231,255,255,126,0,0,0,0,0,0,0,0,108,254,254,254,254,124,56,16,0,0,0,0,0,0,0,0,16,56,124,254,124,56,16,0,0,0,0,0,0,0,0,24,60,60,231,231,231,24,24,60,0,0,0,0,0,0,0,24,60,126,255,255,126,24,24,60,0,0,0,0,0,0,0,0,0,0,24,60,60,24,0,0,0,0,0,0,255,255,255,255,255,255,231,195,195,231,255,255,255,255,255,255,0,0,0,0,0,60,102,66,66,102,60,0,0,0,0,0,255,255,255,255,255,195,153,189,189,153,195,255,255,255,255,255,0,0,30,14,26,50,120,204,204,204,204,120,0,0,0,0,0,0,60,102,102,102,102,60,24,126,24,24,0,0,0,0,0,0,63,51,63,48,48,48,48,112,240,224,0,0,0,0,0,0,127,99,127,99,99,99,99,103,231,230,192,0,0,0,0,0,0,24,24,219,60,231,60,219,24,24,0,0,0,0,0,128,192,224,240,248,254,248,240,224,192,128,0,0,0,0,0,2,6,14,30,62,254,62,30,14,6,2,0,0,0,0,0,0,24,60,126,24,24,24,126,60,24,0,0,0,0,0,0,0,102,102,102,102,102,102,102,0,102,102,0,0,0,0,0,0,127,219,219,219,123,27,27,27,27,27,0,0,0,0,0,124,198,96,56,108,198,198,108,56,12,198,124,0,0,0,0,0,0,0,0,0,0,0,254,254,254,254,0,0,0,0,0,0,24,60,126,24,24,24,126,60,24,126,0,0,0,0,0,0,24,60,126,24,24,24,24,24,24,24,0,0,0,0,0,0,24,24,24,24,24,24,24,126,60,24,0,0,0,0,0,0,0,0,0,24,12,254,12,24,0,0,0,0,0,0,0,0,0,0,0,48,96,254,96,48,0,0,0,0,0,0,0,0,0,0,0,0,192,192,192,254,0,0,0,0,0,0,0,0,0,0,0,40,108,254,108,40,0,0,0,0,0,0,0,0,0,0,16,56,56,124,124,254,254,0,0,0,0,0,0,0,0,0,254,254,124,124,56,56,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,60,60,60,24,24,24,0,24,24,0,0,0,0,0,102,102,102,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,108,108,254,108,108,108,254,108,108,0,0,0,0,24,24,124,198,194,192,124,6,6,134,198,124,24,24,0,0,0,0,0,0,194,198,12,24,48,96,198,134,0,0,0,0,0,0,56,108,108,56,118,220,204,204,204,118,0,0,0,0,0,48,48,48,32,0,0,0,0,0,0,0,0,0,0,0,0,0,12,24,48,48,48,48,48,48,24,12,0,0,0,0,0,0,48,24,12,12,12,12,12,12,24,48,0,0,0,0,0,0,0,0,0,102,60,255,60,102,0,0,0,0,0,0,0,0,0,0,0,24,24,126,24,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,24,24,48,0,0,0,0,0,0,0,0,0,0,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,24,0,0,0,0,0,0,0,0,2,6,12,24,48,96,192,128,0,0,0,0,0,0,56,108,198,198,214,214,198,198,108,56,0,0,0,0,0,0,24,56,120,24,24,24,24,24,24,126,0,0,0,0,0,0,124,198,6,12,24,48,96,192,198,254,0,0,0,0,0,0,124,198,6,6,60,6,6,6,198,124,0,0,0,0,0,0,12,28,60,108,204,254,12,12,12,30,0,0,0,0,0,0,254,192,192,192,252,6,6,6,198,124,0,0,0,0,0,0,56,96,192,192,252,198,198,198,198,124,0,0,0,0,0,0,254,198,6,6,12,24,48,48,48,48,0,0,0,0,0,0,124,198,198,198,124,198,198,198,198,124,0,0,0,0,0,0,124,198,198,198,126,6,6,6,12,120,0,0,0,0,0,0,0,0,24,24,0,0,0,24,24,0,0,0,0,0,0,0,0,0,24,24,0,0,0,24,24,48,0,0,0,0,0,0,0,6,12,24,48,96,48,24,12,6,0,0,0,0,0,0,0,0,0,126,0,0,126,0,0,0,0,0,0,0,0,0,0,96,48,24,12,6,12,24,48,96,0,0,0,0,0,0,124,198,198,12,24,24,24,0,24,24,0,0,0,0,0,0,0,124,198,198,222,222,222,220,192,124,0,0,0,0,0,0,16,56,108,198,198,254,198,198,198,198,0,0,0,0,0,0,252,102,102,102,124,102,102,102,102,252,0,0,0,0,0,0,60,102,194,192,192,192,192,194,102,60,0,0,0,0,0,0,248,108,102,102,102,102,102,102,108,248,0,0,0,0,0,0,254,102,98,104,120,104,96,98,102,254,0,0,0,0,0,0,254,102,98,104,120,104,96,96,96,240,0,0,0,0,0,0,60,102,194,192,192,222,198,198,102,58,0,0,0,0,0,0,198,198,198,198,254,198,198,198,198,198,0,0,0,0,0,0,60,24,24,24,24,24,24,24,24,60,0,0,0,0,0,0,30,12,12,12,12,12,204,204,204,120,0,0,0,0,0,0,230,102,102,108,120,120,108,102,102,230,0,0,0,0,0,0,240,96,96,96,96,96,96,98,102,254,0,0,0,0,0,0,198,238,254,254,214,198,198,198,198,198,0,0,0,0,0,0,198,230,246,254,222,206,198,198,198,198,0,0,0,0,0,0,124,198,198,198,198,198,198,198,198,124,0,0,0,0,0,0,252,102,102,102,124,96,96,96,96,240,0,0,0,0,0,0,124,198,198,198,198,198,198,214,222,124,12,14,0,0,0,0,252,102,102,102,124,108,102,102,102,230,0,0,0,0,0,0,124,198,198,96,56,12,6,198,198,124,0,0,0,0,0,0,126,126,90,24,24,24,24,24,24,60,0,0,0,0,0,0,198,198,198,198,198,198,198,198,198,124,0,0,0,0,0,0,198,198,198,198,198,198,198,108,56,16,0,0,0,0,0,0,198,198,198,198,214,214,214,254,238,108,0,0,0,0,0,0,198,198,108,124,56,56,124,108,198,198,0,0,0,0,0,0,102,102,102,102,60,24,24,24,24,60,0,0,0,0,0,0,254,198,134,12,24,48,96,194,198,254,0,0,0,0,0,0,60,48,48,48,48,48,48,48,48,60,0,0,0,0,0,0,0,128,192,224,112,56,28,14,6,2,0,0,0,0,0,0,60,12,12,12,12,12,12,12,12,60,0,0,0,0,16,56,108,198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,48,48,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,120,12,124,204,204,204,118,0,0,0,0,0,0,224,96,96,120,108,102,102,102,102,124,0,0,0,0,0,0,0,0,0,124,198,192,192,192,198,124,0,0,0,0,0,0,28,12,12,60,108,204,204,204,204,118,0,0,0,0,0,0,0,0,0,124,198,254,192,192,198,124,0,0,0,0,0,0,56,108,100,96,240,96,96,96,96,240,0,0,0,0,0,0,0,0,0,118,204,204,204,204,204,124,12,204,120,0,0,0,224,96,96,108,118,102,102,102,102,230,0,0,0,0,0,0,24,24,0,56,24,24,24,24,24,60,0,0,0,0,0,0,6,6,0,14,6,6,6,6,6,6,102,102,60,0,0,0,224,96,96,102,108,120,120,108,102,230,0,0,0,0,0,0,56,24,24,24,24,24,24,24,24,60,0,0,0,0,0,0,0,0,0,236,254,214,214,214,214,198,0,0,0,0,0,0,0,0,0,220,102,102,102,102,102,102,0,0,0,0,0,0,0,0,0,124,198,198,198,198,198,124,0,0,0,0,0,0,0,0,0,220,102,102,102,102,102,124,96,96,240,0,0,0,0,0,0,118,204,204,204,204,204,124,12,12,30,0,0,0,0,0,0,220,118,102,96,96,96,240,0,0,0,0,0,0,0,0,0,124,198,96,56,12,198,124,0,0,0,0,0,0,16,48,48,252,48,48,48,48,54,28,0,0,0,0,0,0,0,0,0,204,204,204,204,204,204,118,0,0,0,0,0,0,0,0,0,102,102,102,102,102,60,24,0,0,0,0,0,0,0,0,0,198,198,214,214,214,254,108,0,0,0,0,0,0,0,0,0,198,108,56,56,56,108,198,0,0,0,0,0,0,0,0,0,198,198,198,198,198,198,126,6,12,248,0,0,0,0,0,0,254,204,24,48,96,198,254,0,0,0,0,0,0,14,24,24,24,112,24,24,24,24,14,0,0,0,0,0,0,24,24,24,24,24,24,24,24,24,24,24,24,0,0,0,0,112,24,24,24,14,24,24,24,24,112,0,0,0,0,0,0,118,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,56,108,198,198,198,254,0,0,0,0,0 };\nuint32_t fb_x, fb_y;\n#endif\n#ifdef CONSOLE_VGA\nuint16_t vga_x, vga_y;\n#endif\n\n/**\n * Initialize the console\n */\nvoid console_init(void)\n{\n#ifdef CONSOLE_SERIAL\n    if(FB && FB->serial) FB->serial->setmode(0, 115200, 8, 0, 1); else\n    __asm__ __volatile__(\n        \"movl %0, %%edx;\"\n        \"xorb %%al, %%al;outb %%al, %%dx;\"               /* IER int off */\n        \"movb $0x80, %%al;addb $2,%%dl;outb %%al, %%dx;\" /* LCR set divisor mode */\n        \"movb $1, %%al;subb $3,%%dl;outb %%al, %%dx;\"    /* DLL divisor lo 115200 */\n        \"xorb %%al, %%al;incb %%dl;outb %%al, %%dx;\"     /* DLH divisor hi */\n        \"incb %%dl;outb %%al, %%dx;\"                     /* FCR fifo off */\n        \"movb $0x43, %%al;incb %%dl;outb %%al, %%dx;\"    /* LCR 8N1, break on */\n        \"movb $0x8, %%al;incb %%dl;outb %%al, %%dx;\"     /* MCR Aux out 2 */\n        \"xorb %%al, %%al;subb $4,%%dl;inb %%dx, %%al\"    /* clear receiver/transmitter */\n    : : \"a\"(CONSOLE_SERIAL + 1): \"rdx\");\n#endif\n#ifdef CONSOLE_FB\n    fb_x = fb_y = 4;\n#endif\n#ifdef CONSOLE_VGA\n    vga_x = vga_y = 0;\n    if(!vidmode.framebuffer_addr && !ST) memset((void*)0xB8000, 0, 160 * 25);\n#endif\n#ifdef CONSOLE_UEFI\n    if(ST && ST->ConOut) ST->ConOut->Reset(ST->ConOut, 0);\n#endif\n}\n\n/**\n * Display a character on boot console\n */\nvoid console_putc(uint8_t c)\n{\n#ifdef CONSOLE_UEFI\n    uint16_t tmp[2];\n#endif\n#ifdef CONSOLE_FB\n    psf2_t *font = (psf2_t*)font_psf;\n    uint32_t x, y, line, mask, offs, bpl = (font->width + 7) >> 3;\n    uint8_t *glyph, *fb = (uint8_t*)vidmode.framebuffer_addr;\n#endif\n    if(FB && FB->serial) FB->serial->send(0, c); else\n    __asm__ __volatile__(\n        \"xorl %%ebx, %%ebx; movb %0, %%bl;\"\n#ifdef CONSOLE_SERIAL\n        \"movl $10000,%%ecx;\"\n        \"1:inb %%dx, %%al;pause;\"\n        \"cmpb $0xff,%%al;je 2f;\"\n        \"dec %%ecx;jz 2f;\"\n        \"andb $0x20,%%al;jz 1b;\"\n        \"subb $5,%%dl;movb %%bl, %%al;outb %%al, %%dx;2:;\"\n#endif\n#ifdef CONSOLE_BOCHS_E9\n        \"movb %%bl, %%al;outb %%al, $0xe9;\"\n#endif\n    ::\"a\"(c),\"d\"(CONSOLE_SERIAL + 5): \"rbx\", \"rcx\");\n\n#ifdef CONSOLE_FB\n    if(fb)\n        switch(c) {\n            case '\\r': fb_x = 4; break;\n            case '\\n': fb_x = 4; fb_y += font->height; break;\n            default:\n                if(fb_x + font->width + 5 >= vidmode.framebuffer_width) { fb_x = 4; fb_y += font->height; }\n                if(fb_y + font->height + 5 > vidmode.framebuffer_height) {\n                    x = fb_y; fb_y = vidmode.framebuffer_height - font->height - 5; x -= fb_y;\n                    offs = 0; line = x * vidmode.framebuffer_pitch;\n                    for(y = x; y < vidmode.framebuffer_height; y++,\n                      offs += vidmode.framebuffer_pitch, line += vidmode.framebuffer_pitch)\n                        memcpy(fb + offs, fb + line, vidmode.framebuffer_pitch);\n                    for(y = fb_y, offs = fb_y * vidmode.framebuffer_pitch; y < vidmode.framebuffer_height; y++,\n                      offs += vidmode.framebuffer_pitch)\n                        memset(fb + offs, 0, vidmode.framebuffer_pitch);\n                }\n                glyph = font_psf + font->headersize + (c > 0 && c < font->numglyph ? c : 0) * font->bytesperglyph;\n                offs = fb_y * vidmode.framebuffer_pitch + fb_x * ((vidmode.framebuffer_bpp + 7) >> 3); fb_x += (font->width + 1);\n                for(y = 0; y < font->height; y++, glyph += bpl, offs += vidmode.framebuffer_pitch) {\n                    line = offs; mask = 1 << (font->width - 1);\n                    for(x = 0; x < font->width && mask; x++, mask >>= 1) {\n                        switch(vidmode.framebuffer_bpp) {\n                            case 15: case 16: *((uint16_t*)(fb + line)) = ((int)*glyph) & mask ? 0xFFFF : fb_bg; line += 2; break;\n                            case 24: *((uint32_t*)(fb + line)) = ((int)*glyph) & mask ? 0xFFFFFF : fb_bg; line += 3; break;\n                            case 32: *((uint32_t*)(fb + line)) = ((int)*glyph) & mask ? 0xFFFFFFFF : fb_bg; line += 4; break;\n                        }\n                    }\n                    *((uint32_t*)(fb + line)) = fb_bg;\n                }\n            break;\n        }\n#endif\n#ifdef CONSOLE_VGA\n    if(!fb && !ST)\n        switch(c) {\n            case '\\r': vga_x = 0; break;\n            case '\\n': vga_x = 0; vga_y++; break;\n            default:\n                if(vga_y >= 25) {\n                    memcpy((void*)0xB8000, (void*)0xB8000 + 160, 160 * 24); vga_x = 0; vga_y = 24;\n                    memset((void*)0xB8000 + 24 * 160, 0, 160);\n                }\n                *((uint16_t*)((uintptr_t)0xB8000 + vga_y * 160 + vga_x++ * 2)) = 0x0f00 | (c & 0xff);\n            break;\n        }\n#endif\n#ifdef CONSOLE_UEFI\n    if(ST && ST->ConOut) { tmp[0] = c; tmp[1] = 0; ST->ConOut->OutputString(ST->ConOut, tmp); }\n#endif\n}\n\n/**\n * Display (extremely minimal) formated message on console\n * %c: an ASCII character\n * %d: a decimal number\n * %x: a hexadecimal number\n * %p: a pointer\n * %s: a zero terminated ASCII string (8 bit)\n * %S: a zero terminated WCHAR string (16 bit characters, truncated to 8 bit)\n * %D: dump 16 bytes from given address\n */\nvoid printf(char *fmt, ...)\n{\n    __builtin_va_list args;\n    uint8_t *ptr;\n    int64_t arg;\n    uint16_t *u;\n    int len, sign, i, l;\n    char *p, tmpstr[19], n;\n\n    __builtin_va_start(args, fmt);\n    arg = 0;\n    while(*fmt) {\n        if(*fmt == '%') {\n            fmt++;\n            if(*fmt == '%') goto put;\n            len=l=0; while(*fmt >= '0' && *fmt <= '9') { len *= 10; len += *fmt - '0'; fmt++; }\n            if(*fmt == 'l') { l++; fmt++; }\n            if(*fmt == 'c') { arg = __builtin_va_arg(args, int); console_putc((uint8_t)arg); fmt++; continue; } else\n            if(*fmt == 'd') {\n                if(!l) arg = (int32_t)__builtin_va_arg(args, int32_t);\n                else arg = __builtin_va_arg(args, int64_t);\n                sign = 0; if((int)arg < 0) { arg = -arg; sign++; }\n                i = 18; tmpstr[i] = 0;\n                do { tmpstr[--i] = '0' + (arg % 10); arg /= 10; } while(arg != 0 && i > 0);\n                if(sign) tmpstr[--i] = '-';\n                if(len > 0 && len < 18) { while(i > 18 - len) tmpstr[--i] = ' '; }\n                p = &tmpstr[i];\n                goto putstring;\n            } else\n            if(*fmt == 'x' || *fmt == 'p') {\n                if(*fmt == 'x' && !l) arg = (int32_t)__builtin_va_arg(args, int32_t);\n                else arg = __builtin_va_arg(args, int64_t);\n                i = 16; tmpstr[i] = 0; if(*fmt == 'p') len = 16;\n                do { n = arg & 0xf; tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); arg >>= 4; } while(arg != 0 && i > 0);\n                if(len > 0 && len <= 16) { while(i > 16 - len) tmpstr[--i] = '0'; }\n                p = &tmpstr[i];\n                goto putstring;\n            } else\n            if(*fmt == 's') {\n                p = __builtin_va_arg(args, char*);\nputstring:      if(p == (void*)0) p = \"(null)\";\n                while(*p) console_putc(*p++);\n            }\n            if(*fmt == 'S') {\n                u = __builtin_va_arg(args, uint16_t*);\n                if(u == (void*)0) u = L\"(null)\";\n                while(*u) console_putc(*u++);\n            } else\n            if(*fmt == 'D') {\n                arg = __builtin_va_arg(args, int64_t);\n                if(len < 1) len = 1;\n                do {\n                    for(i = 28; i >= 0; i -= 4) { n = (arg >> i) & 15; n += (n>9?0x37:0x30); console_putc(n); }\n                    console_putc(':'); console_putc(' ');\n                    ptr = (uint8_t*)(uintptr_t)arg;\n                    for(i = 0; i < 16; i++) {\n                        n = (ptr[i] >> 4) & 15; n += (n>9?0x37:0x30); console_putc(n);\n                        n = ptr[i] & 15; n += (n>9?0x37:0x30); console_putc(n);\n                        console_putc(' ');\n                    }\n                    console_putc(' ');\n                    for(i = 0; i < 16; i++)\n                        console_putc(ptr[i] < 32 || ptr[i] >= 127 ? '.' : ptr[i]);\n                    console_putc('\\r'); console_putc('\\n');\n                    arg += 16;\n                } while(--len);\n            }\n        } else {\nput:        console_putc(*fmt);\n        }\n        fmt++;\n    }\n    __builtin_va_end(args);\n}\n\n/**************** Progress bar ****************/\n\n/**\n * Initialize the progress bar\n */\nuint64_t pb_init(uint64_t size)\n{\n    uint32_t c, i, x;\n\n    pb_fb = NULL; pb_m = (size >> 9) + 1; pb_l = 0;\n    if(!vidmode.framebuffer_addr || !size || pb_m < vidmode.framebuffer_width - 4) return 0;\n    pb_b = (vidmode.framebuffer_bpp + 7) >> 3;\n    pb_fb = (uint8_t*)vidmode.framebuffer_addr + (vidmode.framebuffer_height - 4) * vidmode.framebuffer_pitch + 2 * pb_b;\n    c = FB_COLOR(32, 32, 32);\n    for(i = x = 0; x < vidmode.framebuffer_width - 4; x++, i += pb_b)\n        switch(vidmode.framebuffer_bpp) {\n            case 15: case 16: *((uint16_t*)(pb_fb + i)) = *((uint16_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = c; break;\n            case 24: case 32: *((uint32_t*)(pb_fb + i)) = *((uint32_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = c; break;\n        }\n    return size / (vidmode.framebuffer_width - 4);\n}\n\n/**\n * Draw the progress bar\n */\nvoid pb_draw(uint64_t curr)\n{\n    uint32_t i;\n\n    if(pb_fb) {\n        i = pb_l; pb_l = ((curr >> 9) * (vidmode.framebuffer_width - 4) / pb_m) * pb_b;\n        for(; i < pb_l; i++)\n            switch(vidmode.framebuffer_bpp) {\n                case 15: case 16: *((uint16_t*)(pb_fb + i)) = *((uint16_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = 0xFFFF; break;\n                case 24: case 32: *((uint32_t*)(pb_fb + i)) = *((uint32_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = 0xFFFFFF; break;\n            }\n    }\n}\n\n/**\n * Close the progress bar\n */\nvoid pb_fini(void)\n{\n    uint32_t i, x;\n\n    if(pb_fb)\n        for(i = x = 0; x < vidmode.framebuffer_width - 2; x++, i += pb_b)\n            switch(vidmode.framebuffer_bpp) {\n                case 15: case 16: *((uint16_t*)(pb_fb + i)) = *((uint16_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = fb_bg; break;\n                case 24: case 32: *((uint32_t*)(pb_fb + i)) = *((uint32_t*)(pb_fb + vidmode.framebuffer_pitch + i)) = fb_bg; break;\n            }\n    pb_fb = NULL;\n}\n\n/**************** BIOS-specific functions ****************/\n\n/* IMPORTANT !!! No function below this line allowed to use more than 1k stack! CLang should generate a warning if they do\n * (actually Clang's stack limit is set to 512 bytes). Also these BIOS routine calls must be in the first 32k in order to work */\n\nuint64_t data_lba, fat_lba;\nuint8_t vbr[512], data[512];\nuint32_t fat[1024], fat_cache, file_clu;\nuint16_t lfn[261];\nguid_t bootuuid;\n\n/**\n * Sort memory map\n */\nstatic void sort_map(multiboot_mmap_entry_t *dst, int num)\n{\n    int i, j;\n    uint64_t top;\n    multiboot_mmap_entry_t tmp;\n\n    for(i = 1; i < num; i++) {\n        for(j = i; j > 0 && dst[j].base_addr < dst[j - 1].base_addr; j--) {\n            memcpy(&tmp, &dst[j - 1], sizeof(multiboot_mmap_entry_t));\n            memcpy(&dst[j - 1], &dst[j], sizeof(multiboot_mmap_entry_t));\n            memcpy(&dst[j], &tmp, sizeof(multiboot_mmap_entry_t));\n        }\n        top = dst[i].base_addr + dst[i].length;\n        if(dst[i].type == MULTIBOOT_MEMORY_AVAILABLE && top > ram) ram = top;\n    }\n}\n\n/**\n * Load a sector from boot drive using BIOS\n */\nvoid bios_loadsec(uint64_t lba, void *dst)\n{\n    if(ST || !dst) return;\n    *((uint16_t*)0x502) = 1; *((uint32_t*)0x504) = 0x600; *((uint64_t*)0x508) = lba;\n    __asm__ __volatile__(\n    /* let's see if we have master ATA IDE PIO (probably emulation, but still, it is about 100x times faster than BIOS) */\n    \"cmpb $0x80, (0x4ff);jne 2f;\"\n    \"movw $0x1F7, %%dx;inb %%dx, %%al;\"\n    \"cmpb $0, %%al;je 2f;\"\n    \"cmpb $0xff, %%al;je 2f;\"\n    \"1:inb %%dx, %%al;\"\n    \"andb $0xC0, %%al;\"\n    \"cmpb $0x40, %%al;jne 1b;\"\n    \"movb $0x0a, %%al;movw $0x3F6, %%dx;outb %%al, %%dx;\"\n    \"movb $0x40, %%al;movw $0x1F6, %%dx;outb %%al, %%dx;\"\n    \"xorb %%al, %%al;movw $0x1F2, %%dx;outb %%al, %%dx;\"\n    \"movq %%rbx, %%rax;shrq $24, %%rax;movw $0x1F3, %%dx;outb %%al, %%dx;\"\n    \"shrq $8, %%rax;movw $0x1F4, %%dx;outb %%al, %%dx;\"\n    \"shrq $8, %%rax;movw $0x1F5, %%dx;outb %%al, %%dx;\"\n    \"movb $1, %%al;movw $0x1F2, %%dx;outb %%al, %%dx;\"\n    \"movq %%rbx, %%rax;movw $0x1F3, %%dx;outb %%al, %%dx;\"\n    \"shrq $8, %%rax;movw $0x1F4, %%dx;outb %%al, %%dx;\"\n    \"shrq $8, %%rax;movw $0x1F5, %%dx;outb %%al, %%dx;\"\n    \"movb $0x24, %%al;movw $0x1F7, %%dx;outb %%al, %%dx;\"\n    \"1:inb %%dx, %%al;\"\n    \"andb $0xC1, %%al;\"\n    \"cmpb $0x01, %%al;je 2f;\"\n    \"cmpb $0x40, %%al;jne 1b;\"\n    \"movq $128, %%rcx;\"\n    \"movw $0x1F0, %%dx;\"\n    \"cld;rep insl;\"\n    \"jmp 3f;\"\n    /* otherwise fallback to BIOS services, which means switching CPU mode and copy data, so it's slow */\n    /* go BIOS mode */\n    \"2:pushq %%rdi;\"\n    \"movq $0x600, %%rdi;movq $64, %%rcx;xorq %%rax, %%rax;repnz stosq;\"\n    \"movq $16, %%rax;push %%rax;\"       /* long -> compat */\n    \"movq $1f, %%rax;push %%rax;\"\n    \"lretq;.code32;1:;\"\n    \"movl %%cr0, %%eax;\"                /* disable CR0.PG */\n    \"btcl $31, %%eax;\"\n    \"movl %%eax, %%cr0;\"\n    \"ljmp $8,$1f;1:;\"                   /* compat -> legacy prot */\n    \"movl %%cr0, %%eax;\"                /* disable CR0.PR */\n    \"andb $0xfe, %%al;\"\n    \"movl %%eax, %%cr0;\"\n    \"ljmp $0,$1f;.code16;1:;\"           /* prot -> real */\n    \"xorw %%ax, %%ax;movw %%ax, %%ds;movw %%ax, %%es;movw %%ax, %%ss;\"\n    /* do the BIOS call */\n    \"movb $0x42, %%ah;\"\n    \"movw $0x500, %%si;\"\n    \"movb -1(%%si), %%dl;\"\n    \"clc;int $0x13;\"\n    /* go back to long mode */\n    \"movl %%cr0, %%eax;\"                /* enable CR0.PR */\n    \"orb $1, %%al;\"\n    \"movl %%eax, %%cr0;\"\n    /* AAAAAHHHHH... we have to workaround a compiler bug... This is a dirty hack that takes advantage of the\n     * fact that machine code 0xEA is the same in prot and real encoding just with different operand sizes.\n     * smuggle the real mode second operand in prot mode first operand */\n    \".code32;ljmp $16,$1f+0x100000;1:;\"/* real -> prot */\n    \"movl %%cr0, %%eax;\"                /* enable CR0.PG */\n    \"btsl $31, %%eax;\"\n    \"movl %%eax, %%cr0;\"\n    \"ljmp $32,$1f;.code64;1:;\"          /* prot -> long */\n    \"movw $40, %%ax;movw %%ax, %%ds;movw %%ax, %%es;movw %%ax, %%ss;\"\n    /* copy data from BIOS buffer to final position */\n    \"xorq %%rcx, %%rcx;\"\n    \"xorq %%rsi, %%rsi;\"\n    \"movb $64, %%cl;\"\n    \"movw $0x600, %%si;\"\n    \"popq %%rdi;\"\n    \"cmpq %%rsi, %%rdi;je 3f;\"\n    \"repnz movsq;3:\"\n    ::\"b\"(lba),\"D\"(dst):\"rax\",\"rcx\",\"rdx\",\"rsi\",\"memory\");\n}\n\n/**\n * Set up framebuffer with VESA VBE 2.0 BIOS\n */\nvoid bios_vbe(uint32_t width, uint32_t height, uint32_t bpp)\n{\n    if(ST || width < 320 || height < 200 || bpp < 15) return;\n    memset((void*)0x580, 0, 128);\n    __asm__ __volatile__(\n    /* go BIOS mode */\n    \"shlq $32, %%rcx;\"\n    \"shlq $16, %%rbx;\"\n    \"addq %%rbx, %%rcx;\"\n    \"addq %%rax, %%rcx;\"\n    \"xorq %%rax, %%rax;pushq %%rax;\"\n    \"pushq %%rdi;\"\n    \"pushq %%rcx;\"\n    \"movq $16, %%rax;push %%rax;\"\n    \"movq $1f, %%rax;push %%rax;\"\n    \"lretq;.code32;1:;\"\n    \"movl %%cr0, %%eax;\"\n    \"btcl $31, %%eax;\"\n    \"movl %%eax, %%cr0;\"\n    \"ljmp $8,$1f;1:;\"\n    \"movl %%cr0, %%eax;\"\n    \"andb $0xfe, %%al;\"\n    \"movl %%eax, %%cr0;\"\n    \"ljmp $0,$1f;.code16;1:;\"\n    \"xorw %%ax, %%ax;movw %%ax, %%ds;movw %%ax, %%es;movw %%ax, %%ss;\"\n    /* get EDID information */\n    \"movw $0x4f15, %%ax;\"\n    \"movw $0x0001, %%bx;\"\n    \"xorw %%cx, %%cx;\"\n    \"xorw %%dx, %%dx;\"\n    \"movw $0x580, %%di;\"\n    \"int $0x10;\"\n    /* do the VBE BIOS call */\n    \"movw $0x600, %%di;\"\n    \"movl $0x32454256, 0(%%di);\"\n    \"movw $0x4f00, %%ax;\"\n    \"pushw %%ds;pushw %%es;\"\n    \"int $0x10;\"\n    \"popw %%es;popw %%ds;\"\n    \"cmpw $0x004f, %%ax;jne 2f;\"\n    /* copy modes list out to workaround buggy VBE BIOSes */\n    \"xorl %%esi, %%esi;\"\n    \"xorl %%edi, %%edi;\"\n    \"movw (0x60E), %%si;\"\n    \"movw (0x610), %%ax;\"\n    \"movw %%ax, %%ds;\"\n    \"movw $0xA00, %%di;\"\n    \"movw $256, %%cx;\"\n    \"1: lodsw;\"\n    \"cmpw $0xffff, %%ax;je 1f;\"\n    \"cmpw $0, %%ax;je 1f;\"\n    \"stosw;\"\n    \"dec %%cx;jnz 1b;\"\n    \"1:;xorw %%ax, %%ax;stosw;\"\n    \"movw %%ax, %%ds;\"\n    /* iterate on modes and query info on each */\n    \"movw $0xffff, 20(%%esp);\"          /*   stack:   */\n    \"movw $0xA00, %%si;\"                /* 20(%esp) - best match mode */\n    \"1:movw $0, (0x600);\"               /* 18(%esp) - best match height */\n    \"lodsw;\"                            /* 16(%esp) - best match width */\n    \"orw %%ax, %%ax;jz 1f;\"             /*  8(%esp) - vidmode buffer pointer */\n    \"movw %%ax, %%cx;\"                  /*  4(%esp) - requested bpp */\n    \"movw $0x600, %%di;\"                /*  2(%esp) - requested height */\n    \"movw $0x4f01, %%ax;\"               /*  0(%esp) - requested width */\n    \"pushw %%cx;pushw %%si;pushw %%ds;pushw %%es;\"\n    \"int $0x10;\"\n    \"popw %%es;popw %%ds;popw %%si;popw %%cx;\"\n    \"cmpw $0x004f, %%ax;jne 1b;\"        /* mode listed, but not supported */\n    \"movw (0x600), %%ax;\"\n    \"andw $0x9b, %%ax;\"\n    \"cmpw $0x9b, %%ax;jne 1b;\"          /* not the mode we're looking for. Not packed pixel linear framebuffer */\n    \"movb 4(%%esp), %%al;\"\n    \"cmpb (0x619), %%al;jne 1b;\"        /* bpp matches? */\n    \"movw (0x614), %%ax;\"\n    \"cmpw 2(%%esp), %%ax;ja 1b;\"        /* height smaller or equal than required? */\n    \"cmpw 18(%%esp), %%ax;jb 1b;\"       /* and bigger than the last best result? */\n    \"movw (0x612), %%ax;\"\n    \"cmpw 0(%%esp), %%ax;ja 1b;\"        /* width smaller or equal than required? */\n    \"cmpw 16(%%esp), %%ax;jb 1b;\"       /* and bigger than the last best result? */\n    /* this is the best result we have so far, store it */\n    \"movw %%ax, 16(%%esp);\"\n    \"movw (0x614), %%ax;\"\n    \"movw %%ax, 18(%%esp);\"\n    \"movw %%cx, 20(%%esp);\"\n    \"jmp 1b;\"\n    \"1:cmpw $0xffff, 20(%%esp);je 2f;\"\n    /* set up mode */\n    \"movw 20(%%esp), %%bx;\"\n    \"orw $0x6000, %%bx;\"\n    \"movw $0x4f02, %%ax;\"\n    \"pushw %%cx;pushw %%si;pushw %%ds;pushw %%es;\"\n    \"int $0x10;\"\n    \"popw %%es;popw %%ds;popw %%si;popw %%cx;\"\n    \"cmpw $0x004f, %%ax;jne 2f;\"        /* not worked, so don't store it */\n    /* looks good, store vidmode */\n    \"movw 20(%%esp), %%cx;\"\n    \"movw $0x600, %%di;\"\n    \"movw $0x4f01, %%ax;\"\n    \"pushw %%cx;pushw %%si;pushw %%ds;pushw %%es;\"\n    \"int $0x10;\"\n    \"popw %%es;popw %%ds;popw %%si;popw %%cx;\"\n    \"cmpw $0x004f, %%ax;jne 2f;\"        /* should never happen */\n    \"movl 8(%%esp), %%edi;\"\n    \"movl (0x628), %%eax;\"\n    \"movl %%eax, 8(%%edi);\"             /* vidmode.framebuffer_addr lo */\n    \"movl (0x62c), %%eax;\"\n    \"movl %%eax, 12(%%edi);\"            /* vidmode.framebuffer_addr hi */\n    \"movw (0x610), %%ax;\"\n    \"movw %%ax, 16(%%edi);\"             /* vidmode.framebuffer_pitch */\n    \"movw (0x612), %%ax;\"\n    \"movw %%ax, 20(%%edi);\"             /* vidmode.framebuffer_width */\n    \"movw (0x614), %%ax;\"\n    \"movw %%ax, 24(%%edi);\"             /* vidmode.framebuffer_height */\n    \"movb (0x619), %%al;\"\n    \"movb %%al, 28(%%edi);\"             /* vidmode.framebuffer_bpp */\n    \"movb $1,   29(%%edi);\"             /* vidmode.framebuffer_type */\n    \"movw (0x61F), %%ax;xchgb %%al, %%ah;\"\n    \"movw %%ax, 32(%%edi);\"             /* vidmode.framebuffer_red_field_position + mask */\n    \"movw (0x621), %%ax;xchgb %%al, %%ah;\"\n    \"movw %%ax, 34(%%edi);\"             /* vidmode.framebuffer_green_field_position + mask */\n    \"movw (0x623), %%ax;xchgb %%al, %%ah;\"\n    \"movw %%ax, 36(%%edi);\"             /* vidmode.framebuffer_blue_field_position + mask */\n    \"2:;\"\n    /* go back to long mode */\n    \"movl %%cr0, %%eax;\"\n    \"orb $1, %%al;\"\n    \"movl %%eax, %%cr0;\"\n    \".code32;ljmp $16,$1f+0x100000;1:;\"\n    \"movl %%cr0, %%eax;\"\n    \"btsl $31, %%eax;\"\n    \"movl %%eax, %%cr0;\"\n    \"ljmp $32,$1f;.code64;1:;\"\n    \"movw $40, %%ax;movw %%ax, %%ds;movw %%ax, %%es;movw %%ax, %%ss;\"\n    \"addq $24, %%rsp;\"\n    ::\"a\"(width),\"b\"(height),\"c\"(bpp),\"D\"(&vidmode):\"rsi\",\"rdx\",\"memory\");\n    if(!vidmode.framebuffer_addr) printf(\" VESA: no framebuffer\\r\\n\");\n#ifdef CONSOLE_FB\n    else fb_x = fb_y = 4;\n#endif\n}\n\n/**\n * Get E820 memory map\n */\nint bios_e820(multiboot_mmap_entry_t *dst)\n{\n    int ret = 0;\n\n    if(ST || !dst) return 0;\n    __asm__ __volatile__(\n    /* go BIOS mode */\n    \"pushq %%rdi;xorq %%rdi, %%rdi;pushq $0;\"\n    \"movq $16, %%rax;push %%rax;\"\n    \"movq $1f, %%rax;push %%rax;\"\n    \"lretq;.code32;1:;\"\n    \"movl %%cr0, %%eax;\"\n    \"btcl $31, %%eax;\"\n    \"movl %%eax, %%cr0;\"\n    \"ljmp $8,$1f;1:;\"\n    \"movl %%cr0, %%eax;\"\n    \"andb $0xfe, %%al;\"\n    \"movl %%eax, %%cr0;\"\n    \"ljmp $0,$1f;.code16;1:;\"\n    \"xorw %%ax, %%ax;movw %%ax, %%ds;movw %%ax, %%es;movw %%ax, %%ss;\"\n    /* do the BIOS call */\n    \"clc;xorl %%ebx, %%ebx;movl $0x600, %%edi;\"\n    \"1:movl $0xE820, %%eax;\"\n    \"movl $0x534d4150, %%edx;\"\n    \"xorl %%ecx, %%ecx;\"\n    \"movb $20, %%cl;\"\n    \"int $0x15;jc 1f;\"\n    \"addl $20, %%edi;xorl %%eax, %%eax;stosl;\"\n    \"incl 0(%%esp);\"\n    \"or %%ebx, %%ebx;jnz 1b;\"\n    /* go back to long mode */\n    \"1:movl %%cr0, %%eax;\"\n    \"orb $1, %%al;\"\n    \"movl %%eax, %%cr0;\"\n    \".code32;ljmp $16,$1f+0x100000;1:;\"\n    \"movl %%cr0, %%eax;\"\n    \"btsl $31, %%eax;\"\n    \"movl %%eax, %%cr0;\"\n    \"ljmp $32,$1f;.code64;1:;\"\n    \"movw $40, %%ax;movw %%ax, %%ds;movw %%ax, %%es;movw %%ax, %%ss;\"\n    \"movq %%rdi, %%rcx;movq $0x600, %%rsi;subq %%rsi, %%rcx;\"\n    \"popq %%rbx;popq %%rdi;repnz movsb;movq %%rbx, %%rax;\"\n    :\"=a\"(ret):\"D\"(dst):\"rbx\",\"rcx\",\"rdx\",\"rsi\",\"memory\");\n    /* make sure of it that the memory map is sorted. Should be, so bubble-sort is affordable here */\n    sort_map(dst, ret);\n    if(ret < 1) printf(\" E820: unable to get memory map\\r\\n\");\n    return ret;\n}\n\n/**\n * Chainload fallback to VBR or FreeBSD boot or BIOS boot partition\n */\nvoid bios_fallback(void)\n{\n    __asm__ __volatile__(\n    \".byte 0xe8;.long 0;\"               /* relocate real mode code to 0x600 */\n    \"1:popq %%rsi;addq $2f - 1b, %%rsi;\"\n    \"movq $0x600, %%rdi;\"\n    \"movq $3f - 2f, %%rcx;repnz movsb;\"\n    \"movq $16, %%rax;push %%rax;\"       /* long -> compat */\n    \"movq $1f, %%rax;push %%rax;\"\n    \"lretq;.code32;4:.word 0x3ff;.quad 0;1:;\"\n    \"lidt (4b);\"                        /* set up IVT */\n    \"movl %%cr0, %%eax;\"                /* disable CR0.PG */\n    \"btcl $31, %%eax;\"\n    \"movl %%eax, %%cr0;\"\n    \"ljmp $8,$1f;1:;\"                   /* compat -> legacy prot */\n    \"movl %%cr0, %%eax;\"                /* disable CR0.PR */\n    \"andb $0xfe, %%al;\"\n    \"movl %%eax, %%cr0;\"\n    \"ljmp $0,$0x600;.code16;2:;\"        /* prot -> real */\n    \"xorw %%ax, %%ax;movw %%ax, %%ds;movw %%ax, %%es;movw %%ax, %%ss;\"\n    \"movw $0x7C00, %%bx;movw %%bx, %%sp;\"\n    \"movb $0xF4, (%%bx);\" /* move a halt instruction at jump address in case BIOS int fails */\n    /* load sectors and jump to the code. We might not have a magic... so nothing to check for */\n    \"movb $0x42, %%ah;\"\n    \"movw $0x500, %%si;\"\n    \"movb -1(%%si), %%dl;\"\n    \"clc;push %%dx;int $0x13;\"          /* load sectors */\n    \"movw $3, %%ax;int $0x10;pop %%dx;\" /* restore VGA text mode / clear screen */\n    \"cld;cli;ljmp $0, $0x7C00;\"\n    \"3:\":::);\n}\n\n/**\n * Initialize page tables\n */\nvoid bios_pagetables(int g)\n{\n    int i;\n    memset(&pt[1], 0, 0xFF8);\n    memset(&pt[513], 0, 0xFF8);\n    memset(&pt[1025], 0, 0x4FF8);\n    pt[0] = (uintptr_t)pt + 4096 + 3;\n    for(i = 0; i < g; i++) pt[512 + i] = (uintptr_t)pt + (i + 2) * 4096 + 3;\n    for(i = 0; i < g * 512; i++) pt[1024 + i] = (uintptr_t)i * 2 * 1024 * 1024 + 0x83;\n}\n\n/**************** EFI-specific functions ****************/\n\nefi_handle_t *IM;\nefi_boot_services_t *BS;\nefi_file_handle_t *root_dir;\nefi_file_handle_t *f;\nefi_file_info_t info;\nmemalloc_t ptrs[64];\nuint32_t nptr;\n\n/**\n * Set up framebuffer with UEFI GOP\n */\nvoid efi_gop(uint32_t width, uint32_t height, uint32_t bpp)\n{\n    guid_t gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;\n    efi_gop_t *gop = NULL;\n    efi_gop_mode_info_t *info = NULL;\n    efi_status_t status;\n    uintn_t isiz = sizeof(efi_gop_mode_info_t), i;\n    uint32_t m, b = 0, bw = 0, bh = 0, bm = -1U;\n\n    if(!ST || !BS || width < 320 || height < 200 || bpp < 15) return;\n    status = BS->LocateProtocol(&gopGuid, NULL, (void**)&gop);\n    if(!EFI_ERROR(status) && gop) {\n        /* we got the interface, get current mode */\n        status = gop->QueryMode(gop, gop->Mode ? gop->Mode->Mode : 0, &isiz, &info);\n        if(EFI_ERROR(status) || !gop->Mode)\n            status = gop->SetMode(gop, 0);\n        if(!EFI_ERROR(status)) {\n            /* iterate on modes and find the largest screen with the requested bpp */\n            for(i = 0; i < gop->Mode->MaxMode; i++) {\n                status = gop->QueryMode(gop, i, &isiz, &info);\n                if(EFI_ERROR(status) || info->PixelFormat > PixelBitMask) continue;\n                switch(info->PixelFormat) {\n                    case PixelRedGreenBlueReserved8BitPerColor:\n                    case PixelBlueGreenRedReserved8BitPerColor: b = 32; break;\n                    default:\n                        for(m = info->PixelInformation.RedMask | info->PixelInformation.GreenMask | info->PixelInformation.BlueMask,\n                            b = 32; b > 0 && !(m & (1 << (b - 1))); b--);\n                    break;\n                }\n                if(bpp == b && info->HorizontalResolution <= width && info->VerticalResolution <= height &&\n                  info->HorizontalResolution > bw && info->VerticalResolution > bh) {\n                    bm = i; bw = info->HorizontalResolution; bh = info->VerticalResolution;\n                }\n            }\n        }\n        /* try the best mode that we've found */\n        if(bm != -1U) {\n            status = gop->SetMode(gop, bm);\n            if(!EFI_ERROR(status)) {\n#ifdef CONSOLE_FB\n                fb_x = fb_y = 4;\n#endif\n                status = gop->QueryMode(gop, gop->Mode ? gop->Mode->Mode : 0, &isiz, &info);\n                switch(info->PixelFormat) {\n                    case PixelRedGreenBlueReserved8BitPerColor:\n                        vidmode.framebuffer_red_field_position = 0; vidmode.framebuffer_red_mask_size = 8;\n                        vidmode.framebuffer_green_field_position = 8; vidmode.framebuffer_green_mask_size = 8;\n                        vidmode.framebuffer_blue_field_position = 16; vidmode.framebuffer_blue_mask_size = 8;\n                        b = 32;\n                    break;\n                    case PixelBlueGreenRedReserved8BitPerColor:\n                        vidmode.framebuffer_red_field_position = 16; vidmode.framebuffer_red_mask_size = 8;\n                        vidmode.framebuffer_green_field_position = 8; vidmode.framebuffer_green_mask_size = 8;\n                        vidmode.framebuffer_blue_field_position = 0; vidmode.framebuffer_blue_mask_size = 8;\n                        b = 32;\n                    break;\n                    default:\n                        for(m = info->PixelInformation.RedMask | info->PixelInformation.GreenMask | info->PixelInformation.BlueMask,\n                            b = 32; b > 0 && !(m & (1 << (b - 1))); b--);\n                        for(vidmode.framebuffer_red_field_position = 0;\n                            !(info->PixelInformation.RedMask & (1 << vidmode.framebuffer_red_field_position));\n                            vidmode.framebuffer_red_field_position++);\n                        for(vidmode.framebuffer_red_mask_size = 0;\n                            info->PixelInformation.RedMask &\n                                (1 << (vidmode.framebuffer_red_field_position + vidmode.framebuffer_red_mask_size));\n                            vidmode.framebuffer_red_mask_size++);\n                        for(vidmode.framebuffer_green_field_position = 0;\n                            !(info->PixelInformation.GreenMask & (1 << vidmode.framebuffer_green_field_position));\n                            vidmode.framebuffer_green_field_position++);\n                        for(vidmode.framebuffer_green_mask_size = 0;\n                            info->PixelInformation.GreenMask &\n                                (1 << (vidmode.framebuffer_green_field_position + vidmode.framebuffer_green_mask_size));\n                            vidmode.framebuffer_green_mask_size++);\n                        for(vidmode.framebuffer_blue_field_position = 0;\n                            !(info->PixelInformation.BlueMask & (1 << vidmode.framebuffer_blue_field_position));\n                            vidmode.framebuffer_blue_field_position++);\n                        for(vidmode.framebuffer_blue_mask_size = 0;\n                            info->PixelInformation.BlueMask &\n                                (1 << (vidmode.framebuffer_blue_field_position + vidmode.framebuffer_blue_mask_size));\n                            vidmode.framebuffer_blue_mask_size++);\n                    break;\n                }\n                vidmode.framebuffer_addr = gop->Mode->FrameBufferBase;\n                vidmode.framebuffer_pitch = info->PixelsPerScanLine * ((b + 7) >> 3);\n                vidmode.framebuffer_width = info->HorizontalResolution;\n                vidmode.framebuffer_height = info->VerticalResolution;\n                vidmode.framebuffer_bpp = b;\n                vidmode.framebuffer_type = 1;\n            }\n        }\n        if(!vidmode.framebuffer_addr) { printf(\" GOP: no framebuffer\\r\\n\"); }\n    }\n}\n\n/**\n * Get EDID Info\n */\nvoid efi_edid(uint8_t **ptr, uint32_t *size)\n{\n    guid_t gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;\n    guid_t edid1Guid = EFI_EDID_ACTIVE_GUID;\n    guid_t edid2Guid = EFI_EDID_DISCOVERED_GUID;\n    efi_edid_t *edid = NULL;\n    efi_handle_t *handles = (efi_handle_t*)kernel_buf;\n    uintn_t i = sizeof(kernel_buf);\n\n    *size = 0; *ptr = NULL;\n    memset(handles, 0, i);\n    if(!EFI_ERROR(BS->LocateHandle(ByProtocol, &gopGuid, NULL, &i, handles)) &&\n      ((!EFI_ERROR(BS->HandleProtocol(handles[0], &edid1Guid, (void **)&edid)) && edid && edid->SizeOfEdid && edid->Edid) ||\n       (!EFI_ERROR(BS->HandleProtocol(handles[0], &edid2Guid, (void **)&edid)) && edid && edid->SizeOfEdid && edid->Edid))) {\n        *size = edid->SizeOfEdid; *ptr = edid->Edid;\n    }\n}\n\n/**\n * Get EFI memory map\n */\nint efi_memmap(multiboot_mmap_entry_t *dst)\n{\n    int ret = 0;\n    uint64_t top;\n    efi_status_t status;\n    efi_memory_descriptor_t *memory_map = NULL, *mement;\n    uintn_t memory_map_size = 0, map_key = 0, desc_size = 0;\n\n    if(!ST || !BS) return 0;\n    /* get memory map size */\n    status = BS->GetMemoryMap(&memory_map_size, NULL, &map_key, &desc_size, NULL);\n    if(status != EFI_BUFFER_TOO_SMALL || !memory_map_size) goto err;\n    /* allocate buffer. This might increase the memory map's size */\n    memory_map_size += 4 * desc_size;\n    status = BS->AllocatePool(EfiLoaderData, memory_map_size, (void**)&memory_map);\n    if(EFI_ERROR(status) || !memory_map) goto err;\n    /* get memory map */\n    status = BS->GetMemoryMap(&memory_map_size, memory_map, &map_key, &desc_size, NULL);\n    if(EFI_ERROR(status)) { status = BS->FreePool(memory_map); goto err; }\n    if(dst) {\n        /* convert to Multiboot2 memory entry tags */\n        for(mement = memory_map; (uint8_t*)mement < (uint8_t*)memory_map + memory_map_size;\n          mement = NextMemoryDescriptor(mement, desc_size), ret++) {\n            dst[ret].base_addr = mement->PhysicalStart;\n            dst[ret].length = mement->NumberOfPages << 12;\n            dst[ret].reserved = mement->Type;\n            dst[ret].type = ((mement->Type > EfiReservedMemoryType && mement->Type < EfiRuntimeServicesCode) ||\n                mement->Type == EfiConventionalMemory ? MULTIBOOT_MEMORY_AVAILABLE :\n                (mement->Type == EfiUnusableMemory ? MULTIBOOT_MEMORY_BADRAM :\n                (mement->Type == EfiACPIReclaimMemory ? MULTIBOOT_MEMORY_ACPI_RECLAIMABLE :\n                (mement->Type == EfiACPIMemoryNVS ? MULTIBOOT_MEMORY_NVS : MULTIBOOT_MEMORY_RESERVED))));\n        }\n        /* make sure of it that the memory map is sorted. Should be, so bubble-sort is affordable here */\n        sort_map(dst, ret);\n    } else {\n        /* just iterate through to find the top of memory, aka the amount of RAM we have */\n        for(mement = memory_map; (uint8_t*)mement < (uint8_t*)memory_map + memory_map_size;\n          mement = NextMemoryDescriptor(mement, desc_size)) {\n            top = mement->PhysicalStart + (mement->NumberOfPages << 12);\n            if(mement->Type == EfiConventionalMemory && top > ram) ram = top;\n        }\n    }\n    status = BS->FreePool(memory_map);\nerr:if(dst && ret < 1) printf(\" UEFI: unable to get memory map\\r\\n\");\n    return ret;\n}\n\n/**\n * Allocate and zero out a page on UEFI\n */\nuint64_t efi_alloc(void)\n{\n    efi_status_t status;\n    uint64_t page = 0;\n    status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 1, (efi_physical_address_t*)&page);\n    if(EFI_ERROR(status)) page = 0;\n    else memset((void*)page, 0, 4096);\n    return page;\n}\n\n/**\n * Allocate reclaimable memory buffer on UEFI\n */\nefi_physical_address_t efi_allocpages(efi_allocate_type_t Type, uintn_t NoPages, efi_physical_address_t Memory)\n{\n    efi_status_t status;\n\n    if(!ST || !BS) return 0;\n    status = BS->AllocatePages(Type, EfiLoaderData, NoPages, (efi_physical_address_t*)&Memory);\n    if(EFI_ERROR(status)) Memory = 0;\n    else {\n        /* we must keep record of the allocated memory ourselves... Good job, UEFI! */\n        ptrs[nptr].Memory = Memory;\n        ptrs[nptr].NoPages = NoPages;\n        nptr++;\n    }\n    return Memory;\n}\n\n/**\n * Free pages\n */\nvoid efi_freepages(void)\n{\n    uint32_t i;\n\n    if(ST) {\n        if(hack_buf) { BS->FreePages(hack_buf, 1024); hack_buf = 0; }\n        if(nptr) {\n            for(i = 0; i < nptr; i++)\n                if(ptrs[i].Memory && ptrs[i].NoPages) BS->FreePages(ptrs[i].Memory, ptrs[i].NoPages);\n            nptr = 0; memset(&ptrs, 0, sizeof(ptrs));\n        }\n    }\n}\n\n/**\n * Open a file on UEFI\n */\nint efi_open(uint16_t *fn)\n{\n    efi_status_t status;\n    guid_t infGuid = EFI_FILE_INFO_GUID;\n    uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t);\n    int i;\n\n    if(!ST || !root_dir || !fn || !*fn) return 0;\n    for(i = 0; fn[i]; i++) if(fn[i] == '/') fn[i] = '\\\\';\n    status = root_dir->Open(root_dir, &f, fn, EFI_FILE_MODE_READ, 0);\n    if(EFI_ERROR(status)) { f = NULL; file_size = 0; return 0; }\n    status = f->GetInfo(f, &infGuid, &fsiz, &info);\n    file_size = EFI_ERROR(status) ? 0 : (uint64_t)info.FileSize;\n    return 1;\n}\n\n/**\n * Read data from file on UEFI\n */\nuint64_t efi_read(uint64_t offs, uint64_t size, void *buf)\n{\n    efi_status_t status;\n    efi_input_key_t key = { 0 };\n    uint64_t blksize, curr;\n\n    if(!ST || !f || offs >= file_size || !size || !buf) return 0;\n    if(offs + size > file_size) size = file_size - offs;\n    status = f->SetPosition(f, offs);\n    if(EFI_ERROR(status)) return 0;\n    /* calculate how many bytes to read for one pixel progress. If zero, then no progress bar, read everything in one batch */\n    if((blksize = pb_init(size))) {\n        for(curr = 0; !EFI_ERROR(status) && curr < size; curr += blksize) {\n            /* check for user interruption */\n            if(!bkp && !rq) {\n                status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key);\n                if(!EFI_ERROR(status) && key.UnicodeChar) rq = 1;\n            }\n            if(size - curr < blksize) blksize = size - curr;\n            status = f->Read(f, &blksize, buf + curr);\n            pb_draw(curr);\n        }\n    } else {\n        /* check for user interruption */\n        if(!bkp && !rq) {\n            status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key);\n            if(!EFI_ERROR(status) && key.UnicodeChar) rq = 1;\n        }\n        status = f->Read(f, &size, buf);\n    }\n    return EFI_ERROR(status) ? 0 : size;\n}\n\n/**\n * Close file on UEFI\n */\nvoid efi_close(void)\n{\n    if(ST && f) f->Close(f);\n    f = NULL; file_size = 0;\n}\n\n/**\n * Generate tags for system tables on UEFI\n */\nvoid efi_systables(void)\n{\n    guid_t smGuid = SMBIOS_TABLE_GUID, r1Guid = ACPI_TABLE_GUID, r2Guid = ACPI_20_TABLE_GUID;\n    efi_configuration_table_t *tbl;\n    uint32_t i;\n    uint8_t *s;\n\n    if(!ST || !tags_ptr) return;\n    for(i = 0, tbl = ST->ConfigurationTable; i < ST->NumberOfTableEntries; i++, tbl++) {\n        if(!memcmp(&tbl->VendorGuid, &smGuid, sizeof(guid_t))) {\n            s = tbl->VendorTable;\n            memset(tags_ptr, 0, sizeof(multiboot_tag_smbios_t));\n            ((multiboot_tag_smbios_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_SMBIOS;\n            ((multiboot_tag_smbios_t*)tags_ptr)->size = sizeof(multiboot_tag_smbios_t) + (uint32_t)s[5];\n            ((multiboot_tag_smbios_t*)tags_ptr)->major = s[7];\n            ((multiboot_tag_smbios_t*)tags_ptr)->minor = s[8];\n            memcpy(((multiboot_tag_smbios_t*)tags_ptr)->tables, s, (uint32_t)s[5]);\n            tags_ptr += (((multiboot_tag_smbios_t*)tags_ptr)->size + 7) & ~7;\n        } else\n        if(!memcmp(&tbl->VendorGuid, &r2Guid, sizeof(guid_t))) {\n            s = tbl->VendorTable;\n            ((multiboot_tag_new_acpi_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_ACPI_NEW;\n            ((multiboot_tag_new_acpi_t*)tags_ptr)->size = sizeof(multiboot_tag_new_acpi_t) + 36;\n            memcpy(((multiboot_tag_new_acpi_t*)tags_ptr)->rsdp, s, 36);\n            tags_ptr += (((multiboot_tag_new_acpi_t*)tags_ptr)->size + 7) & ~7;\n            rsdp_ptr = (uintptr_t)s;\n        }\n    }\n    /* only generate old ACPI tag if 64-bit RSDP wasn't found */\n    for(i = 0, tbl = ST->ConfigurationTable; i < ST->NumberOfTableEntries && !rsdp_ptr; i++, tbl++)\n        if(!memcmp(&tbl->VendorGuid, &r1Guid, sizeof(guid_t))) {\n            s = tbl->VendorTable;\n            ((multiboot_tag_old_acpi_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_ACPI_OLD;\n            ((multiboot_tag_old_acpi_t*)tags_ptr)->size = sizeof(multiboot_tag_old_acpi_t) + 24;\n            memcpy(((multiboot_tag_old_acpi_t*)tags_ptr)->rsdp, s, 24);\n            tags_ptr += (((multiboot_tag_old_acpi_t*)tags_ptr)->size + 7) & ~7;\n            rsdp_ptr = (uintptr_t)s;\n        }\n}\n\n/**\n * Initialize UEFI related things\n */\nvoid efi_init(void)\n{\n    efi_loaded_image_protocol_t *LIP = NULL;\n    efi_simple_file_system_protocol_t *sfs = NULL;\n    guid_t dppGuid = EFI_DEVICE_PATH_PROTOCOL_GUID;\n    guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;\n    guid_t sfsGuid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;\n    uint8_t *buf = NULL, *ptr, *end;\n\n    BS = ST->BootServices;\n    /* we don't need this buffer, we just need this area to be marked as used in the memory map, so that\n     * subsequent allocations won't pollute it. If UEFI already occupies this area, that sucks, there's\n     * nothing we can do about it and would most likely result in \"memory already in use\" errors in\n     * fw_loadseg. Otherwise this memory is freed in efi_freepages called from fw_loadkernel. */\n    hack_buf = file_buf;\n    if(EFI_ERROR(BS->AllocatePages(AllocateAddress, EfiLoaderData, 1024, (efi_physical_address_t*)&hack_buf))) hack_buf = 0;\n    /* set up framebuffer */\n    efi_gop(fb_w, fb_h, fb_bpp);\n    if(!vidmode.framebuffer_addr) { fb_w = 640; fb_h = 480; efi_gop(fb_w, fb_h, fb_bpp); }\n    if(IM && BS && BS->HandleProtocol) {\n        BS->HandleProtocol(IM, &lipGuid, (void **)&LIP);\n        if(!EFI_ERROR(BS->HandleProtocol(LIP->DeviceHandle, &sfsGuid, (void **)&sfs))) {\n            /* get boot partition's root directory */\n            if(EFI_ERROR(sfs->OpenVolume(sfs, &root_dir))) root_dir = NULL;\n        }\n        /* get the ESP's device path */\n        if(!EFI_ERROR(BS->HandleProtocol(LIP->DeviceHandle, &dppGuid, (void **)&buf)) && buf) {\n            /* also get the boot partition's UniquePartitionGUID */\n            for(ptr = buf, end = buf + 32768; ptr < end && *ptr != 0x7F && (ptr[0] != 4 || ptr[1] != 1); ptr += (ptr[3] << 8) | ptr[2]);\n            if(*ptr == 4) memcpy(&bootuuid, &((efi_hard_disk_device_path_t*)ptr)->PartitionSignature, sizeof(guid_t));\n            BS->FreePool(buf);\n        }\n    }\n    /* if this fails, that sucks, because we don't have a console yet. We'll report it later */\n    pt = NULL;\n    if(EFI_ERROR(BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 68, (efi_physical_address_t*)&pt))) pt = NULL;\n    /* otherwise set up the same page tables we have with BIOS, but don't active it yet */\n    else bios_pagetables(64);\n}\n\n/**\n * Free all EFI related buffers\n */\nvoid efi_freeall(void)\n{\n    if(!ST || !BS) return;\n    if(conf_buf) { BS->FreePool(conf_buf); conf_buf = NULL; }\n    if(logo_buf) { BS->FreePool(logo_buf); logo_buf = NULL; }\n    if(hack_buf) { BS->FreePages(hack_buf, 1024); hack_buf = 0; }\n}\n\n/* we can't include this sooner, because the routines above must be in the first 32k. This is because we must\n * access those from real mode, and we're loaded at 0x8000, and the real mode segment's limit is 0xFFFF bytes. */\n#include \"inflate.h\"\n\n/**\n * Generate tags for system tables on FOSSBIOS\n */\nvoid fb_systables(void)\n{\n    rsdp_t *rsdp;\n    int i, s;\n\n    if(ST || !FB) return;\n\n    /* create a fake ACPI table */\n    ((multiboot_tag_old_acpi_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_ACPI_OLD;\n    ((multiboot_tag_old_acpi_t*)tags_ptr)->size = sizeof(multiboot_tag_old_acpi_t) + sizeof(rsdp_t);\n    rsdp = (rsdp_t*)&((multiboot_tag_old_acpi_t*)tags_ptr)->rsdp;\n    memset(rsdp, 0, sizeof(rsdp_t));\n    memcpy(&rsdp->magic, \"RSD PTR \", 8);\n    rsdp->rev = 1; rsdp->rsdt = (uint32_t)(uintptr_t)&rsdt;\n    for(s = 0, i = 0; i < (int)sizeof(rsdp_t); i++) { s += *(((uint8_t*)rsdp) + i); } rsdp->chksum = 0x100 - s;\n    memset(&rsdt, 0, sizeof(rsdt_t));\n    memcpy(&rsdt.hdr.magic, \"RSDT\", 4);\n    rsdt.hdr.rev = 1; rsdt.hdr.size = sizeof(sdt_hdr_t) + 1 * sizeof(uint32_t);\n    /* add fake FADT and DSDT tables to the ACPI list with the GUDT data */\n    rsdt.table_ptr[0] = (uint32_t)(uintptr_t)&fadt; /* DSDT is pointed by FADT, not RSDT */\n    memset(&fadt, 0, sizeof(fadt_t));\n    memcpy(&fadt.hdr.magic, \"FACP\", 4);\n    fadt.hdr.rev = 2; fadt.hdr.size = sizeof(fadt_t); fadt.dsdt = (uint32_t)(uintptr_t)FB->conf; fadt.x_dsdt = (uintptr_t)FB->conf;\n    for(s = 0, i = 0; i < (int)sizeof(fadt); i++) { s += *(((uint8_t*)&fadt) + i); } fadt.hdr.chksum = 0x100 - s;\n    for(s = 0, i = 0; i < (int)sizeof(rsdt_t); i++) { s += *(((uint8_t*)&rsdt) + i); } rsdt.hdr.chksum = 0x100 - s;\n    tags_ptr += (((multiboot_tag_old_acpi_t*)tags_ptr)->size + 7) & ~7;\n}\n\n/**\n * Get FOSSBIOS memory map\n */\nint fb_memmap(multiboot_mmap_entry_t *dst)\n{\n    int ret, i, j;\n    uint64_t top;\n    multiboot_mmap_entry_t tmp;\n    fb_mement_t *mement;\n\n    if(ST || !FB || !dst) return 0;\n\n    ret = FB->system->nummap;\n    mement = FB->system->memmap;\n    for(i = 0; i < ret; i++) {\n        dst[i].base_addr = mement[i].base;\n        dst[i].length = mement[i].size & ~7;\n        dst[i].reserved = mement[i].size & 7;\n        switch(dst[i].reserved) {\n            case FB_MEM_FREE:\n            case FB_MEM_USED:\n            case FB_MEM_BIOS: dst[i].type = MULTIBOOT_MEMORY_AVAILABLE; break;\n            case FB_MEM_ROM:\n            case FB_MEM_MMIO: dst[i].type = MULTIBOOT_MEMORY_RESERVED; break;\n            case FB_MEM_NVS: dst[i].type = MULTIBOOT_MEMORY_NVS; break;\n            default: dst[i].type = MULTIBOOT_MEMORY_BADRAM; break;\n        }\n    }\n    /* make sure of it that the memory map is sorted. Should be, so bubble-sort is affordable here */\n    for(i = 1; i < ret; i++) {\n        for(j = i; j > 0 && dst[j].base_addr < dst[j - 1].base_addr; j--) {\n            memcpy(&tmp, &dst[j - 1], sizeof(multiboot_mmap_entry_t));\n            memcpy(&dst[j - 1], &dst[j], sizeof(multiboot_mmap_entry_t));\n            memcpy(&dst[j], &tmp, sizeof(multiboot_mmap_entry_t));\n        }\n        top = dst[i].base_addr + dst[i].length;\n        if(dst[i].type == MULTIBOOT_MEMORY_AVAILABLE && top > ram) ram = top;\n    }\n    if(ret < 1) printf(\" SYS: unable to get memory map\\r\\n\");\n    return ret;\n}\n\n/**\n * Set up linear framebuffer with FOSSBIOS\n */\nvoid fb_lfb(uint32_t width, uint32_t height, uint32_t bpp)\n{\n    fb_vidmode_t *mode;\n    uint32_t i, bw = 0, bh = 0, bm = -1U;\n\n    if(ST || !FB || !FB->video || width < 320 || height < 200 || bpp < 15) return;\n    /* iterate on modes and find the largest screen with the requested bpp */\n    mode = FB->video->vidmodes;\n    for(i = 0; i < FB->video->nummodes; i++, mode++)\n        if(bpp == mode->bpp && mode->width <= width && mode->height <= height && mode->width > bw && mode->height > bh) {\n            bm = i; bw = mode->width; bh = mode->height;\n        }\n    /* try the best mode that we've found */\n    if(bm != -1U && FB->video->setmode(bm)) {\n#ifdef CONSOLE_FB\n        fb_x = fb_y = 4;\n#endif\n        mode = &FB->video->vidmodes[bm];\n        switch(mode->bpp) {\n            case 15:\n                vidmode.framebuffer_red_mask_size = vidmode.framebuffer_green_mask_size = vidmode.framebuffer_blue_mask_size = 5;\n            break;\n            case 16:\n                vidmode.framebuffer_red_mask_size = vidmode.framebuffer_blue_mask_size = 5; vidmode.framebuffer_green_mask_size = 6;\n            break;\n            default:\n                vidmode.framebuffer_red_mask_size = vidmode.framebuffer_green_mask_size = vidmode.framebuffer_blue_mask_size = 8;\n            break;\n        }\n        vidmode.framebuffer_red_field_position = mode->red;\n        vidmode.framebuffer_green_field_position = mode->green;\n        vidmode.framebuffer_blue_field_position = mode->blue;\n        vidmode.framebuffer_addr = (uintptr_t)FB->video->lfb;\n        vidmode.framebuffer_pitch = mode->pitch;\n        vidmode.framebuffer_width = mode->width;\n        vidmode.framebuffer_height = mode->height;\n        vidmode.framebuffer_bpp = mode->bpp;\n        vidmode.framebuffer_type = 1;\n    }\n    if(!vidmode.framebuffer_addr) { printf(\" LFB: no framebuffer\\r\\n\"); }\n}\n\n/**\n * Set up framebuffer with legacy BIOS or FOSSBIOS\n */\nvoid fw_lfb(uint32_t width, uint32_t height, uint32_t bpp)\n{\n    FB ? fb_lfb(width, height, bpp) : bios_vbe(width, height, bpp);\n}\n\n/**\n * Load a sector from legacy BIOS or FOSSBIOS\n */\nvoid fw_loadsec(uint64_t lba, void *dst)\n{\n    uint8_t al;\n\n    if(FB) {\n        if(!bkp && !rq && FB->input && FB->input->haskey()) rq = 1;\n        if(FB->storage) FB->storage->read(bootdev, 512, lba, dst);\n    } else {\n        if(!bkp && !rq) {\n            __asm__ __volatile__(\"inb $0x64, %%al;\":\"=a\"(al)::);\n            if(al != 0xFF && al & 1) rq = 1;\n        }\n        bios_loadsec(lba, dst);\n    }\n}\n\n/**\n * Sleep 1 usec\n */\nvoid bios_sleep(void)\n{\n            /* NOTE: this should be the right solution, as it only relies on PS/2 alone and needs nothing else. However qemu's\n             * PS/2 emulation is buggy, the oscillation is host freq dependent and not constant as it is on a real hardware. */\n#if 0\n            /* wait a bit, PS/2 control port's bit 4 is oscillating at 15 usecs, use that (67 * 15 = 1005 usecs) */\n            __asm__ __volatile__ (\"inb $0x61,%%al;andb $0x10,%%al;movb %%al,%%ah;movw $67, %%cx;\"\n            \"1:;inb $0x61,%%al;andb $0x10,%%al;cmpb %%al,%%ah;je 1b;movb %%al,%%ah;nop;pause;dec %%cx;jnz 1b;\" : : : \"rax\", \"rbx\", \"rcx\", \"rdx\");\n#else\n            /* wait a bit, polling the PIT latch for delay. 1000 usec = 1,193,182 Hz / 1000 ms = 1193 */\n            __asm__ __volatile__ (\"movw $1193, %%cx;\"                                                       /* cx = ticks to wait */\n            \"xor %%al,%%al;outb %%al,$0x43;inb $0x40,%%al;movb %%al,%%bl;inb $0x40,%%al;movb %%al,%%bh;\"    /* bx = last counter */\n            \"1:xor %%al,%%al;outb %%al,$0x43;inb $0x40,%%al;movb %%al,%%ah;inb $0x40,%%al;xchgb %%al,%%ah;\" /* ax = current counter */\n            \"nop;pause;subw %%ax,%%bx;subw %%bx,%%cx;movw %%ax,%%bx;jae 1b;\" /* cx -= (bx - ax); bx = ax; while(cx > 0); */\n             : : : \"rax\", \"rbx\", \"rcx\");\n#endif\n}\n\n/**\n * Allocate and zero out a page on BIOS\n */\nuint64_t bios_alloc(void)\n{\n    uint64_t page = file_buf;\n    file_buf += 4096;\n    memset((void*)page, 0, 4096);\n    return page;\n}\n\n/**\n * Get the next cluster from FAT\n */\nuint32_t bios_nextclu(uint32_t clu)\n{\n    uint64_t i;\n\n    if(ST || clu < 2 || clu >= 0x0FFFFFF8) return 0;\n    if(clu < fat_cache || clu > fat_cache + 1023) {\n        fat_cache = clu & ~1023;\n        for(i = 0; i < 8; i++) fw_loadsec(fat_lba + (fat_cache >> 7) + i, &fat[i << 7]);\n    }\n    clu = fat[clu - fat_cache];\n    return clu < 2 || clu >= 0x0FFFFFF8 ? 0 : clu;\n}\n\n/**\n * Open a file on BIOS\n */\nint bios_open(uint16_t *fn)\n{\n    uint64_t lba;\n    uint32_t clu = bpb->rc;\n    int i, n = 0, m = 0;\n    uint8_t secleft = 0, *dir = data + sizeof(data);\n    uint16_t *u, *s = fn, a, b;\n\n    if(ST || !root_dir || !fn || !*fn) return 0;\n    file_size = file_clu = 0;\n    memset(lfn, 0, sizeof(lfn));\n    while(1) {\n        /* have we reached the end of the sector? */\n        if(dir >= data + sizeof(data)) {\n            if(secleft) { secleft--; lba++; }\n            else {\n                if(clu < 2 || clu >= 0x0FFFFFF8) return 0;\n                secleft = bpb->spc - 1;\n                lba = clu * bpb->spc + data_lba;\n                clu = bios_nextclu(clu);\n            }\n            fw_loadsec(lba, &data);\n            dir = data;\n        }\n        /* empty space? End of directory then */\n        if(!dir[0]) return 0;\n        /* not a deleted entry or current and parent entries? */\n        if(dir[0] != 5 && dir[0] != 0xE5 && (dir[0] != '.' || (dir[1] != '.' && dir[1] != ' '))) {\n            /* is this an LFN block? */\n            if(dir[0xB] == 0xF) {\n                /* first LFN block? */\n                if(!n || (dir[0] & 0x40)) {\n                    memset(lfn, 0, sizeof(lfn));\n                    n = dir[0] & 0x1F;\n                    /* bad record, not sure what to do. Let's reset state and continue with next entry */\n                    if(n < 1 || n > 20) { n = m = 0; dir += 32; continue; }\n                    u = lfn + (n - 1) * 13;\n                }\n                /* get the next part of UCS-2 characters */\n                for(i = 0; i < 5; i++)\n                    u[i] = dir[i*2+2] << 8 | dir[i*2+1];\n                for(i = 0; i < 6; i++)\n                    u[i+5] = dir[i*2+0xF] << 8 | dir[i*2+0xE];\n                u[11] = dir[0x1D] << 8 | dir[0x1C];\n                u[12] = dir[0x1F] << 8 | dir[0x1E];\n                u -= 13;\n                n--;\n                /* indicate that the next directory entry belongs to an LFN */\n                m = (!n && u < lfn);\n            } else\n            if(!(dir[0xB] & 8)) {\n                /* if we don't have an LFN already, generate it from the 8.3 name in this entry */\n                if(!m) {\n                    for(i = 0; i < 8; i++) lfn[i] = dir[i];\n                    while(i && lfn[i - 1] == ' ') i--;\n                    if(dir[8] != ' ') {\n                        lfn[i++] = '.'; lfn[i++] = dir[8];\n                        if(dir[9] != ' ') {\n                            lfn[i++] = dir[9];\n                            if(dir[10] != ' ') { lfn[i++] = dir[10]; }\n                        }\n                    }\n                    lfn[i] = 0;\n                } else m = 0;\n                /* filename match? */\n                if(*s == '/') s++;\n                for(i = 0; lfn[i] && s[i] && s[i] != '/'; i++) {\n                    a = lfn[i]; if(a >= 'A' && a <= 'Z') a += 'a' - 'A';\n                    b = s[i]; if(b >= 'A' && b <= 'Z') b += 'a' - 'A';\n                    if(a != b) break;\n                }\n                if(!lfn[i]) {\n                    clu = (dir[0x15] << 24) | (dir[0x14] << 16) | (dir[0x1B] << 8) | dir[0x1A];\n                    /* is this a directory? */\n                    if(dir[0xB] & 0x10) {\n                        if(s[i] != '/') return 0;\n                        /* go to subdirectory */\n                        s += i + 1; n = m = secleft = 0; dir = data + sizeof(data);\n                        continue;\n                    } else {\n                        /* no, it's a file, then we have located what we were looking for */\n                        if(clu < 2 || clu >= 0x0FFFFFF8) return 0;\n                        file_clu = clu;\n                        file_size = (dir[0x1F] << 24) | (dir[0x1E] << 16) | (dir[0x1D] << 8) | dir[0x1C];\n                        break;\n                    }\n                }\n            }\n        }\n        dir += 32;\n    }\n    return 1;\n}\n\n/**\n * Read data from file on BIOS\n */\nuint64_t bios_read(uint64_t offs, uint64_t size, void *buf)\n{\n    uint64_t lba = 0, rem, o;\n    uint32_t clu = file_clu, nc, ns = 0, os = 0, rs = 512;\n    uint8_t secleft = 0;\n\n    if(ST || file_clu < 2 || offs >= file_size || !size || !buf) return 0;\n    if(offs + size > file_size) size = file_size - offs;\n    rem = size;\n\n    pb_init(size);\n    if(offs) {\n        nc = offs / (bpb->spc << 9); o = offs % (bpb->spc << 9);\n        ns = o >> 9; os = o & 0x1ff; rs = 512 - os;\n        if(nc) { while(nc-- && clu) { clu = bios_nextclu(clu); } if(!clu) return 0; }\n        secleft = bpb->spc - ns - 1;\n        lba = clu * bpb->spc + ns - 1 + data_lba;\n    }\n    while(rem && !rq) {\n        if(secleft) { secleft--; lba++; }\n        else {\n            if(!clu) break;\n            secleft = bpb->spc - 1;\n            lba = clu * bpb->spc + data_lba;\n            clu = bios_nextclu(clu);\n        }\n        if(rs > rem) rs = rem;\n        if(rs < 512) {\n            fw_loadsec(lba, data);\n            memcpy(buf, data + os, rs); os = 0;\n        } else {\n            fw_loadsec(lba, buf);\n            if(os) { memcpy(buf, buf + os, rs); os = 0; }\n        }\n        buf += rs; rem -= rs; rs = 512;\n        pb_draw(size - rem);\n    }\n    pb_fini();\n    return (size - rem);\n}\n\n/**\n * Close file on BIOS\n */\nvoid bios_close(void)\n{\n    file_clu = file_size = 0;\n}\n\n/**\n * Generate tags for system tables on BIOS\n */\nvoid bios_systables(void)\n{\n    int sm = 0, rp = 0, i;\n    uint8_t *s, chk;\n\n    for(s = (uint8_t*)0x9A000; s < (uint8_t*)0x100000 && !(sm & rp); s += 16) {\n        if(!memcmp(s, \"_SM_\", 4)) {\n            for(chk = 0, i = 0; (uint32_t)i < (uint32_t)s[5]; i++) chk += s[i];\n            if(!chk) {\n                memset(tags_ptr, 0, sizeof(multiboot_tag_smbios_t));\n                ((multiboot_tag_smbios_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_SMBIOS;\n                ((multiboot_tag_smbios_t*)tags_ptr)->size = sizeof(multiboot_tag_smbios_t) + (uint32_t)s[5];\n                ((multiboot_tag_smbios_t*)tags_ptr)->major = s[7];\n                ((multiboot_tag_smbios_t*)tags_ptr)->minor = s[8];\n                memcpy(((multiboot_tag_smbios_t*)tags_ptr)->tables, s, (uint32_t)s[5]);\n                tags_ptr += (((multiboot_tag_smbios_t*)tags_ptr)->size + 7) & ~7;\n            }\n            sm = 1;\n        } else\n        if(!memcmp(s, \"RSD PTR \", 8)) {\n            if(s[15] < 2) {\n                ((multiboot_tag_old_acpi_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_ACPI_OLD;\n                ((multiboot_tag_old_acpi_t*)tags_ptr)->size = sizeof(multiboot_tag_old_acpi_t) + 24;\n                memcpy(((multiboot_tag_old_acpi_t*)tags_ptr)->rsdp, s, 24);\n                tags_ptr += (((multiboot_tag_old_acpi_t*)tags_ptr)->size + 7) & ~7;\n            } else {\n                ((multiboot_tag_new_acpi_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_ACPI_NEW;\n                ((multiboot_tag_new_acpi_t*)tags_ptr)->size = sizeof(multiboot_tag_new_acpi_t) + 36;\n                memcpy(((multiboot_tag_new_acpi_t*)tags_ptr)->rsdp, s, 36);\n                tags_ptr += (((multiboot_tag_new_acpi_t*)tags_ptr)->size + 7) & ~7;\n            }\n            rsdp_ptr = (uintptr_t)s;\n            rp = 1;\n        }\n    }\n}\n\n/**\n * Initialize BIOS related things\n */\nvoid bios_init(void)\n{\n    guid_t espGuid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID;\n    guid_t fbbGuid = { 0x83bd6b9d, 0x7f41, 0x11dc, { 0xbe, 0x0b, 0x00, 0x15, 0x60, 0xb8, 0x4f, 0x0f } };\n    guid_t bbpGuid = { 0x21686148, 0x6449, 0x6e6f, { 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } };\n    uint64_t i, j, k, l, n;\n\n    /* finish up the page tables (up to 5G to be safe) */\n    /* We couldn't do this sooner, as this overwrites the PMBR code at 0x7C00 */\n    pt = (uint64_t*)0x1000;\n    bios_pagetables(5);\n    __asm__ __volatile__(\"movq %%rax, %%cr3\"::\"a\"(0x1000):);\n    fw_lfb(fb_w, fb_h, fb_bpp);\n    if(!vidmode.framebuffer_addr) {\n        fb_w = 800; fb_h = 600; fw_lfb(fb_w, fb_h, fb_bpp);\n        if(!vidmode.framebuffer_addr) { fb_w = 640; fb_h = 480; fw_lfb(fb_w, fb_h, fb_bpp); }\n    }\n\n    /* get boot partition's root directory */\n    fw_loadsec(1, &vbr);\n    if(!memcmp(&vbr, EFI_PTAB_HEADER_ID, 8)) {\n        /* found GPT */\n        j = ((gpt_header_t*)&vbr)->SizeOfPartitionEntry;\n        l = ((gpt_header_t*)&vbr)->PartitionEntryLBA;\n        n = ((gpt_header_t*)&vbr)->NumberOfPartitionEntries;\n        /* look for ESP in the first 8 sectors only. Should be the very first entry anyway */\n        for(k = 0; k < 8 && n; k++) {\n            fw_loadsec(l + k, &vbr);\n            for(i = 0; i + j <= 512; i += j, n--) {\n                /* does ESP type match? */\n                if(!root_dir && !memcmp(&((gpt_entry_t*)&vbr[i])->PartitionTypeGUID, &espGuid, sizeof(guid_t))) {\n                    root_dir = (void*)(((gpt_entry_t*)&vbr[i])->StartingLBA);\n                    memcpy(&bootuuid, &(((gpt_entry_t*)&vbr[i])->UniquePartitionGUID), sizeof(guid_t));\n                } else\n                /* look for fallback option: FreeBSD boot or BIOS boot partition type? */\n                if(!vbr_lba && (\n                  !memcmp(&((gpt_entry_t*)&vbr[i])->PartitionTypeGUID, &fbbGuid, sizeof(guid_t)) ||\n                  !memcmp(&((gpt_entry_t*)&vbr[i])->PartitionTypeGUID, &bbpGuid, sizeof(guid_t)))) {\n                    vbr_lba = ((gpt_entry_t*)&vbr[i])->StartingLBA;\n                    vbr_size = ((gpt_entry_t*)&vbr[i])->EndingLBA - ((gpt_entry_t*)&vbr[i])->StartingLBA + 1;\n                } else\n                /* look for fallback option: maybe marked for legacy boot? (should override part type fallbacks) */\n                if(((gpt_entry_t*)&vbr[i])->Attributes & EFI_PART_USED_BY_OS && ((gpt_entry_t*)&vbr[i])->StartingLBA > 2) {\n                    vbr_lba = ((gpt_entry_t*)&vbr[i])->StartingLBA;\n                    vbr_size = 1;\n                }\n\n            }\n        }\n    } else {\n        /* fallback to MBR partitioning scheme */\n        fw_loadsec(0, &vbr);\n        if(vbr[510] == 0x55 && vbr[511] == 0xAA)\n            for(i = 0x1c0; i < 510; i += 16)\n                if(vbr[i - 2] == 0x80/*active*/ && (vbr[i + 2] == 0xC/*FAT32*/ || vbr[i + 2] == 0xEF/*ESP*/)) {\n                    root_dir = (void*)(uint64_t)(*((uint32_t*)&vbr[i + 6]));\n                    memcpy(&bootuuid.Data1, \"PART\", 4); memcpy(bootuuid.Data4, \"boot\", 4);\n                    bootuuid.Data2 = *((uint8_t*)0x4ff); bootuuid.Data3 = (i - 0x1c0) / 16;\n                    break;\n                }\n    }\n    /* we shamelessly reuse the pointer to store the boot partition's start LBA, because later we use that as\n     * a flag to see if we have found a file system, otherwise we add it to data_lba and never use it again */\n    if(root_dir) {\n        fw_loadsec((uint64_t)root_dir, &vbr);\n        bpb = (esp_bpb_t*)&vbr;\n        if(vbr[510] != 0x55 || vbr[511] != 0xAA || bpb->bps != 512 || !bpb->spc || bpb->spf16 || !bpb->spf32)\n            root_dir = NULL;\n        else {\n            /* calculate the LBA address of the FAT and the first data sector */\n            fat_lba = bpb->rsc + (uint64_t)root_dir;\n            data_lba = bpb->spf32 * bpb->nf + bpb->rsc - 2 * bpb->spc + (uint64_t)root_dir;\n            /* load the beginning of the FAT into the cache */\n            for(i = 0; i < 8; i++) fw_loadsec(fat_lba + i, &fat[i << 7]);\n            fat_cache = 0;\n        }\n    }\n}\n\n/**************** Common functions ****************/\n\n/**\n * Initialize firmware related stuff\n */\nvoid fw_init(efi_handle_t image, efi_system_table_t *systab, uint16_t bdev)\n{\n    /* make sure SSE is enabled, because some say there are buggy firmware in the wild not enabling (and also needed if we come\n     * from boot_x86.asm). No supported check, because according to AMD64 Spec Vol 2, all long mode capable CPUs must also\n     * support SSE2 at least. We don't need them, but it's more than likely that a kernel is compiled using SSE instructions. */\n    __asm__ __volatile__ (\n    \"movq %%cr0, %%rax;andb $0xF1, %%al;movq %%rax, %%cr0;\"     /* clear MP, EM, TS (FPU emulation off) */\n    \"movq %%cr4, %%rax;orw $3 << 9, %%ax;movq %%rax, %%cr4;\"    /* set OSFXSR, OSXMMEXCPT (enable SSE) */\n    :::\"rax\");\n\n    /* the default framebuffer resolution. We set this up anyway so that we can display console messages\n     * on screen, but later this will be changed to whatever the user requested. */\n    fb_w = 800; fb_h = 600; fb_bpp = 32;\n\n    /* initialize everything to zero */\n    IM = 0; ST = NULL; FB = NULL; bootdev = 0;\n    if((uint32_t)(uintptr_t)image == 0xF055B105) {\n        FB = (fossbios_t*)systab;\n        if(bdev < (FB->storage ? FB->storage->num : 0)) bootdev = bdev;\n    } else {\n        ST = systab;\n        IM = image;\n    }\n    root_dir = NULL; BS = NULL; bpb = NULL; f = NULL; memmap = NULL; initrd = NULL; num_memmap = verbose = bkp = rq = nptr = smp = 0;\n    zero_page = NULL; memset(&ptrs, 0, sizeof(ptrs));\n    conf_buf = kernel = cmdline = NULL; kernel_entry = logo_buf = tags_ptr = NULL; kernel_mode = MODE_MB64;\n    rsdp_ptr = mod_buf = dsdt_ptr = ram = vbr_lba = vbr_size = hack_buf = 0; in_exc = 0;\n    memset(&bootuuid, 0, sizeof(guid_t)); memset(&vidmode, 0, sizeof(vidmode)); fb_bg = 0; pb_fb = NULL;\n    /* things with fixed address */\n    tags_buf = (uint8_t*)0x20000; file_buf = 0x100000;\n\n    /* do firmware specific initialization */\n    if(ST) efi_init(); else bios_init();\n    if(!vidmode.framebuffer_addr) vidmode.framebuffer_width = vidmode.framebuffer_height = vidmode.framebuffer_bpp = 0;\n    console_init();\n}\n\n/**\n * Display a boot splash\n */\nvoid fw_bootsplash(void)\n{\n    uint32_t c;\n    uint8_t *fb = (uint8_t*)vidmode.framebuffer_addr;\n    int i, j, k, l, x, y, w, h, o, m, p, px, py, b = (vidmode.framebuffer_bpp + 7) >> 3;\n\n    /* clear screen */\n    if(!fb) return;\n    for(j = y = 0; y < (int)vidmode.framebuffer_height; y++, j += vidmode.framebuffer_pitch)\n        for(i = j, x = 0; x < (int)vidmode.framebuffer_width; x++, i += b)\n            if(b == 2) *((uint16_t*)(fb + i)) = (uint16_t)fb_bg; else *((uint32_t*)(fb + i)) = fb_bg;\n#ifdef CONSOLE_FB\n    fb_x = fb_y = 4;\n#endif\n    /* only indexed RLE compressed TGA images supported */\n    if(!logo_buf || logo_buf[0] || logo_buf[1] != 1 || logo_buf[2] != 9 || logo_buf[3] || logo_buf[4] ||\n        (logo_buf[7] != 24 && logo_buf[7] != 32)) return;\n    /* uncompress image */\n    o = (logo_buf[17] & 0x20); w = (logo_buf[13] << 8) + logo_buf[12]; h = (logo_buf[15] << 8) + logo_buf[14];\n    if(w < 1 || h < 1) return;\n    px = ((int)vidmode.framebuffer_width - w) / 2; py = ((int)vidmode.framebuffer_height - h) / 2;\n    m = ((logo_buf[7] >> 3) * ((logo_buf[6] << 8) | logo_buf[5])) + 18; y = i = 0;\n    for(l = 0, x = w, y = -1; l < w * h && (uint32_t)m < logo_size;) {\n        k = logo_buf[m++];\n        if(k > 127) { p = 0; k -= 127; j = logo_buf[m++] * (logo_buf[7] >> 3) + 18; } else { p = 1; k++; }\n        l += k;\n        while(k--) {\n            if(p) j = logo_buf[m++] * (logo_buf[7] >> 3) + 18;\n            if(x == w) { x = 0; i = ((py + (!o ? h - y - 1 : y)) * (int)vidmode.framebuffer_pitch + (px + x) * b); y++; }\n            if(py + y > 0 && py + y < (int)vidmode.framebuffer_height - 1) {\n                if(px + x > 0 && px + x < (int)vidmode.framebuffer_width - 1) {\n                    c = FB_COLOR(logo_buf[j + 2], logo_buf[j + 1], logo_buf[j + 0]);\n                    if(b == 2) *((uint16_t*)(fb + i)) = (uint16_t)c; else *((uint32_t*)(fb + i)) = c;\n                }\n                i += b;\n            }\n            x++;\n        }\n    }\n}\n\n/**\n * Open a file\n */\nint fw_open(char *fn)\n{\n    uint16_t *d, c;\n    char *s;\n\n    if(!root_dir || !fn || !*fn) return 0;\n    /* UTF-8 to WCHAR */\n    for(s = fn, d = wcname; *s && *s != ' ' && *s != '\\r' && *s != '\\n' && d < &wcname[PATH_MAX - 2]; d++) {\n        if((*s & 128) != 0) {\n            if(!(*s & 32)) { c = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); s++; } else\n            if(!(*s & 16)) { c = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); s += 2; } else\n            if(!(*s & 8)) { c = ((*s & 0x7)<<18)|((*(s+1) & 0x3F)<<12)|((*(s+2) & 0x3F)<<6)|(*(s+3) & 0x3F); *s += 3; }\n            else c = 0;\n        } else c = *s;\n        s++; if(c == '\\\\' && *s == ' ') { c = ' '; s++; }\n        *d = c;\n    }\n    *d = 0;\n    return ST ? efi_open(wcname) : bios_open(wcname);\n}\n\n/**\n * Read data from file\n */\nuint64_t fw_read(uint64_t offs, uint64_t size, void *buf)\n{\n    if(!root_dir || offs >= file_size || !size || !buf) return 0;\n    return ST ? efi_read(offs, size, buf) : bios_read(offs, size, buf);\n}\n\n/**\n * Close file\n */\nvoid fw_close(void)\n{\n    ST ? efi_close() : bios_close();\n}\n\n/**\n * Load and parse config (everything except modules)\n */\nvoid fw_loadconfig(void)\n{\n    efi_status_t status;\n    char *s, *e, *a;\n    uint32_t r, g, b;\n    int l, m = 0;\n\n    if(bkp) { fw_bootsplash(); printf(\"Aborted, loading backup configuration...\\r\\n\"); }\n\n    kernel = NULL;\n    tags_buf = (uint8_t*)0x20000;\n    /* as a fallback, we try to load the first menuentry from easyboot's configuration */\n    if(fw_open(\"simpleboot.cfg\") || (!bkp && fw_open(\"easyboot/menu.cfg\"))) {\n        if(ST) {\n            if(!conf_buf) {\n                status = BS->AllocatePool(EfiLoaderData, file_size + 1, (void**)&conf_buf);\n                if(EFI_ERROR(status) || !conf_buf) { fw_close(); goto err; }\n            }\n        } else {\n            conf_buf = (char*)tags_buf;\n            tags_buf += (file_size + 7) & ~7;\n        }\n        fw_read(0, file_size, conf_buf);\n        conf_buf[file_size] = 0;\n        fw_close();\n        fb_w = vidmode.framebuffer_width; fb_h = vidmode.framebuffer_height; fb_bpp = vidmode.framebuffer_bpp; fb_bg = 0; smp = 0;\n        for(s = conf_buf; *s;) {\n            /* find beginning of a line */\n            while(*s && (*s == '\\r' || *s == '\\n' || *s == ' ' || *s == '\\t')) s++;\n            for(a = s; *a && *a != ' ' && *a != '\\r' && *a != '\\n'; a++);\n            for(e = a; *e && *e != '\\r' && *e != '\\n'; e++);\n            for(; a < e && *a == ' '; a++);\n            /* 's' points to the start of the command,\n             * 'a' to the first argument,\n             * 'e' to the end of the line */\n            l = !memcmp(s, \"backup\", 6);\n            if(bkp ^ l) { s = e; continue; } else if(bkp & l) s += 6;\n            if(!memcmp(s, \"multicore\", 9)) smp = 1;\n            if(a >= e) { s = e; continue; }\n            if(!memcmp(s, \"menuentry\", 9)) {\n                if(++m > 1) break;\n            } else\n            if(!memcmp(s, \"verbose\", 7)) {\n                a = getint(a, &verbose);\n            } else\n            if(!memcmp(s, \"framebuffer\", 11)) {\n                a = getint(a, &fb_w); while(a < e && *a == ' ') a++;\n                a = getint(a, &fb_h); while(a < e && *a == ' ') a++;\n                a = getint(a, &fb_bpp);\n                if(fb_w < 320 || fb_w > 65536 || fb_h < 200 || fb_h > 65536 || fb_bpp < 15 || fb_bpp > 32) {\n                    fb_w = vidmode.framebuffer_width; fb_h = vidmode.framebuffer_height; fb_bpp = vidmode.framebuffer_bpp;\n                }\n            } else\n            if(!memcmp(s, \"bootsplash\", 10)) {\n                if(*a == '#') {\n                    a++; a = gethex(a, &r); a = gethex(a, &g); a = gethex(a, &b);\n                    fb_bg = FB_COLOR(r, g, b);\n                    while(a < e && *a == ' ') a++;\n                }\n                if(a < e) {\n                    if(fw_open(a)) {\n                        if(ST) {\n                            if(logo_buf) { BS->FreePool(logo_buf); logo_buf = NULL; }\n                            status = BS->AllocatePool(EfiLoaderData, file_size, (void**)&logo_buf);\n                            if(EFI_ERROR(status)) logo_buf = NULL;\n                        } else {\n                            logo_buf = tags_buf;\n                            tags_buf += (file_size + 7) & ~7;\n                        }\n                        if(verbose) printf(\"Loading logo '%S' (%ld bytes)...\\r\\n\", wcname, file_size);\n                        logo_size = file_size;\n                        fw_read(0, file_size, logo_buf);\n                        fw_close();\n                    } else if(verbose) printf(\"WARNING: unable to load '%S'\\r\\n\", wcname);\n                }\n                fw_bootsplash();\n            } else\n            if(a < e && !memcmp(s, \"kernel\", 6)) {\n                kernel = a;\n                for(; a < e && *a && *a != ' ' && *a != '\\r' && *a != '\\n'; a++)\n                    if(*a == '\\\\' && a[1] == ' ') a++;\n                while(a < e && *a == ' ') a++;\n                if(*a && *a != '\\r' && *a != '\\n') cmdline = a;\n            }\n            /* go to the next line */\n            s = e;\n        }\n    }\nerr:if(!kernel) kernel = (char*)defkernel;\n    if(!bkp && (volatile char)definitrd[63] == 1) smp = 1;\n}\n\n/**\n * Detect config file independent configuration and generate tags for them\n */\nvoid fw_loadsetup()\n{\n    efi_status_t status;\n    multiboot_tag_loader_t *stag;\n    multiboot_tag_mmap_t *mtag;\n    char *c;\n\n    if(!ST) {\n        mod_buf = 0;\n        file_buf = 0x100000;\n    }\n    if(!bkp && ST) {\n        tags_buf = NULL;\n        status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, TAGS_MAX, (efi_physical_address_t*)&tags_buf);\n        if(EFI_ERROR(status)) tags_buf = NULL;\n    }\n    tags_ptr = tags_buf;\n    if(tags_ptr) {\n        /* MBI header */\n        ((multiboot_info_t*)tags_buf)->total_size = ((multiboot_info_t*)tags_buf)->reserved = 0;\n        tags_ptr += sizeof(multiboot_info_t);\n        /* loader tag */\n        stag = (multiboot_tag_loader_t*)tags_ptr;\n        stag->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME;\n        stag->size = bkp ? 28 : 19;\n        memcpy(stag->string, SIMPLEBOOT_MAGIC, 11);\n        if(bkp) memcpy(stag->string + 10, \" (backup)\", 10);\n        tags_ptr += (stag->size + 7) & ~7;\n        /* commandline tag */\n        if(cmdline) {\n            for(c = cmdline; *c && *c != '\\r' && *c != '\\n'; c++);\n            stag = (multiboot_tag_loader_t*)tags_ptr;\n            stag->type = MULTIBOOT_TAG_TYPE_CMDLINE;\n            stag->size = 9 + c - cmdline;\n            memcpy(stag->string, cmdline, c - cmdline); stag->string[c - cmdline] = 0;\n            tags_ptr += (stag->size + 7) & ~7;\n            /* overwrite the cmdline pointer with this new, zero terminated string */\n            cmdline = stag->string;\n        }\n        /* get memory map early, because we'll need it on BIOS to decide where to load the kernel\n         * for UEFI this must be done as the last step, because the memory map will change during boot */\n        if(!ST) {\n            /* get system tables and generate tags for them */\n            FB ? fb_systables() : bios_systables();\n            /* generate memory map tag */\n            mtag = (multiboot_tag_mmap_t*)tags_ptr;\n            mtag->type = MULTIBOOT_TAG_TYPE_MMAP;\n            mtag->entry_size = sizeof(multiboot_mmap_entry_t);\n            mtag->entry_version = 0;\n            num_memmap = FB ? fb_memmap(mtag->entries) : bios_e820(mtag->entries);\n            if(num_memmap > 0) {\n                memmap = mtag->entries;\n                mtag->size = sizeof(multiboot_tag_mmap_t) + num_memmap * sizeof(multiboot_mmap_entry_t);\n                tags_ptr += (mtag->size + 7) & ~7;\n            }\n        } else {\n            /* get system tables and generate tags for them */\n            efi_systables();\n            /* we can't use it, however we still have to query the memory map on UEFI too to determine how much RAM we have */\n            efi_memmap(NULL);\n        }\n        ram &= ~(2 * 1024 * 1024 - 1);\n    }\n}\n\n/**\n * Parse config for modules and load them\n */\nvoid fw_loadmodules(void)\n{\n    uint64_t unc_buf;\n    uint32_t uncomp;\n    uint8_t *ptr, tmp[16];\n    int n = 0, f = 0, l;\n    multiboot_tag_module_t *tag;\n    char *s, *e, *a;\n\n    if(conf_buf) {\n        for(s = conf_buf; !rq && !f && *s;) {\n            /* find beginning of a line */\n            while(*s && (*s == '\\r' || *s == '\\n' || *s == ' ' || *s == '\\t')) s++;\n            for(a = s; *a && *a != ' ' && *a != '\\r' && *a != '\\n'; a++);\n            for(e = a; *e && *e != '\\r' && *e != '\\n'; e++);\n            for(; a < e && *a == ' '; a++);\n            /* 's' points to the start of the command,\n             * 'a' to the first argument,\n             * 'e' to the end of the line */\n            l = !memcmp(s, \"backup\", 6);\n            if(a >= e || bkp ^ l) { s = e; continue; } else if(bkp & l) s += 6;\n            if(!memcmp(s, \"module\", 6)) {\nldinitrd:       if(fw_open(a)) {\n                    fw_read(0, 16, (void*)tmp);\n                    uncomp = 0;\n                    if(tmp[0] == 0x1f && tmp[1] == 0x8b)\n                        fw_read(file_size - 4, 4, (void*)&uncomp);\n                    else\n                    if(tmp[0] == 'G' && tmp[1] == 'U' && tmp[2] == 'D' && tmp[8] == 0x78)\n                        uncomp = (((tmp[4] | (tmp[5] << 8)) + 7) & ~7) + ((tmp[6] | (tmp[7] << 8)) << 4);\n                    if(ST) {\n                        /* if it's a gzip compressed module, then get another buffer for uncompressed data,\n                         * and then ditch the compressed buffer after inflation */\n                        if(uncomp) unc_buf = efi_allocpages(AllocateAnyPages, (uncomp + 4095) >> 12, 0);\n                        else unc_buf = 0;\n                        mod_buf = efi_allocpages(AllocateAnyPages, (file_size + 4095) >> 12, 0);\n                        ptr = unc_buf ? (uint8_t*)unc_buf : (uint8_t*)mod_buf;\n                    } else {\n                        ptr = (uint8_t*)file_buf;\n                        /* if it's a gzip compressed module, then load it at position + uncompressed size,\n                         * and uncompress to position. Compressed buffer will be overwritten by the next module. */\n                        if(uncomp) {\n                            unc_buf = file_buf;\n                            file_buf += (uncomp + 4095) & ~4095;\n                            mod_buf = file_buf;\n                        } else {\n                            unc_buf = 0;\n                            mod_buf = file_buf;\n                            file_buf += (file_size + 4095) & ~4095;\n                        }\n                    }\n                    if(mod_buf) {\n                        if(verbose) printf(\"Loading module '%S' (%ld bytes)...\\r\\n\", wcname, file_size);\n                        fw_read(0, file_size, (void*)mod_buf);\n                        if(unc_buf) {\n                            if(verbose) printf(\"Uncompressing (%d bytes)...\\r\\n\", uncomp);\n                            uncompress((uint8_t*)mod_buf, (uint8_t*)unc_buf, uncomp);\n                        }\n                        /* if it's a DTB, DSDT or a GUDT, don't add it to the modules list, add it to the ACPI tables */\n                        if(ptr[0] == 0xD0 && ptr[1] == 0x0D && ptr[2] == 0xFE && ptr[3] == 0xED) {\n                            if(verbose) printf(\"DTB detected...\\r\\n\");\n                            dsdt_ptr = (uint64_t)ptr;\n                        } else\n                        if(((ptr[0] == 'D' && ptr[1] == 'S') || (ptr[0] == 'G' && ptr[1] == 'U')) && ptr[2] == 'D' && ptr[3] == 'T') {\n                            if(verbose) printf(\"%c%cDT detected...\\n\", ptr[0], ptr[1]);\n                            dsdt_ptr = (uint64_t)ptr;\n                        } else {\n                            if(tags_ptr) {\n                                tag = (multiboot_tag_module_t*)tags_ptr;\n                                tag->type = MULTIBOOT_TAG_TYPE_MODULE;\n                                tag->size = sizeof(multiboot_tag_module_t) + e - a + 1;\n                                tag->mod_start = unc_buf ? (uint32_t)(uintptr_t)unc_buf : (uint32_t)(uintptr_t)mod_buf;\n                                tag->mod_end = unc_buf ? (uint32_t)(uintptr_t)unc_buf + uncomp :\n                                    (uint32_t)(uintptr_t)mod_buf + (uint32_t)file_size;\n                                memcpy(tag->string, a, e - a); tag->string[e - a] = 0;\n                                if(verbose > 2) printf(\"%D\\r\\n\", tag->mod_start);\n                                tags_ptr += (tag->size + 7) & ~7;\n                                if(!initrd) initrd = tag;\n                            }\n                            n++;\n                        }\n                        if(ST && unc_buf && nptr) {\n                            nptr--; BS->FreePages(ptrs[nptr].Memory, ptrs[nptr].NoPages);\n                        }\n                    }\n                    fw_close();\n                } else if(verbose) printf(\"WARNING: unable to load '%S'\\r\\n\", wcname);\n            }\n            /* go to the next line */\n            s = e;\n        }\n    }\n    /* if no modules were loaded, but we have a default initrd name, try to add that */\n    if(!n && !f) { f = 1; if((volatile char)definitrd[0]) { a = (char*)definitrd; for(e = a; *e; e++){} goto ldinitrd; } }\n    if(!n && f == 1) { f = 2; a = bkp ? \"ibmpc/initrd.bak\" : \"ibmpc/initrd\"; e = a + (bkp ? 16 : 12); goto ldinitrd; }\n}\n\n/**\n * Map virtual memory\n */\nint fw_map(uint64_t phys, uint64_t virt, uint32_t size)\n{\n    uint64_t end = virt + size, *ptr, *next = NULL, orig = file_buf;\n\n    /* is this a canonical address? We handle virtual memory up to 256TB */\n    if(!pt || ((virt >> 48L) != 0x0000 && (virt >> 48L) != 0xffff)) return 0;\n\n    /* walk the page tables and add the missing pieces */\n    for(virt &= ~4095, phys &= ~4095; virt < end; virt += 4096) {\n        /* 512G */\n        ptr = &pt[(virt >> 39L) & 511];\n        if(!*ptr) { if(!(*ptr = (ST ? efi_alloc() : bios_alloc()))) return 0; else *ptr |= 3; }\n        /* 1G */\n        ptr = (uint64_t*)(*ptr & ~4095); ptr = &ptr[(virt >> 30L) & 511];\n        if(!*ptr) { if(!(*ptr = (ST ? efi_alloc() : bios_alloc()))) return 0; else *ptr |= 3; }\n        /* 2M if we previously had a large page here, split it into 4K pages */\n        ptr = (uint64_t*)(*ptr & ~4095); ptr = &ptr[(virt >> 21L) & 511];\n        if(!*ptr || *ptr & 0x80) { if(!(*ptr = (ST ? efi_alloc() : bios_alloc()))) return 0; else *ptr |= 3; }\n        /* 4K */\n        ptr = (uint64_t*)(*ptr & ~4095); ptr = &ptr[(virt >> 12L) & 511];\n        /* if this page is already mapped, that means the kernel has invalid, overlapping segments */\n        if(!*ptr) { *ptr = (uint64_t)next; next = ptr; }\n    }\n    /* resolve the linked list */\n    for(end = ((phys == orig ? file_buf : phys) + size - 1) & ~4095; next; end -= 4096, next = ptr) {\n        ptr = (uint64_t*)*next; *next = end | 3;\n    }\n    return 1;\n}\n\n/**\n * Load a kernel segment\n */\nint fw_loadseg(uint32_t offs, uint32_t filesz, uint64_t vaddr, uint32_t memsz)\n{\n    uint64_t top;\n    uint8_t *buf = (uint8_t*)(uintptr_t)vaddr;\n    uint32_t size, i;\n\n    if(!memsz || !file_size) return 1;\n    if(verbose > 1) printf(\"  segment %08x[%08x] -> %08x[%08x]\\r\\n\", offs, filesz, vaddr, memsz);\n    size = (memsz + (vaddr & 4095) + 4095) & ~4095;\n    if(ST) {\n        if(vaddr > ram) {\n            /* possibly a higher-half kernel's segment, we must map it */\n            if(!(buf = (uint8_t*)efi_allocpages(AllocateAnyPages, size >> 12, 0)) || !fw_map((uint64_t)buf, vaddr, size)) goto err;\n        } else {\n            /* try to allocate memory exactly at the requested address */\n            if(!efi_allocpages(AllocateAddress, size >> 12, vaddr & ~4095)) goto err;\n            buf = (uint8_t*)(uintptr_t)vaddr;\n        }\n    } else {\n        /* no overwriting of the loader data */\n        if(vaddr < 0x20000 + (TAGS_MAX + 2) * 4096) goto err;\n        if(vaddr > ram) {\n            /* possibly a higher-half kernel's segment, we must map it */\n            if(!fw_map(file_buf, vaddr, size)) goto err;\n            buf = (void*)file_buf; file_buf += size;\n        } else {\n            /* make sure we load modules after the kernel to avoid any conflict */\n            top = ((uintptr_t)buf + size + 4095) & ~4095; if(file_buf < top) file_buf = top;\n            /* let's see if the memory where the segment wants to be loaded is free or not */\n            for(i = 0; memmap && i < num_memmap; i++)\n                /* find which memory slot it fits */\n                if(memmap[i].base_addr <= vaddr && memmap[i].base_addr + memmap[i].length > vaddr) {\n                    /* if that slot isn't free or the end doesn't fit in the slot too, then that's a problem */\n                    if(memmap[i].type != MULTIBOOT_MEMORY_AVAILABLE ||\n                      memmap[i].base_addr + memmap[i].length < (vaddr & ~4095) + size)\n                        goto err;\n                    break;\n                }\n            /* if no memory slots found, that's a dunno. Not used memory for sure, so let's try to load it, maybe works... */\n        }\n    }\n    if(filesz) fw_read(offs, filesz, buf);\n    if(memsz > filesz) memset(buf + filesz, 0, memsz - filesz);\n    return 1;\nerr:printf(\"ERROR: unable to load segment %08lx[%x], memory already in use\\r\\n\", vaddr, memsz);\n    return 0;\n}\n\n/**\n * Load the kernel\n */\nint fw_loadkernel(void)\n{\n    void *p = (void*)kernel_buf;\n    linux_boot_t *hdr = (linux_boot_t*)(kernel_buf + 0x1f1);\n    efi_status_t status;\n    pe_hdr *pe;\n    pe_sec *sec;\n    uint8_t *ptr;\n    uint64_t offs;\n    int i;\n\n    /* make sure all previously allocated memory (in first pass) is freed, because we need fixed addresses */\n    efi_freepages();\n    wcname[0] = 0;\n    if(!((kernel && *kernel && fw_open(kernel)) || fw_open(\"ibmpc/core\"))) {\n        smp = 0;\n        if(wcname[0]) printf(\"ERROR: kernel '%S' not found\\r\\n\", wcname);\n        else printf(\"ERROR: kernel not found\\r\\n\");\n        /* if we are on BIOS and we have a partition marked bootable (or FreeBSD boot or BIOS boot partition), try that */\n        if(!ST && vbr_lba && vbr_size) { kernel_mode = MODE_VBR; return 1; }\n        return 0;\n    }\n    fw_read(0, sizeof(kernel_buf), p);\n    /* we must check Linux before COFF/PE, because it might disguise itself as an EFI app */\n    if(hdr->boot_flag == 0xAA55 && !memcmp(&hdr->header, HDRSMAG, 4)) {\n        if(hdr->version < 0x20c || ((hdr->pref_address + file_size) >> 32L)) {\n            printf(\"ERROR: unsupported Linux boot protocol version\\r\\n\"); goto err;\n        }\n        /* it's a Linux kernel */\n        kernel_mode = MODE_LIN; smp = 0;\n        if(verbose) printf(\"Loading Linux kernel '%S'...\\r\\n\", wcname);\n        if(!zero_page) zero_page = (linux_boot_params_t*)(ST ? efi_alloc() : 0x90000);\n        if(ST) {\n            i = 0;\n            if(cmdline) for(; cmdline[i] && cmdline[i] != '\\r' && cmdline[i] != '\\n'; i++);\n            if(!zero_page) {\n                i += (int)sizeof(linux_boot_params_t) + 1;\n                status = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, (i + 4095) >> 12, (efi_physical_address_t*)&zero_page);\n                if(EFI_ERROR(status)) {\n                    zero_page = NULL;\n                    status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, (i + 4095) >> 12, (efi_physical_address_t*)&zero_page);\n                    if(EFI_ERROR(status) || ((uint64_t)zero_page >> 32L)) { printf(\"ERROR: zero page allocation error\\r\\n\"); goto err; }\n                }\n            }\n        }\n        if(!hdr->setup_sects) hdr->setup_sects = 4;\n        memset(zero_page, 0, sizeof(linux_boot_params_t));\n        memcpy(&zero_page->hdr, hdr, 0x202 - 0x1f1 + kernel_buf[0x201]);\n        zero_page->hdr.root_dev = 0x100; zero_page->hdr.root_flags = 1; zero_page->hdr.vid_mode = 0xffff;\n        zero_page->hdr.type_of_loader = 0xff;\n        /*zero_page->hdr.type_of_loader = 0xe0; zero_page->hdr.ext_loader_type = 0x14;*/\n        if(cmdline) {\n            ptr = (uint8_t*)zero_page + sizeof(linux_boot_params_t);\n            zero_page->hdr.cmd_line_ptr = (uint32_t)(uintptr_t)ptr;\n            for(i = 0; i < 32767 && cmdline[i] && cmdline[i] != '\\r' && cmdline[i] != '\\n'; i++) ptr[i] = cmdline[i];\n            ptr[i] = 0;\n        }\n        if(!fw_loadseg((hdr->setup_sects + 1) * 512, hdr->init_size, hdr->pref_address, hdr->init_size)) goto err;\n        kernel_entry = (uint8_t*)(uintptr_t)hdr->pref_address + 512;\n    } else\n    if(!memcmp(((Elf32_Ehdr*)p)->e_ident, ELFMAG, 4) &&\n      (((Elf32_Ehdr*)p)->e_machine == EM_386 || ((Elf32_Ehdr*)p)->e_machine == EM_X86_64)) {\n        /* it's a Multiboot2 ELF kernel */\n        kernel_mode = ((Elf32_Ehdr*)p)->e_ident[EI_CLASS] == ELFCLASS64 ? MODE_MB64 : MODE_MB32;\n        if(verbose) printf(\"Loading Multiboot2 ELF%d kernel '%S'...\\r\\n\", kernel_mode == MODE_MB64 ? 64 : 32, wcname);\n        if(kernel_mode == MODE_MB64) {\n            kernel_entry = (uint8_t*)(uintptr_t)((Elf64_Ehdr*)p)->e_entry;\n            ptr = p + ((Elf64_Ehdr*)p)->e_phoff;\n            for(i = 0; !rq && i < ((Elf64_Ehdr*)p)->e_phnum && ptr + ((Elf64_Ehdr*)p)->e_phentsize < kernel_buf + sizeof(kernel_buf);\n              i++, ptr += ((Elf64_Ehdr*)p)->e_phentsize)\n                if(((Elf64_Phdr*)ptr)->p_type == PT_LOAD && !fw_loadseg(\n                    (((Elf64_Phdr*)ptr)->p_offset), (((Elf64_Phdr*)ptr)->p_filesz),\n                    (((Elf64_Phdr*)ptr)->p_vaddr), (((Elf64_Phdr*)ptr)->p_memsz))) goto err;\n        } else {\n            kernel_entry = (uint8_t*)(uintptr_t)((Elf32_Ehdr*)p)->e_entry;\n            ptr = p + ((Elf32_Ehdr*)p)->e_phoff;\n            for(i = 0; !rq && i < ((Elf32_Ehdr*)p)->e_phnum && ptr + ((Elf32_Ehdr*)p)->e_phentsize < kernel_buf + sizeof(kernel_buf);\n              i++, ptr += ((Elf32_Ehdr*)p)->e_phentsize)\n                if(((Elf32_Phdr*)ptr)->p_type == PT_LOAD && !fw_loadseg(\n                    ((Elf32_Phdr*)ptr)->p_offset, ((Elf32_Phdr*)ptr)->p_filesz,\n                    (uint64_t)((Elf32_Phdr*)ptr)->p_vaddr, ((Elf32_Phdr*)ptr)->p_memsz)) goto err;\n        }\n    } else\n    if(((mz_hdr*)p)->magic == MZ_MAGIC && ((pe_hdr*)(p + ((mz_hdr*)p)->peaddr))->magic == PE_MAGIC &&\n      (((pe_hdr*)(p + ((mz_hdr*)p)->peaddr))->machine == IMAGE_FILE_MACHINE_I386 ||\n       ((pe_hdr*)(p + ((mz_hdr*)p)->peaddr))->machine == IMAGE_FILE_MACHINE_AMD64)) {\n        /* it's a Multiboot2 COFF/PE kernel */\n        pe = (pe_hdr*)(p + ((mz_hdr*)p)->peaddr);\n        kernel_mode = pe->file_type == PE_OPT_MAGIC_PE32PLUS ? MODE_MB64 : MODE_PE32;\n        offs = kernel_mode == MODE_MB64 ? (uint32_t)pe->data.pe64.img_base : pe->data.pe32.img_base;\n        kernel_entry = offs + (uint8_t*)(uintptr_t)pe->entry_point;\n        if(verbose) printf(\"Loading Multiboot2 PE%d kernel '%S'...\\r\\n\", kernel_mode == MODE_MB64 ? 64 : 32, wcname);\n        sec = (pe_sec*)((uint8_t*)pe + pe->opt_hdr_size + 24);\n        for(i = 0; !rq && i < pe->sections && (uint8_t*)&sec[1] < kernel_buf + sizeof(kernel_buf); i++, sec++)\n            if(!fw_loadseg(sec->raddr, sec->rsiz,\n                /* the PE section vaddr field is only 32 bits, we must make sure that it properly sign extended to 64 bit */\n                offs + (pe->file_type == PE_OPT_MAGIC_PE32PLUS ? (int64_t)(int32_t)sec->vaddr : sec->vaddr), sec->vsiz)) goto err;\n    } else {\n        printf(\"ERROR: unknown kernel format '%S'\\r\\n\", wcname);\nerr:    fw_close();\n        smp = 0;\n        return 0;\n    }\n    fw_close();\n    /* force GRUB compatible prot mode entry point even with 64 bit kernels (volatile is needed because of a Clang optimizer bug) */\n    if(kernel_mode == MODE_MB64 && (volatile char)definitrd[63] == 2) kernel_mode = MODE_MB32;\n    if(kernel_mode != MODE_MB64) smp = 0;\n    return 1;\n}\n\n/**\n * Finish up MBI tags\n */\nvoid fw_fini(void)\n{\n    int i, n = 0;\n    fadt_t *fadt;\n    multiboot_tag_t *t;\n    multiboot_tag_smp_t *st = NULL;\n    multiboot_tag_mmap_t *tag;\n    efi_status_t status;\n    efi_memory_descriptor_t *memory_map = NULL;\n    uintn_t memory_map_size = 0, map_key = 0, desc_size = 0;\n    uint32_t desc_ver = 0, ow, oh, ob, a, b;\n    uint8_t *rsdt = NULL, *lapic = NULL, *p, *q, *e, *ptr, *end, s, *edid = NULL;\n    uint64_t c, d;\n    static uint8_t ids[256];\n\n    if(vidmode.framebuffer_addr) {\n        if(vidmode.framebuffer_width != fb_w || vidmode.framebuffer_height != fb_h || vidmode.framebuffer_bpp != fb_bpp) {\n            ow = vidmode.framebuffer_width; oh = vidmode.framebuffer_height; ob = vidmode.framebuffer_bpp;\n            if(ST) efi_gop(fb_w, fb_h, fb_bpp); else fw_lfb(fb_w, fb_h, fb_bpp);\n            if(!vidmode.framebuffer_addr) { if(ST) efi_gop(ow, oh, ob); else fw_lfb(ow, oh, ob); }\n            fw_bootsplash();\n        }\n        if(tags_ptr && vidmode.framebuffer_addr) {\n            vidmode.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;\n            vidmode.size = sizeof(vidmode);\n            vidmode.framebuffer_type = 1;\n            vidmode.reserved = 0;\n            memcpy(tags_ptr, &vidmode, vidmode.size);\n            tags_ptr += (vidmode.size + 7) & ~7;\n        }\n        fw_map(vidmode.framebuffer_addr, vidmode.framebuffer_addr,\n            (vidmode.framebuffer_pitch * vidmode.framebuffer_height + 4095) & ~4095);\n    }\n    if(tags_ptr) {\n        if(ST) efi_edid(&edid, (uint32_t*)&i); else { edid = FB ? (FB->video ? FB->video->edid : NULL) : (uint8_t*)0x580; i = 128; }\n        if(edid && i > 0 && *((uint64_t*)(edid + 8))) {\n            ((multiboot_tag_edid_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_EDID;\n            ((multiboot_tag_edid_t*)tags_ptr)->size = i + 8;\n            memcpy(tags_ptr + 8, edid, i);\n            tags_ptr += (i + 15) & ~7;\n        }\n        if(dsdt_ptr && !(\n          (((uint8_t*)(uintptr_t)dsdt_ptr)[0] == 0xD0 && ((uint8_t*)(uintptr_t)dsdt_ptr)[1] == 0x0D &&\n          ((uint8_t*)(uintptr_t)dsdt_ptr)[2] == 0xFE && ((uint8_t*)(uintptr_t)dsdt_ptr)[3] == 0xED) ||\n          (((((uint8_t*)(uintptr_t)dsdt_ptr)[0] == 'D' && ((uint8_t*)(uintptr_t)dsdt_ptr)[1] == 'S') ||\n          (((uint8_t*)(uintptr_t)dsdt_ptr)[0] == 'G' && ((uint8_t*)(uintptr_t)dsdt_ptr)[1] == 'U')) &&\n          ((uint8_t*)(uintptr_t)dsdt_ptr)[2] == 'D' && ((uint8_t*)(uintptr_t)dsdt_ptr)[3] == 'T'))) dsdt_ptr = 0;\n        /* look for the RSD PTR */\n        for(t = (multiboot_tag_t*)(tags_buf + sizeof(multiboot_info_t)); (uint8_t*)t < tags_ptr;\n          t = (multiboot_tag_t*)((uint8_t*)t + ((t->size + 7) & ~7))) {\n            if(t->type == MULTIBOOT_TAG_TYPE_ACPI_OLD || t->type == MULTIBOOT_TAG_TYPE_ACPI_NEW) {\n                rsdt = t->type == MULTIBOOT_TAG_TYPE_ACPI_OLD ?\n                    (uint8_t*)(uintptr_t)*((uint32_t*)&((multiboot_tag_old_acpi_t*)t)->rsdp[16]) :\n                    (uint8_t*)*((uint64_t*)&((multiboot_tag_new_acpi_t*)t)->rsdp[24]);\n                /* found RSDP, iterate on ACPI tables */\n                if((rsdt[0] == 'R' || rsdt[0] == 'X') && !memcmp(rsdt + 1, \"SDT\", 3))\n                    for(ptr = rsdt + 36, end = (uint8_t*)(rsdt + ((fadt_t*)rsdt)->hdr.size); ptr < end;\n                      ptr += rsdt[0] == 'X' ? 8 : 4) {\n                        p = rsdt[0] == 'X' ? (uint8_t*)((uintptr_t)*((uint64_t*)ptr)) : (uint8_t*)((uintptr_t)*((uint32_t*)ptr));\n                        fadt = (fadt_t*)p;\n                        /* found FADT, patch DSDT addresses and recalculate checksum */\n                        if(dsdt_ptr && !memcmp(&fadt->hdr.magic, \"FACP\", 4)) {\n                            fadt->dsdt = (uint32_t)dsdt_ptr;\n                            if(fadt->hdr.rev >= 2 && fadt->hdr.size > sizeof(fadt_t)) fadt->x_dsdt = dsdt_ptr;\n                            fadt->hdr.chksum = 0;\n                            for(s = 0, i = 0; i < (int)fadt->hdr.size; i++) { s += *(((uint8_t*)fadt) + i); }\n                            fadt->hdr.chksum = 0x100 - s;\n                        } else\n                        /* some buggy EFI (TianoCore *khm*) lists APIC table multiple times... */\n                        if(smp && !memcmp(p, \"APIC\", 4)) {\n                            if(!lapic) lapic = (uint8_t*)(uintptr_t)(*((uint32_t*)(p + 0x24)));\n                            for(n = 0, q = p + 44, e = p + *((uint32_t*)(p + 4)); q < e && q[1]; q += q[1])\n                                switch(q[0]) {\n                                    case 0: if((q[4] & 1) && q[3] != 0xFF) ids[n++] = q[3]; break;\n                                    case 5: lapic = (uint8_t*)(uintptr_t)*((uint64_t*)(q + 4)); break;\n                                }\n                        }\n                    }\n            }\n        }\n        /* multicore */\n        if(smp) {\n            ((multiboot_tag_smp_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_SMP;\n            ((multiboot_tag_smp_t*)tags_ptr)->size = sizeof(multiboot_tag_smp_t);\n            st = (multiboot_tag_smp_t*)tags_ptr;\n            st->numcores = n; st->running = 1;\n            __asm__ __volatile__ (\"movl $1, %%eax; cpuid; shrl $24, %%ebx;\" : \"=b\"(a) : : );\n            st->bspid = a; *((uint64_t*)0x8fff8) = a;\n            tags_ptr += (((multiboot_tag_smp_t*)tags_ptr)->size + 7) & ~7;\n            /* measure CPU clock cycles (must do before ExitBootServices on EFI) */\n            __asm__ __volatile__ ( \"rdtsc\" : \"=a\"(a),\"=d\"(b)); c = ((uint64_t)b << 32UL)|(uint64_t)a;\n            ST ? BS->Stall(1000) : (FB ? FB->system->udelay(1000) : bios_sleep());\n            __asm__ __volatile__ ( \"rdtsc\" : \"=a\"(a),\"=d\"(b));\n            *((uint64_t*)0x548) = ((((uint64_t)b << 32UL)|(uint64_t)a) - c) / 5000;\n            if(*((uint64_t*)0x548) < 1) *((uint64_t*)0x548) = 1;\n        }\n        /* partition UUIDs */\n        ((multiboot_tag_partuuid_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_PARTUUID;\n        ((multiboot_tag_partuuid_t*)tags_ptr)->size = 24;\n        memcpy(((multiboot_tag_partuuid_t*)tags_ptr)->bootuuid, &bootuuid, sizeof(guid_t));\n        tags_ptr += (((multiboot_tag_partuuid_t*)tags_ptr)->size + 7) & ~7;\n        /* EFI tags */\n        if(ST) {\n            tag = (multiboot_tag_mmap_t*)tags_ptr;\n            tag->type = MULTIBOOT_TAG_TYPE_MMAP;\n            tag->entry_size = sizeof(multiboot_mmap_entry_t);\n            tag->entry_version = 0;\n            num_memmap = efi_memmap(tag->entries);\n            if(num_memmap > 0) {\n                memmap = tag->entries;\n                tag->size = sizeof(multiboot_tag_mmap_t) + num_memmap * sizeof(multiboot_mmap_entry_t);\n                tags_ptr += (tag->size + 7) & ~7;\n            }\n            ((multiboot_tag_efi64_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_EFI64;\n            ((multiboot_tag_efi64_t*)tags_ptr)->size = 16;\n            ((multiboot_tag_efi64_t*)tags_ptr)->pointer = (uintptr_t)ST;\n            tags_ptr += (((multiboot_tag_efi64_t*)tags_ptr)->size + 7) & ~7;\n            ((multiboot_tag_efi64_ih_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_EFI64_IH;\n            ((multiboot_tag_efi64_ih_t*)tags_ptr)->size = 16;\n            ((multiboot_tag_efi64_ih_t*)tags_ptr)->pointer = (uintptr_t)IM;\n            tags_ptr += (((multiboot_tag_efi64_ih_t*)tags_ptr)->size + 7) & ~7;\n        }\n        /* terminator tag */\n        ((multiboot_tag_t*)tags_ptr)->type = MULTIBOOT_TAG_TYPE_END;\n        ((multiboot_tag_t*)tags_ptr)->size = 8;\n        tags_ptr += (((multiboot_tag_t*)tags_ptr)->size + 7) & ~7;\n        ((multiboot_info_t*)tags_buf)->total_size = tags_ptr - tags_buf;\n    } else tags_buf = NULL;\n    if(kernel_mode == MODE_LIN && zero_page) {\n        if(memmap && num_memmap) {\n            for(i = 0; (uint32_t)i < num_memmap && i < E820_MAX_ENTRIES_ZEROPAGE; i++) {\n                zero_page->e820_table[i].addr = memmap[i].base_addr;\n                zero_page->e820_table[i].size = memmap[i].length;\n                zero_page->e820_table[i].type = memmap[i].type;\n            }\n            zero_page->e820_entries = i;\n        }\n        if(vidmode.framebuffer_addr) {\n            zero_page->lfb_width = vidmode.framebuffer_width;\n            zero_page->lfb_height = vidmode.framebuffer_height;\n            zero_page->lfb_depth = vidmode.framebuffer_bpp;\n            zero_page->lfb_base = vidmode.framebuffer_addr;\n            zero_page->lfb_size = (vidmode.framebuffer_pitch * vidmode.framebuffer_height * vidmode.framebuffer_bpp) >> 3;\n            zero_page->lfb_linelength = vidmode.framebuffer_pitch;\n            zero_page->red_size = vidmode.framebuffer_red_mask_size;\n            zero_page->red_pos = vidmode.framebuffer_red_field_position;\n            zero_page->green_size = vidmode.framebuffer_green_mask_size;\n            zero_page->green_pos = vidmode.framebuffer_green_field_position;\n            zero_page->blue_size = vidmode.framebuffer_blue_mask_size;\n            zero_page->blue_pos = vidmode.framebuffer_blue_field_position;\n            zero_page->orig_video_isVGA = ST ? VIDEO_TYPE_EFI : VIDEO_TYPE_VLFB;\n            zero_page->hdr.vid_mode = VIDEO_MODE_CUR;\n        }\n        zero_page->acpi_rsdp_addr = rsdp_ptr;\n        if(initrd) {\n            zero_page->hdr.ramdisk_image = initrd->mod_start;\n            zero_page->hdr.ramdisk_size = initrd->mod_end - initrd->mod_start;\n        }\n    }\n    if(ST) {\n        efi_freeall();\n        status = BS->GetMemoryMap(&memory_map_size, NULL, &map_key, &desc_size, NULL);\n        /* if we're booting Linux, then pass UEFI data to zero page. Otherwise just simply use \"map_key\" for exit boot services */\n        if(status == EFI_BUFFER_TOO_SMALL && kernel_mode == MODE_LIN && zero_page) {\n            memory_map_size += 4 * desc_size;\n            status = BS->AllocatePool(EfiLoaderData, memory_map_size, (void**)&memory_map);\n            if(!EFI_ERROR(status)) {\n                status = BS->GetMemoryMap(&memory_map_size, memory_map, &map_key, &desc_size, &desc_ver);\n                if(!EFI_ERROR(status)) {\n                    memcpy(&zero_page->efi_loader_signature, \"EL64\", 4);\n                    zero_page->efi_memmap = (uint32_t)(uintptr_t)memory_map;\n                    zero_page->efi_memmap_hi = (uint32_t)((uintptr_t)memory_map >> 32L);\n                    zero_page->efi_memmap_size = memory_map_size;\n                    zero_page->efi_memdesc_size = desc_size;\n                    zero_page->efi_memdesc_version = desc_ver;\n                    zero_page->efi_systab = (uint32_t)(uintptr_t)ST;\n                    zero_page->efi_systab_hi = (uint32_t)((uintptr_t)ST >> 32L);\n                }\n            }\n        }\n        BS->ExitBootServices(IM, map_key);\n    }\n    /* new GDT (this must be below 1M because we need it in real mode) */\n    *((uint16_t*)0x510) = 0x3F;                 /* value */\n    *((uint64_t*)0x512) = 0x560;\n    *((uint64_t*)0x568) = 0x000098000000FFFFUL; /*   8 - legacy real cs */\n    *((uint64_t*)0x570) = 0x00CF9A000000FFFFUL; /*  16 - prot mode cs */\n    *((uint64_t*)0x578) = 0x00CF92000000FFFFUL; /*  24 - prot mode ds */\n    *((uint64_t*)0x580) = 0x00AF9A000000FFFFUL; /*  32 - long mode cs */\n    *((uint64_t*)0x588) = 0x00CF92000000FFFFUL; /*  40 - long mode ds */\n    *((uint64_t*)0x590) = 0x0000890000000068UL; /*  48 - long mode tss descriptor */\n    *((uint64_t*)0x598) = 0x0000000000000000UL; /*       cont. */\n    /* now that we have left the firmware realm behind, we can get some real work done :-) */\n    __asm__ __volatile__ (\n    /* fw_loadseg might have altered the paging tables for higher-half kernels. Better to reload */\n    /* CR3 to kick the MMU, but on UEFI we can only do this after we have called ExitBootServices */\n    \"movq %%rax, %%cr3;\"\n    /* Set up dummy exception handlers */\n    \".byte 0xe8;.long 0;\"                       /* absolute address to set the code segment register */\n    \"1:popq %%rax;\"\n    \"movq %%rax, %%rsi;addq $4f - 1b, %%rsi;\"   /* pointer to the code stubs */\n    \"movq %%rax, %%rdi;addq $5f - 1b, %%rdi;\"   /* pointer to IDT */\n    \"movq $0x598, %%rax;\"                       /* patch GDT */\n    \"movq %%rax, %%rcx;andl $0xffffff, %%ecx;addl %%ecx, -6(%%rax);\"\n    \"movq %%rax, %%rcx;shrq $24, %%rcx;movq %%rcx, -1(%%rax);\"\n    \"lgdt (0x510);\"                             /* we must set up a new GDT with a TSS */\n    \"movq $48, %%rax;ltr %%ax;\"                 /* load TR */\n    \"movw $32, %%cx;\\n\"                         /* we set up 32 entires in IDT */\n    \"1:movq %%rsi, %%rax;movw $0x8F01, %%ax;shlq $16, %%rax;movw $32, %%ax;shlq $16, %%rax;movw %%si, %%ax;stosq;\"\n    \"movq %%rsi, %%rax;shrq $32, %%rax;stosq;\"\n    \"addq $16, %%rsi;decw %%cx;jnz 1b;\"         /* next entry */\n    \"movw $2f-5f-1,(0x520);movq $5f, (0x522);\"\n    \"lidt (0x520);jmp 2f;\"                      /* set up IDT */\n    /* TSS */\n    \".long 0;.long 0x1000;.long 0;.long 0x1000;.long 0;.long 0x1000;.long 0;\"\n    \".long 0;.long 0;.long 0x1000;.long 0;\"\n    /* ISRs */\n    \"1:popq %%r8;movq 16(%%rsp),%%r9;jmp fw_exc;\"\n    \".balign 16;4:xorq %%rdx, %%rdx; xorb %%cl, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $1, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $2, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $3, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $4, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $5, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $6, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $7, %%cl;jmp 1b;\"\n    \".balign 16;popq %%rdx; movb $8, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $9, %%cl;jmp 1b;\"\n    \".balign 16;popq %%rdx; movb $10, %%cl;jmp 1b;\"\n    \".balign 16;popq %%rdx; movb $11, %%cl;jmp 1b;\"\n    \".balign 16;popq %%rdx; movb $12, %%cl;jmp 1b;\"\n    \".balign 16;popq %%rdx; movb $13, %%cl;jmp 1b;\"\n    \".balign 16;popq %%rdx; movb $14, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $15, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $16, %%cl;jmp 1b;\"\n    \".balign 16;popq %%rdx; movb $17, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $18, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $19, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $20, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $21, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $22, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $23, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $24, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $25, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $26, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $27, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $28, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $29, %%cl;jmp 1b;\"\n    \".balign 16;popq %%rdx; movb $30, %%cl;jmp 1b;\"\n    \".balign 16;xorq %%rdx, %%rdx; movb $31, %%cl;jmp 1b;\"\n    /* IDT */\n    \".balign 16;5:.space (32*16);2:\"\n    ::\"a\"(pt):\"rcx\",\"rsi\",\"rdi\");\n    if(smp && n > 1 && lapic && st) {\n/* Memory layout (only valid when kernel entry isn't zero)\n *    0x510 -   0x520   GDT value\n *    0x520 -   0x530   IDT value\n *    0x530 -   0x538   page table root\n *    0x538 -   0x540   kernel entry point (also SMP semaphor)\n *    0x540 -   0x548   tags_buf\n *    0x548 -   0x550   CPU clockcycles in 1 msec\n *    0x550 -   0x558   lapic address\n *    0x558 -   0x559   AP is running flag\n *    0x560 -   0x590   GDT table\n */\n        if(verbose) printf(\"Initializing SMP (%d cores)...\\n\", n);\n        *((volatile uint64_t*)0x530) = (uint64_t)pt;\n        *((volatile uint64_t*)0x538) = (uint64_t)0;\n        *((volatile uint64_t*)0x540) = (uintptr_t)tags_buf;\n        *((volatile uint64_t*)0x550) = (uint64_t)lapic;\n        /* relocate AP startup code to 0x8000 (this will destroy getint(), gethex(), but that's\n         * okay, we have already finished parsing the configuration file, we don't need 'em) */\n        __asm__ __volatile__(\n        /* relocate code */\n        \".byte 0xe8;.long 0;\"\n        \"1:popq %%rsi;addq $1f - 1b, %%rsi;movq $0x8000, %%rdi;movq $99f - 1f, %%rcx;repnz movsb;jmp 99f;\"\n        /* do the real mode -> prot mode -> long mode trampoline */\n        \"1:.code16;cli;cld;xorw %%ax, %%ax;movw %%ax, %%ds;incb (0x558);\"\n        /* spinlock waiting for the kernel entry address */\n        \"2:pause;cmpl $0, (0x538);jnz 3f;cmpl $0, (0x53C);jz 2b;3:;\"\n        /* initialize AP */\n        \"lgdt (0x510);movl %%cr0, %%eax;orb $1, %%al;movl %%eax, %%cr0;\"\n        \".code32;ljmp $16,$2f-1b+0x108000;2:;\"\n        \"movw $24, %%ax;movw %%ax, %%ds;\"\n        \"movl (0x530), %%eax;movl %%eax, %%cr3;\"\n        \"movl $0xE0, %%eax;movl %%eax, %%cr4;\"\n        \"movl $0x0C0000080, %%ecx;rdmsr;btsl $8, %%eax;wrmsr;\"\n        \"movl %%cr0, %%eax;xorb %%cl, %%cl;orl %%ecx, %%eax;btcl $16, %%eax;btsl $31, %%eax;movl %%eax, %%cr0;\"\n        \"lgdt (0x510);ljmp $32,$1f-1b+0x8000;\"\n        \".code64;1:;lgdt (0x510);movw $40, %%ax;movw %%ax, %%ds;movw %%ax, %%es;movw %%ax, %%ss;\"\n        \"lidt (0x520);movq (0x550), %%rbx;\"\n        /* enable lapic */\n        \"movl $0x1000000, 0xD0(%%rbx);movl $0xFFFFFFFF, 0xE0(%%rbx);\"\n        \"movl 0xF0(%%rbx), %%eax;orl $0x100, %%eax;movl %%eax,0xF0(%%rbx);\"\n        \"movl $0, 0x80(%%rbx);movl $0, 0x280(%%rbx);movl 0x280(%%rbx), %%eax;movl 0x20(%%rbx), %%eax;\"\n        \"shrl $24, %%eax;andq $0xff, %%rax;movq %%rax, %%rbx;shll $10, %%eax;\"\n        /* execute 64-bit kernel */\n        \"movq $0x90000, %%rsp;subq %%rax, %%rsp;movq %%rsp, %%rbp;pushq %%rbx;\"             /* stack = 0x90000 - coreid * 1024 */\n        \"movq (0x530), %%rax;movq %%rax, %%cr3;\"                                            /* kick the MMU to flush cache */\n        \"xorq %%rax, %%rax;movl $0x36d76289, %%eax;movq %%rax, %%rcx;movq %%rax, %%rdi;\"    /* set arguments */\n        \"movq (0x540), %%rbx;movq %%rbx, %%rdx;movq %%rbx, %%rsi;\"\n        /* execute 64-bit kernel (stack: 8 byte aligned, and contains the core's id) */\n        /* note: the entry point's function prologue will push rbp, and after that the stack becomes 16 byte aligned as expected */\n        \"movq (0x538), %%r8;jmp *%%r8;\"                                                     /* jump to kernel entry */\n        \"99:\":::);\n\n        /* enable Local APIC */\n        *((volatile uint32_t*)(lapic + 0x0D0)) = (1 << 24);\n        *((volatile uint32_t*)(lapic + 0x0E0)) = 0xFFFFFFFF;\n        *((volatile uint32_t*)(lapic + 0x0F0)) = *((volatile uint32_t*)(lapic + 0x0F0)) | 0x1FF;\n        *((volatile uint32_t*)(lapic + 0x080)) = 0;\n        st->bspid = *((volatile uint32_t*)(lapic + 0x20)) >> 24; *((uint64_t*)0x8fff8) =  st->bspid;\n        /* initialize APs */\n        for(i = 0; i < n; i++) {\n            if(ids[i] == st->bspid) continue;\n            *((volatile uint32_t*)(lapic + 0x280)) = 0;                 /* clear APIC errors */\n            a = *((volatile uint32_t*)(lapic + 0x280));\n            send_ipi(ids[i], 0xfff00000, 0x00C500);                     /* trigger INIT IPI */\n            sleep(1);\n            send_ipi(ids[i], 0xfff00000, 0x008500);                     /* deassert INIT IPI */\n        }\n        sleep(10);                                                      /* wait 10 msec */\n        /* start APs */\n        for(i = 0; i < n; i++) {\n            if(ids[i] == st->bspid) continue;\n            *((volatile uint8_t*)0x558) = 0;\n            send_ipi(ids[i], 0xfff0f800, 0x004608);                     /* trigger SIPI, start at 0800:0000h */\n            for(a = 250; !*((volatile uint8_t*)0x558) && a > 0; a--)    /* wait for AP with 250 msec timeout */\n                sleep(1);\n            if(!*((volatile uint8_t*)0x558)) {\n                send_ipi(ids[i], 0xfff0f800, 0x004608);\n                sleep(250);\n            }\n            if(*((volatile uint8_t*)0x558)) st->running++;\n        }\n    } else smp = 0;\n    *((uint64_t*)0x558) = 0;\n}\n\n/**\n * Dummy exception handler\n */\nvoid fw_exc(uint8_t excno, uint64_t exccode, uint64_t rip, uint64_t rsp)\n{\n    uint64_t cr2, cr3;\n#if defined(CONSOLE_FB) || defined(CONSOLE_VGA)\n    uint32_t i;\n#endif\n#ifdef CONSOLE_FB\n    uint32_t j, x, y, b;\n#endif\n    if(!in_exc) {\n        in_exc++;\n        __asm__ __volatile__(\"movq %%cr2, %%rax;movq %%cr3, %%rbx;\":\"=a\"(cr2),\"=b\"(cr3)::);\n#ifdef CONSOLE_FB\n        if(vidmode.framebuffer_addr) {\n            b = (vidmode.framebuffer_bpp + 7) >> 3;\n            fb_x = fb_y = 4; fb_bg = FB_COLOR(255, 0, 0);\n            for(j = y = 0; y < 8 + (((psf2_t*)font_psf)->height << 1); y++, j += vidmode.framebuffer_pitch)\n                for(i = j, x = 0; x < vidmode.framebuffer_width; x++, i += b)\n                    if(b == 2) *((uint16_t*)(vidmode.framebuffer_addr + i)) = (uint16_t)fb_bg;\n                    else *((uint32_t*)(vidmode.framebuffer_addr + i)) = fb_bg;\n        }\n#endif\n#ifdef CONSOLE_VGA\n        vga_x = vga_y = 0;\n        if(!vidmode.framebuffer_addr && !ST) {\n            for(i = 0; i < 320; i += 2) *((uint16_t*)((uintptr_t)0xB8000 + i)) = 0x4f20;\n            for(; i < 2000; i += 2) *((uint16_t*)((uintptr_t)0xB8000 + i)) = 0x0f20;\n        }\n#endif\n        printf(\"Simpleboot Exception Handler\\r\\nException %02x #%s code %016x\\r\\n\\r\\n\",\n            excno, excno < 32 ? excstr[(int)excno] : \"INTR\", exccode);\n#ifdef CONSOLE_FB\n        fb_bg = 0;\n#endif\n        printf(\"RIP %016x RSP %016x CR2 %016x CR3 %016x\\r\\n\\r\\nCode\\r\\n%D\\r\\nStack\\r\\n%4D\\r\\n\",\n            rip, rsp, cr2, cr3, rip, rsp);\n    }\n    __asm__ __volatile__(\"1: cli; hlt; jmp 1b\");\n}\n\n/*****************************************\n *     Simpleboot loader entry point     *\n *****************************************/\nefi_status_t _start (efi_handle_t image, efi_system_table_t *systab, uint16_t bdev)\n{\n    uint8_t al;\n\n    /* initialize UEFI or BIOS */\n    fw_init(image, systab, bdev);\n    printf(\"Simpleboot loader, Copyright (c) 2023 bzt, MIT license\\r\\n\");\n    /* now that we can display error messages, let's see if we got everything we need */\n    if(!pt) { printf(\"ERROR: unable to allocate memory\\r\\n\"); goto err; }\n    if(!root_dir) { printf(\"ERROR: unable to locate boot partition\\r\\n\"); goto err; }\n\n    /* load and parse simpleboot.cfg */\nagain:\n    fw_loadconfig();\n    fw_loadsetup();\n    if(!ram) { printf(\"ERROR: unable to determine the amount of RAM\\r\\n\"); goto err; }\n    else if(verbose && !bkp) printf(\"Physical RAM %ld Megabytes\\r\\n\", ram / 1024 / 1024 + 2);\n\n    /* now we have the kernel's filename, try to load that, it's a critical error if fails */\n    if(!fw_loadkernel()) goto err;\n    /* last step, load modules too */\n    fw_loadmodules();\n    /* if the user pressed a key during loading, fallback to backup and do over */\n    if(!bkp && rq) { bkp++; rq = 0; goto again; }\n\n    /* finish up things, finalize tags list */\n    fw_fini();\n\n    /* transfer control to kernel. Should never return */\n    if(kernel_mode != MODE_VBR) {\n        if(!kernel_entry) { printf(\"ERROR: no kernel entry point\\r\\n\"); goto err; }\n        if(verbose > 2) printf(\"Kernel entry:\\r\\n%4D\", kernel_entry);\n    }\n    switch(kernel_mode) {\n        case MODE_VBR:\n            if(verbose > 1)\n                printf(\"Transfering real mode control to 0:7C00 (LBA %d size %d sector(s))\\r\\n\", vbr_lba, vbr_size);\n            *((uint16_t*)0x502) = vbr_size > 127 ? 127 : vbr_size; *((uint32_t*)0x504) = 0x7C00; *((uint64_t*)0x508) = vbr_lba;\n            bios_fallback();\n        break;\n        case MODE_PE32:\n        case MODE_MB32:\n            if(verbose > 1)\n                printf(\"Transfering prot mode control to %08x(%08x, %08x[%x])\\r\\n\", kernel_entry,\n                    MULTIBOOT2_BOOTLOADER_MAGIC, tags_buf, tags_ptr - tags_buf);\n            /* execute 32-bit kernels in protected mode */\n            *((uint32_t*)0x8fffc) = (uint32_t)(uintptr_t)tags_buf;\n            *((uint32_t*)0x8fff8) = MULTIBOOT2_BOOTLOADER_MAGIC;\n            *((uint32_t*)0x8fff4) = 0xDEADBEEF;\n            __asm__ __volatile__(\n            \"movq $0x10, %%rax;push %%rax;\"     /* unfortunately Clang doesn't allow \"callq 1f(%%rip)\", */\n            \"movq $0x600, %%rdi;push %%rdi;\"    /* but we need to relocate trampoline to 0x600 (we need */\n            \".byte 0xe8;.long 0;\"               /* absolute address to set the code segment register) */\n            \"1:popq %%rsi;\"\n            \"addq $1f - 1b, %%rsi;\"\n            \"movq $2f - 1f, %%rcx;\"\n            \"repnz movsb;\"\n            \"lretq;.code32;1:;\"                 /* long -> compat, setting code segment to 32-bit */\n            \"movl %%cr0, %%eax;\"                /* disable paging */\n            \"btcl $31, %%eax;\"\n            \"movl %%eax, %%cr0;\"\n            \"movw $0x18, %%ax;movw %%ax, %%ds;\" /* set 32-bit segment selectors */\n            \"movw %%ax, %%es;movw %%ax, %%ss;\"\n            \"movw %%ax, %%fs;movw %%ax, %%gs;\"\n            \"movl %%ebx, %%esi;\"\n            \"movl $0x0C0000080, %%ecx;\"         /* disable long in EFER MSR */\n            \"rdmsr;btcl $8, %%eax;wrmsr;\"       /* on 32-bit, this messes with %edx */\n            \"xorl %%eax, %%eax;lidt (%%eax);\"   /* disable IDT */\n            /* CDECL uses the stack for arguments, but fastcall uses %ecx, %edx */\n            \"movl $0x8fff4, %%esp; movl %%esp, %%ebp;\"\n            \"movl 8(%%esp), %%edx;movl %%edx, %%ebx;movl 4(%%esp), %%eax; movl %%eax, %%ecx;\"\n            \"jmp *%%esi;2:;\"\n            ::\"b\"(kernel_entry):);\n        break;\n        case MODE_MB64:\n            if(verbose > 1)\n                printf(\"Transfering long mode control to %08x(%08x, %08x[%x])\\r\\n\", kernel_entry,\n                    MULTIBOOT2_BOOTLOADER_MAGIC, tags_buf, tags_ptr - tags_buf);\n            /* tell APs to execute kernel */\n            if(smp) { *((volatile uint64_t*)0x538) = (uintptr_t)kernel_entry; __asm__ __volatile__(\"pause\":::\"memory\"); }\n            /* execute 64-bit kernels in long mode */\n             __asm__ __volatile__(\n            \"movq %%rcx, %%r8;\"\n            /* SysV ABI uses %rdi, %rsi, but fastcall uses %rcx, %rdx */\n            \"movq %%rax, %%rcx;movq %%rax, %%rdi;\"\n            \"movq %%rbx, %%rdx;movq %%rbx, %%rsi;\"\n            \"movq $0x90000, %%rsp; movq %%rsp, %%rbp; subl $8, %%esp;\"\n            \"jmp *%%r8\"\n            ::\"a\"(MULTIBOOT2_BOOTLOADER_MAGIC),\"b\"(tags_buf),\"c\"(kernel_entry):);\n        break;\n        case MODE_LIN:\n            if(verbose > 1)\n                printf(\"Transfering long mode control to %08x(%08x)\\r\\n\", kernel_entry, zero_page);\n            /* execute Linux kernel in 64 bit mode */\n            __asm__ __volatile__(\n            \"jmp *%%rax\"\n            ::\"S\"(zero_page),\"a\"(kernel_entry):);\n        break;\n    }\n    printf(\"ERROR: kernel should not have returned\\r\\n\");\n\n    /* there's nowhere to return to on BIOS, halt machine */\nerr:if(!systab) {\n        if(bkp) __asm__ __volatile__(\"1: cli; hlt; jmp 1b\");\n        else while(1) {\n            __asm__ __volatile__(\"inb $0x64, %%al;pause;pause;pause;\":\"=a\"(al)::);\n            if(al != 0xFF && al & 1) { bkp++; rq = 0; goto again; }\n        }\n    }\n    /* on UEFI we should return an error status, and the firmware should get the next option from the boot order list */\n    return EFI_LOAD_ERROR;\n}\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/misc/bin2h.c",
    "content": "/*\n * src/misc/bin2h.c\n * https://gitlab.com/bztsrc/simpleboot\n *\n * Copyright (C) 2023 bzt (bztsrc@gitlab), MIT license\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * @brief Simple helper utility for embedding binary data into C source (\"ld -b\" isn't portable)\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"../loader.h\"  /* elf headers */\n\nint main(int argc, char **argv)\n{\n    FILE *f, *h, *b;\n    int size, i, j, k;\n    unsigned char *buff = NULL;\n    char name[256];\n\n    if(argc < 2){ printf(\"bin2h <bin file> [bin file2...]\\r\\n\"); return 1; }\n    h = fopen(\"data.h\", \"w\"); if(!h) { fprintf(stderr, \"bin2h: unable to open data.h\\r\\n\"); return 1; }\n    fprintf(h, \"/*\\n\"\n        \" * src/data.h\\n\"\n        \" * https://codeberg.org/bzt/simpleboot\\n\"\n        \" *\\n\"\n        \" * Copyright (C) 2023 bzt, MIT license\\n\"\n        \" *\\n\"\n        \" * Permission is hereby granted, free of charge, to any person obtaining a copy\\n\"\n        \" * of this software and associated documentation files (the \\\"Software\\\"), to\\n\"\n        \" * deal in the Software without restriction, including without limitation the\\n\"\n        \" * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\\n\"\n        \" * sell copies of the Software, and to permit persons to whom the Software is\\n\"\n        \" * furnished to do so, subject to the following conditions:\\n\"\n        \" *\\n\"\n        \" * The above copyright notice and this permission notice shall be included in\\n\"\n        \" * all copies or substantial portions of the Software.\\n\"\n        \" *\\n\"\n        \" * THE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\\n\"\n        \" * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\\n\"\n        \" * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\\n\"\n        \" * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\\n\"\n        \" * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\\n\"\n        \" * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\\n\"\n        \" *\\n\"\n        \" * @brief Embedded loader binary data, used by the image creator\\n\"\n        \" */\\n\\n/* generated by bin2h, do not edit */\\n\\n\");\n    for(i = 1; i < argc; i++){\n        f = fopen(argv[i],\"rb\");\n        if(f) {\n            fseek(f, 0, SEEK_END);\n            size = (int)ftell(f);\n            fseek(f, 0, SEEK_SET);\n            buff = (unsigned char*)malloc(size + 512);\n            if(!buff) { fprintf(stderr, \"bin2h: memory allocation error\\r\\n\"); return 2; }\n            fread(buff, 1, size, f);\n            fclose(f);\n            for(j = 0; argv[i][j]; j++) { name[j] = argv[i][j] == '.' || argv[i][j] <= ' ' ? '_' : argv[i][j]; } name[j] = 0;\n            /* ehhh LLVM lld accepts -stub flag, but then does nothing with it, lld/COFF/Writer.cpp always writes dosProgram */\n            if(!strcmp(name, \"loader_x86_efi\")) {\n                memset(buff + size, 0, 512);\n                size = (size + 511) & ~511;\n                memset(buff + 0x40, 0, 0x38); memcpy(buff + 0x40, \"Simpleboot https://codeberg.org/bzt/simpleboot\\0x86_64\", 53);\n                b = fopen(\"loader_x86.efi\", \"wb\"); if(b) { fwrite(buff, 1, size, b); fclose(b); }\n            }\n            /* objcopy can't interpret program headers from another platform's elf... */\n            if(!strcmp(name, \"loader_rpi_o\")) {\n                k = (int)((Elf64_Phdr*)(buff + ((Elf64_Ehdr*)buff)->e_phoff))->p_offset;\n                size = (int)((Elf64_Phdr*)(buff + ((Elf64_Ehdr*)buff)->e_phoff))->p_filesz;\n                /* patch _bss_start and _bss_end values, must be right after the default names */\n                for(j = 0; j < size - 128; j += 16)\n                    if(!memcmp(buff + j + k, \"kernel\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 16)) {\n                        *((uint32_t*)(buff + j + k + 128)) =\n                            (uint32_t)((Elf64_Phdr*)(buff + ((Elf64_Ehdr*)buff)->e_phoff))->p_vaddr +\n                            (uint32_t)((Elf64_Phdr*)(buff + ((Elf64_Ehdr*)buff)->e_phoff))->p_filesz;\n                        *((uint32_t*)(buff + j + k + 128 + 4)) =\n                            ((uint32_t)((Elf64_Phdr*)(buff + ((Elf64_Ehdr*)buff)->e_phoff))->p_vaddr +\n                            (uint32_t)((Elf64_Phdr*)(buff + ((Elf64_Ehdr*)buff)->e_phoff))->p_memsz + 4095) & ~4095;\n                        break;\n                    }\n                /* make sure we write out multiple of 512 bytes */\n                memset(buff + k + size, 0, 512);\n                size = (size + 511) & ~511;\n                /* it would be enough just to include in data.h, but also write out as bin file for debugging */\n                strcpy(name, \"loader_rpi_bin\");\n                b = fopen(\"loader_rpi.bin\", \"wb\");\n                if(!b) { fclose(h); free(buff); fprintf(stderr, \"bin2h: unable to open loader_rpi.bin\\r\\n\"); return 1; }\n                fwrite(buff + k, 1, size, b);\n                fclose(b);\n            } else k = 0;\n            fprintf(h, \"unsigned char %s[%u] = { \", name, size);\n            for(j = 0; j < size; j++) fprintf(h, \"%s%d\", j?\",\":\"\", buff[j + k]);\n            fprintf(h, \" };\\n\");\n            free(buff);\n        }\n    }\n    fclose(h);\n    return 0;\n}\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/misc/deb_control",
    "content": "Package: simpleboot\nVersion: VERSION\nArchitecture: ARCH\nEssential: no\nSection: tools\nPriority: optional\nMaintainer: bzt\nHomepage: https://codeberg.org/bzt/simpleboot\nInstalled-Size: SIZE\nDescription: Dependency-free, all-in-one boot loader and bootable disk image creator.\n  It creates a bootable disk image that can boot Linux kernels or any other\n  Multiboot2 compliant kernels in various formats.\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/rombios_x86.asm",
    "content": ";\n;  src/rombios_x86.asm\n;  https://codeberg.org/bzt/simpleboot\n;\n;  Copyright (C) 2023 bzt, MIT license\n;\n;  Permission is hereby granted, free of charge, to any person obtaining a copy\n;  of this software and associated documentation files (the \"Software\"), to\n;  deal in the Software without restriction, including without limitation the\n;  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n;  sell copies of the Software, and to permit persons to whom the Software is\n;  furnished to do so, subject to the following conditions:\n;\n;  The above copyright notice and this permission notice shall be included in\n;  all copies or substantial portions of the Software.\n;\n;  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n;  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n;  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n;  DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n;  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n;  IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n;\n;  @brief Legacy mode BIOS Option ROM for Simpleboot, written with\n;      flatassembler: https://flatassembler.net It's job is to extract loader_x86.efi's\n;      sections from the ROM buffer, set up long mode and pass control to it\n;\n;  Memory layout on handover:\n;        0h -   400h    IVT (must be preserved)\n;      400h -   4FFh    BDA (must be preserved)\n;      4FFh -   500h    BIOS boot drive code\n;      500h -   510h    BIOS LBA packet\n;      510h -   550h    GDT\n;      550h -  1000h    stack (2k+)\n;     1000h -  8000h    paging tables\n;     8000h - 60000h    loader_x86.efi's sections\n;    9A000h - A0000h    EBDA (must be preserved)\n\nsimpleboot_addr equ     08000h\n\n            ORG         07C00h\n            USE16\n\n;*********************************************************************\n;*                             code                                  *\n;*********************************************************************\nrom_header: db          55h, 0AAh\n.size:      db          0\n            jmp         short @f\n            nop\n.checksum:  db          0\n            ;---- set up environment ----\n@@:         cli\n            cld\n            mov         al, 0FFh                ; disable PIC\n            out         021h, al\n            out         0A1h, al\n            in          al, 70h                 ; disable NMI\n            or          al, 80h\n            out         70h, al\n            xor         ax, ax\n            mov         es, ax\n            mov         ss, ax\n            mov         sp, 07C00h\n            ; find our position in memory.\n            push        cs\n            pop         ds\n            xor         esi, esi\n            call        @f\n@@:         pop         si\n            sub         si, @b-rom_header\n            xor         eax, eax\n            xor         ebp, ebp                ; ebp = ROM payload\n            mov         bp, si\n            add         bp, rom_end-rom_header\n            mov         ax, cs\n            shl         eax, 4\n            add         ebp, eax\n            mov         di, sp\n            ;---- relocate ourselves to 0:7C00 ----\n            mov         cx, 100h\n            repnz       movsw\n            jmp         0:@f\n@@:         xor         ax, ax\n            mov         ds, ax\n            mov         byte [4FFh], 80h        ; BIOS drive code\n            ;---- enable protmode ----\n            mov         ax, 2401h               ; enable A20\n            int         15h\n            mov         si, GDT_value\n            mov         di, 510h\n            mov         cx, word[si]\n            repnz       movsb\n            lgdt        [510h]\n            mov         eax, cr0\n            or          al, 1\n            mov         cr0, eax\n            jmp         16:@f\n            USE32\n@@:         mov         ax, 24\n            mov         ds, ax\n            mov         es, ax\n            ; look for long mode supported flag\n            xor         edx, edx\n            mov         eax, 80000001h\n            cpuid\n            bt          edx, 29\n            jnc         .die\n            ;---- enable longmode ----\n            xor         eax, eax\n            mov         ah, 010h\n            mov         cr3, eax\n            ; we only map 2M here, loader will finish up the rest overwriting us in the process\n            mov         edx, eax                ; PML4\n            mov         ebx, eax\n            xor         eax, eax\n            mov         dword [ebx], 02003h     ; pointer to 2M PDPE\n            mov         dword [ebx + 4], eax\n            add         ebx, edx                ; 2M PDPE\n            mov         dword [ebx], 03003h\n            mov         dword [ebx + 4], eax\n            add         ebx, edx                ; 2M PDE\n            mov         dword [ebx], 00083h\n            mov         dword [ebx + 4], eax\n            mov         al, 0E0h                ; set PAE, MCE, PGE; clear everything else\n            mov         cr4, eax\n            mov         ecx, 0C0000080h         ; EFER MSR\n            rdmsr\n            bts         eax, 8                  ; enable long mode page tables\n            wrmsr\n            mov         eax, cr0\n            xor         cl, cl\n            or          eax, ecx\n            btc         eax, 16                 ; clear WP\n            mov         cr0, eax                ; enable paging with cache disabled (set PE, CD)\n            lgdt        [510h]                  ; read 80 bit address (16+64)\n            jmp         32:@f\n            USE64\n@@:         xor         rax, rax                ; load long mode segments\n            mov         ax, 40\n            mov         ds, ax\n            mov         es, ax\n            mov         ss, ax\n            mov         ax, simpleboot_addr\n            ;---- parse loader_x86.efi (PE / COFF format) ----\n            mov         ebx, ebp                ; load buffer address\n            cmp         word [ebx], 5A4Dh       ; check MZ\n            jne         .die\n            mov         r8d, ebx\n            xor         r9, r9\n            add         ebx, dword [ebx + 0x3c] ; get COFF header\n            cmp         word [ebx], 4550h       ; check PE\n            jne         .die\n            mov         dl, byte [ebx + 6]      ; number of sections\n            mov         r9d, dword [ebx + 0x28] ; entry point\n            mov         ebp, dword [ebx + 0x2c] ; code base\n            add         r9d, eax\n            sub         r9d, ebp\n            add         bx, word [ebx + 0x14]   ; add header size\n            add         bx, 24                  ; ebx now points to section table\n@@:         mov         edi, dword [ebx + 12]   ; copy sections from PE into VA\n            add         edi, eax\n            sub         edi, ebp                ; dest: virtual address + reloc offset - code base\n            mov         ecx, dword [ebx + 16]   ; size of raw data\n            mov         esi, dword [ebx + 20]\n            add         esi, r8d                ; source: pointer to raw data + load offset\n            repnz       movsb\n            add         ebx, 40                 ; go to next section\n            dec         dl\n            jnz         @b\n            xor         rsp, rsp\n            mov         sp, 1000h               ; set stack\n            xor         rcx, rcx                ; image handle\n            xor         rdx, rdx                ; system table pointer\n            jmp         r9                      ; jump to relocated entry point\n            ;---- die function ----\n            ; written in a way that it's decodeable as prot mode as well as long mode instructions\n.die:       mov         esi, .err\n            mov         edi, 0B8000h\n            mov         ah, 04fh\n@@:         lodsb\n            or          al, al\n            jz          @f\n            stosw\n            jmp         @b\n@@:         hlt\n            align       8\n\n;*********************************************************************\n;*                          data area                                *\n;*********************************************************************\n.err:       db          \"ROM-ERR\", 0\nGDT_value:  dw          rom_end-GDT_value       ; value / null descriptor\n            dd          510h\n            dw          0\n            dd          0000FFFFh,00009800h     ;  8 - legacy real cs\n            dd          0000FFFFh,00CF9A00h     ; 16 - prot mode cs\n            dd          0000FFFFh,008F9200h     ; 24 - prot mode ds\n            dd          0000FFFFh,00AF9A00h     ; 32 - long mode cs\n            dd          0000FFFFh,00CF9200h     ; 40 - long mode ds\nrom_end:\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/romfoss_x86.asm",
    "content": ";\n;  src/romfoss_x86.asm\n;  https://codeberg.org/bzt/simpleboot\n;\n;  Copyright (C) 2023 bzt, MIT license\n;\n;  Permission is hereby granted, free of charge, to any person obtaining a copy\n;  of this software and associated documentation files (the \"Software\"), to\n;  deal in the Software without restriction, including without limitation the\n;  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n;  sell copies of the Software, and to permit persons to whom the Software is\n;  furnished to do so, subject to the following conditions:\n;\n;  The above copyright notice and this permission notice shall be included in\n;  all copies or substantial portions of the Software.\n;\n;  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n;  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n;  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n;  DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n;  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n;  IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n;\n;  @brief FOSSBIOS boot ROM for Simpleboot, written with flatassembler:\n;      https://flatassembler.net It's job is to extract loader_x86.efi's\n;      sections from the ROM buffer and pass control to it\n;\n;  Memory layout on handover:\n;        0h -  1000h    stack (2k+)\n;     8000h - 60000h    loader_x86.efi's sections\n;\n; FOSSBIOS is a 64-bit long mode BIOS which uses SysV ABI so passes\n; a pointer to the FOSSBIOS Main Structure to functions in rdi\n\nsimpleboot_addr equ     08000h\n\n            ORG         0h\n            USE64\n\n; FOSSBIOS Main Structure\nvirtual at 0\nfossbios.magic:   dd    ?\nfossbios.arch:    dw    ?\nfossbios.wordsize:db    ?\nfossbios.endian:  db    ?\nfossbios.oem:     dq    ?\nfossbios.conf:    dq    ?\nfossbios.system:  dq    ?\nfossbios.proc:    dq    ?\nfossbios.video:   dq    ?\nfossbios.storage: dq    ?\nfossbios.serial:  dq    ?\nfossbios.input:   dq    ?\nfossbios.clock:   dq    ?\nfossbios.audio:   dq    ?\nfossbios.net:     dq    ?\nfossbios.power:   dq    ?\nend virtual\n\n; FOSSBIOS System Services\nvirtual at 0\nsystem.magic:     dd    ?\nsystem.nument:    dd    ?\nsystem.memmap:    dq    ?\nsystem.boot:      dq    ?\nend virtual\n\n;*********************************************************************\n;*                             code                                  *\n;*********************************************************************\ninit:       ;---- initialization ----\n            ; find our function\n            call        @f\n@@:         pop         rax\n            add         rax, boot-@b\n            ; set \"system->boot()\" hook\n            mov         rdi, qword [rdi + fossbios.system]\n            mov         qword [rdi + system.boot], rax\n            xor         rax, rax\n            xor         rdx, rdx\n            ret\n\nboot:       ;---- boot procedure ----\n            mov         r10, rdi\n            xor         rsp, rsp\n            mov         sp, 1000h               ; set stack\n            ; find our data\n            call        @f\n@@:         pop         rbx\n            add         rbx, payload-@b\n            xor         rax, rax\n            mov         ax, simpleboot_addr\n            ;---- parse loader_x86.efi (PE / COFF format) ----\n            mov         r8, rbx\n            xor         r9, r9\n            xor         rdi, rdi\n            add         rbx, qword [rbx + 0x3c] ; get COFF header\n            mov         dl, byte [rbx + 6]      ; number of sections\n            mov         r9d, dword [rbx + 0x28] ; entry point\n            mov         ebp, dword [rbx + 0x2c] ; code base\n            add         r9d, eax\n            sub         r9d, ebp\n            add         bx, word [rbx + 0x14]   ; add header size\n            add         bx, 24                  ; ebx now points to section table\n@@:         mov         edi, dword [rbx + 12]   ; copy sections from PE into VA\n            add         edi, eax\n            sub         edi, ebp                ; dest: virtual address + reloc offset - code base\n            mov         ecx, dword [rbx + 16]   ; size of raw data\n            mov         esi, dword [rbx + 20]\n            add         rsi, r8                 ; source: pointer to raw data + load offset\n            repnz       movsb\n            add         rbx, 40                 ; go to next section\n            dec         dl\n            jnz         @b\n            ;---- set FOSSBIOS Boot Loader arguments ----\n            ; rdi: magic\n            ; rsi: pointer to FOSSBIOS Main Structure\n            ; rdx: boot device index\n            xor         rdx, rdx\n            mov         rsi, r10\n            xor         rdi, rdi\n            mov         edi, 0F055B105h\n            jmp         r9                      ; jump to relocated entry point\npayload:\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/simpleboot/src/simpleboot.c",
    "content": "/*\n * src/simpleboot.c\n * https://gitlab.com/bztsrc/simpleboot\n *\n * Copyright (C) 2023 bzt, MIT license\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * @brief The bootable disk image generator utility\n *\n * Since this tool is run by users in a hosted environment, and not during boot\n * like the rest, so for portability it has both POSIX and WIN32 bindings. Mostly\n * tested on Linux though, the mingw version might have bugs.\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <time.h>\n#include <dirent.h>\n#include <sys/stat.h>\n#include \"loader.h\"\n#include \"data.h\"\n#ifdef __WIN32__\n#include <windows.h>\n#endif\n#ifndef PATH_MAX\n#define PATH_MAX 4096\n#endif\n\n#define FIRST_PARTITION 2048        /* in sectors, 1M alignment */\n#define GPT_SECTORS       62        /* must be smaller than than FIRST_PARTITION - 2 and 16 * 2048 (ISO9660 start) */\n\nconst char sbver[] = \"1.0.0\";       /* tool's version (loaders have different versions) */\n\nguid_t dguid, pguid, ptguid[100], puguid[100];\nint64_t disksize = 35, partsize = 33, psize[100] = { 0 }, imgsize, totsize = 0, fat_numclu, fat_freeclu, read_size;\nuint8_t *img = NULL, img_tail[(GPT_SECTORS+1)<<9], *fs_base, *cluster = NULL, *pdata = NULL;\nuint32_t *fat_fat32 = NULL, fat_nextcluster, ts_x86, ts_rpi;\nuint64_t boot_lba = 0, data_lba = 0;\nesp_bpb_t *bpb;\nvoid *f;\nchar *in = NULL, *out = NULL;\nchar *kernel = NULL, kernelfree = 0, bkpkrnl = 0, bkpfb = 0, bkplogo = 0, full[PATH_MAX], *pfile[100] = { 0 };\nint verbose = 0, skipbytes = 0, fat_bpc, fat_spf, num_mod = 0, num_bkp = 0, smp = 0, bkpsmp = 0, nump = 0;\nint fb_w = 800, fb_h = 600, fb_bpp = 32;\nstruct tm *fat_ts;\nstruct stat dev_st;\n#ifdef __WIN32__\nWCHAR szFile[PATH_MAX];\n#else\nchar *realpath(const char*, char*);\nint fdatasync(int);\n#endif\nint dev_read(void *f, uint64_t off, void *buf, uint32_t size);\nint dev_write(void *f, uint64_t off, void *buf, uint32_t size);\n\n/**\n * Read a file entirely into memory\n */\nunsigned char* readfileall(char *file, int chkonly)\n{\n#ifdef __WIN32__\n    HANDLE f;\n    DWORD r, t;\n    int i;\n#else\n    FILE *f;\n#endif\n    unsigned char *data = NULL;\n\n    read_size = 0;\n    if(!file || !*file) return NULL;\n    data = (unsigned char*)strrchr(file, '/');\n    if(data && !*(data + 1)) return NULL;\n    data = NULL;\n#ifdef __WIN32__\n    memset(&szFile, 0, sizeof(szFile));\n    MultiByteToWideChar(CP_UTF8, 0, file, -1, szFile, PATH_MAX);\n    for(i = 0; szFile[i]; i++) if(szFile[i] == L'/') szFile[i] = L'\\\\';\n    f = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);\n    if(f != INVALID_HANDLE_VALUE) {\n        r = GetFileSize(f, NULL);\n        read_size = (int64_t)r;\n        if(!chkonly) {\n            data = (unsigned char*)malloc(read_size + 1);\n            if(!data) { fprintf(stderr, \"%ssimpleboot: unable to allocate memory\\r\\n\", verbose ? \"\\n\" : \"\"); exit(1); }\n            memset(data, 0, read_size + 1);\n            if(!ReadFile(f, data, r, &t, NULL)) t = 0;\n            read_size = (int64_t)t;\n        }\n        CloseHandle(f);\n    }\n#else\n    f = fopen(file, \"rb\");\n    if(f) {\n        fseek(f, 0L, SEEK_END);\n        read_size = (int64_t)ftell(f);\n        fseek(f, 0L, SEEK_SET);\n        if(!chkonly) {\n            data = (unsigned char*)malloc(read_size + 1);\n            if(!data) { fprintf(stderr, \"%ssimpleboot: unable to allocate memory\\r\\n\", verbose ? \"\\n\" : \"\"); exit(1); }\n            memset(data, 0, read_size + 1);\n            read_size = (int64_t)fread(data, 1, read_size, f);\n        }\n        fclose(f);\n    }\n#endif\n    if(!read_size && data) { free(data); data = NULL; }\n    return data;\n}\n\n/*** gzip deflate ***/\n\n#define HASH_BITS 12\n#define HASH_SIZE (1<<HASH_BITS)\n#define MIN_MATCH 3\n#define MAX_MATCH 258\n#define MAX_OFFSET 32768\n#define TO_Lc(x, y) x - 3, y - 3\n#define FROM_Lc(x) (x + 3)\n\ntypedef struct { uint32_t b, c, t; uint8_t *s, *d; uint16_t e[16], f[288], g[16], h[288]; } zlib_z_t;\ntypedef struct { uint8_t e; uint8_t min, max; } zlib_c_t;\ntypedef struct { uint8_t c, e; uint16_t min, max; } zlib_d_t;\nzlib_z_t d;\nuint8_t *zlib_h[HASH_SIZE];\nstatic const uint8_t mb[256] = {0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,0x08,0x88,0x48,0xc8,\n  0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,\n  0x74,0xf4,0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,\n  0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,0x06,0x86,\n  0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,\n  0x3e,0xbe,0x7e,0xfe,0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,0x09,0x89,0x49,0xc9,0x29,0xa9,\n  0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,\n  0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,\n  0x53,0xd3,0x33,0xb3,0x73,0xf3,0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,0x07,0x87,0x47,0xc7,\n  0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,\n  0x7f,0xff};\nstatic const zlib_c_t lc[] = { {0,TO_Lc(3,3)},{0,TO_Lc(4,4)},{0,TO_Lc(5,5)},{0,TO_Lc(6,6)},{0,TO_Lc(7,7)},{0,TO_Lc(8,8)},\n  {0,TO_Lc(9,9)},{0,TO_Lc(10,10)},{1,TO_Lc(11,12)},{1,TO_Lc(13,14)},{1,TO_Lc(15,16)},{1,TO_Lc(17,18)},{2,TO_Lc(19,22)},\n  {2,TO_Lc(23,26)},{2,TO_Lc(27,30)},{2,TO_Lc(31,34)},{3,TO_Lc(35,42)},{3,TO_Lc(43,50)},{3,TO_Lc(51,58)},{3,TO_Lc(59,66)},\n  {4,TO_Lc(67,82)},{4,TO_Lc(83,98)},{4,TO_Lc(99,114)},{4,TO_Lc(115,130)},{5,TO_Lc(131,162)},{5,TO_Lc(163,194)},{5,TO_Lc(195,226)},\n  {5,TO_Lc(227,257)},{0,TO_Lc(258,258)}};\nstatic const zlib_d_t dc[] = { {0,0,1,1},{1,0,2,2},{2,0,3,3},{3,0,4,4},{4,1,5,6},{5,1,7,8},{6,2,9,12},{7,2,13,16},{8,3,17,24},\n  {9,3,25,32},{10,4,33,48},{11,4,49,64},{12,5,65,96},{13,5,97,128},{14,6,129,192},{15,6,193,256},{16,7,257,384},{17,7,385,512},\n  {18,8,513,768},{19,8,769,1024},{20,9,1025,1536},{21,9,1537,2048},{22,10,2049,3072},{23,10,3073,4096},{24,11,4097,6144},\n  {25,11,6145,8192},{26,12,8193,12288},{27,12,12289,16384},{28,13,16385,24576},{29,13,24577,32768}};\nvoid zlib_o(uint32_t b, int n) { d.b|=b<<d.c; d.c+=n; while(d.c >= 8){ d.d[d.t++] = (uint8_t)(d.b & 0xFF); d.b >>= 8; d.c -= 8; } }\n\nuint32_t compressBound(uint32_t len) { return len + (len >> 12) + (len >> 14) + (len >> 25) + 13 + 18; }\nuint32_t compress(uint8_t *in, uint8_t *out, uint32_t siz)\n{\n    const zlib_d_t *r;\n    const zlib_c_t *l;\n    const uint8_t *t = in + siz - MIN_MATCH;\n    const uint8_t *q;\n    uint8_t **b, *s, c;\n    int i, j, k, m, n, o, p, h;\n\n    memset(&d, 0, sizeof(d));\n    d.d = out + 2; out[0] = 0x78; out[1] = 0xDA;\n    zlib_o(1, 1); zlib_o(1, 2);\n    while(in < t) {\n        h = (in[0] << 16) | (in[1] << 8) | in[2]; h = ((h >> (3*8 - HASH_BITS)) - h) & (HASH_SIZE - 1);\n        b = &zlib_h[h & (HASH_SIZE - 1)]; s = *b; *b = in;\n        if(s && in > s && (in - s) <= MAX_OFFSET && !memcmp(in, s, MIN_MATCH)) {\n            for(in += MIN_MATCH, q = s + MIN_MATCH, o = MIN_MATCH; *in == *q && o < MAX_MATCH && in < t; in++, q++, o++);\n            p = in - o - s;\n            while(o > 0) {\n                m = (o > 260 ? 258 : o <= 258 ? o : o - 3); o -= m; i = -1; j = sizeof(lc) / sizeof(*lc);\n                while(1) {\n                    k = (j + i) / 2;\n                    if(m < FROM_Lc(lc[k].min)) j = k; else if(m > FROM_Lc(lc[k].max)) i = k; else { l = &lc[k]; break; }\n                }\n                n = l - lc + 257;\n                if(n <= 279) zlib_o(mb[(n - 256) * 2], 7); else zlib_o(mb[0xc0 - 280 + n], 8);\n                if (l->e) zlib_o(m - FROM_Lc(l->min), l->e);\n                i = -1; j = sizeof(dc) / sizeof(*dc);\n                while(1) {\n                    k = (j + i) / 2;\n                    if(p < dc[k].min) j = k; else if (p > dc[k].max) i = k; else { r = &dc[k]; break; }\n                }\n                zlib_o(mb[r->c * 8], 5);\n                if(r->e) zlib_o(p - r->min, r->e);\n            }\n        } else { c = *in++; if(c <= 143) zlib_o(mb[0x30 + c], 8); else zlib_o(1 + 2 * mb[0x90 - 144 + c], 9); }\n    }\n    t += MIN_MATCH;\n    while(in < t) { c = *in++; if(c <= 143) zlib_o(mb[0x30 + c], 8); else zlib_o(1 + 2 * mb[0x90 - 144 + c], 9); }\n    zlib_o(0, 7); zlib_o(0, 7);\n    return d.t + 2;\n}\n\n/**\n * CRC calculation with precalculated lookup table\n */\nuint32_t crc32_lookup[256]={\n    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832,\n    0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,\n    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a,\n    0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,\n    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,\n    0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,\n    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,\n    0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\n    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4,\n    0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,\n    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074,\n    0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,\n    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525,\n    0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,\n    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,\n    0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\n    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76,\n    0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,\n    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6,\n    0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\n    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,\n    0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,\n    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7,\n    0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\n    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,\n    0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,\n    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330,\n    0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,\n    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};\nuint32_t crc32_calc(unsigned char *start,int length)\n{\n    uint32_t crc32_val=0xffffffff;\n    while(length--) crc32_val=(crc32_val>>8)^crc32_lookup[(crc32_val&0xff)^(unsigned char)*start++];\n    crc32_val^=0xffffffff;\n    return crc32_val;\n}\n\n/**\n * Convert LBA to CHS\n */\nvoid chs(uint32_t lba, void *chs)\n{\n    /* we don't have a real geometry, so assume 16 heads and 63 sectors */\n    uint64_t c, h = 16, s = 63;\n    c = lba / (h*s); lba %= h*s;\n    *((uint8_t*)(chs+3)) = c & 0xff;\n    *((uint8_t*)(chs+2)) = ((c >> 2) & 0xc0) | ((lba % s) + 1);\n    *((uint8_t*)(chs+1)) = lba / s;\n}\n\n/**\n * Add GUID Partitioning Table\n */\nvoid gpt_create(void)\n{\n    uint64_t lba;\n    guid_t efiguid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID;\n    gpt_header_t *hdr = (gpt_header_t *)(img + 512);\n    gpt_entry_t *entry = (gpt_entry_t *)(img + 1024);\n    int i, j;\n    char *name = \"EFI System Partition\", *part = \"Partition \";\n\n    /* Protective Master Boot Record (we don't really need nor use this, just for backward compatibility) */\n    memcpy(img+0x1B8, &dguid.Data1, 4);             /* WinNT disk id */\n    /* MBR, EFI System Partition / boot partition. */\n    img[0x1C0-2]=0x80;                              /* bootable flag */\n    chs(FIRST_PARTITION, img+0x1BE);                /* start CHS */\n    img[0x1C0+2]=0xC;                               /* type, LBA FAT32 (0xC) */\n    chs(FIRST_PARTITION+partsize/512-1, img+0x1C2); /* end CHS */\n    *((uint32_t*)(img+0x1C0+6)) = FIRST_PARTITION;  /* start LBA */\n    *((uint32_t*)(img+0x1C0+10)) = partsize/512;    /* number of sectors */\n    /* MBR, protective img entry */\n    chs(1, img+0x1CE);                              /* start CHS */\n    img[0x1D0+2]=0xEE;                              /* type */\n    chs(GPT_SECTORS-1, img+0x1D2);                  /* end CHS */\n    *((uint32_t*)(img+0x1D0+6)) = 1;                /* start LBA */\n    *((uint32_t*)(img+0x1D0+10)) = GPT_SECTORS-1;   /* number of sectors */\n\n    /* GPT header */\n    memcpy(&hdr->Signature, EFI_PTAB_HEADER_ID, 8);\n    hdr->Revision = 0x10000;\n    hdr->HeaderSize = 92;\n    hdr->MyLBA = 1;\n    hdr->AlternateLBA = disksize / 512 - 1;\n    hdr->FirstUsableLBA = FIRST_PARTITION;\n    hdr->LastUsableLBA = disksize / 512 - GPT_SECTORS - 1;\n    memcpy(&hdr->DiskGUID, &dguid, sizeof(guid_t));\n    hdr->PartitionEntryLBA = 2;\n    hdr->NumberOfPartitionEntries = GPT_SECTORS * 512 / sizeof(gpt_entry_t);\n    hdr->SizeOfPartitionEntry = sizeof(gpt_entry_t);\n\n    /* GPT, EFI System Partition (ESP) */\n    memcpy(&entry->PartitionTypeGUID, &efiguid, sizeof(guid_t));\n    memcpy(&entry->UniquePartitionGUID, &pguid, sizeof(guid_t));\n    entry->StartingLBA = FIRST_PARTITION;\n    entry->EndingLBA = FIRST_PARTITION + (partsize / 512) - 1;\n    for(i = 0; name[i]; i++) entry->PartitionName[i] = name[i];\n    lba = (FIRST_PARTITION * 512 + partsize + 1024*1024-1) & ~(1024*1024-1);\n\n    for(j = 0; j < nump; j++)\n        if(psize[j] > 0) {\n            /* GPT, Extra Partition(s) */\n            entry++;\n            memcpy(&entry->PartitionTypeGUID, &ptguid[j], sizeof(guid_t));\n            memcpy(&entry->UniquePartitionGUID, &puguid[j], sizeof(guid_t));\n            entry->StartingLBA = lba / 2048;\n            lba += (psize[i] + 1024*1024-1) & ~(1024*1024-1);\n            entry->EndingLBA = lba / 2048 - 1;\n            for(i = 0; part[i]; i++) entry->PartitionName[i] = part[i];\n            entry->PartitionName[i++] = (j / 10) + '0';\n            entry->PartitionName[i++] = (j % 10) + '0';\n        }\n\n    /* calculate checksums */\n    hdr->PartitionEntryArrayCRC32 = crc32_calc((unsigned char*)entry, hdr->NumberOfPartitionEntries * hdr->SizeOfPartitionEntry);\n    hdr->CRC32 = crc32_calc((unsigned char*)hdr, hdr->HeaderSize);\n\n    /* secondary GPT */\n    memcpy(img_tail, img + 1024, GPT_SECTORS * 512);\n    hdr = (gpt_header_t*)(img_tail + GPT_SECTORS * 512);\n    memcpy(hdr, img + 512, 512);\n    hdr->MyLBA = disksize / 512 - 1;\n    hdr->AlternateLBA = 1;\n    hdr->PartitionEntryLBA = disksize / 512 - GPT_SECTORS - 1;\n    hdr->CRC32 = 0; hdr->CRC32 = crc32_calc((unsigned char*)hdr, hdr->HeaderSize);\n}\n\n/**\n * Set an integer value both little-endian and big-endian in El Torito records\n */\nvoid setinte(uint32_t val, unsigned char *ptr) {\n    uint8_t *v = (uint8_t*)&val;\n    ptr[0] = ptr[7] = v[0]; ptr[1] = ptr[6] = v[1]; ptr[2] = ptr[5] = v[2]; ptr[3] = ptr[4] = v[3];\n}\n\n/**\n * Add ISO9660 El Torito Boot Catalog for bootable CDROM\n * WARNING: optical discs are obsolete, not a real world use case any more, so dirty hacks ahead\n */\nvoid etbc_create(void)\n{\n    uint8_t *iso = img + 16 * 2048;\n    char isodate[128];\n    int i;\n\n    /* How and why this ugly hack works on legacy BIOS:\n     * 1. Normally on EFI the firmware locates the ESP in the GPT and parses it to find the 2nd stage loader as a file.\n     *    The ESP's VBR is never executed (actually fat_format() does not place any code here at all).\n     * 2. On BIOS, the very first sector is loaded and executed. Originally on an IBM PC this MBR loaded and executed\n     *    the partition's VBR; however boot_x86.asm directly loads the 2nd stage so the ESP's VBR again, irrelevant.\n     * 3. EFI firmware in El Torito mode (see below) locates the ESP in the Boot Catalog and again, interprets it as a\n     *    file system, so the ESP's VBR code isn't used in this case either.\n     * 4. Now the BIOS firmware in El Torito mode loads the sector where the Boot Catalog points (which must be the\n     *    ESP's VBR because of case 3) and directly executes it. This is the only case when the VBR's code matters.\n     * So cdemu_x86.asm in this sector simulates a secondary HDD with the CDROM's data, loads the MBR and executes it,\n     * and after that everything goes like in case 2, business as usual.\n     *\n     * Install HDD emulation of CDROM for BIOS code into the ESP VBR */\n    memcpy(fs_base, cdemu_x86_bin, sizeof(cdemu_x86_bin));\n\n    /* from the UEFI spec section 12.3.2.1 ISO-9660 and El Torito\n      \"...A Platform ID of 0xEF indicates an EFI System Partition. The Platform ID is in either the Section\n      Header Entry or the Validation Entry of the Booting Catalog as defined by the “El Torito”\n      specification. EFI differs from “El Torito” “no emulation” mode in that it does not load the “no\n      emulation” image into memory and jump to it. EFI interprets the “no emulation” image as an EFI\n      system partition.\"\n     * so we must record the ESP in the Boot Catalog, that's how UEFI locates it */\n\n    sprintf((char*)&isodate, \"%04d%02d%02d%02d%02d%02d00\",\n        fat_ts->tm_year+1900,fat_ts->tm_mon+1,fat_ts->tm_mday,fat_ts->tm_hour,fat_ts->tm_min,fat_ts->tm_sec);\n\n    /* 16th sector: Primary Volume Descriptor */\n    iso[0]=1;   /* Header ID */\n    memcpy(&iso[1], \"CD001\", 5);\n    iso[6]=1;   /* version */\n    for(i=8;i<72;i++) iso[i]=' ';\n    memcpy(&iso[40], \"BOOT CDROM\", 10);   /* Volume Identifier */\n    setinte((disksize+2047)/2048, &iso[80]);\n    iso[120]=iso[123]=1;        /* Volume Set Size */\n    iso[124]=iso[127]=1;        /* Volume Sequence Number */\n    iso[129]=iso[130]=8;        /* logical blocksize (0x800) */\n    iso[156]=0x22;              /* root directory recordsize */\n    setinte(20, &iso[158]);     /* root directory LBA */\n    setinte(2048, &iso[166]);   /* root directory size */\n    iso[174]=fat_ts->tm_year;   /* root directory create date */\n    iso[175]=fat_ts->tm_mon+1;\n    iso[176]=fat_ts->tm_mday;\n    iso[177]=fat_ts->tm_hour;\n    iso[178]=fat_ts->tm_min;\n    iso[179]=fat_ts->tm_sec;\n    iso[180]=0;                 /* timezone UTC (GMT) */\n    iso[181]=2;                 /* root directory flags (0=hidden,1=directory) */\n    iso[184]=iso[187]=1;        /* root directory number */\n    iso[188]=1;                 /* root directory filename length */\n    for(i=190;i<813;i++) iso[i]=' ';    /* Volume data */\n    memcpy(&iso[318], \"SIMPLEBOOT <HTTPS://CODEBERG.ORG/BZT/SIMPLEBOOT>\", 48);\n    memcpy(&iso[446], \"SIMPLEBOOT\", 10);\n    memcpy(&iso[574], \"BOOT CDROM\", 10);\n    for(i=702;i<813;i++) iso[i]=' ';    /* file descriptors */\n    memcpy(&iso[813], &isodate, 16);    /* volume create date */\n    memcpy(&iso[830], &isodate, 16);    /* volume modify date */\n    for(i=847;i<863;i++) iso[i]='0';    /* volume expiration date */\n    for(i=864;i<880;i++) iso[i]='0';    /* volume shown date */\n    iso[881]=1;                         /* filestructure version */\n    for(i=883;i<1395;i++) iso[i]=' ';   /* file descriptors */\n    /* 17th sector: Boot Record Descriptor */\n    iso[2048]=0;    /* Header ID */\n    memcpy(&iso[2049], \"CD001\", 5);\n    iso[2054]=1;    /* version */\n    memcpy(&iso[2055], \"EL TORITO SPECIFICATION\", 23);\n    setinte(19, &iso[2048+71]);         /* Boot Catalog LBA */\n    /* 18th sector: Volume Descritor Terminator */\n    iso[4096]=0xFF; /* Header ID */\n    memcpy(&iso[4097], \"CD001\", 5);\n    iso[4102]=1;    /* version */\n    /* 19th sector: Boot Catalog */\n    iso[6144]=1;    /* Header ID, Validation Entry */\n    iso[6145]=0;    /* Platform 80x86 */\n    iso[6172]=0xaa; /* magic bytes */\n    iso[6173]=0x55;\n    iso[6174]=0x55;\n    iso[6175]=0xaa;\n    iso[6176]=0x88; /* Bootable, Initial/Default Entry */\n    iso[6182]=4;    /* Sector Count */\n    *((uint32_t*)(iso + 6184)) = FIRST_PARTITION/4; /* ESP Start LBA */\n    iso[6208]=0x91; /* Header ID, Final Section Header Entry */\n    iso[6209]=0xEF; /* Platform EFI */\n    iso[6210]=1;    /* Number of entries */\n    iso[6240]=0x88; /* Bootable, Section Entry */\n    *((uint16_t*)(iso + 6246)) = partsize/512;      /* Sector Count */\n    *((uint32_t*)(iso + 6248)) = FIRST_PARTITION/4; /* ESP Start LBA */\n    /* 20th sector: Root Directory */\n    /* . */\n    iso[8192]=0x21 + 1;          /* recordsize */\n    setinte(20, &iso[8194]);     /* LBA */\n    setinte(2048, &iso[8202]);   /* size */\n    iso[8210]=fat_ts->tm_year;   /* date */\n    iso[8211]=fat_ts->tm_mon+1;\n    iso[8212]=fat_ts->tm_mday;\n    iso[8213]=fat_ts->tm_hour;\n    iso[8214]=fat_ts->tm_min;\n    iso[8215]=fat_ts->tm_sec;\n    iso[8216]=0;                 /* timezone UTC (GMT) */\n    iso[8217]=2;                 /* flags (0=hidden,1=directory) */\n    iso[8220]=iso[8223]=1;       /* serial */\n    iso[8224]=1;                 /* filename length */\n    iso[8225]=0;                 /* filename '.' */\n    /* .. */\n    iso[8226]=0x21 + 1;          /* recordsize */\n    setinte(20, &iso[8228]);     /* LBA */\n    setinte(2048, &iso[8236]);   /* size */\n    iso[8244]=fat_ts->tm_year;   /* date */\n    iso[8245]=fat_ts->tm_mon+1;\n    iso[8246]=fat_ts->tm_mday;\n    iso[8247]=fat_ts->tm_hour;\n    iso[8248]=fat_ts->tm_min;\n    iso[8249]=fat_ts->tm_sec;\n    iso[8250]=0;                 /* timezone UTC (GMT) */\n    iso[8251]=2;                 /* flags (0=hidden,1=directory) */\n    iso[8254]=iso[8257]=1;       /* serial */\n    iso[8258]=1;                 /* filename length */\n    iso[8259]='\\001';            /* filename '..' */\n}\n\n/**\n * Create legacy ROM images (use loader_cb.c instead if you can)\n */\nvoid rom_create(char *path)\n{\n    pcirom_t *pci;\n    fb_rom_t *foss;\n    FILE *f = NULL;\n    char *out = NULL, *name;\n    uint8_t buf[512 + 65536], in[512 + 65536];\n    int i, c, romsize = 512 + ((sizeof(loader_x86_efi) + 511) & ~511);\n\n    /* get directory from output image path */\n    if(!path || !*path || !memcmp(path, \"/dev/\", 5) || !memcmp(path, \"\\\\\\\\.\\\\\", 4)) {\n        if(!(out = (char*)malloc(32))) goto err;\n        name = out;\n    } else {\n        if(!(out = (char*)malloc(strlen(path) + 32))) goto err;\n        strcpy(out, path);\n        if((name = strrchr(out, '/'))) name++; else\n        if((name = strrchr(out, '\\\\'))) name++; else name = out;\n    }\n\n    /* save legacy BIOS Expansion ROM */\n    strcpy(name, \"sb_bios.rom\");\n    memset(buf, 0, romsize);\n    memcpy(buf, rombios_x86_bin, sizeof(rombios_x86_bin));\n    memcpy(buf + sizeof(rombios_x86_bin), loader_x86_efi, sizeof(loader_x86_efi));\n    buf[2] = romsize >> 9;\n    for(i = c = 0; i < romsize; i++) { c += buf[i]; } buf[6] = (uint8_t)(256 - c);\n    if(!(f = fopen(out, \"wb\")) || !fwrite(buf, 1, romsize, f)) goto err;\n    fclose(f);\n\n    /* save legacy UEFI PCI Option ROM */\n    strcpy(name, \"sb_uefi.rom\");\n    memset(buf, 0, romsize);\n    memcpy(buf + sizeof(pcirom_t), loader_x86_efi, sizeof(loader_x86_efi));\n    pci = (pcirom_t*)buf;\n    pci->magic[0] = 0x55; pci->magic[1] = 0xAA;\n    pci->InitializationSize = pci->ImageLength = romsize >> 9;\n    pci->EfiSignature = 0x0EF1;\n    pci->EfiSubsystem = 0xA;\n    pci->EfiMachineType = IMAGE_FILE_MACHINE_AMD64;\n    pci->EfiImageHeaderOffset = sizeof(pcirom_t);\n    pci->PcirOffset = 0x1C;\n    memcpy(&pci->Signature, \"PCIR\", 4);\n    pci->VendorId = 0x8086;\n    pci->DeviceId = 0x100E;\n    pci->Length = 24;\n    pci->ClassCode[0] = 0; /* no signed check for PCI_CLASS_VGA */\n    pci->CodeType = 0x03;\n    pci->Indicator = 0x80;\n    for(i = c = 0; i < romsize; i++) { c += buf[i]; } pci->checksum = (uint8_t)(256 - c);\n    if(!(f = fopen(out, \"wb\")) || !fwrite(buf, 1, romsize, f)) goto err;\n    fclose(f);\n\n    /* save FOSSBIOS ROM */\n    strcpy(name, \"sb_foss.rom\");\n    memset(buf, 0, romsize);\n    memcpy(in, romfoss_x86_bin, sizeof(romfoss_x86_bin));\n    memcpy(in + sizeof(romfoss_x86_bin), loader_x86_efi, sizeof(loader_x86_efi));\n    foss = (fb_rom_t*)buf;\n    foss->magic[0] = 0x55; foss->magic[1] = 0xAA;\n    foss->fossmagic[0] = 0xF0; foss->fossmagic[1] = 0x55; foss->fossmagic[2] = 0xB1; foss->fossmagic[3] = 0x05;\n    foss->arch = 0;     /* x86 */\n    foss->wordsize = 8; /* 64-bit */\n    foss->type = 1;     /* boot services */\n    foss->uncompressed = sizeof(romfoss_x86_bin) + sizeof(loader_x86_efi);\n    foss->compressed = compress(in, buf + sizeof(fb_rom_t), foss->uncompressed);\n    romsize = (sizeof(fb_rom_t) + foss->compressed + 511) & ~511;\n    foss->size = romsize >> 9;\n    memcpy(&foss->pcir[4], \"Simpleboot\\0x86_64\", 17);\n    foss->crc = crc32_calc(buf, sizeof(fb_rom_t) + foss->compressed);\n    if(!(f = fopen(out, \"wb\")) || !fwrite(buf, 1, romsize, f)) goto err;\n    fclose(f);\n    free(out);\n    return;\n\nerr:fprintf(stderr, \"simpleboot: unable to save ROM images\\r\\n\");\n    if(out) free(out);\n    if(f) fclose(f);\n}\n\n/**\n * Finish FAT\n */\nvoid fat_finish(void)\n{\n    int i;\n\n    fat_nextcluster -= 2;\n    i = fat_freeclu ? fat_freeclu : ((partsize - (fat_spf*fs_base[0x10]+fs_base[0xE]) * 512)/fat_bpc) - fat_nextcluster;\n    fs_base[0x3E8] = i & 0xFF; fs_base[0x3E9] = (i >> 8) & 0xFF;\n    fs_base[0x3EA] = (i >> 16) & 0xFF; fs_base[0x3EB] = (i >> 24) & 0xFF;\n    fs_base[0x3EC] = fat_nextcluster & 0xFF; fs_base[0x3ED] = (fat_nextcluster >> 8) & 0xFF;\n    fs_base[0x3EE] = (fat_nextcluster >> 16) & 0xFF; fs_base[0x3EF] = (fat_nextcluster >> 24) & 0xFF;\n    /* copy backup boot sectors */\n    memcpy(fs_base + (fs_base[0x32]*512), fs_base, 1024);\n}\n\n/**\n * Add a 8.3 FAT directory entry\n */\nuint8_t *fat_dirent83(uint8_t *ptr, char *name, int type, uint32_t clu, uint32_t size)\n{\n    int i;\n\n    for(i = 0; i < 11 && name[i]; i++) ptr[i] = name[i];\n    while(i < 11) ptr[i++] = ' ';\n    memset(ptr + 11, 0, 21);\n    ptr[0xB] = type;\n    i = (fat_ts->tm_hour << 11) | (fat_ts->tm_min << 5) | (fat_ts->tm_sec/2);\n    ptr[0xE] = ptr[0x16] = i & 0xFF; ptr[0xF] = ptr[0x17] = (i >> 8) & 0xFF;\n    i = ((fat_ts->tm_year+1900-1980) << 9) | ((fat_ts->tm_mon+1) << 5) | (fat_ts->tm_mday);\n    ptr[0x10] = ptr[0x12] = ptr[0x18] = i & 0xFF; ptr[0x11] = ptr[0x13] = ptr[0x19] = (i >> 8) & 0xFF;\n    ptr[0x1A] = clu & 0xFF; ptr[0x1B] = (clu >> 8) & 0xFF;\n    ptr[0x14] = (clu >> 16) & 0xFF; ptr[0x15] = (clu >> 24) & 0xFF;\n    ptr[0x1C] = size & 0xFF; ptr[0x1D] = (size >> 8) & 0xFF;\n    ptr[0x1E] = (size >> 16) & 0xFF; ptr[0x1F] = (size >> 24) & 0xFF;\n    return ptr + 32;\n}\n\n/**\n * Format the partition to FAT32\n */\nvoid fat_format(void)\n{\n    int i = FIRST_PARTITION;\n    uint32_t *fat_fat32_1, *fat_fat32_2;\n    uint8_t *fat_rootdir;\n\n    fat_numclu = partsize / 512; fat_freeclu = 0;\n    if(fat_numclu < 67584) { fprintf(stderr, \"simpleboot: not enough clusters\\r\\n\"); exit(1); }\n    /* make BPB (FAT superblock) */\n    memcpy(fs_base + 3, \"MSWIN4.1\", 8);\n    fs_base[0xC] = 2; fs_base[0x10] = 2; fs_base[0x15] = 0xF8; fs_base[0x1FE] = 0x55; fs_base[0x1FF] = 0xAA;\n    fs_base[0x18] = 240; fs_base[0x19] = 3; fs_base[0x1A] = 16;\n    memcpy(fs_base + 0x1C, &i, 4);\n    memcpy(fs_base + 0x20, &fat_numclu, 4);\n    fs_base[0xD] = 1; fs_base[0xE] = 8;\n    fat_spf = (fat_numclu*4) / 512 + fs_base[0xE];\n    fs_base[0x24] = fat_spf & 0xFF; fs_base[0x25] = (fat_spf >> 8) & 0xFF;\n    fs_base[0x26] = (fat_spf >> 16) & 0xFF; fs_base[0x27] = (fat_spf >> 24) & 0xFF;\n    fs_base[0x2C] = 2; fs_base[0x30] = 1; fs_base[0x32] = 6; fs_base[0x40] = 0x80; fs_base[0x42] = 0x29;\n    memcpy(fs_base + 0x43, &pguid, 4);\n    memcpy(fs_base + 0x47, \"EFI System FAT32   \", 19);\n    memcpy(fs_base + 0x200, \"RRaA\", 4); memcpy(fs_base + 0x3E4, \"rrAa\", 4);\n    for(i = 0; i < 8; i++) fs_base[0x3E8 + i] = 0xFF;\n    fs_base[0x3FE] = 0x55; fs_base[0x3FF] = 0xAA;\n    fat_bpc = fs_base[0xD] * 512;\n    fat_rootdir = fs_base + (fat_spf*fs_base[0x10]+fs_base[0xE]) * 512;\n    fat_fat32_1 = (uint32_t*)(&fs_base[fs_base[0xE] * 512]);\n    fat_fat32_2 = (uint32_t*)(&fs_base[(fs_base[0xE]+fat_spf) * 512]);\n    fat_fat32_1[0] = fat_fat32_2[0] = 0x0FFFFFF8;\n    fat_fat32_1[1] = fat_fat32_2[1] = fat_fat32_1[2] = fat_fat32_2[2] = 0x0FFFFFFF;\n    fat_nextcluster = 3;\n    /* label in root directory */\n    fat_dirent83(fat_rootdir, \"EFI System \", 8, 0, 0);\n    fat_finish();\n}\n\n/**\n * Find a free cluster (or more)\n */\nuint32_t fat_findclu(uint32_t cnt)\n{\n    uint32_t i, clu;\n\n    if(cnt < 1) cnt = 1;\n    if(fat_freeclu < (int64_t)cnt) {\n        fprintf(stderr, \"%ssimpleboot: not enough space on the boot partition\\r\\n\", verbose ? \"\\n\" : \"\");\n        return 0;\n    }\n    for(clu = 3; clu < fat_nextcluster; clu++) {\n        for(i = 0; i < cnt && clu + i < fat_nextcluster && !fat_fat32[clu + i]; i++);\n        if(i == cnt) break;\n    }\n    if(clu == fat_nextcluster) fat_nextcluster += cnt;\n    fat_freeclu -= cnt;\n    for(i = 0; i < cnt; i++) fat_fat32[clu + i] = clu + i + 1;\n    fat_fat32[clu + i - 1] = 0x0FFFFFFF;\n    return clu;\n}\n\n/**\n * Look up or add a directory entry\n * parent: cluster where we need to add\n * add: 0=just check if entry exists, 1=update or add if doesn't exists, 2=update or add, allocate contiguous clusters\n * name: UTF-8 filename\n * isdir: 1 if the entry is a directory\n * *clu: returned cluster\n * flen: file's length\n */\nint fat_dirent(uint32_t parent, int add, char *name, int isdir, uint32_t *clu, uint32_t flen)\n{\n    char ucase[256], fn[256];\n    uint16_t uc2[32 * 13 + 1], *u;\n    uint32_t i, n, size, last, cnt = 0;\n    uint8_t *s, *dir, *ptr, c;\n\n    *clu = -1U;\n\n    /* convert name to uppercase */\n    for(i = 0; i < 255 && name[i]; i++)\n        ucase[i] = name[i] >= 'a' && name[i] <= 'z' ? name[i] - 'a' + 'A' : name[i];\n    ucase[i] = 0;\n\n    /* get the size */\n    for(i = parent, size = fat_bpc;\n        i != fat_nextcluster && fat_fat32[i] && fat_fat32[i] < 0xFFFFFF8; i = fat_fat32[i], size += fat_bpc);\n    if(!(ptr = (uint8_t*)malloc(size + 4 * fat_bpc))) {\n        fprintf(stderr, \"%ssimpleboot: unable to allocate memory\\r\\n\", verbose ? \"\\n\" : \"\");\n        return 0;\n    }\n    memset(ptr, 0, size + 4 * fat_bpc);\n\n    /* load the entries */\n    i = last = parent; dir = ptr;\n    do {\n        if(!dev_read(f, (data_lba + i * bpb->spc) << 9, dir, fat_bpc)) {\n            free(ptr); fprintf(stderr, \"%ssimpleboot: unable to read '%s'\\r\\n\", verbose ? \"\\n\" : \"\", out); return 0;\n        }\n        last = i; i = fat_fat32[i]; dir += fat_bpc;\n    } while(i && i < fat_nextcluster && i < 0xFFFFFF8);\n\n    /* iterate on entries */\n    for(dir = ptr; dir < ptr + size && *dir && (dir < ptr + 64 || *dir != '.'); dir += 32, cnt++) {\n        memset(fn, 0, sizeof(fn));\n        if(dir[0] == 0xE5) continue;\n        if(dir[0xB] == 0xF) {\n            /* this is an LFN block */\n            memset(uc2, 0, sizeof(uc2));\n            n = dir[0] & 0x1F;\n            u = uc2 + (n - 1) * 13;\n            while(n--) {\n                for(i = 0; i < 5; i++) u[i] = dir[i*2+2] << 8 | dir[i*2+1];\n                for(i = 0; i < 6; i++) u[i+5] = dir[i*2+0xF] << 8 | dir[i*2+0xE];\n                u[11] = dir[0x1D] << 8 | dir[0x1C];\n                u[12] = dir[0x1F] << 8 | dir[0x1E];\n                u -= 13;\n                dir += 32;\n            }\n            for(s = (uint8_t*)fn, u = uc2; *u && s < (uint8_t*)fn + 255; u++)\n                if(*u < 0x80) { *s++ = *u >= 'a' && *u <= 'z' ? *u - 'a' + 'A' : *u; } else\n                if(*u < 0x800) { *s++ = ((*u>>6)&0x1F)|0xC0; *s++ = (*u&0x3F)|0x80; } else\n                { *s++ = ((*u>>12)&0x0F)|0xE0; *s++ = ((*u>>6)&0x3F)|0x80; *s++ = (*u&0x3F)|0x80; }\n            *s = 0;\n        } else {\n            /* use 8.3 name otherwise */\n            for(i = 0, s = (uint8_t*)fn; i < 8 && dir[i] != ' '; i++, s++)\n                *s = dir[i] >= 'a' && dir[i] <= 'z' ? dir[i] - 'a' + 'A' : dir[i];\n            if(dir[8] != ' ') {\n                *s++ = '.';\n                for(i = 8; i < 11 && dir[i] != ' '; i++, s++)\n                    *s = dir[i] >= 'a' && dir[i] <= 'z' ? dir[i] - 'a' + 'A' : dir[i];\n            }\n            *s = 0;\n        }\n        if(!strcmp(fn, ucase)) {\n            *clu = (dir[0x15] << 24) | (dir[0x14] << 16) | (dir[0x1B] << 8) | dir[0x1A];\n            /* if it's a file, delete it */\n            if(!dir[0xB] && add) {\n                for(i = *clu; i && i < fat_nextcluster && i < 0xFFFFFF8;) {\n                    n = fat_fat32[i]; fat_fat32[i] = 0; i = n; fat_freeclu++;\n                }\n                if(*clu) fat_freeclu--;\n                if(!flen) {\n                    *clu = 0; dir[0x1A] = dir[0x1B] = dir[0x14] = dir[0x15] = 0;\n                } else {\n                    /* if we need contiguous allocation, update the cluster too */\n                    if(add == 2) {\n                        if(*clu && *clu < fat_nextcluster && *clu < 0xFFFFFF8) { fat_fat32[*clu] = 0; fat_freeclu++; }\n                        *clu = fat_findclu((flen + fat_bpc - 1) / fat_bpc);\n                        dir[0x1A] = *clu & 0xFF; dir[0x1B] = (*clu >> 8) & 0xFF;\n                        dir[0x14] = (*clu >> 16) & 0xFF; dir[0x15] = (*clu >> 24) & 0xFF;\n                    } else\n                    if(*clu && *clu < fat_nextcluster && *clu < 0xFFFFFF8) fat_fat32[*clu] = 0xFFFFFFF;\n                }\n                dir[0x1C] = flen & 0xFF; dir[0x1D] = (flen >> 8) & 0xFF;\n                dir[0x1E] = (flen >> 16) & 0xFF; dir[0x1F] = (flen >> 24) & 0xFF;\n                /* write out modified directory entry */\n                for(s = ptr, i = parent; s + fat_bpc < dir; s += fat_bpc) i = fat_fat32[i];\n                if(!dev_write(f, ((data_lba + i * bpb->spc) << 9), s, fat_bpc)) {\n                    fprintf(stderr, \"%ssimpleboot: unable to write '%s'\\r\\n\", verbose ? \"\\n\" : \"\", out);\n                }\n            }\n            break;\n        }\n    }\n\n    /* if not found, add the directory entry */\n    if(*clu == -1U && add) {\n        for(i = n = 0; ucase[i] && ucase[i] != '.'; i++);\n        if(ucase[i] == '.') for(; ucase[i + n + 1]; n++);\n        if(i <= 8 && n <= 3 && !strcmp(name, ucase)) {\n            /* use the 8.3 name if possible */\n            memset(fn, ' ', 11);\n            for(i = n = 0; ucase[i]; i++) { if(ucase[i] == '.') n = 8; else fn[n++] = ucase[i]; }\n            n = 0;\n        } else {\n            memset(uc2, 0, sizeof(uc2));\n            for(i = 0, u = uc2, s = (uint8_t*)name; *s; i++, u++) {\n                if((*s & 128) != 0) {\n                    if((*s & 32) == 0) { *u = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); s += 2; } else\n                    if((*s & 16) == 0) { *u = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); s += 3; }\n                } else\n                    *u = *s++;\n            }\n            i = (i + 12) / 13;\n            /* don't convert \"Microsoft\" to \"MICROS~1   \", that's patented... */\n            sprintf(fn, \"~%07xLFN\", cnt++);\n            for(c = 0, n = 0; n < 11; n++)\n                c = (((c & 1) << 7) | ((c & 0xfe) >> 1)) + fn[n];\n            u = uc2 + (i - 1) * 13;\n            for(n = 0; i--; n += 32, u -= 13) {\n                dir[n] = (!n ? 0x40 : 0) | (i + 1);\n                dir[n + 0xB] = 0xF;\n                dir[n + 0xD] = c;\n                memcpy(dir + n + 1, (uint8_t*)u, 10);\n                memcpy(dir + n + 14, (uint8_t*)u + 10, 12);\n                memcpy(dir + n + 28, (uint8_t*)u + 22, 4);\n            }\n        }\n        if(dir + n + 32 >= ptr + size) {\n            /* add new cluster(s) to the parent directory */\n            fat_fat32[last] = fat_findclu(((n + 1) * 32 + fat_bpc - 1) / fat_bpc);\n        }\n        /* add new cluster(s) for file contents */\n        if(!isdir && !flen) *clu = 0;\n        else *clu = fat_findclu(add == 2 ? (flen + fat_bpc - 1) / fat_bpc : 1);\n        fat_dirent83(dir + n, fn, isdir ? 0x10 : 0, *clu, flen);\n        n += 32;\n        /* write out new directory entry */\n        for(s = ptr, i = parent; s + fat_bpc < dir; s += fat_bpc) i = fat_fat32[i];\n        if(!dev_write(f, ((data_lba + i * bpb->spc) << 9), s, fat_bpc)) {\n            fprintf(stderr, \"%ssimpleboot: unable to write '%s'\\r\\n\", verbose ? \"\\n\" : \"\", out);\n        }\n        /* long filenames might cross cluster border */\n        if(dir + n > s + fat_bpc) {\n            i = fat_fat32[i];\n            if(!dev_write(f, ((data_lba + i * bpb->spc) << 9), s + fat_bpc, fat_bpc)) {\n                fprintf(stderr, \"%ssimpleboot: unable to write '%s'\\r\\n\", verbose ? \"\\n\" : \"\", out);\n            }\n        }\n        /* if we have added a directory, then we must create . and .. entries in it as well */\n        if(isdir) {\n            memset(fn, ' ', 11); memset(dir, 0, fat_bpc);\n            fn[0] = '.'; s = fat_dirent83(dir, fn, 0x10, *clu, 0);\n            fn[1] = '.'; s = fat_dirent83(s, fn, 0x10, parent == bpb->rc ? 0 : parent, 0);\n            if(!dev_write(f, ((data_lba + *clu * bpb->spc) << 9), dir, fat_bpc)) {\n                fprintf(stderr, \"%ssimpleboot: unable to write '%s'\\r\\n\", verbose ? \"\\n\" : \"\", out);\n            }\n        }\n    }\n    free(ptr);\n    return (!*clu && !flen) || (*clu > 2 && *clu != bpb->rc && *clu < fat_nextcluster);\n}\n\n/**\n * Add a file to boot partition\n */\nint fat_add(uint32_t parent, char *name, uint8_t *content, uint32_t size)\n{\n    uint32_t clu, i, nc;\n\n    if(fat_dirent(parent, 1, name, 0, &clu, size) && content && size) {\n        /* write out data in cluster sized blocks */\n        for(i = 0; i < size; i += fat_bpc) {\n            if(!dev_write(f, ((data_lba + clu * bpb->spc) << 9), content, fat_bpc)) {\n                fprintf(stderr, \"%ssimpleboot: unable to write '%s'\\r\\n\", verbose ? \"\\n\" : \"\", out);\n                return 0;\n            }\n            if(i + fat_bpc >= size) break;\n            content += fat_bpc;\n            nc = fat_findclu(1);\n            if(!nc) { fat_fat32[clu] = 0xFFFFFFF; return 0; }\n            fat_fat32[clu] = nc;\n            clu = nc;\n        }\n        fat_fat32[clu] = 0xFFFFFFF;\n        /* if we have remaining data, copy it to an empty cluster and write that */\n        if(i < size) {\n            memcpy(cluster, content, size - i);\n            memset(cluster + size - i, 0, fat_bpc - (size - i));\n            if(!dev_write(f, ((data_lba + clu * bpb->spc) << 9), cluster, fat_bpc)) {\n                fprintf(stderr, \"%ssimpleboot: unable to write '%s'\\r\\n\", verbose ? \"\\n\" : \"\", out);\n                return 0;\n            }\n        }\n    }\n    return 1;\n}\n\n/**\n * Print status\n */\nvoid status(char *msg, char *par)\n{\n#ifndef __WIN32__\n#define CL \"\\x1b[K\"\n#else\n#define CL\n#endif\n    if(verbose) {\n        if(!par) printf(\"\\r%-78s\" CL \"\\r\", msg);\n        else printf(\"\\r%s: %-70s\" CL \"\\r\", msg, par);\n        fflush(stdout);\n    }\n}\n\n/**\n * Recursively parse a directory\n */\nvoid parsedir(char *directory, int parent, int calcsize, uint32_t to)\n{\n#ifdef __WIN32__\n    WIN32_FIND_DATAW ffd;\n    HANDLE h;\n    int i, j;\n#else\n    DIR *dir;\n    struct dirent *ent;\n    struct stat st;\n    char *s;\n#endif\n    int64_t dirsize = 0;\n    uint32_t clu = to;\n    unsigned char *tmp;\n\n    if(!parent) { parent = strlen(directory); skipbytes = parent + 1; strncpy(full, directory, sizeof(full)-1); }\n#ifdef __WIN32__\n    memset(&szFile, 0, sizeof(szFile));\n    MultiByteToWideChar(CP_UTF8, 0, directory, -1, szFile, PATH_MAX);\n    for(i = 0; szFile[i]; i++) if(szFile[i] == L'/') szFile[i] = L'\\\\';\n    if(i && szFile[i - 1] != L'\\\\') szFile[i++] = L'\\\\';\n    wcscpy_s(szFile + i, 255, L\"*.*\");\n    h = FindFirstFileW(szFile, &ffd);\n    if(h != INVALID_HANDLE_VALUE) {\n        dirsize = 64;\n        do {\n            if(!wcscmp(ffd.cFileName, L\".\") || !wcscmp(ffd.cFileName, L\"..\")) continue;\n            wcscpy_s(szFile + i, 255, ffd.cFileName);\n            memset(full, 0, sizeof(full)); parent = 0;\n            WideCharToMultiByte(CP_UTF8, 0, szFile, -1, full, sizeof(full) - 1, NULL, NULL);\n            for(j = 0; full[j]; j++) if(full[j] == '\\\\') { full[j] = '/'; parent = j; }\n            read_size = 0;\n            /* no need to check filenames, we've converted it from UCS2 */\n            if(calcsize) dirsize += (((wcslen(ffd.cFileName) + 12) / 13) + 1) * 32;\n            else status(\"Adding\", full + skipbytes);\n            if(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {\n                if(!calcsize) fat_dirent(to, 1, full + parent + 1, 1, &clu, 0);\n                parsedir(full, strlen(full), calcsize, clu);\n            } else {\n                tmp = readfileall(full, calcsize);\n                if(calcsize) totsize += (read_size + 511) & ~511;\n                else fat_add(to, full + parent + 1, tmp, read_size);\n                if(tmp) free(tmp);\n            }\n        } while(FindNextFileW(h, &ffd) != 0);\n        FindClose(h);\n    }\n#else\n    if((dir = opendir(directory)) != NULL) {\n        dirsize = 64;\n        while((ent = readdir(dir)) != NULL) {\n            if(!strcmp(ent->d_name, \".\") || !strcmp(ent->d_name, \"..\")) continue;\n            strncpy(full + parent, \"/\", sizeof(full)-parent-1);\n            strncat(full + parent, ent->d_name, sizeof(full)-parent-1);\n            if(stat(full, &st)) continue;\n            read_size = 0;\n            if(calcsize) {\n                /* we must check if all filenames can be encoded as UCS2 */\n                for(s = ent->d_name; *s; s++)\n                    if((*s & 128) != 0) {\n                        if((*s & 32) == 0) s++; else\n                        if((*s & 16) == 0) s += 2;\n                        else {\n                            fprintf(stderr, \"%ssimpleboot: unable to encode file name '%s'\\r\\n\", verbose ? \"\\n\" : \"\", full);\n                            exit(1);\n                        }\n                    }\n                dirsize += (((s - ent->d_name + 12) / 13) + 1) * 32;\n            } else status(\"Adding\", full + skipbytes);\n            if(S_ISDIR(st.st_mode)) {\n                if(!calcsize) fat_dirent(to, 1, full + parent + 1, 1, &clu, 0);\n                parsedir(full, strlen(full), calcsize, clu);\n            } else\n            if(S_ISREG(st.st_mode)) {\n                tmp = readfileall(full, calcsize);\n                if(calcsize) totsize += (read_size + 511) & ~511;\n                else fat_add(to, full + parent + 1, tmp, read_size);\n                if(tmp) free(tmp);\n            }\n        }\n        closedir(dir);\n    }\n#endif\n    totsize += (dirsize + 511) & ~511;\n    if(parent + 1 == skipbytes) skipbytes = 0;\n}\n\n/**\n * Open a device\n */\nvoid *dev_open(char *file)\n{\n#ifdef __WIN32__\n    HANDLE f = 0;\n    int i;\n\n    memset(&szFile, 0, sizeof(szFile));\n    MultiByteToWideChar(CP_UTF8, 0, file, -1, szFile, PATH_MAX);\n    for(i = 0; szFile[i]; i++) if(szFile[i] == L'/') szFile[i] = L'\\\\';\n    f = CreateFileW(szFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_READ, NULL, OPEN_EXISTING,\n        FILE_FLAG_NO_BUFFERING, NULL);\n    if(f == INVALID_HANDLE_VALUE) f = NULL;\n#else\n    char *full, *mnt, *s;\n    intptr_t f;\n    int l;\n\n    memset(&dev_st, 0, sizeof(dev_st));\n\n    /* resolve relative paths and symlinks first */\n    if(!(full = realpath(file, NULL))) full = file;\n    /* check if the file is mounted by any chance */\n    mnt = (char*)readfileall(\n#ifdef __linux__\n        \"/proc/self/mountinfo\"\n#else\n        \"/etc/mtab\"\n#endif\n        , 0);\n    if(mnt) {\n        for(s = mnt, l = strlen(full); *s; s++) {\n            /* find beginning of a line */\n            while(*s && (*s == '\\r' || *s == '\\n' || *s == ' ' || *s == '\\t')) s++;\n            if(!memcmp(s, full, l)) {\n                fprintf(stderr, \"simpleboot: device '%s' is mounted. Please umount first.\\r\\n\", file);\n                free(mnt); if(full != file) free(full);\n                return 0;\n            }\n            /* skip to the end of the line */\n            while(*s && *s != '\\r' && *s != '\\n') s++;\n        }\n        free(mnt);\n    }\n    /* not fopen because this might be an actual device file, in which case we need exclusive access and non-buffered IO */\n    stat(full, &dev_st);\n    f = open(full, O_RDWR | (S_ISBLK(dev_st.st_mode) ? O_SYNC | O_EXCL : 0));\n    if(full != file) free(full);\n    if(f < 3) f = 0;\n#endif\n    return (void *)f;\n}\n\n/**\n * Read from the device\n */\nint dev_read(void *f, uint64_t off, void *buf, uint32_t size)\n{\n#ifdef __WIN32__\n    DWORD r = size, t;\n    LARGE_INTEGER pos;\n    pos.QuadPart = off;\n    SetFilePointerEx((HANDLE)f, pos, NULL, FILE_BEGIN);\n    if(!ReadFile((HANDLE)f, buf, r, &t, NULL) || r != t) return 0;\n#else\n    if(lseek((intptr_t)f, (off_t)off, SEEK_SET) != (off_t)off || read((intptr_t)f, buf, (ssize_t)size) != (ssize_t)size) return 0;\n#endif\n    return 1;\n}\n\n/**\n * Write to the device\n */\nint dev_write(void *f, uint64_t off, void *buf, uint32_t size)\n{\n#ifdef __WIN32__\n    uint8_t sec[512];\n    DWORD r = size & ~511, t;\n    LARGE_INTEGER pos;\n    pos.QuadPart = off;\n#endif\n    if(verbose > 2) printf(\"simpleboot: dev_write offset %08lx %d bytes\\n\", (long unsigned int)off, size);\n#ifdef __WIN32__\n    SetFilePointerEx((HANDLE)f, pos, NULL, FILE_BEGIN);\n    if(!WriteFile((HANDLE)f, buf, r, &t, NULL) || r != t) return 0;\n    if(r < size) {\n        /* easyboot issue #7: Win reports an 0x57 ERROR_INVALID_PARAMETER if size isn't multiple of 512 */\n        memset(sec, 0, 512); memcpy(sec, buf + r, size - r); r = 512;\n        if(!WriteFile((HANDLE)f, sec, r, &t, NULL) || r != t) return 0;\n    }\n#else\n    if(lseek((intptr_t)f, (off_t)off, SEEK_SET) != (off_t)off || write((intptr_t)f, buf, (ssize_t)size) != (ssize_t)size) return 0;\n#endif\n    return 1;\n}\n\n/**\n * Close a device\n */\nvoid dev_close(void *f)\n{\n#ifdef __WIN32__\n    CloseHandle((HANDLE)f);\n#else\n    if(S_ISBLK(dev_st.st_mode)) fdatasync((intptr_t)f);\n    close((intptr_t)f);\n#endif\n}\n\n/**\n * Check the configuration file for validity and correctness\n */\nvoid check_config(char *in)\n{\n    uint8_t *tmp;\n    int line = 1, i, w, h, b, bkp;\n    char *buf, *end, *s, *e, *a, *n, *d, fn[sizeof(full)];\n\n    skipbytes = strlen(in) + 1;\n    strncpy(full, in, sizeof(full)-1);\n    strncat(full, \"/simpleboot.cfg\", sizeof(full)-1);\n    buf = (char*)readfileall(full, 0);\n    if(!buf) return;\n\n    for(s = buf, end = buf + read_size; s < end && *s; s = e) {\n        /* find beginning of a line */\n        while(s < end && *s && (*s == '\\r' || *s == '\\n' || *s == ' ' || *s == '\\t')) { if(*s == '\\n') { line++; } s++; }\n        for(a = s; a < end && *a && *a != ' ' && *a != '\\r' && *a != '\\n'; a++);\n        for(e = a; e < end && *e && *e != '\\r' && *e != '\\n'; e++);\n        while(a < e && *a == ' ') a++;\n        for(n = a; n < e && *n && *n != ' ' && *n != '\\r' && *n != '\\n'; n++)\n            if(*n == '\\\\' && n[1] == ' ') n++;\n        /* 's' points to the start of the command,\n         * 'a' to the first argument,\n         * 'n' to the end of the first argument (next argument almost), and\n         * 'e' to the end of the line */\n        if(!memcmp(s, \"backup\", 6)) { bkp = 1; s += 6; } else bkp = 0;\n        if(!memcmp(s, \"multicore\", 9)) { if(bkp) bkpsmp++; else smp++; } else\n        if(!memcmp(s, \"verbose\", 7)) {\n            i = atoi(a);\n            if(verbose > 1 && (i < 0 || i > 3)) {\n                fprintf(stderr, \"%ssimpleboot: bad verbosity level '%s' line %u\\r\\n\", verbose ? \"\\n\" : \"\", full, line);\n                exit(1);\n            }\n        } else\n        if(!memcmp(s, \"framebuffer\", 11)) {\n            if(bkp) bkpfb = 1;\n            if(verbose > 1) {\n                w = atoi(a); a = n;\n                while(a < e && *a == ' ') a++;\n                h = atoi(a);\n                for(; a < e && *a && *a != ' ' && *a != '\\r' && *a != '\\n'; a++);\n                while(a < e && *a == ' ') a++;\n                b = atoi(a);\n                if(w < 320 || w > 65536 || h < 200 || h > 65536 || b < 15 || b > 32) {\n                    fprintf(stderr, \"%ssimpleboot: bad framebuffer line in '%s' line %u\\r\\n\", verbose ? \"\\n\" : \"\", full, line);\n                    exit(1);\n                }\n                /* only store the config if the command isn't backup prefixed */\n                if(!bkp) { fb_w = w; fb_h = h; fb_bpp = b; }\n            }\n        } else\n        if(!memcmp(s, \"bootsplash\", 10)) {\n            if(bkp) bkplogo = 1;\n            if(verbose > 1) {\n                if(*a == '#') {\n                    for(a++, i = 0; i < 6; i++)\n                        if(!((a[i] >= '0' && a[i] <= '9') || (a[i] >= 'a' && a[i] <= 'f') || (a[i] >= 'A' && a[i] <= 'F'))) {\n                            *n = 0;\n                            fprintf(stderr, \"%ssimpleboot: not a valid hex color '%s' in '%s' line %u\\r\\n\", verbose ? \"\\n\" : \"\", a,\n                                full, line);\n                            exit(1);\n                        }\n                    while(n < e && *n == ' ') n++;\n                    a = n;\n                }\n                if(a < e) {\n                    memcpy(fn, full, skipbytes); memcpy(fn + skipbytes, a, e - a); fn[skipbytes + (uintptr_t)(e - a)] = 0;\n                    if(!(tmp = readfileall(fn, 0))) {\n                        fprintf(stderr, \"%ssimpleboot: unable to load logo '%s' in '%s' line %u\\r\\n\", verbose ? \"\\n\" : \"\",\n                            fn, full, line);\n                        exit(1);\n                    }\n                    if(!tmp || tmp[0] || tmp[1] != 1 || tmp[2] != 9 || tmp[3] || tmp[4] || (tmp[7] != 24 && tmp[7] != 32)) {\n                        free(tmp);\n                        fprintf(stderr,\n                            \"%ssimpleboot: '%s' is not an indexed RLE compressed TGA image in '%s' line %u\\r\\n\",\n                            verbose ? \"\\n\" : \"\", fn, full, line);\n                        exit(1);\n                    }\n                    free(tmp);\n                }\n            }\n        } else\n        if(!memcmp(s, \"kernel\", 6)) {\n            if(!bkp) {\n                if(kernel < (char*)loader_x86_efi || kernel >= (char*)loader_x86_efi + sizeof(loader_x86_efi)) {\n                    fprintf(stderr, \"%ssimpleboot: kernel already defined in '%s' line %u\\r\\n\", verbose ? \"\\n\" : \"\", full, line);\n                    exit(1);\n                }\n                kernel = (char*)malloc(n - a + 1); kernelfree = 1;\n                if(!kernel) { fprintf(stderr, \"%ssimpleboot: unable to allocate memory\\r\\n\", verbose ? \"\\n\" : \"\"); exit(1); }\n                for(d = kernel, s = a; s < n; s++) {\n                    if(*s == '\\\\' && s[1] == ' ') s++;\n                    *d++ = *s;\n                }\n                *d = 0;\n            } else\n            if(verbose > 1) {\n                bkpkrnl = 1;\n                memcpy(fn, full, skipbytes); memcpy(fn + skipbytes, a, n - a); fn[skipbytes + (uintptr_t)(n - a)] = 0;\n                (void)readfileall(fn, 1);\n                if(!read_size) {\n                    fprintf(stderr, \"%ssimpleboot: unable to load backup kernel '%s' in '%s' line %u\\r\\n\", verbose ? \"\\n\" : \"\",\n                        fn, full, line);\n                    exit(1);\n                }\n            }\n        } else\n        if(!memcmp(s, \"module\", 6)) {\n            if(verbose > 1) {\n                memcpy(fn, full, skipbytes); memcpy(fn + skipbytes, a, n - a); fn[skipbytes + (uintptr_t)(n - a)] = 0;\n                (void)readfileall(fn, 1);\n                if(!read_size) {\n                    fprintf(stderr, \"%ssimpleboot: unable to load module '%s' in '%s' line %u\\r\\n\", verbose ? \"\\n\" : \"\",\n                        fn, full, line);\n                    exit(1);\n                }\n            }\n            if(bkp) num_bkp++; else num_mod++;\n        } else\n        if(*s && *s != '#' && *s != '\\r' && *s != '\\n') {\n            if(verbose > 1) {\n                while(a > s && a[-1] == ' ') { a--; } *a = 0;\n                fprintf(stderr, \"%ssimpleboot: unknown command '%s' in '%s' line %u\\r\\n\", verbose ? \"\\n\" : \"\", s, full, line);\n                exit(1);\n            }\n        }\n    }\n    free(buf);\n    skipbytes = 0;\n}\n\n/**\n * Detect the kernel\n */\nuint8_t *detect_kernel(char *in, uint8_t **exe, int *arch)\n{\n    uint8_t *ptr, *ptr2;\n    linux_boot_t *hdr;\n\n    if(!in || !*in || !kernel || !*kernel) return NULL;\n    *exe = NULL; *arch = 0;\n    strncpy(full, in, sizeof(full)-1);\n    strncat(full, \"/\", sizeof(full)-1);\n    strncat(full, kernel, sizeof(full)-1);\n    ptr = readfileall(full, 0);\n    if(ptr) {\n        hdr = (linux_boot_t*)(ptr + 0x1f1);\n        if(hdr->boot_flag == 0xAA55 && !memcmp(&hdr->header, HDRSMAG, 4)) { *exe = ptr + 0x1f1; return ptr; } else\n        if(((mz_hdr*)ptr)->magic == MZ_MAGIC && ((pe_hdr*)(ptr + ((mz_hdr*)ptr)->peaddr))->magic == PE_MAGIC) {\n            *exe = ptr + ((mz_hdr*)ptr)->peaddr;\n            *arch = ((pe_hdr*)*exe)->machine == IMAGE_FILE_MACHINE_ARM64 ? 1 : 0;\n            return ptr;\n        } else\n        if(!memcmp(((Elf32_Ehdr*)ptr)->e_ident, ELFMAG, 4)) {\n            *exe = ptr;\n            *arch = ((Elf32_Ehdr*)*exe)->e_machine == EM_AARCH64 ? 1 : 0;\n            return ptr;\n        } else {\n            for(ptr2 = ptr; ptr2 < ptr + read_size - sizeof(Elf32_Ehdr); ptr2 += 16)\n                if(!memcmp(((Elf32_Ehdr*)ptr2)->e_ident, ELFMAG, 4)) {\n                    *exe = ptr2;\n                    *arch = ((Elf32_Ehdr*)*exe)->e_machine == EM_AARCH64 ? 1 : 0;\n                    return ptr;\n                }\n        }\n        free(ptr); ptr = NULL;\n    }\n    return ptr;\n}\n\n/**\n * Convert hex string into integer\n */\nuint64_t gethex(char *ptr, int len)\n{\n    uint64_t ret = 0;\n    for(;len--;ptr++) {\n        if(*ptr>='0' && *ptr<='9') {          ret <<= 4; ret += (unsigned int)(*ptr-'0'); }\n        else if(*ptr >= 'a' && *ptr <= 'f') { ret <<= 4; ret += (unsigned int)(*ptr-'a'+10); }\n        else if(*ptr >= 'A' && *ptr <= 'F') { ret <<= 4; ret += (unsigned int)(*ptr-'A'+10); }\n        else break;\n    }\n    return ret;\n}\n\n/**\n * Parse a GUID in string into binary representation\n */\nvoid getguid(char *ptr, guid_t *guid)\n{\n    int i;\n\n    if(!ptr || !*ptr || ptr[8] != '-' || ptr[13] != '-' || ptr[18] != '-') return;\n    memset(guid, 0, sizeof(guid_t));\n    guid->Data1 = gethex(ptr, 8); ptr += 9;\n    guid->Data2 = gethex(ptr, 4); ptr += 5;\n    guid->Data3 = gethex(ptr, 4); ptr += 5;\n    guid->Data4[0] = gethex(ptr, 2); ptr += 2;\n    guid->Data4[1] = gethex(ptr, 2); ptr += 2; if(*ptr == '-') ptr++;\n    for(i = 2; i < 8; i++, ptr += 2) guid->Data4[i] = gethex(ptr, 2);\n}\n\n/**\n * Print usage\n */\nvoid usage(char *cmd)\n{\n    char *tmp = strrchr(cmd,\n#ifdef __WIN32__\n    '\\\\'\n#else\n    '/'\n#endif\n    );\n    if(!tmp) tmp = cmd; else tmp++;\n\n    printf(\"Simpleboot installer v%s, Copyright (c) 2023 bzt, MIT license\\r\\nhttps://codeberg.org/bzt/simpleboot\\r\\n\\r\\n\", sbver);\n    printf(\"%s [-v|-vv] [-k <name>] [-i <name>] [-m|-g] [-s <mb>] [-b <mb>]\\r\\n\", tmp);\n    printf(\"   [-u <guid>] [-p <t> <u> <i>] [-r|-e] [-c] <indir> <outfile|device>\\r\\n\\r\\n\");\n    printf(\"  -v, -vv         increase verbosity / validation\\r\\n\");\n    printf(\"  -k <name>       set the default kernel filename (defaults to 'kernel')\\r\\n\");\n    printf(\"  -i <name>       set the default initrd filename (by default none)\\r\\n\");\n    printf(\"  -m              set multicore to enabled (by default disabled)\\r\\n\");\n    printf(\"  -g              set 32-bit GRUB compatibility mode (by default disabled)\\r\\n\");\n    printf(\"  -s <mb>         set the disk image size in Megabytes (defaults to 35M)\\r\\n\");\n    printf(\"  -b <mb>         set the boot partition size in Megabytes (defaults to 33M)\\r\\n\");\n    printf(\"  -u <guid>       set the boot partition unique identifier (defaults to random)\\r\\n\");\n    printf(\"  -p <t> <u> <i>  add an extra partition (type guid, unique guid, imagefile)\\r\\n\");\n    printf(\"  -r              place loaders in ROM (by default save them into the image)\\r\\n\");\n    printf(\"  -e              add El Torito Boot Catalog (BIOS / EFI CDROM boot support)\\r\\n\");\n    printf(\"  -c              always create a new image file even if it exists\\r\\n\");\n    printf(\"  indir           use the contents of this directory for the boot partition\\r\\n\");\n    printf(\"  outfile         output image file or device name\\r\\n\");\n    printf(\"\\r\\n Flags -k, -i, -m only needed if you don't have a simpleboot.cfg file.\\r\\n\");\n    printf(\" Loader versions: %08x (x86), %08x (rpi)\\r\\n\\r\\n\", ts_x86, ts_rpi);\n    exit(1);\n}\n\n/**\n * Main function\n */\nint simpleboot_main(int argc, char **argv)\n{\n    time_t t;\n    int64_t siz;\n    uint32_t clu, loader_lba = 0;\n    int i, j, arch = 0, docalc = 1, eltorito = 0, rom = 0, create = 0, smpwarn = 0, defsmp = 0, fgrub = 0;\n    char *defkernel = NULL, *definitrd = NULL;\n    guid_t espGuid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID;\n    uint8_t *ptr = loader_x86_efi + ((mz_hdr*)loader_x86_efi)->peaddr, *ph, *exe = NULL;\n    pe_sec *sec = (pe_sec*)(ptr + ((pe_hdr*)ptr)->opt_hdr_size + 24);\n    fb_boot_t *fbcat;\n    uint32_t o, sectop = 0;\n    linux_boot_t *hdr;\n\n    /* get random GUIDs */\n    t = time(NULL); fat_ts = gmtime(&t); srand(t);\n    i = rand(); memcpy(&((uint8_t*)&dguid)[0], &i, 4); i = rand(); memcpy(&((uint8_t*)&dguid)[4], &i, 4);\n    i = rand(); memcpy(&((uint8_t*)&dguid)[8], &i, 4); i = rand(); memcpy(&((uint8_t*)&dguid)[12], &i, 4);\n    i = rand(); memcpy(&((uint8_t*)&pguid)[0], &i, 4); i = rand(); memcpy(&((uint8_t*)&pguid)[4], &i, 4);\n    i = rand(); memcpy(&((uint8_t*)&pguid)[8], &i, 4); i = rand(); memcpy(&((uint8_t*)&pguid)[12], &i, 4);\n\n    /* get loader versions */\n    ts_x86 = ((pe_hdr*)ptr)->timestamp;\n    ts_rpi = crc32_calc(loader_rpi_bin, sizeof(loader_rpi_bin));\n\n    /* parse command line */\n    for(i = 1; i < argc && argv[i]; i++)\n        if(argv[i][0] == '-') {\n            switch(argv[i][1]) {\n                case 'k': defkernel = argv[++i]; break;\n                case 'i': definitrd = argv[++i]; break;\n                case 's': disksize = atoi(argv[++i]); if(docalc) { partsize = disksize - 2; } docalc = 0; break;\n                case 'b': partsize = atoi(argv[++i]); docalc = 0; break;\n                case 'u': getguid(argv[++i], &pguid); break;\n                case 'p':\n                    if(i + 3 >= argc || nump + 1 >= (int)(sizeof(ptguid)/sizeof(ptguid[0]))) usage(argv[0]);\n                    getguid(argv[++i], &ptguid[nump]); getguid(argv[++i], &puguid[nump]); pfile[nump++] = argv[i];\n                break;\n                default:\n                    for(j = 1; argv[i][j]; j++)\n                        switch(argv[i][j]) {\n                            case 'v': verbose++; break;\n                            case 'm': defsmp++; break;\n                            case 'g': fgrub++; break;\n                            case 'r': rom = 1; break;\n                            case 'e': eltorito = 1; break;\n                            case 'c': create = 1; break;\n                            default: usage(argv[0]); break;\n                        }\n                break;\n            }\n        } else\n        if(!in) in = argv[i]; else\n        if(!out) out = argv[i]; else\n            usage(argv[0]);\n    if(!out) usage(argv[0]);\n\n    /* self-integrity check */\n    for(i = 0, sectop = 0; i < (int)sizeof(loader_rpi_bin) - 128; i += 16)\n        if(!memcmp(loader_rpi_bin + i, \"kernel\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 16)) {\n            /* patch default filenames in the loader */\n            if(defkernel && *defkernel) strncpy((char*)loader_rpi_bin + i, defkernel, 63);\n            if(definitrd && *definitrd) strncpy((char*)loader_rpi_bin + i + 64, definitrd, 62);\n            if(defsmp) loader_rpi_bin[i + 127] = 1;\n            if(fgrub) loader_rpi_bin[i + 127] = 2;\n            sectop = *((uint32_t*)(loader_rpi_bin + i + 128 + 4));\n            if(verbose > 2) printf(\"loader_rpi _bss_start %08x _bss_end %08x\\r\\n\", *((uint32_t*)(loader_rpi_bin + i + 128)),\n                sectop);\n            break;\n        }\n    if(i >= (int)sizeof(loader_rpi_bin) - 128 || !sectop || sectop >= 0xA0000) {\n        fprintf(stderr, \"simpleboot: invalid inlined loader_rpi???\\r\\n\");\n        return 1;\n    }\n    for(i = 0, sectop = 0; i < ((pe_hdr*)ptr)->sections; i++, sec++) {\n        if(!strcmp(sec->name, \".rdata\")) {\n            for(kernel = (char*)loader_x86_efi + sec->raddr; strcmp(kernel, \"kernel\"); kernel++);\n            /* patch default filenames in the loader */\n            if(defkernel && *defkernel) strncpy(kernel, defkernel, 63);\n            if(definitrd && *definitrd) strncpy(kernel + 64, definitrd, 62);\n            if(defsmp) kernel[127] = 1;\n            if(fgrub) kernel[127] = 2;\n        }\n        o = sec->vaddr + 0x8000 - ((pe_hdr*)ptr)->code_base + sec->vsiz;\n        if(o > sectop) sectop = o;\n        if(verbose > 2) printf(\"loader_x86 section '%-8s' %08x %5u rel %08x top %08x\\r\\n\", sec->name, sec->vaddr, sec->vsiz,\n            o - sec->vsiz, sectop);\n    }\n    /* max size comes from boot_x86.asm line 72 times two, sectop is the same plus the bss size */\n    if(sizeof(loader_x86_efi) > 120 * 2 * 512 || !sectop || sectop > 0x20000 || !kernel) {\n        fprintf(stderr, \"simpleboot: invalid inlined loader_x86???\\r\\n\");\n        return 1;\n    }\n\n    /* calculate the required minimum partition size */\n    totsize = 0;\n    parsedir(in, 0, 1, 0);\n    skipbytes = 0;\n    if(totsize < 1) {\n        fprintf(stderr, \"simpleboot: input directory not found '%s'\\r\\n\", in);\n        return 1;\n    }\n    /* add FAT table size and round up to Megabytes */\n    totsize += (8 + (((totsize / 512) * 4) / 512) * 2) * 512;\n    totsize = (totsize + 1024 * 1024 - 1) & ~(1024 * 1024 - 1);\n    if(totsize / 1024 > 2047 * 1024) {\n        fprintf(stderr, \"simpleboot: more than 2 Gb contents in '%s'\\r\\n\", in);\n        return 1;\n    }\n\n    /* check configuration and kernel */\n    i = strlen(in);\n    if(in[i - 1] == '/') in[i - 1] = 0;\n    check_config(in);\n    if(!(ptr = detect_kernel(in, &exe, &arch))) { fprintf(stderr, \"simpleboot: kernel file '%s' not found\\r\\n\", full); return 1; }\n    if(rom && arch) { fprintf(stderr, \"simpleboot: legacy ROM booting only supported on x86\\r\\n\"); return 1; }\n    if(rom && eltorito) { fprintf(stderr, \"simpleboot: El Torito and legacy ROM booting are mutually exclusive\\r\\n\"); return 1; }\n\n    /* create image if it doesn't exists */\n    if(create || !(f = dev_open(out))) {\n        /* check partition and disk sizes */\n        if(partsize == 2048) partsize = 2047;\n        if(partsize < 33 || partsize > 2047) {\n            fprintf(stderr, \"simpleboot: bad partition size, must be between 33 Mb and 2 Gb\\r\\n\");\n            return 1;\n        }\n        disksize *= 2048 * 512;\n        partsize *= 2048 * 512;\n        /* expand required minimum partition size (only if neither \"-p\" nor \"-d\" given) */\n        if(docalc && totsize > partsize) {\n            partsize = totsize;\n            if(verbose) printf(\"simpleboot: expanding partition size to %lu Mb\\r\\n\",\n                (unsigned long int)(partsize / 1024L / 1024L));\n        }\n        siz = partsize + (FIRST_PARTITION + GPT_SECTORS + 1) * 512;\n        for(i = 0; i < nump; i++) {\n            if(pfile[i]) { readfileall(pfile[i], 1); psize[i] = read_size; }\n            siz += (psize[i] + 1024*1024-1) & ~(1024*1024-1);\n        }\n        if(disksize < siz) {\n            disksize = siz;\n            if(verbose) printf(\"simpleboot: expanding disk size to %lu Mb\\r\\n\",\n                (unsigned long int)(disksize / 1024 / 1024));\n        }\n#ifdef __WIN32__\n        MultiByteToWideChar(CP_UTF8, 0, out, -1, szFile, PATH_MAX);\n        for(i = 0; szFile[i]; i++) if(szFile[i] == L'/') szFile[i] = L'\\\\';\n        f = CreateFileW(szFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\n#else\n        umask(0111);\n        f = (void*)(intptr_t)open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666);\n#endif\n        if(!f) { fprintf(stderr, \"simpleboot: unable to write '%s'\\r\\n\", out); return 2; }\n\n        imgsize = ((FIRST_PARTITION + 2) << 9) + partsize;\n        if(!(img = (uint8_t*)malloc(imgsize))) { fprintf(stderr, \"simpleboot: unable to allocate memory\\r\\n\"); return 1; }\n        /* generate disk image */\n        status(\"Formatting...\", NULL);\n        memset(img, 0, imgsize); fs_base = img + FIRST_PARTITION * 512;\n        gpt_create();\n        if(eltorito) etbc_create();\n        fat_format();\n        if(!dev_write(f, 0, img, imgsize) || !dev_write(f, disksize - sizeof(img_tail), img_tail, sizeof(img_tail))) {\n            dev_close(f); free(img); fprintf(stderr, \"simpleboot: unable to write '%s'\\r\\n\", out); return 2;\n        }\n        free(img); img = NULL;\n        /* write optional extra partition(s) */\n        for(siz = (FIRST_PARTITION * 512 + partsize + 1024*1024-1) & ~(1024*1024-1), i = 0; i < nump; i++)\n            if(pfile[i] && (pdata = (uint8_t*)readfileall(pfile[i], 0))) {\n                if(!dev_write(f, siz, pdata, psize[i])) {\n                    dev_close(f); free(pdata); fprintf(stderr, \"simpleboot: unable to write '%s'\\r\\n\", out); return 2;\n                }\n                free(pdata); pdata = NULL;\n                siz += (psize[i] + 1024*1024-1) & ~(1024*1024-1);\n            }\n        dev_close(f);\n        if(!(f = dev_open(out))) { fprintf(stderr, \"simpleboot: unable to open '%s'\\r\\n\", out); return 2; }\n    }\n\n    if(!(img = (uint8_t*)malloc(65536+1024))) { fprintf(stderr, \"simpleboot: unable to allocate memory\\r\\n\"); return 1; }\n    fs_base = img + 1024; bpb = (esp_bpb_t*)fs_base;\n\n    /* locate EFI System Partition */\n    if(!dev_read(f, 0, img, 2 * 512)) {\n        fprintf(stderr, \"simpleboot: unable to read '%s'\\r\\n\", out); goto err;\n    }\n    if(!memcmp(img + 512, EFI_PTAB_HEADER_ID, 8)) {\n        /* found GPT */\n        if(verbose) printf(\"\\r\\nGUID Partitioning Table found at LBA %lu\\r\\n\",\n            (long unsigned int)((gpt_header_t*)(img + 512))->PartitionEntryLBA);\n        memcpy(&dguid, &((gpt_header_t*)(img + 512))->DiskGUID, sizeof(guid_t));\n        j = ((gpt_header_t*)(img + 512))->SizeOfPartitionEntry;\n        /* look for ESP in the first 8 sectors only. Should be the very first entry anyway */\n        if(!dev_read(f, ((gpt_header_t*)(img + 512))->PartitionEntryLBA << 9, fs_base, 8 * 512)) goto noesp;\n        for(i = 0; i + j <= 8 * 512; i += j)\n            if(!memcmp(&((gpt_entry_t*)&fs_base[i])->PartitionTypeGUID, &espGuid, sizeof(guid_t))) {\n                boot_lba = ((gpt_entry_t*)&fs_base[i])->StartingLBA;\n                partsize = (((gpt_entry_t*)&fs_base[i])->EndingLBA - ((gpt_entry_t*)&fs_base[i])->StartingLBA + 1) << 9;\n                memcpy(&pguid, &((gpt_entry_t*)&fs_base[i])->UniquePartitionGUID, sizeof(guid_t));\n                /* create hybrid MBR Partitioning scheme */\n                if(img[0x1C2] != 0xC || *((uint32_t*)(img+0x1C0+6)) != boot_lba || *((uint32_t*)(img+0x1C0+10)) != partsize >> 9) {\n                    img[0x1C2] = 0xC;\n                    *((uint32_t*)(img+0x1C0+6)) = boot_lba;\n                    *((uint32_t*)(img+0x1C0+10)) = partsize >> 9;\n                    chs(boot_lba, img+0x1BE);\n                    chs(boot_lba+partsize/512-1, img+0x1C2);\n                }\n                img[0x1BE] = 0x80; img[0x1CE] = img[0x1DE] = img[0x1EE] = 0;\n                if(!*((uint32_t*)(img+0x1B8))) memcpy(img+0x1B8, &dguid.Data1, 4);\n                break;\n            }\n    } else\n    if(img[510] == 0x55 && img[511] == 0xAA) {\n        /* fallback to MBR partitioning scheme */\n        if(verbose) printf(\"\\r\\nPMBR DOS Partitioning Table found at LBA 0\\r\\n\");\n        for(i = 0x1c0; i < 510; i += 16)\n            if(img[i - 2] == 0x80/*active*/ && (img[i + 2] == 0xC/*FAT32*/ || img[i + 2] == 0xEF/*ESP*/)) {\n                boot_lba = (uint64_t)(*((uint32_t*)(img + i + 6)));\n                partsize = (uint64_t)*((uint32_t*)(img + i + 10)) << 9;\n                break;\n            }\n        j = 0;\n    }\n    if(!boot_lba || !dev_read(f, boot_lba << 9, fs_base, 65536) || bpb->bps != 512 || !bpb->spc || bpb->spf16 || !bpb->spf32 ||\n      fs_base[0x32] > 127) {\nnoesp:  if(verbose) printf(\"BPB bps %u spc %u spf16 %u spf32 %u BPB copy LBA %u\\r\\n\", bpb->bps, bpb->spc, bpb->spf16, bpb->spf32,\n            fs_base[0x32]);\n        fprintf(stderr, \"simpleboot: unable to locate boot partition in '%s'\\r\\n\", out); goto err;\n    }\n    if(verbose) {\n        printf(\"Boot partition found at LBA %lu\", (long unsigned int)boot_lba);\n        if(j) printf(\", UUID: %08X-%04X-%04X-%02X%02X%02X%02X%02X%02X%02X%02X\\r\\n\", pguid.Data1, pguid.Data2,\n                pguid.Data3, pguid.Data4[0], pguid.Data4[1], pguid.Data4[2], pguid.Data4[3], pguid.Data4[4], pguid.Data4[5],\n                pguid.Data4[6], pguid.Data4[7]);\n        else printf(\"\\r\\n\");\n        if(verbose > 1)\n            printf(\"BPB bps %u spc %u spf16 %u spf32 %u BPB copy LBA %u\\r\\n\", bpb->bps, bpb->spc, bpb->spf16, bpb->spf32, fs_base[0x32]);\n    }\n    /* add loaders' size, 2 for the directories and 1 plus per loader because they are not multiple of cluster size */\n    if(totsize + 4 * fat_bpc + (int64_t)sizeof(loader_x86_efi) + (int64_t)sizeof(loader_rpi_bin) > partsize) {\n        fprintf(stderr, \"simpleboot: not enough free space on boot partition\\r\\n\"); goto err;\n    }\n\n    if(!(fat_fat32 = (uint32_t*)malloc(bpb->spf32 << 9))) {\n        fprintf(stderr, \"simpleboot: unable to allocate memory\\r\\n\"); goto err;\n    }\n    fat_nextcluster = *((uint32_t*)(fs_base + 0x3EC)) + 2; fat_numclu = partsize >> 9;\n    fat_freeclu = (int64_t)*((uint32_t*)(fs_base + 0x3E8));\n    fat_spf = bpb->spf32; fat_bpc = bpb->spc << 9; data_lba = bpb->spf32 * bpb->nf + bpb->rsc - 2 * bpb->spc + boot_lba;\n    if(!(cluster = (uint8_t*)malloc(fat_bpc))) {\n        fprintf(stderr, \"simpleboot: unable to allocate memory\\r\\n\"); goto err;\n    }\n    /* load FAT */\n    if(!dev_read(f, (bpb->rsc + boot_lba) << 9, fat_fat32, fat_spf << 9)) {\n        fprintf(stderr, \"simpleboot: unable to read '%s'\\r\\n\", out); goto err;\n    }\n\n    /* add files from the given directory */\n    parsedir(in, 0, 0, bpb->rc);\n\n    /* add loaders */\n    if(!rom) {\n        /* add a FOSSBIOS Boot Catalog after the GPT header */\n        fbcat = (fb_boot_t*)(img + 512 + 128);\n        fbcat->magic[0] = 0xB0; fbcat->magic[1] = 0x07; fbcat->magic[2] = 0xCA; fbcat->magic[3] = 0x7A;\n        fbcat->magic[4] = 0x10; fbcat->magic[5] = 0xC0; fbcat->numentries = 2;\n\n        /* stage1 is not a file, it's in the boot sector */\n        memcpy(img, boot_x86_bin, 0x1b8); img[0x1FE] = 0x55; img[0x1FF] = 0xAA;\n        /* we can't use fat_add() for stage2, because it must be defragmented, stored on contiguous clusters */\n        if(fat_dirent(bpb->rc, 1, \"EFI\", 1, &clu, 0) && fat_dirent(clu, 1, \"BOOT\", 1, &clu, 0) &&\n          fat_dirent(clu, 2, \"BOOTX64.EFI\", 0, &clu, sizeof(loader_x86_efi)) &&\n          dev_write(f, (data_lba + clu * bpb->spc) << 9, loader_x86_efi, sizeof(loader_x86_efi))) {\n            fbcat->entries[0].arch = 0;     /* x86 */\n            fbcat->entries[0].wordsize = 8; /* 64-bit */\n            fbcat->entries[0].lba = *((uint32_t*)(img + 0x1b0)) = loader_lba = data_lba + clu * bpb->spc;\n        } else { fprintf(stderr, \"simpleboot: unable to write x86 loader '%s'\\r\\n\", out); goto err; }\n\n        /* we can't use fat_add() for stage2, because it must be defragmented, stored on contiguous clusters */\n        if(fat_dirent(bpb->rc, 2, \"KERNEL8.IMG\", 0, &clu, sizeof(loader_rpi_bin)) &&\n          dev_write(f, (data_lba + clu * bpb->spc) << 9, loader_rpi_bin, sizeof(loader_rpi_bin))) {\n            fbcat->entries[1].arch = 1;     /* ARM */\n            fbcat->entries[1].wordsize = 8; /* 64-bit */\n            fbcat->entries[1].lba = data_lba + clu * bpb->spc;\n        } else { fprintf(stderr, \"simpleboot: unable to write RPi loader '%s'\\r\\n\", out); goto err; }\n\n        /* calculate checksum */\n        for(i = j = 0; i < 3 * 8; i++) { j += *(((uint8_t*)fbcat) + i); }\n        fbcat->chksum = 0x100 - j;\n    }\n\n    /* write out metadata */\n    fat_finish();\n    if(!dev_write(f, boot_lba << 9, bpb, bpb->rsc << 9)) {\n        fprintf(stderr, \"simpleboot: unable to write BPB to '%s'\\r\\n\", out); goto err;\n    }\n    for(i = 0; (uint8_t)i < bpb->nf; i++) {\n        data_lba = (fat_spf * i + bpb->rsc + boot_lba) << 9; j = fat_spf << 9;\n        if(!dev_write(f, data_lba, fat_fat32, j)) {\n            fprintf(stderr, \"simpleboot: unable to write FAT to '%s'\\r\\n\", out); goto err;\n        }\n    }\n    if(!dev_write(f, 0, img, 1024)) {\n        fprintf(stderr, \"simpleboot: unable to write PMBR to '%s'\\r\\n\", out); goto err;\n    }\n    if(verbose) {\n        clu = (fat_numclu - fat_freeclu) * 1000 / fat_numclu;\n        printf(\"Clusters total %u last %u free %u %u.%u%%\\r\\n\", (uint32_t)fat_numclu, (uint32_t)fat_nextcluster,\n            (uint32_t)fat_freeclu, clu / 10, clu % 10);\n    }\n\n    free(img);\n    free(fat_fat32);\n    free(cluster);\n    dev_close(f);\n    if(rom) rom_create(out);\n\n    if(verbose) {\n        printf(\"\\r%-40s\\n\", \"OK\");\n        if(verbose > 1) {\n            /* print out detailed information */\n            printf(\"\\r\\nPartition UUID:    %08X-%04X-%04X-%02X%02X%02X%02X%02X%02X%02X%02X\\r\\n\", pguid.Data1, pguid.Data2,\n                pguid.Data3, pguid.Data4[0], pguid.Data4[1], pguid.Data4[2], pguid.Data4[3], pguid.Data4[4], pguid.Data4[5],\n                pguid.Data4[6], pguid.Data4[7]);\n            printf(\"Boot partition:    start LBA %u, size %u sectors\\r\\n\", FIRST_PARTITION, (uint32_t)(partsize >> 9));\n            switch(arch) {\n                case 1:\n                    printf(\"Loader (rpi):      \\\"kernel8.img\\\" (%08x)\\r\\n\", ts_rpi);\n                break;\n                default:\n                    if(rom)\n                        printf(\"Loader (x86):      in ROM, size %u bytes (%08x)\\r\\n\",\n                            (uint32_t)(512 + ((sizeof(loader_x86_efi) + 511) & ~511)), ts_x86);\n                    else\n                        printf(\"Loader (x86):      start LBA %u, size %u sectors (%08x)\\r\\n\", loader_lba,\n                            (uint32_t)((sizeof(loader_x86_efi) + 511) >> 9), ts_x86);\n                break;\n            }\n            printf(\"Kernel:            \\\"%s\\\"\\r\\n\"\n                   \"Format:            \", kernel);\n            if(exe) {\n                hdr = (linux_boot_t*)exe;\n                if(hdr->boot_flag == 0xAA55 && !memcmp(&hdr->header, HDRSMAG, 4)) {\n                    if(smp) smpwarn = 1;\n                    printf(\"Kernel with Linux/x86 Boot Protocol v%u.%u\", hdr->version >> 8, hdr->version & 0xff);\n                    if(hdr->version < 0x20c)\n                        printf(\"\\r\\n                   (invalid, boot protocol version %x too old)\", hdr->version);\n                    else\n                    if((hdr->pref_address + hdr->init_size) >> 32L)\n                        printf(\"\\r\\n                   (invalid, load address above 4G)\");\n                    else {\n                        printf(\"\\r\\n                   %08x - %08x zero page + cmdline\"\n                               \"\\r\\n                   %08x - %08x kernel image (setup_sects %d, file offs %x)\",\n                                0x90000, 0x9A000, (uint32_t)hdr->pref_address, (uint32_t)hdr->pref_address + hdr->init_size,\n                                hdr->setup_sects, ((hdr->setup_sects ? hdr->setup_sects : 4) + 1) * 512);\n                    }\n                } else\n                if(!memcmp(((Elf32_Ehdr*)exe)->e_ident, ELFMAG, 4)) {\n                    /* 32-bit mode only supported with ELF Multiboot2 kernels */\n                    j = ((Elf32_Ehdr*)exe)->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;\n                    if(smp && j != 64) smpwarn = 1;\n                    printf(\"Multiboot2 ELF%u kernel (%s)\", j, j == 32 && ((Elf32_Ehdr*)exe)->e_machine == EM_386 ? \"i386\" :\n                        (j == 64 && ((Elf32_Ehdr*)exe)->e_machine == EM_X86_64 ? \"x86_64\" :\n                        (j == 64 && ((Elf32_Ehdr*)exe)->e_machine == EM_AARCH64 ? \"Aarch64\" : \"invalid architecture\")));\n                    if(j == 64) {\n                        ph = exe + ((Elf64_Ehdr*)exe)->e_phoff;\n                        for(i = 0; i < ((Elf64_Ehdr*)exe)->e_phnum; i++, ph += ((Elf64_Ehdr*)exe)->e_phentsize) {\n                            if(((Elf64_Phdr*)ph)->p_type == PT_DYNAMIC)\n                                printf(\"\\r\\n                   (invalid, dynamically linked kernel?)\");\n                            else\n                            if(((Elf64_Phdr*)ph)->p_type == PT_INTERP)\n                                printf(\"\\r\\n                   (invalid, not freestanding kernel?)\");\n                            else\n                            if(((Elf64_Phdr*)ph)->p_type == PT_LOAD) {\n                                printf(\"\\r\\n                   %08lx - %08lx %c%c%c\",\n                                    (long unsigned int)(((Elf64_Phdr*)ph)->p_vaddr),\n                                    (long unsigned int)(((Elf64_Phdr*)ph)->p_vaddr + ((Elf64_Phdr*)ph)->p_memsz),\n                                    ((Elf64_Phdr*)ph)->p_flags & PF_R ? 'r' : '.', ((Elf64_Phdr*)ph)->p_flags & PF_W ? 'w' : '.',\n                                    ((Elf64_Phdr*)ph)->p_flags & PF_X ? 'x' : '.');\n                            }\n                            if(ph + ((Elf64_Ehdr*)exe)->e_phentsize > exe + 4096)\n                                printf(\" (invalid, segment descriptor outside of the first page)\");\n                        }\n                    } else {\n                        ph = exe + ((Elf32_Ehdr*)exe)->e_phoff;\n                        for(i = 0; i < ((Elf32_Ehdr*)exe)->e_phnum; i++, ph += ((Elf32_Ehdr*)exe)->e_phentsize) {\n                            if(((Elf32_Phdr*)ph)->p_type == PT_DYNAMIC)\n                                printf(\"\\r\\n                   (invalid, dynamically linked kernel?)\");\n                            else\n                            if(((Elf32_Phdr*)ph)->p_type == PT_INTERP)\n                                printf(\"\\r\\n                   (invalid, not freestanding kernel?)\");\n                            else\n                            if(((Elf32_Phdr*)ph)->p_type == PT_LOAD)\n                                printf(\"\\r\\n                   %08x - %08x rwx\", ((Elf32_Phdr*)ph)->p_vaddr,\n                                    ((Elf32_Phdr*)ph)->p_vaddr + ((Elf32_Phdr*)ph)->p_memsz);\n                            if(ph + ((Elf32_Ehdr*)exe)->e_phentsize > exe + 4096)\n                                printf(\" (invalid, segment descriptor outside of the first page)\");\n                        }\n                    }\n                } else\n                if(((pe_hdr*)exe)->magic == PE_MAGIC) {\n                    sec = (pe_sec*)(exe + ((pe_hdr*)exe)->opt_hdr_size + 24);\n                    j = ((pe_hdr*)exe)->file_type == PE_OPT_MAGIC_PE32PLUS ? 64 : 32;\n                    o = j == 64 ? (uint32_t)((pe_hdr*)exe)->data.pe64.img_base : (uint32_t)((pe_hdr*)exe)->data.pe32.img_base;\n                    if(smp && j != 64) smpwarn = 1;\n                    printf(\"Multiboot2 PE%u kernel (%s)\", j,\n                        ((pe_hdr*)exe)->machine == IMAGE_FILE_MACHINE_I386 ? \"i386\" : (\n                        ((pe_hdr*)exe)->machine == IMAGE_FILE_MACHINE_AMD64 ? \"x86_64\" : (\n                        ((pe_hdr*)exe)->machine == IMAGE_FILE_MACHINE_ARM64 ? \"Aarch64\" : \"invalid architecture\")));\n                    for(i = 0; i < ((pe_hdr*)exe)->sections; i++, sec++) {\n                        printf(\"\\r\\n                   %08x - %08x %s\", o + sec->vaddr, o + sec->vaddr + sec->vsiz, sec->name);\n                        if((uint8_t*)&sec[1] > exe + 4096)\n                            printf(\" (invalid, segment descriptor outside of the first page)\");\n                    }\n                } else printf(\"(unknown kernel format?)\");\n            } else printf(\"(file not found?)\");\n            if(!num_mod && definitrd && *definitrd) {\n                strncpy(full + skipbytes, definitrd, sizeof(full) - 1 - skipbytes);\n                (void)readfileall(full, 1);\n                if(read_size) num_mod++;\n            }\n            printf(\"\\r\\nSMP multicore:     %s\\r\\n\", smpwarn ? \"disabled (only supported with MB64)\" : (smp ? \"yes\" : \"no\"));\n            printf(\"Force 32-bit mode: %s\\r\\n\", fgrub ? \"yes\" : \"no\");\n            printf(\"Number of modules: %u file%s\\r\\n\", num_mod, num_mod > 1 ? \"s\" : \"\");\n            printf(\"Framebuffer:       %u x %u pixels, %u bits per pixel\\r\\n\", fb_w, fb_h, fb_bpp);\n            printf(\"Emergency backup: %s%s%s%s%s\", bkpkrnl | bkplogo | bkpfb || num_bkp > 0 ? \"\" : \" (not configured)\",\n                bkpkrnl ? \" kernel\" : \"\", bkpfb ? \" framebuffer\" : \"\", bkplogo ? \" bootsplash\" : \"\", bkpsmp ? \" multicore\" : \"\");\n            if(num_bkp > 0) printf(\" module(%u)\", num_bkp);\n            printf(\"\\r\\nCDROM bootable:    %s\\r\\n\\r\\n\", eltorito ? \"yes\" : \"no\");\n        }\n    } else { verbose = 1; status(\"OK\\n\", NULL); }\n    if(kernelfree) free(kernel);\n    return 0;\nerr:\n    if(img) free(img);\n    if(fat_fat32) free(fat_fat32);\n    if(cluster) free(cluster);\n    dev_close(f);\n    return 1;\n}\n"
  },
  {
    "path": "kernel-standalone-builder/simpleboot/wrapper.c",
    "content": "#include \"simpleboot/src/simpleboot.c\"\n\n// Note that unfortunately simpleboot calls `exit(1)` whenever something problematic happens\n// instead of doing proper error management, but we just cope with this.\nextern int simpleboot_wrapper(int argc, char **argv) {\n    return simpleboot_main(argc, argv);\n}\n"
  },
  {
    "path": "kernel-standalone-builder/src/bin/main.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse std::{\n    error,\n    path::{Path, PathBuf},\n    str::FromStr,\n};\nuse structopt::StructOpt;\n\n#[derive(Debug, StructOpt)]\n#[structopt(\n    name = \"redshirt-standalone-builder\",\n    about = \"Redshirt standalone kernel builder and tester.\"\n)]\nenum CliOptions {\n    /// Builds and runs the kernel in an emulator.\n    EmulatorRun {\n        /// Location of the Cargo.toml of the standalone kernel library.\n        ///\n        /// If no value is passed, this the file structure is the one of the upstream repository\n        /// and try to find the path in a sibling directory.\n        ///\n        /// It is intended that in the future this can be substituted with the path to a build\n        /// directory, in which case the standalone kernel library gets fetched from crates.io.\n        #[structopt(long, parse(from_os_str))]\n        kernel_cargo_toml: Option<PathBuf>,\n\n        /// If passed, compiles with `--release`.\n        #[structopt(long)]\n        release: bool,\n\n        /// Which target to build for.\n        #[structopt(long)]\n        target: Target,\n\n        /// Which emulator to use.\n        #[structopt(long, default_value = \"qemu\")]\n        emulator: Emulator,\n    },\n\n    /// Builds a bootable image.\n    BuildImage {\n        /// Location of the Cargo.toml of the standalone kernel library.\n        ///\n        /// If no value is passed, this the file structure is the one of the upstream repository\n        /// and try to find the path in a sibling directory.\n        ///\n        /// It is intended that in the future this can be substituted with the path to a build\n        /// directory, in which case the standalone kernel library gets fetched from crates.io.\n        #[structopt(long, parse(from_os_str))]\n        kernel_cargo_toml: Option<PathBuf>,\n\n        /// If passed, compiles with `--release`.\n        #[structopt(long)]\n        release: bool,\n\n        /// Path to the output file. Any existing file will be overwritten.\n        #[structopt(short, long, parse(from_os_str))]\n        out: PathBuf,\n\n        /// What kind of image to generate.\n        ///\n        /// Can be one of: `cdrom`, `sd-card`.\n        ///\n        /// Valid values depend on the target. For example, you can't build a CD-ROM targetting\n        /// the Raspberry Pi.\n        #[structopt(long)]\n        device_type: DeviceTy,\n\n        /// Which target to build for.\n        #[structopt(long)]\n        target: Target,\n    },\n\n    /// Builds and test the kernel in an emulator.\n    EmulatorTest {\n        /// Location of the Cargo.toml of the standalone kernel library.\n        ///\n        /// If no value is passed, this the file structure is the one of the upstream repository\n        /// and try to find the path in a sibling directory.\n        ///\n        /// It is intended that in the future this can be substituted with the path to a build\n        /// directory, in which case the standalone kernel library gets fetched from crates.io.\n        #[structopt(long, parse(from_os_str))]\n        kernel_cargo_toml: Option<PathBuf>,\n\n        /// Which target to build for.\n        #[structopt(long)]\n        target: Target,\n\n        /// Which emulator to use.\n        #[structopt(long, default_value = \"qemu\")]\n        emulator: Emulator,\n    },\n}\n\n#[derive(Debug)]\nenum DeviceTy {\n    Cdrom,\n    SdCard,\n}\n\nimpl FromStr for DeviceTy {\n    type Err = String; // TODO:\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s {\n            \"cdrom\" => Ok(DeviceTy::Cdrom),\n            \"sd-card\" => Ok(DeviceTy::SdCard),\n            _ => Err(\"unrecognized device type\".to_string()),\n        }\n    }\n}\n\n#[derive(Debug)]\nenum Target {\n    HiFiveRiscV,\n    RaspberryPi2,\n    RaspberryPi3,\n    X8664Multiboot2,\n}\n\nimpl From<Target> for redshirt_standalone_builder::image::Target {\n    fn from(target: Target) -> redshirt_standalone_builder::image::Target {\n        match target {\n            Target::HiFiveRiscV => redshirt_standalone_builder::image::Target::HiFiveRiscV,\n            Target::RaspberryPi2 => redshirt_standalone_builder::image::Target::RaspberryPi2,\n            Target::RaspberryPi3 => redshirt_standalone_builder::image::Target::RaspberryPi3,\n            Target::X8664Multiboot2 => redshirt_standalone_builder::image::Target::X8664Multiboot2,\n        }\n    }\n}\n\nimpl FromStr for Target {\n    type Err = String; // TODO:\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s {\n            \"arm-rpi2\" => Ok(Target::RaspberryPi2),\n            \"arm-rpi3\" => Ok(Target::RaspberryPi3),\n            \"riscv-hifive\" => Ok(Target::HiFiveRiscV),\n            \"x86_64-multiboot2\" => Ok(Target::X8664Multiboot2),\n            _ => Err(\"unrecognized target\".to_string()),\n        }\n    }\n}\n\n#[derive(Debug)]\nenum Emulator {\n    Qemu,\n}\n\nimpl From<Emulator> for redshirt_standalone_builder::emulator::Emulator {\n    fn from(emulator: Emulator) -> redshirt_standalone_builder::emulator::Emulator {\n        match emulator {\n            Emulator::Qemu => redshirt_standalone_builder::emulator::Emulator::Qemu,\n        }\n    }\n}\n\nimpl From<Emulator> for redshirt_standalone_builder::test::Emulator {\n    fn from(emulator: Emulator) -> redshirt_standalone_builder::test::Emulator {\n        match emulator {\n            Emulator::Qemu => redshirt_standalone_builder::test::Emulator::Qemu,\n        }\n    }\n}\n\nimpl FromStr for Emulator {\n    type Err = String; // TODO:\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s {\n            \"qemu\" => Ok(Emulator::Qemu),\n            _ => Err(\"unrecognized emulator\".to_string()),\n        }\n    }\n}\n\nfn main() -> Result<(), Box<dyn error::Error + Send + Sync + 'static>> {\n    let cli_opts = CliOptions::from_args();\n\n    // Default value for `kernel-cargo-toml` if no value is provided.\n    let default_kernel_cargo_toml = Path::new(env!(\"CARGO_MANIFEST_DIR\"))\n        .join(\"..\")\n        .join(\"kernel\")\n        .join(\"standalone\")\n        .join(\"Cargo.toml\");\n\n    match cli_opts {\n        CliOptions::BuildImage {\n            kernel_cargo_toml,\n            release,\n            out,\n            device_type: _, // TODO: ?!\n            target,\n        } => {\n            redshirt_standalone_builder::image::build_image(\n                redshirt_standalone_builder::image::Config {\n                    kernel_cargo_toml: &kernel_cargo_toml.unwrap_or(default_kernel_cargo_toml),\n                    release,\n                    output_file: &out,\n                    target: target.into(),\n                },\n            )?;\n        }\n        CliOptions::EmulatorRun {\n            kernel_cargo_toml,\n            release,\n            emulator,\n            target,\n        } => {\n            redshirt_standalone_builder::emulator::run_kernel(\n                redshirt_standalone_builder::emulator::Config {\n                    kernel_cargo_toml: &kernel_cargo_toml.unwrap_or(default_kernel_cargo_toml),\n                    release,\n                    emulator: emulator.into(),\n                    target: target.into(),\n                },\n            )?;\n        }\n        CliOptions::EmulatorTest {\n            kernel_cargo_toml,\n            emulator,\n            target,\n        } => {\n            redshirt_standalone_builder::test::test_kernel(\n                redshirt_standalone_builder::test::Config {\n                    kernel_cargo_toml: &kernel_cargo_toml.unwrap_or(default_kernel_cargo_toml),\n                    emulator: emulator.into(),\n                    target: target.into(),\n                },\n            )?;\n            println!(\"Test successful\");\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "kernel-standalone-builder/src/binary.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse std::{io, path::Path, process::Command};\n\n#[derive(Debug)]\npub enum Architecture {\n    /// 32bits ARM.\n    Arm,\n    /// 64bits ARM.\n    Aarch64,\n}\n\n/// Turn an ELF file into a binary.\n// TODO: implement this in pure Rust?\n// TODO: define exact semantics of what this function does on the file\npub fn elf_to_binary(\n    architecture: Architecture,\n    src: impl AsRef<Path>,\n    dest: impl AsRef<Path>,\n) -> Result<(), io::Error> {\n    let binary = match architecture {\n        Architecture::Arm => \"arm-linux-gnu-objcopy\",\n        Architecture::Aarch64 => \"aarch64-linux-gnu-objcopy\",\n    };\n\n    let status = Command::new(binary)\n        .args(&[\"-O\", \"binary\"])\n        .arg(src.as_ref())\n        .arg(dest.as_ref())\n        .status()?;\n    // TODO: make it configurable where stdout/stderr go?\n    if !status.success() {\n        return Err(io::Error::from(io::ErrorKind::Other));\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "kernel-standalone-builder/src/build.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse std::{\n    fs, io,\n    path::{Path, PathBuf},\n    process::Command,\n};\n\n/// Configuration for building the kernel.\n#[derive(Debug)]\npub struct Config<'a> {\n    /// Path to the `Cargo.toml` of the standalone kernel library.\n    // TODO: once the standalone kernel is on crates.io, make it possible for the kernel builder to run as a completely stand-alone program and pass a build directory instead\n    pub kernel_cargo_toml: &'a Path,\n\n    /// If true, compiles with `--release`.\n    pub release: bool,\n\n    /// Name of the target to pass as `--target`.\n    pub target_name: &'a str,\n\n    /// Suffix of the final binary.\n    pub expected_target_suffix: Option<&'a str>,\n\n    /// JSON target specifications.\n    pub target_specs: Option<&'a str>,\n\n    /// Link script to pass to the linker.\n    pub link_script: Option<&'a str>,\n}\n\n/// Successful build.\n#[derive(Debug)]\npub struct BuildOutput {\n    /// Path to the output of the compilation.\n    pub out_kernel_path: PathBuf,\n}\n\n/// Error that can happen during the build.\n#[derive(Debug, thiserror::Error)]\npub enum Error {\n    #[error(\"Could not start Cargo: {0}\")]\n    CargoNotFound(io::Error),\n\n    #[error(\"Error while building the kernel\")]\n    BuildError,\n\n    #[error(\"Failed to get metadata about the kernel Cargo.toml\")]\n    MetadataFailed,\n\n    #[error(\"Invalid kernel Cargo.toml path\")]\n    BadKernelCargoTomlPath,\n\n    #[error(\"{0}\")]\n    Io(#[from] io::Error),\n}\n\n/// Builds the kernel.\npub fn build(cfg: Config) -> Result<BuildOutput, Error> {\n    assert_ne!(cfg.target_name, \"debug\");\n    assert_ne!(cfg.target_name, \"release\");\n\n    // Determine the path to the file that Cargo will generate.\n    let (output_file, target_dir_with_target) = {\n        let metadata = cargo_metadata::MetadataCommand::new()\n            .manifest_path(&cfg.kernel_cargo_toml)\n            .no_deps()\n            .exec()\n            .map_err(|_| Error::MetadataFailed)?;\n\n        let target_dir_with_target = metadata\n            .target_directory\n            .join(cfg.target_name)\n            .join(\"project\");\n\n        let output_file = target_dir_with_target\n            .join(\"target\")\n            .join(cfg.target_name)\n            .join(if cfg.release { \"release\" } else { \"debug\" })\n            .join(\n                if let Some(expected_target_suffix) = cfg.expected_target_suffix {\n                    format!(\"kernel.{expected_target_suffix}\")\n                } else {\n                    \"kernel\".to_owned()\n                },\n            );\n\n        (output_file, target_dir_with_target)\n    };\n\n    // Create and fill the directory where various source files are put.\n    // If `cargo_clean_needed` is set to true, the build will later be done from scratch.\n    let mut cargo_clean_needed = false;\n    fs::create_dir_all(&target_dir_with_target)?;\n    if let Some(target_specs) = &cfg.target_specs {\n        if write_if_changed(\n            (&target_dir_with_target).join(format!(\"{}.json\", cfg.target_name)),\n            target_specs.as_bytes(),\n        )? {\n            cargo_clean_needed = true;\n        }\n    }\n    if let Some(link_script) = &cfg.link_script {\n        if write_if_changed(\n            (&target_dir_with_target).join(\"link.ld\"),\n            link_script.as_bytes(),\n        )? {\n            // Note: this is overly conservative. Only the linking step needs to be done again, but\n            // there isn't any easy way to retrigger only the linking.\n            cargo_clean_needed = true;\n        }\n    }\n    {\n        let mut cargo_toml_prototype = toml::value::Table::new();\n        // TODO: should write `[profile]` in there\n        cargo_toml_prototype.insert(\"package\".into(), {\n            let mut package = toml::value::Table::new();\n            package.insert(\"name\".into(), \"kernel\".into());\n            package.insert(\"version\".into(), \"1.0.0\".into());\n            package.insert(\"edition\".into(), \"2018\".into());\n            package.into()\n        });\n        cargo_toml_prototype.insert(\"dependencies\".into(), {\n            let mut dependencies = toml::value::Table::new();\n            dependencies.insert(\"redshirt-standalone-kernel\".into(), {\n                let mut wasm_project = toml::value::Table::new();\n                wasm_project.insert(\n                    \"path\".into(),\n                    cfg.kernel_cargo_toml\n                        .parent()\n                        .ok_or(Error::BadKernelCargoTomlPath)?\n                        .display()\n                        .to_string()\n                        .into(),\n                );\n                wasm_project.into()\n            });\n            dependencies.into()\n        });\n        cargo_toml_prototype.insert(\"profile\".into(), {\n            let mut profiles = toml::value::Table::new();\n            profiles.insert(\"release\".into(), {\n                let mut profile = toml::value::Table::new();\n                profile.insert(\"panic\".into(), \"abort\".into());\n                profile.insert(\"lto\".into(), true.into());\n                profile.insert(\"opt-level\".into(), 3.into());\n                profile.into()\n            });\n            profiles.insert(\"dev\".into(), {\n                let mut profile = toml::value::Table::new();\n                profile.insert(\"panic\".into(), \"abort\".into());\n                profile.insert(\"opt-level\".into(), 2.into());\n                profile.into()\n            });\n            profiles.into()\n        });\n        cargo_toml_prototype.insert(\"workspace\".into(), toml::value::Table::new().into());\n        cargo_toml_prototype.insert(\"patch\".into(), {\n            let mut patches = toml::value::Table::new();\n            patches.insert(\"crates-io\".into(), {\n                let crates = toml::value::Table::new();\n                // Uncomment this in order to overwrite dependencies used during the kernel\n                // compilation.\n                /*crates.insert(\"foo\".into(), {\n                    let mut val = toml::value::Table::new();\n                    val.insert(\"path\".into(), \"/path/to/foot\".into());\n                    val.into()\n                });*/\n                crates.into()\n            });\n            patches.into()\n        });\n        write_if_changed(\n            target_dir_with_target.join(\"Cargo.toml\"),\n            toml::to_string_pretty(&cargo_toml_prototype).unwrap(),\n        )?;\n    }\n    {\n        fs::create_dir_all(&target_dir_with_target.join(\"src\"))?;\n        let src = format!(\n            r#\"\n        #![no_std]\n        #![no_main]\n\n        // TODO: these features are necessary because of the fact that we use a macro\n        #![feature(naked_functions)] // TODO: https://github.com/rust-lang/rust/issues/32408\n\n        redshirt_standalone_kernel::__gen_boot! {{\n            entry: redshirt_standalone_kernel::run,\n            memory_zeroing_start: __bss_start,\n            memory_zeroing_end: __bss_end,\n        }}\n        \n        extern \"C\" {{\n            static mut __bss_start: u8;\n            static mut __bss_end: u8;\n        }}\n        \"#\n        );\n        write_if_changed(target_dir_with_target.join(\"src\").join(\"main.rs\"), src)?;\n    }\n\n    if cargo_clean_needed {\n        let status = Command::new(\"cargo\")\n            .arg(\"clean\")\n            .arg(\"--manifest-path\")\n            .arg(target_dir_with_target.join(\"Cargo.toml\"))\n            .status()\n            .map_err(Error::CargoNotFound)?;\n        // TODO: should we make it configurable where the stdout/stderr outputs go?\n        if !status.success() {\n            return Err(Error::BuildError);\n        }\n    }\n\n    // Actually build the kernel.\n    let build_status = Command::new(\"cargo\")\n        .arg(\"build\")\n        .args(\n            cfg.target_specs\n                .is_some()\n                .then_some([\"-Z\", \"build-std=core,alloc\"])\n                .into_iter()\n                .flatten(),\n        ) // TODO: nightly only; cc https://github.com/tomaka/redshirt/issues/300\n        .env(\"RUST_TARGET_PATH\", &target_dir_with_target)\n        .envs(cfg.link_script.is_some().then_some((\n            format!(\n                \"CARGO_TARGET_{}_RUSTFLAGS\",\n                cfg.target_name.replace(\"-\", \"_\").to_uppercase()\n            ),\n            format!(\n                \"-Clink-arg=--script -Clink-arg={}\",\n                target_dir_with_target.join(\"link.ld\").display()\n            ),\n        )))\n        .arg(\"--target\")\n        .arg(cfg.target_name)\n        .arg(\"--manifest-path\")\n        .arg(target_dir_with_target.join(\"Cargo.toml\"))\n        .args(if cfg.release {\n            &[\"--release\"][..]\n        } else {\n            &[][..]\n        })\n        .status()\n        .map_err(Error::CargoNotFound)?;\n    // TODO: should we make it configurable where the stdout/stderr outputs go?\n    if !build_status.success() {\n        return Err(Error::BuildError);\n    }\n\n    assert!(output_file.exists());\n\n    Ok(BuildOutput {\n        out_kernel_path: output_file,\n    })\n}\n\n/// Write to the given `file` if the `content` is different.\n///\n/// Returns `true` if the content was indeed different and a write has been performed.\n///\n/// This function is used in order to not make Cargo trigger a rebuild by writing over a file\n/// with the same content as it already has.\nfn write_if_changed(file: impl AsRef<Path>, content: impl AsRef<[u8]>) -> Result<bool, io::Error> {\n    if fs::read(file.as_ref()).ok().as_deref() != Some(content.as_ref()) {\n        fs::write(file, content.as_ref())?;\n        Ok(true)\n    } else {\n        Ok(false)\n    }\n}\n"
  },
  {
    "path": "kernel-standalone-builder/src/emulator.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse std::{io, path::Path, process::Command};\nuse tempdir::TempDir;\n\n/// Configuration for running the kernel in an emulator.\n#[derive(Debug)]\npub struct Config<'a> {\n    /// Path to the `Cargo.toml` of the standalone kernel.\n    pub kernel_cargo_toml: &'a Path,\n\n    /// If true, compiles with `--release`.\n    pub release: bool,\n\n    /// Which emulator to use.\n    pub emulator: Emulator,\n\n    /// Target platform.\n    pub target: crate::image::Target,\n}\n\n/// Which emulator to use.\n#[derive(Debug)]\npub enum Emulator {\n    Qemu,\n}\n\n/// Error that can happen during the build.\n#[derive(Debug, thiserror::Error)]\npub enum Error {\n    /// Error while building the image.\n    #[error(\"Error while building the image: {0}\")]\n    Build(#[from] crate::image::Error),\n\n    #[error(\"Emulator not found: {0}\")]\n    EmulatorNotFound(io::Error),\n\n    #[error(\"Emulator run failed\")]\n    EmulatorRunFailure,\n\n    #[error(\"{0}\")]\n    Io(#[from] io::Error),\n}\n\n/// Runs the kernel in an emulator.\npub fn run_kernel(cfg: Config) -> Result<(), Error> {\n    let Emulator::Qemu = cfg.emulator;\n\n    match cfg.target {\n        crate::image::Target::X8664Multiboot2 => {\n            let build_dir = TempDir::new(\"redshirt-kernel-temp-loc\")?;\n            crate::image::build_image(crate::image::Config {\n                kernel_cargo_toml: cfg.kernel_cargo_toml,\n                output_file: &build_dir.path().join(\"image\"),\n                release: cfg.release,\n                target: cfg.target,\n            })?;\n\n            let status = Command::new(\"qemu-system-x86_64\")\n                .args(&[\"-m\", \"1024\"])\n                .args(&[\"-serial\", \"stdio\"])\n                .arg(\"-cdrom\")\n                .arg(build_dir.path().join(\"image\"))\n                .args(&[\"-smp\", \"cpus=4\"])\n                // TODO: decide whether to enable this ; can cause compatibility issues but runs way faster .args(&[\"-enable-kvm\", \"-cpu\", \"host\"])\n                .status()\n                .map_err(Error::EmulatorNotFound)?;\n\n            if !status.success() {\n                return Err(Error::EmulatorRunFailure);\n            }\n        }\n\n        crate::image::Target::RaspberryPi2 => {\n            let build_out = crate::build::build(crate::build::Config {\n                kernel_cargo_toml: cfg.kernel_cargo_toml,\n                release: cfg.release,\n                target_name: \"arm-freestanding\",\n                expected_target_suffix: None,\n                target_specs: Some(include_str!(\"../res/specs/arm-freestanding.json\")),\n                link_script: Some(include_str!(\"../res/specs/arm-freestanding.ld\")),\n            })\n            .map_err(crate::image::Error::Build)?;\n\n            let status = Command::new(\"qemu-system-arm\")\n                .args(&[\"-M\", \"raspi2\"])\n                .args(&[\"-m\", \"1024\"])\n                .args(&[\"-serial\", \"stdio\"])\n                .arg(\"-kernel\")\n                .arg(build_out.out_kernel_path)\n                .status()\n                .map_err(Error::EmulatorNotFound)?;\n\n            if !status.success() {\n                return Err(Error::EmulatorRunFailure);\n            }\n        }\n\n        crate::image::Target::RaspberryPi3 => {\n            let build_out = crate::build::build(crate::build::Config {\n                kernel_cargo_toml: cfg.kernel_cargo_toml,\n                release: cfg.release,\n                target_name: \"aarch64-freestanding\",\n                expected_target_suffix: None,\n                target_specs: Some(include_str!(\"../res/specs/aarch64-freestanding.json\")),\n                link_script: Some(include_str!(\"../res/specs/aarch64-freestanding.ld\")),\n            })\n            .map_err(crate::image::Error::Build)?;\n\n            let status = Command::new(\"qemu-system-aarch64\")\n                .args(&[\"-M\", \"raspi3\"])\n                .args(&[\"-m\", \"1024\"])\n                .args(&[\"-serial\", \"stdio\"])\n                .arg(\"-kernel\")\n                .arg(build_out.out_kernel_path)\n                .status()\n                .map_err(Error::EmulatorNotFound)?;\n\n            if !status.success() {\n                return Err(Error::EmulatorRunFailure);\n            }\n        }\n\n        crate::image::Target::HiFiveRiscV => {\n            let build_out = crate::build::build(crate::build::Config {\n                kernel_cargo_toml: cfg.kernel_cargo_toml,\n                release: cfg.release,\n                target_name: \"riscv-hifive\",\n                expected_target_suffix: None,\n                target_specs: Some(include_str!(\"../res/specs/riscv-hifive.json\")),\n                link_script: Some(include_str!(\"../res/specs/riscv-hifive.ld\")),\n            })\n            .map_err(crate::image::Error::Build)?;\n\n            let status = Command::new(\"qemu-system-riscv32\")\n                .args(&[\"-machine\", \"sifive_e\"])\n                .args(&[\"-cpu\", \"sifive-e31\"])\n                .args(&[\"-m\", \"2G\"])\n                .args(&[\"-serial\", \"stdio\"])\n                .arg(\"-kernel\")\n                .arg(build_out.out_kernel_path)\n                .status()\n                .map_err(Error::EmulatorNotFound)?;\n\n            if !status.success() {\n                return Err(Error::EmulatorRunFailure);\n            }\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "kernel-standalone-builder/src/image.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::simpleboot;\nuse std::{\n    fs,\n    io::{self, Read, Seek, SeekFrom, Write},\n    path::Path,\n};\nuse tempdir::TempDir;\n\n/// Configuration for building a bootable image.\n#[derive(Debug)]\npub struct Config<'a> {\n    /// Path to the `Cargo.toml` of the standalone kernel.\n    pub kernel_cargo_toml: &'a Path,\n\n    /// Path where to write the output image.\n    ///\n    /// The path must exist, and any existing file will be overwritten.\n    pub output_file: &'a Path,\n\n    /// If true, compiles with `--release`.\n    pub release: bool,\n\n    /// Platform to compile for.\n    pub target: Target,\n    // TODO: device type\n}\n\n/// Target platform.\n#[derive(Debug)]\npub enum Target {\n    HiFiveRiscV,\n    RaspberryPi2,\n    RaspberryPi3,\n    X8664Multiboot2,\n}\n\n/// Error that can happen during the build.\n#[derive(Debug, thiserror::Error)]\npub enum Error {\n    /// Error while building the kernel.\n    #[error(\"Error while building the kernel: {0}\")]\n    Build(#[from] crate::build::Error),\n\n    #[error(\"{0}\")]\n    Io(#[from] io::Error),\n}\n\n/// Builds a bootable image from a compiled kernel.\npub fn build_image(config: Config) -> Result<(), Error> {\n    match config.target {\n        Target::X8664Multiboot2 => {\n            let build_out = crate::build::build(crate::build::Config {\n                kernel_cargo_toml: config.kernel_cargo_toml,\n                release: config.release,\n                target_name: \"x86_64-multiboot2\",\n                expected_target_suffix: None,\n                target_specs: Some(include_str!(\"../res/specs/x86_64-multiboot2.json\")),\n                link_script: Some(include_str!(\"../res/specs/x86_64-multiboot2.ld\")),\n            })?;\n\n            build_x86_multiboot2_cdrom_iso(build_out.out_kernel_path, config.output_file)?;\n            Ok(())\n        }\n\n        Target::RaspberryPi2 | Target::RaspberryPi3 => {\n            let v7_build_out = crate::build::build(crate::build::Config {\n                kernel_cargo_toml: config.kernel_cargo_toml,\n                release: config.release,\n                target_name: \"arm-freestanding\",\n                expected_target_suffix: None,\n                target_specs: Some(include_str!(\"../res/specs/arm-freestanding.json\")),\n                link_script: Some(include_str!(\"../res/specs/arm-freestanding.ld\")),\n            })?;\n\n            let v8_build_out = crate::build::build(crate::build::Config {\n                kernel_cargo_toml: config.kernel_cargo_toml,\n                release: config.release,\n                target_name: \"aarch64-freestanding\",\n                expected_target_suffix: None,\n                target_specs: Some(include_str!(\"../res/specs/aarch64-freestanding.json\")),\n                link_script: Some(include_str!(\"../res/specs/aarch64-freestanding.ld\")),\n            })?;\n\n            let build_dir = TempDir::new(\"redshirt-sd-card-build\")?;\n            crate::binary::elf_to_binary(\n                crate::binary::Architecture::Arm,\n                v7_build_out.out_kernel_path,\n                build_dir.path().join(\"kernel7.img\"),\n            )?;\n            crate::binary::elf_to_binary(\n                crate::binary::Architecture::Aarch64,\n                v8_build_out.out_kernel_path,\n                build_dir.path().join(\"kernel8.img\"),\n            )?;\n\n            let img_file = fs::OpenOptions::new()\n                .read(true)\n                .write(true)\n                .truncate(true)\n                .create(true)\n                .open(config.output_file)\n                .unwrap();\n            img_file.set_len(1 * 1024 * 1024 * 1024)?;\n            let img_file = fscommon::BufStream::new(img_file);\n            build_raspberry_pi_sd_card(\n                img_file,\n                fs::File::open(build_dir.path().join(\"kernel7.img\")).unwrap(),\n                fs::File::open(build_dir.path().join(\"kernel8.img\")).unwrap(),\n            )?;\n            Ok(())\n        }\n\n        Target::HiFiveRiscV => unimplemented!(),\n    }\n}\n\n/// Builds an x86 bootable CDROM ISO with a multiboot2 bootloader on it.\n///\n/// Assumes that the kernel file is an ELF file that can accept multiboot2 information.\n// TODO: some pure Rust implementation of this one day?\nfn build_x86_multiboot2_cdrom_iso(\n    kernel_path: impl AsRef<Path>,\n    output_file: impl AsRef<Path>,\n) -> Result<(), io::Error> {\n    let build_dir = TempDir::new(\"redshirt-kernel-iso-build\")?;\n\n    fs::create_dir_all(build_dir.path().join(\"iso\"))?;\n    fs::copy(kernel_path, build_dir.path().join(\"iso\").join(\"kernel\"))?;\n    fs::write(\n        build_dir.path().join(\"iso\").join(\"simpleboot.cfg\"),\n        r#\"\nverbose 3\n\"#,\n    )?;\n\n    let output = simpleboot::run_simpleboot([\n        \"-k\",\n        \"kernel\",\n        \"-e\", // CDROM mode.\n        \"-c\", // Always create the image, never modify an existing one.\n        \"-g\", // Multiboot2 doesn't normally support 64bits kernels without EFI loading. This flag provides compatibility.\n        build_dir.path().join(\"iso\").to_str().unwrap(),\n        output_file.as_ref().to_str().unwrap(),\n    ]);\n    if output.is_err() {\n        panic!(\"Error while executing `simpleboot`\");\n    }\n\n    build_dir.close()?;\n    Ok(())\n}\n\n/// Writes the content of a bootable SD card to `out`.\n///\n/// `out` must have pre-allocated space. This function does not grow `out`.\n///\n/// `kernel_32bits` and `kernel_64bits` are the binary content of respectively the 32bits and\n/// 64bits kernels.\n// Reference: https://github.com/raspberrypi/noobs/wiki/Standalone-partitioning-explained\nfn build_raspberry_pi_sd_card(\n    mut out: impl Read + Write + Seek,\n    mut kernel_32bits: impl Read,\n    mut kernel_64bits: impl Read,\n) -> Result<(), io::Error> {\n    out.seek(SeekFrom::Start(0))?;\n\n    // We start by writing a MBR to the disk.\n    // The MBR (Master Boot Record) is the first section of the SD card, and contains information\n    // about the disk, including the paritions table.\n    // We create one partition covering the entire disk.\n    let mut mbr = mbrman::MBR::new_from(&mut out, 512, [0xff, 0x00, 0x34, 0x56]).unwrap();\n    mbr[1] = mbrman::MBRPartitionEntry {\n        boot: false,\n        first_chs: mbrman::CHS::empty(),\n        sys: 0x0c, // FAT32\n        last_chs: mbrman::CHS::empty(),\n        starting_lba: 1,\n        sectors: mbr.disk_size - 1,\n    };\n    mbr.write_into(&mut out).unwrap();\n\n    // Now wrapping `out` so that it only represents the first partition.\n    let mut out = fscommon::StreamSlice::new(out, 512, 512 * u64::from(mbr.disk_size - 1)).unwrap();\n    out.seek(SeekFrom::Start(0))?;\n\n    // Format partition as FAT32.\n    let format_opts = fatfs::FormatVolumeOptions::new()\n        .fat_type(fatfs::FatType::Fat32)\n        .volume_id(0x48481111)\n        .volume_label(*b\"boot       \");\n    fatfs::format_volume(&mut out, format_opts)?;\n\n    // Open the file system in order to write out files.\n    let fs = fatfs::FileSystem::new(out, fatfs::FsOptions::new())?;\n\n    // Copy the content of `firmware/boot`, plus the kernels, to the FAT32 file system.\n    {\n        let root_dir = fs.root_dir();\n\n        let local_path = Path::new(\"res\").join(\"rpi-firmware\").join(\"boot\");\n        for entry in walkdir::WalkDir::new(&local_path) {\n            let entry = entry.unwrap();\n            let path = entry.path().strip_prefix(&local_path).unwrap();\n            let path_string = path.display().to_string();\n\n            if path_string.is_empty() || &path_string == \".\" || &path_string == \"..\" {\n                continue;\n            }\n\n            if entry.file_type().is_dir() {\n                root_dir.create_dir(&path_string).unwrap();\n                continue;\n            }\n\n            let mut file = root_dir.create_file(&path_string)?;\n            io::copy(&mut fs::File::open(local_path.join(path))?, &mut file)?;\n        }\n\n        let kernel_32bits = {\n            let mut buf = Vec::new();\n            kernel_32bits.read_to_end(&mut buf)?;\n            buf\n        };\n\n        {\n            let mut file = root_dir.create_file(\"kernel.img\")?;\n            io::copy(&mut io::Cursor::new(&kernel_32bits), &mut file)?;\n        }\n        {\n            let mut file = root_dir.create_file(\"kernel7.img\")?;\n            io::copy(&mut io::Cursor::new(&kernel_32bits), &mut file)?;\n        }\n        {\n            let mut file = root_dir.create_file(\"kernel7l.img\")?;\n            io::copy(&mut io::Cursor::new(&kernel_32bits), &mut file)?;\n        }\n        {\n            let mut file = root_dir.create_file(\"kernel8.img\")?;\n            io::copy(&mut kernel_64bits, &mut file)?;\n        }\n    }\n\n    fs.unmount()?;\n    Ok(())\n}\n"
  },
  {
    "path": "kernel-standalone-builder/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Collection of commands that can build a kernel.\n\npub mod binary;\npub mod build;\npub mod emulator;\npub mod image;\npub mod test;\n\nmod simpleboot;\n"
  },
  {
    "path": "kernel-standalone-builder/src/simpleboot.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse std::{ffi::CString, iter};\n\nextern \"C\" {\n    fn simpleboot_wrapper(\n        argc: std::os::raw::c_int,\n        argv: *mut *mut std::os::raw::c_char,\n    ) -> std::os::raw::c_int;\n}\n\npub fn run_simpleboot<'a>(args: impl IntoIterator<Item = &'a str>) -> Result<(), ()> {\n    let args = iter::once(CString::new(\"simpleboot\").unwrap())\n        .chain(args.into_iter().map(|s| CString::new(s).unwrap()))\n        .collect::<Vec<_>>();\n    let args_ptrs = args\n        .iter()\n        .map(|a| a.as_c_str().as_ptr())\n        .collect::<Vec<_>>();\n\n    let out = unsafe {\n        simpleboot_wrapper(\n            args.len() as std::os::raw::c_int,\n            args_ptrs.as_ptr().cast_mut().cast(),\n        )\n    };\n\n    if out == 0 {\n        Ok(())\n    } else {\n        Err(())\n    }\n}\n"
  },
  {
    "path": "kernel-standalone-builder/src/test.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse futures::{channel::oneshot, executor, prelude::*};\nuse std::{\n    collections::VecDeque,\n    io::{self, Write as _},\n    path::Path,\n    process::{Command, Stdio},\n    thread,\n    time::Duration,\n};\nuse tempdir::TempDir;\n\n/// Configuration for testing the kernel in an emulator.\n#[derive(Debug)]\npub struct Config<'a> {\n    /// Path to the `Cargo.toml` of the standalone kernel.\n    pub kernel_cargo_toml: &'a Path,\n\n    /// Which emulator to use.\n    pub emulator: Emulator,\n\n    /// Target platform.\n    pub target: crate::image::Target,\n}\n\n/// Which emulator to use.\n#[derive(Debug)]\npub enum Emulator {\n    Qemu,\n}\n\n/// Error that can happen during the build.\n#[derive(Debug, thiserror::Error)]\npub enum Error {\n    /// Error while building the image.\n    #[error(\"Error while building the image: {0}\")]\n    Build(#[from] crate::image::Error),\n\n    #[error(\"Emulator not found: {0}\")]\n    EmulatorNotFound(io::Error),\n\n    #[error(\"Emulator run failed\")]\n    EmulatorRunFailure,\n\n    #[error(\"Timeout while waiting for success\")]\n    Timeout,\n\n    #[error(\"{0}\")]\n    Io(#[from] io::Error),\n}\n\n/// Runs the kernel in an emulator.\npub fn test_kernel(cfg: Config) -> Result<(), Error> {\n    let Emulator::Qemu = cfg.emulator;\n\n    match cfg.target {\n        crate::image::Target::X8664Multiboot2 => {\n            let build_dir = TempDir::new(\"redshirt-kernel-temp-loc\")?;\n            crate::image::build_image(crate::image::Config {\n                kernel_cargo_toml: cfg.kernel_cargo_toml,\n                output_file: &build_dir.path().join(\"image\"),\n                release: false,\n                target: cfg.target,\n            })?;\n\n            run_until_line(\n                &mut Command::new(\"qemu-system-x86_64\")\n                    .args(&[\"-m\", \"1024\"])\n                    // CPU choice is somewhat arbitrary, but should be the same everywhere\n                    // tests are run.\n                    .args(&[\"-cpu\", \"core2duo\"])\n                    .args(&[\"-display\", \"none\"])\n                    .args(&[\"-serial\", \"stdio\"])\n                    .args(&[\"-monitor\", \"none\"])\n                    .arg(\"-cdrom\")\n                    .arg(build_dir.path().join(\"image\"))\n                    .args(&[\"-smp\", \"cpus=4\"]),\n            )?;\n        }\n\n        crate::image::Target::RaspberryPi2 => {\n            let build_out = crate::build::build(crate::build::Config {\n                kernel_cargo_toml: cfg.kernel_cargo_toml,\n                release: false,\n                target_name: \"arm-freestanding\",\n                expected_target_suffix: None,\n                target_specs: Some(include_str!(\"../res/specs/arm-freestanding.json\")),\n                link_script: Some(include_str!(\"../res/specs/arm-freestanding.ld\")),\n            })\n            .map_err(crate::image::Error::Build)?;\n\n            run_until_line(\n                &mut Command::new(\"qemu-system-arm\")\n                    .args(&[\"-M\", \"raspi2\"])\n                    .args(&[\"-m\", \"1024\"])\n                    .args(&[\"-display\", \"none\"])\n                    .args(&[\"-serial\", \"stdio\"])\n                    .args(&[\"-monitor\", \"none\"])\n                    .arg(\"-kernel\")\n                    .arg(build_out.out_kernel_path),\n            )?;\n        }\n\n        crate::image::Target::RaspberryPi3 => {\n            let build_out = crate::build::build(crate::build::Config {\n                kernel_cargo_toml: cfg.kernel_cargo_toml,\n                release: false,\n                target_name: \"aarch64-freestanding\",\n                expected_target_suffix: None,\n                target_specs: Some(include_str!(\"../res/specs/aarch64-freestanding.json\")),\n                link_script: Some(include_str!(\"../res/specs/aarch64-freestanding.ld\")),\n            })\n            .map_err(crate::image::Error::Build)?;\n\n            run_until_line(\n                &mut Command::new(\"qemu-system-aarch64\")\n                    .args(&[\"-M\", \"raspi3\"])\n                    .args(&[\"-m\", \"1024\"])\n                    .args(&[\"-display\", \"none\"])\n                    .args(&[\"-serial\", \"stdio\"])\n                    .args(&[\"-monitor\", \"none\"])\n                    .arg(\"-kernel\")\n                    .arg(build_out.out_kernel_path),\n            )?;\n        }\n\n        crate::image::Target::HiFiveRiscV => {\n            let build_out = crate::build::build(crate::build::Config {\n                kernel_cargo_toml: cfg.kernel_cargo_toml,\n                release: false,\n                target_name: \"riscv-hifive\",\n                expected_target_suffix: None,\n                target_specs: Some(include_str!(\"../res/specs/riscv-hifive.json\")),\n                link_script: Some(include_str!(\"../res/specs/riscv-hifive.ld\")),\n            })\n            .map_err(crate::image::Error::Build)?;\n\n            run_until_line(\n                &mut Command::new(\"qemu-system-riscv32\")\n                    .args(&[\"-machine\", \"sifive_e\"])\n                    .args(&[\"-cpu\", \"sifive-e31\"])\n                    .args(&[\"-m\", \"2G\"])\n                    .args(&[\"-display\", \"none\"])\n                    .args(&[\"-serial\", \"stdio\"])\n                    .args(&[\"-monitor\", \"none\"])\n                    .arg(\"-kernel\")\n                    .arg(build_out.out_kernel_path),\n            )?;\n        }\n    }\n\n    Ok(())\n}\n\nfn run_until_line(command: &mut Command) -> Result<(), Error> {\n    let mut child = command\n        .stdin(Stdio::null())\n        .stdout(Stdio::piped())\n        .spawn()\n        .map_err(Error::EmulatorNotFound)?;\n\n    let stdout = child.stdout.take().unwrap();\n    let timeout = futures_timer::Delay::new(Duration::from_secs(30));\n\n    let result = executor::block_on(async move {\n        futures::select! {\n            outcome = signal_when_line_detected(stdout).fuse() => {\n                outcome.map_err(|_| Error::EmulatorRunFailure)\n            }\n            _ = timeout.fuse() => {\n                Err(Error::Timeout)\n            }\n        }\n    });\n\n    // Killing the children, otherwise it stays alive.\n    let _ = child.kill();\n    result\n}\n\nfn signal_when_line_detected(read: impl io::Read + Send + 'static) -> oneshot::Receiver<()> {\n    let expected = b\"[boot] boot successful\";\n    let (tx, rx) = oneshot::channel();\n\n    thread::spawn(move || {\n        let mut bytes = read.bytes();\n        let mut window = (0..expected.len()).map(|_| 0u8).collect::<VecDeque<_>>();\n\n        loop {\n            window.pop_front();\n            window.push_back(match bytes.next() {\n                Some(Ok(b)) => {\n                    // TODO: add a CLI option to control this?\n                    let _ = io::stdout().write_all(&[b]);\n                    b\n                }\n                _ => return,\n            });\n\n            let mut window_iter = window.iter();\n            let mut expected_iter = expected.iter();\n            loop {\n                match (window_iter.next(), expected_iter.next()) {\n                    (Some(a), Some(b)) if a == b => continue,\n                    (None, None) => {\n                        let _ = tx.send(());\n                        return;\n                    }\n                    _ => break,\n                }\n            }\n        }\n    });\n\n    rx\n}\n"
  },
  {
    "path": "programs/.cargo/config.toml",
    "content": "# Note: this file exists in order to provide a more convenient development environment in the\n# redshirt repository. It is not mandatory to put a similar file next to programs developed for\n# redshirt. The redshirt programs builder automatically makes sure (in `redshirt-core`) makes sure\n# that the module is built with the appropriate options.\n\n[build]\ntarget = \"wasm32-wasip1\"\n\n[target.'wasm32-wasip1']\nrustflags = [\"-C\", \"link-arg=--export-table\", \"-C\", \"link-arg=--import-memory\"]\n"
  },
  {
    "path": "programs/.dockerignore",
    "content": "target\n"
  },
  {
    "path": "programs/Cargo.toml",
    "content": "[workspace]\nmembers = [\n    \"compositor\",\n    \"diagnostics-http-server\",\n    \"dummy-system-time\",\n    \"e1000\",\n    \"hello-world\",\n    \"network-manager\",\n    \"log-to-kernel\",\n    \"pci-printer\",\n    \"rpi-framebuffer\",\n    \"stub\",\n    \"third-party/wasm-timer\",\n    \"vga-vbe\",\n]\n\n[profile.dev]\nopt-level = 1\n\n[profile.dev.package.\"*\"]\nopt-level = 3\n\n[profile.test.package.\"*\"]\nopt-level = 3\n\n[profile.release]\nopt-level = 3\nlto = true\ncodegen-units = 1\npanic = 'abort'\n\n[patch.crates-io]\nwasm-timer = { path = \"./third-party/wasm-timer\" }\n"
  },
  {
    "path": "programs/compositor/Cargo.toml",
    "content": "[package]\nname = \"compositor\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[dependencies]\nahash = { version = \"0.6.2\", default-features = false }\nfutures = \"0.3.21\"\nhashbrown = { version = \"0.12.0\", default-features = false }\nrand = \"0.8.5\"\nredshirt-framebuffer-interface = { path = \"../../interface-wrappers/framebuffer\" }\nredshirt-interface-interface = { path = \"../../interface-wrappers/interface\" }\nredshirt-syscalls = { path = \"../../interface-wrappers/syscalls\" }\nredshirt-time-interface = { path = \"../../interface-wrappers/time\" }\nredshirt-video-output-interface = { path = \"../../interface-wrappers/video-output\" }\n"
  },
  {
    "path": "programs/compositor/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! The compositor is responsible for gathering all video outputs, mouse inputs, keyboard inputs,\n//! and framebuffers, and mix them together.\n//!\n//!                       +--------------------------------------------+\n//!                       |                                            |\n//!                 <-->  |                                            |  +-->\n//!                       |                                            |\n//!                 <-->  |     +================================>     |  +-->\n//!                       |                                            |\n//!   framebuffer   <-->  |                                            |  +-->    video output\n//!    interface          |                 compositor                 |           interface\n//!                 <-->  |                                            |  +-->\n//!                       |                                            |\n//!                 <-->  |     <================+                     |  +-->\n//!                       |                      |                     |\n//!                 <-->  |                      +                     |  +-->\n//!                       |                                            |\n//!                       +--------------------------------------------+\n//!\n//!                                    ^    ^    ^    ^    ^\n//!                                    |    |    |    |    |\n//!                                    +    +    +    +    +\n//!\n//!                                human-input-related interfaces\n//!                                (e.g. mouse, keyboard, touch)\n//!\n//!\n//! The compositor considers that there is a *desktop* of infinite dimensions. Framebuffers and\n//! video outputs each have an area that overlaps this desktop.\n\n#![no_std]\n\nextern crate alloc;\n\nuse alloc::{collections::VecDeque, vec, vec::Vec};\nuse core::{cmp::Eq, convert::TryFrom as _, hash::Hash, iter, mem, ops::Range};\n\nmod rect;\n\npub struct Compositor<TFbId, TOutId, TFb, TOut> {\n    framebuffers: hashbrown::HashMap<TFbId, Framebuffer<TFb>, ahash::RandomState>,\n    video_outputs: hashbrown::HashMap<TOutId, VideoOutput<TOut>, ahash::RandomState>,\n\n    next_framebuffer_position: (u32, u32),\n}\n\nstruct Framebuffer<TFb> {\n    position: rect::Rect,\n    user_data: TFb,\n    /// Rows of pixels. Each pixel is a RGBA color.\n    rgb_data: Vec<[u8; 4]>,\n}\n\nstruct VideoOutput<TOut> {\n    position: rect::Rect,\n    format: Format,\n    user_data: TOut,\n    /// List of areas that need to be refreshed. In local coordinates.\n    needs_refresh: VecDeque<rect::Rect>,\n}\n\nimpl<TFbId: Clone + Eq + Hash, TOutId: Clone + Eq + Hash, TFb, TOut>\n    Compositor<TFbId, TOutId, TFb, TOut>\n{\n    pub fn with_seed(seed: [u8; 64]) -> Self {\n        Compositor {\n            framebuffers: hashbrown::HashMap::with_capacity_and_hasher(\n                256,\n                ahash::RandomState::with_seeds(\n                    u64::from_ne_bytes(<[u8; 8]>::try_from(&seed[0..8]).unwrap()),\n                    u64::from_ne_bytes(<[u8; 8]>::try_from(&seed[8..16]).unwrap()),\n                    u64::from_ne_bytes(<[u8; 8]>::try_from(&seed[16..24]).unwrap()),\n                    u64::from_ne_bytes(<[u8; 8]>::try_from(&seed[24..32]).unwrap()),\n                ),\n            ),\n            video_outputs: hashbrown::HashMap::with_capacity_and_hasher(\n                16,\n                ahash::RandomState::with_seeds(\n                    u64::from_ne_bytes(<[u8; 8]>::try_from(&seed[32..40]).unwrap()),\n                    u64::from_ne_bytes(<[u8; 8]>::try_from(&seed[40..48]).unwrap()),\n                    u64::from_ne_bytes(<[u8; 8]>::try_from(&seed[48..56]).unwrap()),\n                    u64::from_ne_bytes(<[u8; 8]>::try_from(&seed[56..64]).unwrap()),\n                ),\n            ),\n            next_framebuffer_position: (20, 20),\n        }\n    }\n\n    pub fn add_video_output(\n        &mut self,\n        id: TOutId,\n        width: u32,\n        height: u32,\n        format: Format,\n        user_data: TOut,\n    ) -> VideoOutputAccess<TFbId, TOutId, TFb, TOut> {\n        debug_assert!(self.video_outputs.values().any(|out| out.position.x == 0));\n        let x_position = self\n            .video_outputs\n            .values()\n            .fold(0, |total, out| total + out.position.width);\n        debug_assert!(!self\n            .video_outputs\n            .values()\n            .any(|out| out.position.x + out.position.width > x_position));\n\n        // TODO: error if duplicate\n        self.video_outputs.insert(\n            id.clone(),\n            VideoOutput {\n                position: rect::Rect {\n                    width,\n                    height,\n                    x: x_position,\n                    y: 0,\n                },\n                format,\n                needs_refresh: {\n                    let mut list = VecDeque::with_capacity(16);\n                    list.push_back(rect::Rect {\n                        x: 0,\n                        y: 0,\n                        width,\n                        height,\n                    });\n                    list\n                },\n                user_data,\n            },\n        );\n\n        VideoOutputAccess { parent: self, id }\n    }\n\n    pub fn video_output_by_id(\n        &mut self,\n        id: &TOutId,\n    ) -> Option<VideoOutputAccess<TFbId, TOutId, TFb, TOut>> {\n        if self.video_outputs.contains_key(id) {\n            Some(VideoOutputAccess {\n                parent: self,\n                id: id.clone(),\n            })\n        } else {\n            None\n        }\n    }\n\n    pub fn video_outputs(&self) -> impl ExactSizeIterator<Item = &TOutId> {\n        self.video_outputs.keys()\n    }\n\n    pub fn add_framebuffer(\n        &mut self,\n        id: TFbId,\n        width: u32,\n        height: u32,\n        user_data: TFb,\n    ) -> FramebufferAccess<TFbId, TOutId, TFb, TOut> {\n        let fb_position = rect::Rect {\n            width,\n            height,\n            x: self.next_framebuffer_position.0,\n            y: self.next_framebuffer_position.1,\n        };\n\n        // TODO: error if duplicate\n        self.framebuffers.insert(\n            id.clone(),\n            Framebuffer {\n                position: fb_position,\n                user_data,\n                // TODO: return error instead of panicking if width*height is too large; there is clearly some attack vector with these width and height values\n                rgb_data: (0..usize::try_from(width * height).unwrap())\n                    .map(|_| [0; 4])\n                    .collect(),\n            },\n        );\n\n        self.next_framebuffer_position.0 = (self.next_framebuffer_position.0 + 20) % 300;\n        self.next_framebuffer_position.1 = (self.next_framebuffer_position.1 + 20) % 200;\n\n        // Invalidate areas from video outputs that overlap with the newly-created framebuffer.\n        for video_output in self.video_outputs.values_mut() {\n            let overlap = match video_output.position.intersection(&fb_position) {\n                Some(ov) => ov,\n                None => continue,\n            };\n\n            // `overlap` contains desktop positions, while `needs_refresh` contains positions\n            // relative to the video output.\n            video_output.needs_refresh.push_back(rect::Rect {\n                x: overlap.x - video_output.position.x,\n                y: overlap.y - video_output.position.y,\n                width: overlap.width,\n                height: overlap.height,\n            });\n        }\n\n        FramebufferAccess { parent: self, id }\n    }\n\n    pub fn framebuffer_by_id(\n        &mut self,\n        id: &TFbId,\n    ) -> Option<FramebufferAccess<TFbId, TOutId, TFb, TOut>> {\n        if self.framebuffers.contains_key(id) {\n            Some(FramebufferAccess {\n                parent: self,\n                id: id.clone(),\n            })\n        } else {\n            None\n        }\n    }\n\n    pub fn framebuffers(&self) -> impl ExactSizeIterator<Item = &TFbId> {\n        self.framebuffers.keys()\n    }\n\n    /// Updates the state machine after one frame has passed.\n    pub fn next_frame(&mut self) {\n        // TODO: is this necessary? consider removing if this does nothing\n    }\n\n    /// Finds the color of the pixel at the given desktop coordinates.\n    fn desktop_pixel(&self, x: u32, y: u32) -> [u8; 3] {\n        // TODO: this method is probably naive and super slow\n        // TODO: properly handle z layers\n\n        let mut accumulator = [255, 255, 255];\n\n        for framebuffer in self.framebuffers.values() {\n            let fb_offset_x = match x.checked_sub(framebuffer.position.x) {\n                Some(off) => off,\n                None => continue,\n            };\n\n            let fb_offset_y = match y.checked_sub(framebuffer.position.y) {\n                Some(off) => off,\n                None => continue,\n            };\n\n            if fb_offset_x >= framebuffer.position.width {\n                continue;\n            }\n\n            if fb_offset_y >= framebuffer.position.height {\n                continue;\n            }\n\n            let fb_pixel = framebuffer.rgb_data\n                [usize::try_from(fb_offset_y * framebuffer.position.width + fb_offset_x).unwrap()];\n            accumulator = blend(fb_pixel, accumulator);\n        }\n\n        accumulator\n    }\n}\n\nfn blend(a: [u8; 4], b: [u8; 3]) -> [u8; 3] {\n    let b_alpha = u16::from(255 - a[3]);\n\n    let r = u16::from(a[0]) * u16::from(a[3]) + u16::from(b[0]) * b_alpha;\n    let g = u16::from(a[2]) * u16::from(a[3]) + u16::from(b[1]) * b_alpha;\n    let b = u16::from(a[1]) * u16::from(a[3]) + u16::from(b[2]) * b_alpha;\n\n    [\n        u8::try_from(r / 255).unwrap(),\n        u8::try_from(g / 255).unwrap(),\n        u8::try_from(b / 255).unwrap(),\n    ]\n}\n\n/// Access to a framebuffer within a [`Compositor`].\npub struct FramebufferAccess<'a, TFbId, TOutId, TFb, TOut> {\n    parent: &'a mut Compositor<TFbId, TOutId, TFb, TOut>,\n    id: TFbId,\n}\n\nimpl<'a, TFbId: Clone + Eq + Hash, TOutId: Clone + Eq + Hash, TFb, TOut>\n    FramebufferAccess<'a, TFbId, TOutId, TFb, TOut>\n{\n    /// Removes the framebuffer from the compositor state machine.\n    pub fn remove(self) -> TFb {\n        self.parent.framebuffers.remove(&self.id).unwrap().user_data\n    }\n\n    pub fn user_data(&self) -> &TFb {\n        &self.parent.framebuffers.get(&self.id).unwrap().user_data\n    }\n\n    pub fn user_data_mut(&mut self) -> &mut TFb {\n        &mut self\n            .parent\n            .framebuffers\n            .get_mut(&self.id)\n            .unwrap()\n            .user_data\n    }\n\n    /// Sets the content of the framebuffer.\n    ///\n    /// This potentially pushes pending changes to the various video outputs that can later be\n    /// retreived using [`VideoOutputAccess::drain_pending_changes`].\n    pub fn set_content(&mut self, x_range: Range<u32>, y_range: Range<u32>, data: &[u8]) {}\n}\n\n/// Access to a video output within a [`Compositor`].\npub struct VideoOutputAccess<'a, TFbId, TOutId, TFb, TOut> {\n    parent: &'a mut Compositor<TFbId, TOutId, TFb, TOut>,\n    id: TOutId,\n}\n\nimpl<'a, TFbId: Clone + Eq + Hash, TOutId: Clone + Eq + Hash, TFb, TOut>\n    VideoOutputAccess<'a, TFbId, TOutId, TFb, TOut>\n{\n    /// Removes the video output from the compositor state machine.\n    pub fn remove(self) -> TOut {\n        self.parent\n            .video_outputs\n            .remove(&self.id)\n            .unwrap()\n            .user_data\n    }\n\n    pub fn user_data(&self) -> &TOut {\n        &self.parent.video_outputs.get(&self.id).unwrap().user_data\n    }\n\n    pub fn user_data_mut(&mut self) -> &mut TOut {\n        &mut self\n            .parent\n            .video_outputs\n            .get_mut(&self.id)\n            .unwrap()\n            .user_data\n    }\n\n    pub fn drain_pending_changes<'b: 'a>(&'b mut self) -> impl Iterator<Item = PendingChange> + 'b {\n        iter::from_fn(move || {\n            let video_output = self.parent.video_outputs.get_mut(&self.id).unwrap();\n            let area = video_output.needs_refresh.pop_front()?;\n            let video_output_position = video_output.position;\n            let video_output_format = video_output.format;\n\n            Some(PendingChange {\n                screen_x_start: area.x,\n                screen_x_len: area.width,\n                screen_y_start: area.y,\n                pixels: (area.y..area.y + area.height)\n                    .map(|y| {\n                        let desktop_y = y + video_output_position.y;\n                        (area.x..area.x + area.width)\n                            .flat_map(|x| {\n                                let desktop_x = x + video_output_position.x;\n                                let pixel = self.parent.desktop_pixel(desktop_x, desktop_y);\n                                convert_format(pixel, &video_output_format)\n                            })\n                            .collect()\n                    })\n                    .collect(),\n            })\n        })\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct PendingChange {\n    pub screen_x_start: u32,\n    // TODO: not necessary?\n    pub screen_x_len: u32,\n    pub screen_y_start: u32,\n    /// Rows of pixels.\n    pub pixels: Vec<Vec<u8>>,\n}\n\n#[derive(Debug, Copy, Clone)]\npub enum Format {\n    R8G8B8X8,\n}\n\nfn convert_format(pixel: [u8; 3], format: &Format) -> impl Iterator<Item = u8> {\n    match format {\n        Format::R8G8B8X8 => iter::once(pixel[0])\n            .chain(iter::once(pixel[1]))\n            .chain(iter::once(pixel[2]))\n            .chain(iter::once(0xff)),\n    }\n}\n"
  },
  {
    "path": "programs/compositor/src/main.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n#![recursion_limit = \"2048\"]\n\nuse futures::prelude::*;\nuse rand::RngCore as _;\nuse redshirt_framebuffer_interface::ffi as fb_ffi;\nuse redshirt_interface_interface::DecodedInterfaceOrDestroyed;\nuse redshirt_syscalls::{Decode as _, MessageId, Pid};\nuse redshirt_time_interface::Delay;\nuse redshirt_video_output_interface::ffi as vid_ffi;\nuse std::{collections::VecDeque, convert::TryFrom as _, time::Duration};\n\nfn main() {\n    redshirt_syscalls::block_on(async_main())\n}\n\nasync fn async_main() {\n    // Register the interfaces.\n    let mut video_registration =\n        redshirt_interface_interface::register_interface(vid_ffi::INTERFACE)\n            .await\n            .unwrap();\n    let mut framebuffer_events_registration =\n        redshirt_interface_interface::register_interface(fb_ffi::INTERFACE_WITH_EVENTS)\n            .await\n            .unwrap();\n    let mut framebuffer_noevents_registration =\n        redshirt_interface_interface::register_interface(fb_ffi::INTERFACE_WITHOUT_EVENTS)\n            .await\n            .unwrap();\n\n    // Main state machine holding all the information used below.\n    let mut compositor = compositor::Compositor::with_seed({\n        let mut seed = [0; 64];\n        rand::thread_rng().fill_bytes(&mut seed);\n        seed\n    });\n\n    struct VideoOutput {\n        next_frame_messages: VecDeque<MessageId>,\n    }\n\n    struct Framebuffer {\n        next_event_messages: VecDeque<MessageId>,\n    }\n\n    let mut next_frame = Delay::new(Duration::from_secs(0)).fuse();\n\n    loop {\n        futures::select! {\n            video_output_event = video_registration.next_message_raw().fuse() => {\n                match video_output_event {\n                    DecodedInterfaceOrDestroyed::Interface(msg) => {\n                        match vid_ffi::VideoOutputMessage::decode(msg.actual_data).unwrap() {\n                            vid_ffi::VideoOutputMessage::Register { id, width, height, format } => {\n                                let format = match format {\n                                    vid_ffi::Format::R8G8B8X8 => compositor::Format::R8G8B8X8,\n                                };\n\n                                compositor.add_video_output((msg.emitter_pid, id), width, height, format, VideoOutput {\n                                    next_frame_messages: VecDeque::with_capacity(16),\n                                });\n                            }\n                            vid_ffi::VideoOutputMessage::Unregister(id) => {\n                                if let Some(vo) = compositor.video_output_by_id(&(msg.emitter_pid, id)) {\n                                    let video_output = vo.remove();\n                                    for message_id in video_output.next_frame_messages {\n                                        redshirt_interface_interface::emit_message_error(message_id);\n                                    }\n                                }\n                            }\n                            vid_ffi::VideoOutputMessage::NextImage(id) => {\n                                if let Some(message_id) = msg.message_id {\n                                    if let Some(mut vo) = compositor.video_output_by_id(&(msg.emitter_pid, id)) {\n                                        // TODO: add some limit to the number of events\n                                        vo.user_data_mut().next_frame_messages.push_back(message_id)\n                                    } else {\n                                        redshirt_interface_interface::emit_message_error(message_id)\n                                    }\n                                }\n                            }\n                        }\n                    },\n                    DecodedInterfaceOrDestroyed::ProcessDestroyed(destroyed) => {\n                        for video_output_id in compositor.video_outputs().cloned().collect::<Vec<_>>() {\n                            if video_output_id.0 != destroyed.pid {\n                                continue;\n                            }\n\n                            compositor.video_output_by_id(&video_output_id).unwrap().remove();\n                        }\n                    }\n                }\n            },\n\n            framebuffer_event = framebuffer_events_registration.next_message_raw().fuse() => {\n                match framebuffer_event {\n                    DecodedInterfaceOrDestroyed::Interface(msg) => {\n                        match msg.actual_data.0.get(0) {\n                            Some(0) if msg.actual_data.0.len() == 13 => {\n                                let fb_id = u32::from_le_bytes(<[u8; 4]>::try_from(&msg.actual_data.0[1..5]).unwrap());\n                                let width = u32::from_le_bytes(<[u8; 4]>::try_from(&msg.actual_data.0[5..9]).unwrap());\n                                let height = u32::from_le_bytes(<[u8; 4]>::try_from(&msg.actual_data.0[9..13]).unwrap());\n                                compositor.add_framebuffer((msg.emitter_pid, fb_id), width, height, Framebuffer {\n                                    next_event_messages: VecDeque::with_capacity(16),\n                                });\n                            }\n                            Some(1) if msg.actual_data.0.len() == 5 => {\n                                let fb_id = u32::from_le_bytes(<[u8; 4]>::try_from(&msg.actual_data.0[1..5]).unwrap());\n                                if let Some(fb) = compositor.framebuffer_by_id(&(msg.emitter_pid, fb_id)) {\n                                    let framebuffer = fb.remove();\n                                    for message_id in framebuffer.next_event_messages {\n                                        redshirt_interface_interface::emit_message_error(message_id);\n                                    }\n                                }\n                            }\n                            // TODO: Some(2) handling\n                            Some(3) if msg.actual_data.0.len() == 5 => {\n                                let fb_id = u32::from_le_bytes(<[u8; 4]>::try_from(&msg.actual_data.0[1..5]).unwrap());\n                                if let Some(message_id) = msg.message_id {\n                                    if let Some(mut fb) = compositor.framebuffer_by_id(&(msg.emitter_pid, fb_id)) {\n                                        // TODO: add some limit to the number of events\n                                        fb.user_data_mut().next_event_messages.push_back(message_id);\n                                    } else {\n                                        redshirt_interface_interface::emit_message_error(message_id);\n                                    }\n                                }\n                            }\n                            _ => {\n                                if let Some(message_id) = msg.message_id {\n                                    redshirt_interface_interface::emit_message_error(message_id);\n                                }\n                            }\n                        }\n                    },\n                    DecodedInterfaceOrDestroyed::ProcessDestroyed(destroyed) => {\n                        for framebuffer_id in compositor.framebuffers().cloned().collect::<Vec<_>>() {\n                            if framebuffer_id.0 != destroyed.pid {\n                                continue;\n                            }\n\n                            compositor.framebuffer_by_id(&framebuffer_id).unwrap().remove();\n                        }\n                    }\n                }\n            },\n\n            () = next_frame => {\n                compositor.next_frame();\n                next_frame = Delay::new(Duration::new(0, 16666667)).fuse();\n                for video_output_id in compositor.video_outputs().cloned().collect::<Vec<_>>() {\n                    let mut video_output = compositor.video_output_by_id(&video_output_id).unwrap();\n\n                    let message_id = match video_output.user_data_mut().next_frame_messages.pop_front() {\n                        Some(m) => m,\n                        None => continue,\n                    };\n\n                    redshirt_interface_interface::emit_answer(message_id, vid_ffi::NextImage {\n                        changes: video_output.drain_pending_changes().map(|change| {\n                            vid_ffi::NextImageChange {\n                                screen_x_start: change.screen_x_start,\n                                screen_x_len: change.screen_x_len,\n                                screen_y_start: change.screen_y_start,\n                                pixels: change.pixels,\n                            }\n                        }).collect(),\n                    });\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "programs/compositor/src/rect.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse core::cmp;\n\n#[derive(Debug, Copy, Clone, PartialEq, Eq)]\npub struct Rect {\n    pub x: u32,\n    pub y: u32,\n    pub width: u32,\n    pub height: u32,\n}\n\nimpl Rect {\n    /// Returns the intersection between this rectangle and another.\n    ///\n    /// Returns `None` if the two rectangles don't overlap.\n    pub fn intersection(&self, other: &Rect) -> Option<Rect> {\n        let (x, width) = line_intersect(self.x, self.width, other.x, other.width)?;\n        let (y, height) = line_intersect(self.y, self.height, other.y, other.height)?;\n\n        Some(Rect {\n            x,\n            y,\n            width,\n            height,\n        })\n    }\n}\n\nfn line_intersect(base: u32, len: u32, other_base: u32, other_len: u32) -> Option<(u32, u32)> {\n    if base < other_base {\n        let overlap_len = len.checked_sub(other_base - base)?;\n        Some((other_base, cmp::min(overlap_len, other_len)))\n    } else {\n        let overlap_len = other_len.checked_sub(base - other_base)?;\n        Some((base, cmp::min(overlap_len, len)))\n    }\n}\n"
  },
  {
    "path": "programs/diagnostics-http-server/Cargo.toml",
    "content": "[package]\nname = \"diagnostics-http-server\"\nversion = \"0.1.0\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[dependencies]\nfutures = \"0.3.21\"\nhyper = { version = \"0.14.17\", default-features = false, features = [\"server\", \"http1\"] }\nlog = \"0.4.14\"\nredshirt-kernel-debug-interface = { path = \"../../interface-wrappers/kernel-debug\" }\nredshirt-log-interface = { path = \"../../interface-wrappers/log\" }\nredshirt-syscalls = { path = \"../../interface-wrappers/syscalls\" }\nredshirt-tcp-interface = { path = \"../../interface-wrappers/tcp\" }\n"
  },
  {
    "path": "programs/diagnostics-http-server/src/main.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Starts an HTTP server listening on 0.0.0.0:8000 and reporting Prometheus metrics.\n\nuse futures::{channel::mpsc, prelude::*};\nuse std::{pin::Pin, task::Context, task::Poll};\n\nfn main() {\n    redshirt_log_interface::init();\n\n    redshirt_syscalls::block_on(async move {\n        let listener = redshirt_tcp_interface::TcpListener::bind(&\"0.0.0.0:8000\".parse().unwrap())\n            .await\n            .unwrap();\n\n        log::info!(\"Kernel Prometheus metrics now available on http://0.0.0.0:8000/metrics\");\n\n        let stream = stream::unfold(listener, |l| async move {\n            let connec = l.accept().await.0;\n            Some((connec, l))\n        });\n\n        let mut active_conncs =\n            stream::FuturesUnordered::<Pin<Box<dyn Future<Output = ()>>>>::new();\n        active_conncs.push(Box::pin(future::pending()));\n        let (tx, mut rx) = mpsc::unbounded();\n\n        let http = hyper::server::conn::Http::new().with_executor(Executor { pusher: tx });\n\n        let mut server = hyper::server::Builder::new(\n            Accept {\n                next_connec: Box::pin(stream),\n            },\n            http,\n        )\n        .serve(hyper::service::make_service_fn(|_| async {\n            Ok::<_, hyper::Error>(hyper::service::service_fn(|req| async move {\n                if req.uri().path() == \"/metrics\" {\n                    let metrics = redshirt_kernel_debug_interface::get_prometheus_metrics().await;\n                    hyper::Response::builder()\n                        .status(hyper::StatusCode::OK)\n                        .header(\"Content-Type\", \"text/plain; version=0.0.4\")\n                        .body(hyper::Body::from(metrics))\n                } else {\n                    hyper::Response::builder()\n                        .status(hyper::StatusCode::NOT_FOUND)\n                        .body(hyper::Body::from(\"Not found\"))\n                }\n            }))\n        }));\n\n        loop {\n            let new_connec =\n                match future::select(future::select(&mut server, rx.next()), active_conncs.next())\n                    .await\n                {\n                    future::Either::Left((future::Either::Left((_, _)), _)) => {\n                        println!(\"server finished\");\n                        break;\n                    }\n                    future::Either::Left((future::Either::Right((new_connec, _)), _)) => {\n                        new_connec.unwrap()\n                    }\n                    future::Either::Right((_, _)) => continue,\n                };\n\n            active_conncs.push(new_connec);\n        }\n    });\n}\n\nstruct Accept {\n    next_connec: Pin<Box<dyn Stream<Item = redshirt_tcp_interface::TcpStream>>>,\n}\n\nimpl hyper::server::accept::Accept for Accept {\n    type Conn = redshirt_tcp_interface::TcpStream;\n    type Error = std::io::Error;\n\n    fn poll_accept(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context,\n    ) -> Poll<Option<Result<Self::Conn, Self::Error>>> {\n        match Stream::poll_next(Pin::new(&mut self.next_connec), cx) {\n            Poll::Ready(Some(c)) => Poll::Ready(Some(Ok(c))),\n            Poll::Ready(None) => Poll::Ready(None),\n            Poll::Pending => Poll::Pending,\n        }\n    }\n}\n\n#[derive(Clone)]\nstruct Executor {\n    pusher: mpsc::UnboundedSender<Pin<Box<dyn Future<Output = ()>>>>,\n}\n\nimpl<T: Future<Output = ()> + 'static> hyper::rt::Executor<T> for Executor {\n    fn execute(&self, future: T) {\n        self.pusher.unbounded_send(Box::pin(future)).unwrap()\n    }\n}\n"
  },
  {
    "path": "programs/dummy-system-time/Cargo.toml",
    "content": "[package]\nname = \"dummy-system-time\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[dependencies]\nredshirt-interface-interface = { path = \"../../interface-wrappers/interface\" }\nredshirt-syscalls = { path = \"../../interface-wrappers/syscalls\" }\nredshirt-system-time-interface = { path = \"../../interface-wrappers/system-time\" }\n"
  },
  {
    "path": "programs/dummy-system-time/src/main.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse redshirt_interface_interface::DecodedInterfaceOrDestroyed;\nuse redshirt_syscalls::Decode as _;\nuse redshirt_system_time_interface::ffi as sys_time_ffi;\n\nfn main() {\n    redshirt_syscalls::block_on(async_main())\n}\n\nasync fn async_main() {\n    let mut registration =\n        redshirt_interface_interface::register_interface(sys_time_ffi::INTERFACE)\n            .await\n            .unwrap();\n\n    loop {\n        let interface_event = registration.next_message_raw().await;\n        let msg = match interface_event {\n            DecodedInterfaceOrDestroyed::Interface(msg) => msg,\n            DecodedInterfaceOrDestroyed::ProcessDestroyed(_) => continue,\n        };\n\n        let msg_data = sys_time_ffi::TimeMessage::decode(msg.actual_data).unwrap();\n        let sys_time_ffi::TimeMessage::GetSystem = msg_data;\n\n        if let Some(id) = msg.message_id {\n            redshirt_interface_interface::emit_answer(id, &0u128);\n        }\n    }\n}\n"
  },
  {
    "path": "programs/e1000/Cargo.toml",
    "content": "[package]\nname = \"e1000\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[dependencies]\nderive_more = \"0.99.17\"\nfutures = \"0.3.21\"\nredshirt-ethernet-interface = { path = \"../../interface-wrappers/ethernet\" }\nredshirt-hardware-interface = { path = \"../../interface-wrappers/hardware\" }\nredshirt-pci-interface = { path = \"../../interface-wrappers/pci\" }\nredshirt-syscalls = { path = \"../../interface-wrappers/syscalls\" }\nredshirt-time-interface = { path = \"../../interface-wrappers/time\" }\nsmallvec = \"1.8.0\"\n"
  },
  {
    "path": "programs/e1000/src/device.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Bibliography:\n//!\n//! - https://www.intel.com/content/dam/doc/manual/pci-pci-x-family-gbe-controllers-software-dev-manual.pdf\n//! - https://wiki.osdev.org/Intel_8254x\n//!\n\nuse core::{convert::TryFrom as _, fmt, mem, time::Duration};\nuse futures::lock::Mutex;\nuse redshirt_hardware_interface::malloc::PhysicalBuffer;\nuse redshirt_time_interface::Delay;\n\n/// State of a device.\n//\n// # Device overview\n//\n// To use a e1000-compatible card, one must allocate two ring buffers in physical memory, one\n// receive descriptors ring buffer and one transmit descriptors ring buffer, and configure to\n// device to use these ring buffers.\n//\n// These two ring buffers contain *descriptors* indicating the read or write operation to perform.\n// These descriptors contain pointers to other buffers that contain the actual data.\n//\n// While the device is active, it will automatically process the content of these ring buffers.\n// This driver only needs to write a single register (the read descripor tail or transmit\n// descriptor tail) to indicate to the device that the ring buffer has been updated. Once the\n// device has written incoming data in a read descriptor or transmitted data in a transmit\n// descriptor, it writes a flag in the descriptor itself, which this driver can read to determine\n// that the descriptor either contains data or is available for a new transmit.\npub struct Device {\n    /// Base physical address of the memory-mapped registers.\n    regs_base_address: u64,\n    /// MAC address of the device.\n    mac_address: [u8; 6],\n\n    /// Ring buffer of receive descriptors. Read by the hardware.\n    receive_descriptors: PhysicalBuffer<[ReceiveDescriptor]>,\n    /// For each descriptor in the ring buffer, a buffer where the data is going to be received.\n    receive_buffers: Vec<PhysicalBuffer<[u8]>>,\n    /// Index within `receive_buffers` of the next descriptor that is expected to receive data.\n    /// The `Mutex` must be locked while the descriptor in question is being checked. If the\n    /// receive descriptor tail register must be written, it must be done before unlocking this\n    /// mutex to guarantee the lack of race conditions.\n    receive_next: Mutex<usize>,\n\n    /// Ring buffer of transmit descriptors. Read by the hardware.\n    transmit_descriptors: PhysicalBuffer<[TransmitDescriptor]>,\n    /// For each descriptor in the ring buffer, a buffer from where the data is located.\n    /// While we could allocate a new buffer for every single write, re-using the same buffers\n    /// every time also saves us from having to properly track lifetimes.\n    transmit_buffers: Vec<PhysicalBuffer<[u8]>>,\n    /// State of the transmit descriptors. If the transmit descriptor tail register must be\n    /// written, it must be done before unlocking this mutex to guarantee the lack of race\n    /// conditions.\n    transmit_state: Mutex<TransmitState>,\n}\n\nstruct TransmitState {\n    /// Index in the transmit descriptors of the next transmit descriptor that we can use to send\n    /// something. Always corresponds to the \"transmit queue tail\" register.\n    next_available: usize,\n\n    /// Index in the transmit descriptors of the next transmit descriptor that the hardware is\n    /// currently sending and that we will attempt to reclaim.\n    /// If `next_reclaim` is equal to `next_available`, then there's an ambiguity as to whether\n    /// the queue is full or empty. To avoid this, we never fully reclaim all the transmit\n    /// descriptors and always leave at least one transmit descriptor owned by the hardware.\n    /// Therefore, if the two values are equal it means that the queue is full.\n    next_reclaim: usize,\n}\n\n// List of registers, which their offset, in bytes, relative to the base mapping address.\nconst REGS_CTRL: u64 = 0x0;\nconst REGS_STATUS: u64 = 0x8;\nconst REGS_FCAL: u64 = 0x28;\nconst REGS_FCAH: u64 = 0x2c;\nconst REGS_FCT: u64 = 0x30;\nconst REGS_ICR: u64 = 0xc0;\nconst REGS_ITR: u64 = 0xc4;\nconst REGS_IMS: u64 = 0xd0;\nconst REGS_IMC: u64 = 0xd8;\nconst REGS_RCTL: u64 = 0x100;\nconst REGS_FCTTV: u64 = 0x170;\nconst REGS_TCTL: u64 = 0x400;\nconst REGS_RDBAL: u64 = 0x2800;\nconst REGS_RDBAH: u64 = 0x2804;\nconst REGS_RDLEN: u64 = 0x2808;\nconst REGS_RDH: u64 = 0x2810;\nconst REGS_RDT: u64 = 0x2818;\nconst REGS_RDTR: u64 = 0x2820;\nconst REGS_TDBAL: u64 = 0x3800;\nconst REGS_TDBAH: u64 = 0x3804;\nconst REGS_TDLEN: u64 = 0x3808;\nconst REGS_TDH: u64 = 0x3810;\nconst REGS_TDT: u64 = 0x3818;\nconst REGS_MTA_BASE: u64 = 0x5200;\nconst REGS_RAL: u64 = 0x5400;\nconst REGS_RAH: u64 = 0x5404;\n\n#[derive(Debug, Copy, Clone)]\n#[repr(packed)]\nstruct ReceiveDescriptor {\n    buffer_address: u64,\n    length: u16,\n    // reserved, on some devices\n    checksum: u16,\n    status: u8,\n    errors: u8,\n    // reserved, on some devices\n    special: u16,\n}\n\n// This is a so-called \"legacy\" descriptor.\n#[derive(Debug, Copy, Clone)]\n#[repr(packed)]\nstruct TransmitDescriptor {\n    buffer_address: u64,\n    length: u16,\n    checksum_offset: u8,\n    command: u8,\n    status: u8, // also includes a \"reserved\" field\n    checksum_start: u8,\n    special: u16,\n}\n\nimpl Device {\n    /// Assumes that a e1000 device is mapped starting at `base_port` and reinitializes it\n    /// to a starting state.\n    pub async unsafe fn reset(regs_base_address: u64) -> Result<DevicePrototype, InitErr> {\n        // Set the RST flag in order to reset the device.\n        redshirt_hardware_interface::write_one_u32(\n            regs_base_address + REGS_CTRL,\n            redshirt_hardware_interface::read_one_u32(regs_base_address + REGS_CTRL).await\n                | (1 << 26),\n        );\n\n        // Specs recommend to wait for 1µs.\n        Delay::new(Duration::from_micros(1)).await;\n\n        // Wait for reset to be complete.\n        {\n            let mut attempts = 0;\n            loop {\n                attempts += 1;\n                if attempts >= 1000 {\n                    return Err(InitErr::Timeout);\n                }\n\n                let val =\n                    redshirt_hardware_interface::read_one_u32(regs_base_address + REGS_CTRL).await;\n                if (val & (1 << 26)) == 0 {\n                    break;\n                }\n\n                Delay::new(Duration::from_millis(5)).await;\n            }\n        }\n\n        Ok(DevicePrototype { regs_base_address })\n    }\n\n    /// Returns the MAC address of the device.\n    pub fn mac_address(&self) -> [u8; 6] {\n        self.mac_address\n    }\n\n    /// Reads the next pending Ethernet frame waiting to be delivered, if any.\n    ///\n    /// Returns `None` if there's no packet available.\n    ///\n    /// > **Note**: This function is asynchronous, but it returns as soon as it determines that\n    /// >           no packet is available. It does *not* wait for one packet to be available.\n    pub async unsafe fn read_one_incoming(&self) -> Option<Vec<u8>> {\n        let mut receive_next = self.receive_next.lock().await;\n        debug_assert!(*receive_next < self.receive_descriptors.len());\n\n        // Read the next descriptor that we expect the hardware to write to.\n        let mut next_descriptor: ReceiveDescriptor = self\n            .receive_descriptors\n            .read_one(*receive_next)\n            .await\n            .unwrap();\n\n        // When the hardware has written the descriptor, it sets this bit on the status to mark\n        // it as ready. If the bit is not set, no packet is ready.\n        if next_descriptor.status & (1 << 0) == 0 {\n            return None;\n        }\n\n        // Normally, there is a N-to-one mapping between descriptors and packets. In other words,\n        // packets can occupy more than one descriptor. However, since we use 16 kiB buffers, it\n        // is guaranteed that packets will never use more than one descriptor.\n        // Check the \"end of packet\" bit.\n        assert!(next_descriptor.status & (1 << 1) != 0);\n\n        // The `errors` field indicates whether the packet is a correct or a faulty packet.\n        // We configure the device to not put faulty packets in the receive queue, and thus\n        // shouldn't find any.\n        assert_eq!(next_descriptor.errors, 0);\n\n        // Now reading the actual packet of data.\n        let packet = {\n            let mut packet = Vec::<u8>::with_capacity(usize::from(next_descriptor.length));\n            packet.set_len(packet.capacity());\n            self.receive_buffers[*receive_next]\n                .read_slice(0, &mut packet[..])\n                .await;\n            packet\n        };\n\n        // Overwrite the status byte of the descriptor to 0 to set it as \"non-ready\". This is not\n        // a requirement from the hardware, but it is necessary for us to differentiate ready from\n        // non-ready descriptors.\n        // TODO: optimize by writing only the status byte; needs `PhysicalBuffer` API tweaking\n        next_descriptor.status = 0;\n        self.receive_descriptors\n            .write_one(*receive_next, next_descriptor);\n\n        // Inform the hardware of the new tail. Note that the tail is one-past the last descriptor\n        // that he hardware is allowed to write. Therefore this write doesn't permit the hardware\n        // to write on `receive_next`, but it permits the hardware to write on `receive_next - 1`.\n        redshirt_hardware_interface::write_one_u32(\n            self.regs_base_address + REGS_RDT,\n            u32::try_from(*receive_next).unwrap(),\n        );\n\n        // Update `receive_next` for the next time.\n        *receive_next = (*receive_next + 1) % self.receive_descriptors.len();\n\n        // Success!\n        Some(packet)\n    }\n\n    /// Sends a packet out. Returns an error if the device's buffer is full, in which case we must\n    /// try again later.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the packet is too large.\n    ///\n    pub async unsafe fn send_packet<T>(&self, packet: T) -> Result<(), T>\n    where\n        T: AsRef<[u8]>,\n    {\n        let mut transmit_state = self.transmit_state.lock().await;\n        debug_assert!(transmit_state.next_available < self.transmit_descriptors.len());\n        debug_assert!(transmit_state.next_reclaim < self.transmit_descriptors.len());\n\n        // If our local head and tail are equal, it means that the queue is full.\n        if transmit_state.next_available == transmit_state.next_reclaim {\n            // We try to solve the queue being full by reclaiming descriptors whose transmission\n            // is finished.\n            loop {\n                // Don't reclaim too much!\n                let potential_next_reclaim =\n                    (transmit_state.next_reclaim + 1) % self.transmit_descriptors.len();\n                if potential_next_reclaim == transmit_state.next_available {\n                    break;\n                }\n\n                // Read the next descriptor that we expect the hardware to have finished\n                // processing.\n                let next_descriptor: TransmitDescriptor = self\n                    .transmit_descriptors\n                    .read_one(transmit_state.next_reclaim)\n                    .await\n                    .unwrap();\n\n                // When the hardware has finished processing the descriptor, it sets this bit on\n                // the status to mark it as done. If the bit is not set, the packet is still\n                // being transferred.\n                if next_descriptor.status & (1 << 0) == 0 {\n                    break;\n                }\n\n                // We can now treat this descriptor as reclaimed by incrementing `next_reclaim`.\n                transmit_state.next_reclaim = potential_next_reclaim;\n            }\n        }\n\n        // If it is still full, return with an error.\n        if transmit_state.next_available == transmit_state.next_reclaim {\n            return Err(packet);\n        }\n\n        // If we reach here, we know that `next_available` is free.\n\n        // Write the actual packet of data.\n        self.transmit_buffers[transmit_state.next_available].write_slice(0, packet.as_ref());\n\n        // Write the transmit descriptor itself.\n        self.transmit_descriptors.write_one(\n            transmit_state.next_available,\n            TransmitDescriptor {\n                buffer_address: self.transmit_buffers[transmit_state.next_available].pointer(),\n                length: u16::try_from(packet.as_ref().len()).unwrap(),\n                checksum_offset: 0,\n                command: {\n                    let mut cmd = 0;\n                    cmd |= 1 << 0; // This descriptor is the end of the packet.\n                    cmd |= 1 << 1; // Insert the CRC field in the packet.\n                    cmd |= 1 << 3; // Hardware should write back the \"status\" field when done.\n                    cmd\n                },\n                status: 0,\n                checksum_start: 0,\n                special: 0,\n            },\n        );\n\n        // Bump the value for the next time.\n        transmit_state.next_available =\n            (transmit_state.next_available + 1) % self.transmit_descriptors.len();\n\n        // Inform the hardware of the new tail. The hardware will start transmitting this\n        // descriptor.\n        redshirt_hardware_interface::write_one_u32(\n            self.regs_base_address + REGS_TDT,\n            u32::try_from(transmit_state.next_available).unwrap(),\n        );\n\n        Ok(())\n    }\n\n    /// Must be called when the device generates an interrupt.\n    ///\n    /// Returns a packet of data received from the network, if any.\n    pub async unsafe fn on_interrupt(&self) -> Vec<Vec<u8>> {\n        // Note: there exists a register indicating the cause for the interrupt, but we choose to\n        // ignore it and check everything.\n        // However, the action of reading it has the side-effect of clearing its bits, which is\n        // necessary for the next interrupt to be triggered.\n        let _ = redshirt_hardware_interface::read_one_u32(self.regs_base_address + REGS_ICR).await;\n\n        let mut out = Vec::with_capacity(8);\n        while let Some(packet) = self.read_one_incoming().await {\n            out.push(packet);\n        }\n        out\n    }\n}\n\nimpl fmt::Debug for Device {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_struct(\"Device\")\n            .field(\"regs_base_address\", &self.regs_base_address)\n            .field(\"mac_address\", &self.mac_address)\n            .finish()\n    }\n}\n\nimpl Drop for Device {\n    fn drop(&mut self) {\n        unsafe {\n            // Set the RST flag in order to reset the device.\n            redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_CTRL, 1 << 26);\n        }\n    }\n}\n\n/// Error that can happen during [`Device::reset`] or [`DevicePrototype::init`].\n#[derive(Debug, derive_more::Display)]\npub enum InitErr {\n    /// Device is taking too long to respond.\n    Timeout,\n}\n\n/// A device after it has been reinitialized but before it is active.\npub struct DevicePrototype {\n    /// Base physical address of the mapped memory of this device.\n    regs_base_address: u64,\n}\n\nimpl DevicePrototype {\n    /// Finish initializing the device.\n    pub async fn init(self) -> Result<Device, InitErr> {\n        unsafe {\n            // Documentation mentions that we should write 0 to the flow control registers if\n            // we don't use flow control.\n            redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_FCAL, 0);\n            redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_FCAH, 0);\n            redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_FCT, 0);\n            redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_FCTTV, 0);\n\n            // We set the flags of the CTRL register, effectively enabling the link with the\n            // outside.\n            redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_CTRL, {\n                let mut ctl =\n                    redshirt_hardware_interface::read_one_u32(self.regs_base_address + REGS_CTRL)\n                        .await;\n                ctl &= !(1 << 3); // Stop resetting link\n                ctl |= 1 << 5; // Automatic speed detection\n                ctl |= 1 << 6; // Set link up\n                ctl &= !(1 << 7); // Documentation says this bit should be cleared\n                ctl &= !(1 << 30); // Documentation says this bit should be cleared\n                ctl &= !(1 << 31); // Documentation says this bit should be cleared\n                ctl\n            });\n\n            // The interrupt throttling register prevents interrupts from being generated too\n            // often.\n            redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_ITR, {\n                // The value to pass is multiplied by 256ns to obtain the minimum interval between\n                // two interrupts.\n                // Here we set this interval to the arbitrary value of 1ms.\n                1000 * 4\n            });\n\n            // The documentation mentions that one must clear the IMS and IMC in order to prevent\n            // a deadlock using the 82547GI/EI.\n            redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_IMS, 0xffff);\n            redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_IMC, 0xffff);\n\n            // The IMS decides which interrupts are generated by the device.\n            // It is a \"set when written\" kind of register. In other words, writing 0 has no effect\n            // and writing 1 sets the bit.\n            redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_IMS, {\n                let mut mask = 0;\n                // TODO: should we process link broken interrupts? is there something to do? look\n                // in specs\n                mask |= 1 << 4; // Went over threshold for occupied space in receive descriptors.\n                mask |= 1 << 6; // Receive descriptors buffer full.\n                mask |= 1 << 7; // Timer after data has been received.\n                mask\n            });\n\n            // Delay between a received packet and the interrupt. Recommended to be set to 0, as\n            // we benefit from `REGS_ITR` instead.\n            redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_RDTR, 0);\n\n            // Reading the MAC address.\n            let mac_address: [u8; 6] = {\n                let lo =\n                    redshirt_hardware_interface::read_one_u32(self.regs_base_address + REGS_RAL)\n                        .await\n                        .to_le_bytes();\n                let hi =\n                    redshirt_hardware_interface::read_one_u32(self.regs_base_address + REGS_RAH)\n                        .await\n                        .to_le_bytes();\n                [lo[0], lo[1], lo[2], lo[3], hi[0], hi[1]]\n            };\n\n            // Configure the receive descriptor ring buffer.\n            let (receive_descriptors, receive_buffers) = {\n                let receive_descriptors = PhysicalBuffer::new_uninit_slice_with_align(32, 16)\n                    .await\n                    .assume_init();\n\n                // Each receive descriptor has an associated 16 kiB buffer where the packet will be\n                // written to.\n                let receive_buffers = {\n                    let mut b = Vec::with_capacity(receive_descriptors.len());\n                    for _ in 0..receive_descriptors.len() {\n                        b.push(\n                            PhysicalBuffer::new_uninit_slice(16 * 1024)\n                                .await\n                                .assume_init(),\n                        );\n                    }\n                    b\n                };\n\n                // Filling `receive_descriptors`. Only the `buffer_address` field is read by the\n                // hardware, while all the other fields will be written.\n                for n in 0..receive_descriptors.len() {\n                    receive_descriptors.write_one(\n                        n,\n                        ReceiveDescriptor {\n                            buffer_address: receive_buffers[n].pointer(),\n                            length: 0,\n                            checksum: 0,\n                            status: 0,\n                            errors: 0,\n                            special: 0,\n                        },\n                    );\n                }\n\n                // Indicate to the device the ring buffer address.\n                let address = receive_descriptors.pointer();\n                assert_eq!(address % 16, 0);\n                redshirt_hardware_interface::write_one_u32(\n                    self.regs_base_address + REGS_RDBAH,\n                    u32::try_from(address >> 32).unwrap(),\n                );\n                redshirt_hardware_interface::write_one_u32(\n                    self.regs_base_address + REGS_RDBAL,\n                    u32::try_from(address & 0xffffffff).unwrap(),\n                );\n\n                // Length of the ring buffer.\n                // \"16\" is the size in bytes of each descriptor.\n                debug_assert_eq!(mem::size_of::<ReceiveDescriptor>(), 16);\n                let rdlen = u32::try_from(receive_descriptors.len() * 16).unwrap();\n                assert_eq!(rdlen % 128, 0);\n                redshirt_hardware_interface::write_one_u32(\n                    self.regs_base_address + REGS_RDLEN,\n                    rdlen,\n                );\n                // Head of the ring buffer.\n                redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_RDH, 0);\n                // Tail of the ring buffer. The tail is defined as the last descriptor that is\n                // part of the buffer (not a one-past-the-end value).\n                redshirt_hardware_interface::write_one_u32(\n                    self.regs_base_address + REGS_RDT,\n                    u32::try_from(receive_descriptors.len() - 1).unwrap(),\n                );\n\n                // The MTA registers are filters for incoming packets. Initializing everything to\n                // 0 as recommended by documentation, even though these filters will normally not\n                // be used.\n                for n in 0..128 {\n                    redshirt_hardware_interface::write_one_u32(\n                        self.regs_base_address + REGS_MTA_BASE + n * 4,\n                        0,\n                    );\n                }\n\n                // Read control register.\n                redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_RCTL, {\n                    let mut rctl = 0u32;\n                    rctl |= 1 << 1; // Enable reading\n                    rctl |= 1 << 3; // Don't filter unicast packets\n                    rctl |= 1 << 4; // Don't filter multicast packets\n                    rctl |= 1 << 5; // Receive long packets\n                    rctl |= 0b00 << 8; // Interrupt generated when free space is <1/2 of total\n                    rctl |= 1 << 15; // Accept broadcast packets\n                    rctl |= 0b01 << 16; // Buffer size = 1 kiB, but...\n                    rctl |= 1 << 25; // Multiply buffer size by 16, so it's actually 16 kiB\n                    rctl |= 1 << 26; // Strip Ethernet checksum field\n                    rctl\n                });\n\n                (receive_descriptors, receive_buffers)\n            };\n\n            // Configure the transmit descriptor ring buffer.\n            let transmit_descriptors = {\n                // We fill the transmit descriptors by making it look like the hardware has\n                // previously successfully performed the write.\n                let transmit_descriptors = PhysicalBuffer::new_uninit_slice_with_align(32, 16)\n                    .await\n                    .assume_init();\n                for n in 0..transmit_descriptors.len() {\n                    transmit_descriptors.write_one(\n                        n,\n                        TransmitDescriptor {\n                            buffer_address: 0,\n                            length: 0,\n                            checksum_offset: 0,\n                            command: 0,\n                            status: 1,\n                            checksum_start: 0,\n                            special: 0,\n                        },\n                    )\n                }\n\n                // Indicate to the device the ring buffer address.\n                let address = transmit_descriptors.pointer();\n                assert_eq!(address % 16, 0);\n                redshirt_hardware_interface::write_one_u32(\n                    self.regs_base_address + REGS_TDBAH,\n                    u32::try_from(address >> 32).unwrap(),\n                );\n                redshirt_hardware_interface::write_one_u32(\n                    self.regs_base_address + REGS_TDBAL,\n                    u32::try_from(address & 0xffffffff).unwrap(),\n                );\n\n                // Length of the ring buffer.\n                // \"16\" is the size in bytes of each descriptor.\n                debug_assert_eq!(mem::size_of::<TransmitDescriptor>(), 16);\n                let tdlen = u32::try_from(receive_descriptors.len() * 16).unwrap();\n                assert_eq!(tdlen % 128, 0);\n                redshirt_hardware_interface::write_one_u32(\n                    self.regs_base_address + REGS_TDLEN,\n                    tdlen,\n                );\n                // Head of the ring buffer.\n                redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_TDH, 0);\n                // Tail of the ring buffer. The tail is defined as one beyond the last descriptor\n                // that the hardware might read from. By setting it to 0, the hardware won't read\n                // from any descriptor.\n                redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_TDT, 0);\n\n                // Transmit control register.\n                redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_TCTL, {\n                    let mut tctl = 0u32;\n                    tctl |= 1 << 1; // Enable writing\n                    tctl |= 1 << 3; // Automatically pad packets that are too short\n                                    // Number of attempts before we give up transmitting. 0xf is\n                                    // the recommended value.\n                    tctl |= 0xf << 4;\n                    // Number of garbage bytes to use for collision detection.\n                    // Recommended: 0x40 for full-duplex, 0x200 for half-duplex.\n                    tctl |= 0x40 << 12;\n                    tctl\n                });\n\n                transmit_descriptors\n            };\n\n            // Each transmit descriptor has an associated 16 kiB buffer where the actual packet is\n            // located.\n            let transmit_buffers = {\n                let mut b = Vec::with_capacity(transmit_descriptors.len());\n                for _ in 0..transmit_descriptors.len() {\n                    b.push(\n                        PhysicalBuffer::new_uninit_slice(16 * 1024)\n                            .await\n                            .assume_init(),\n                    );\n                }\n                b\n            };\n\n            // Wait for link to be up.\n            {\n                let mut attempts = 0u32;\n                loop {\n                    attempts += 1;\n                    if attempts >= 1000 {\n                        return Err(InitErr::Timeout);\n                    }\n\n                    let val = redshirt_hardware_interface::read_one_u32(\n                        self.regs_base_address + REGS_STATUS,\n                    )\n                    .await;\n                    if (val & (1 << 1)) != 0 {\n                        break;\n                    }\n\n                    Delay::new(Duration::from_millis(5)).await;\n                }\n            }\n\n            // Since the `Drop` implementation of the prototype resets the device again (by\n            // safety), we finish the initialization by mem::forget-ting the prototype.\n            let next_reclaim = transmit_buffers.len() - 1;\n            let device = Device {\n                regs_base_address: self.regs_base_address,\n                mac_address,\n                receive_descriptors,\n                receive_buffers,\n                receive_next: Mutex::new(0),\n                transmit_descriptors,\n                transmit_buffers,\n                transmit_state: Mutex::new(TransmitState {\n                    next_available: 0,\n                    next_reclaim,\n                }),\n            };\n            mem::forget(self);\n            Ok(device)\n        }\n    }\n}\n\nimpl fmt::Debug for DevicePrototype {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_struct(\"DevicePrototype\")\n            .field(\"regs_base_address\", &self.regs_base_address)\n            .finish()\n    }\n}\n\nimpl Drop for DevicePrototype {\n    fn drop(&mut self) {\n        unsafe {\n            // Set the RST flag in order to reset the device.\n            redshirt_hardware_interface::write_one_u32(self.regs_base_address + REGS_CTRL, 1 << 26);\n        }\n    }\n}\n"
  },
  {
    "path": "programs/e1000/src/main.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Driver for the Intel 8254x network cards family.\n//!\n//! This family of network cards is widely implemented in emulators such as QEmu, BOCHS, or\n//! VirtualBox.\n//!\n//! This program scans the PCI space for the e1000. If it finds it, it registers a new network\n//! interface towards the network manager, and handles the communication between the network\n//! manager and the hardware.\n\nuse futures::prelude::*;\nuse redshirt_ethernet_interface::interface;\n\nmod device;\n\nfn main() {\n    redshirt_syscalls::block_on(async_main());\n}\n\nasync fn async_main() {\n    let mut e1000_devices = Vec::new();\n\n    let pci_devices = redshirt_pci_interface::get_pci_devices().await;\n    for device in pci_devices {\n        // List of all the devices that we support.\n        // While there exists a wide range of features that some devices support and some others\n        // don't, we only support the common denominator of features between all these devices.\n        match (device.vendor_id, device.device_id) {\n            (0x8086, 0x100e)\n            | (0x8086, 0x100f)\n            | (0x8086, 0x1010)\n            | (0x8086, 0x1011)\n            | (0x8086, 0x1012)\n            | (0x8086, 0x1013)\n            | (0x8086, 0x1015)\n            | (0x8086, 0x1016)\n            | (0x8086, 0x1017)\n            | (0x8086, 0x1018)\n            | (0x8086, 0x1019)\n            | (0x8086, 0x101a)\n            | (0x8086, 0x101d)\n            | (0x8086, 0x1026)\n            | (0x8086, 0x1027)\n            | (0x8086, 0x1028)\n            | (0x8086, 0x1076)\n            | (0x8086, 0x1077)\n            | (0x8086, 0x1078)\n            | (0x8086, 0x1079)\n            | (0x8086, 0x107a)\n            | (0x8086, 0x107b)\n            | (0x8086, 0x1107)\n            | (0x8086, 0x1112) => {}\n            _ => continue,\n        };\n\n        let base_address = device\n            .base_address_registers\n            .iter()\n            .filter_map(|bar| match bar {\n                redshirt_pci_interface::PciBaseAddressRegister::Memory { base_address }\n                    if *base_address != 0 =>\n                {\n                    Some(*base_address)\n                }\n                _ => None,\n            })\n            .next();\n\n        let base_address = match base_address {\n            Some(p) => p,\n            None => continue,\n        };\n\n        let pci_lock = match redshirt_pci_interface::PciDeviceLock::lock(device.location).await {\n            Ok(l) => l,\n            // PCI device is already handled by a different driver.\n            Err(_) => continue,\n        };\n\n        // Start by resetting the device, in case it was active.\n        let device_prototype = match unsafe { device::Device::reset(base_address.into()) }.await {\n            Ok(p) => p,\n            Err(_) => continue,\n        };\n\n        // We need to inform the PCI bus that this device needs access to RAM.\n        // We only do this *after* resetting the device, otherwise it might have accidentally been\n        // still active and trying to perform memory writes.\n        pci_lock.set_command(true, true, false);\n\n        // Now that the device has access to memory, finish initialization.\n        let device = match device_prototype.init().await {\n            Ok(d) => d,\n            Err(_) => continue,\n        };\n\n        // Inform the Ethernet interface that a device is available.\n        let registration = interface::register_interface(interface::InterfaceConfig {\n            mac_address: device.mac_address(),\n        })\n        .await;\n\n        // `e1000_devices` is processed after we have finished enumerating all PCI devices.\n        e1000_devices.push((registration, pci_lock, device));\n    }\n\n    // Now that devices detection has been performed, we switch to phase 2: processing the\n    // detected devices.\n\n    if e1000_devices.is_empty() {\n        return;\n    }\n    e1000_devices.shrink_to_fit();\n\n    let mut tasks = stream::FuturesUnordered::new();\n    for (registration, pci_lock, device) in &e1000_devices {\n        // This task is dedicated to sending out packets in destination to the device.\n        tasks.push(\n            async move {\n                loop {\n                    let packet = registration.packet_to_send().await;\n                    unsafe {\n                        // TODO: this can panic if we are trying to send out data at a faster\n                        // rate than the device is capable of\n                        device.send_packet(packet).await.unwrap();\n                    }\n                }\n            }\n            .boxed_local(),\n        );\n\n        // This task is dedicated to listening to IRQs and pulling packets received from the\n        // network.\n        tasks.push(\n            async move {\n                loop {\n                    // Note that we grab a future to the next IRQ *before* calling `on_interrupt`,\n                    // otherwise IRQs that happen right after `on_interrupt` has returned wouldn't\n                    // be caught.\n                    let next_interrupt = pci_lock.next_interrupt();\n\n                    for packet in unsafe { device.on_interrupt().await } {\n                        registration.packet_from_network().await.send(packet)\n                    }\n\n                    next_interrupt.await;\n                }\n            }\n            .boxed_local(),\n        );\n    }\n\n    // Processing the tasks here.\n    while let Some(_) = tasks.next().await {}\n}\n"
  },
  {
    "path": "programs/hello-world/Cargo.toml",
    "content": "[package]\nname = \"hello-world\"\nversion = \"0.1.0\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n"
  },
  {
    "path": "programs/hello-world/src/main.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nfn main() {\n    println!(\"hello world\");\n}\n"
  },
  {
    "path": "programs/log-to-kernel/Cargo.toml",
    "content": "[package]\nname = \"log-to-kernel\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[dependencies]\nredshirt-interface-interface = { path = \"../../interface-wrappers/interface\" }\nredshirt-kernel-log-interface = { path = \"../../interface-wrappers/kernel-log\" }\nredshirt-log-interface = { path = \"../../interface-wrappers/log\" }\nredshirt-syscalls = { path = \"../../interface-wrappers/syscalls\" }\n"
  },
  {
    "path": "programs/log-to-kernel/src/main.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Implements the log interface by redirecting the logs as kernel logs.\n\nuse redshirt_log_interface::ffi;\nuse redshirt_syscalls::Decode as _;\n\nfn main() {\n    redshirt_syscalls::block_on(async_main());\n}\n\nasync fn async_main() -> ! {\n    let mut registration = redshirt_interface_interface::register_interface(ffi::INTERFACE)\n        .await\n        .unwrap();\n\n    loop {\n        let msg = match registration.next_message_raw().await {\n            redshirt_interface_interface::DecodedInterfaceOrDestroyed::Interface(m) => m,\n            redshirt_interface_interface::DecodedInterfaceOrDestroyed::ProcessDestroyed(_) => {\n                continue\n            }\n        };\n\n        assert_eq!(msg.interface, ffi::INTERFACE);\n\n        if let Ok(message) = ffi::DecodedLogMessage::decode(msg.actual_data) {\n            let level = match message.level() {\n                ffi::Level::Error => \"ERR \",\n                ffi::Level::Warn => \"WARN\",\n                ffi::Level::Info => \"INFO\",\n                ffi::Level::Debug => \"DEBG\",\n                ffi::Level::Trace => \"TRCE\",\n            };\n\n            let kernel_message =\n                format!(\"[{:?}] [{}] {}\", msg.emitter_pid, level, message.message());\n            redshirt_kernel_log_interface::log(kernel_message.as_bytes());\n        } else {\n            let kernel_message = format!(\"[{:?}] Bad log message\", msg.emitter_pid);\n            redshirt_kernel_log_interface::log(kernel_message.as_bytes());\n        }\n    }\n}\n"
  },
  {
    "path": "programs/network-manager/Cargo.toml",
    "content": "[package]\nname = \"network-manager\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[dependencies]\nfnv = { version = \"1.0.7\", default-features = false }\nfutures = \"0.3\"\nhashbrown = { version = \"0.12.0\", default-features = false }\nlog = \"0.4\"\nparity-scale-codec = \"1.3.6\"\nrand = \"0.8.5\"\nredshirt-ethernet-interface = { path = \"../../interface-wrappers/ethernet\" }\nredshirt-interface-interface = { path = \"../../interface-wrappers/interface\" }\nredshirt-log-interface = { path = \"../../interface-wrappers/log\" } # TODO: remove\nredshirt-syscalls = { path = \"../../interface-wrappers/syscalls\" }\nredshirt-tcp-interface = { path = \"../../interface-wrappers/tcp\" }\nredshirt-time-interface = { path = \"../../interface-wrappers/time\" }\nthiserror = \"1.0.30\"\n\n[dependencies.smoltcp]\nversion = \"0.7.5\"\ndefault-features = false\nfeatures = [\"ethernet\", \"proto-dhcpv4\", \"proto-ipv4\", \"proto-ipv6\", \"socket-udp\", \"socket-tcp\", \"std\"]\n"
  },
  {
    "path": "programs/network-manager/src/interface.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Manages a registered networking interface.\n//!\n//! This module manages the state of a single networking interface. This state consists of:\n//!\n//! - The local MAC address.\n//! - The local IP address, sub-net mask, and gateway.\n//! - The known neighbouring nodes, automatically discovered through ARP or NDP.\n//! - A list of TCP sockets active on this interface and their state.\n//! - A buffer of data waiting to be sent out on the interface. It is the role of the user of this\n//! module to empty this buffer.\n//! - (Optional) The state of a DHCP client.\n//!\n//! > **Note**: Most of this is delegated to the `smoltcp` library, but this should be considered\n//! >           as an implementation detail.\n//!\n//! # Usage\n//!\n//! - Create a [`NetInterfaceState`] by calling [`NetInterfaceState::new`].\n//! - When some data arrives from the network, call [`NetInterfaceState::inject_interface_data`].\n//! - Call [`NetInterfaceState::next_event`] to be informed of events on the interface. Events can\n//! be generated in response to a call to [`NetInterfaceState::inject_interface_data`], but also\n//! spontaneously after a certain time has elapsed.\n//! - If [`NetInterfaceEvent::EthernetCableOut`] is generated, call\n//! [`NetInterfaceState::read_ethernet_cable_out`] in order to obtain the data to send out to the\n//! network.\n//!\n\n// TODO: write more docs ^\n// TODO: implement UDP\n\nuse crate::port_assign;\n\nuse fnv::FnvBuildHasher;\nuse hashbrown::HashMap;\nuse smoltcp::{dhcp::Dhcpv4Client, phy, time::Instant};\nuse std::{\n    cmp,\n    collections::BTreeMap,\n    convert::TryFrom as _,\n    fmt, mem,\n    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},\n};\n\n/// State machine encompassing an Ethernet interface and the sockets operating on it.\n// TODO: Debug\npub struct NetInterfaceState<TSockUd> {\n    /// State of the Ethernet interface.\n    ethernet: smoltcp::iface::EthernetInterface<'static, RawDevice>,\n\n    /// State of the DHCPv4 client, if enabled.\n    dhcp_v4_client: Option<Dhcpv4Client>,\n\n    /// If false, we have to report to the user that data is available (if that is the case).\n    reported_available_data: bool,\n\n    /// Collection of all the active sockets that currently operate on this interface.\n    sockets: smoltcp::socket::SocketSet<'static>,\n\n    /// State of the sockets. Maintained in parallel with [`NetInterfaceState`].\n    sockets_state: HashMap<SocketId, SocketState<TSockUd>, FnvBuildHasher>,\n\n    /// TCP ports reservation.\n    tcp_ports_assign: port_assign::PortAssign,\n\n    /// If true, we should check the state of all the sockets at the next call to `next_event`.\n    check_sockets_required: bool,\n\n    /// Future that triggers the next time we should poll [`NetInterfaceState::ethernet`].\n    /// Must be set to `None` whenever we modify [`NetInterfaceState::ethernet`] in such a way that\n    /// it could produce an event.\n    ethernet_poll_delay: Option<redshirt_time_interface::Delay>,\n}\n\n/// Configuration for a [`NetInterfaceState`] under construction.\n#[derive(Debug)]\npub struct Config {\n    /// How the interface knows its own IP address.\n    pub ip_address: ConfigIpAddr,\n    /// MAC address of the device.\n    pub mac_address: [u8; 6],\n}\n\n/// How the interface knows its IP address.\n#[derive(Debug)]\npub enum ConfigIpAddr {\n    /// IP address defined ahead of time.\n    FixedIpv4 {\n        ip_address: Ipv4Addr,\n        /// Length in bits of the subnet mask.\n        /// Must be inferior to 32.\n        prefix_len: u8,\n        gateway: Ipv4Addr,\n    },\n\n    /// IP address defined ahead of time.\n    FixedIpv6 {\n        ip_address: Ipv6Addr,\n        /// Length in bits of the subnet mask.\n        /// Must be inferior to 128.\n        prefix_len: u8,\n        gateway: Ipv6Addr,\n    },\n\n    /// Use DHCPv4 to automatically discover the surrounding IPv4 network.\n    ///\n    /// A [`NetInterfaceEvent::DhcpDiscovery`] event will be generated on success.\n    DHCPv4,\n}\n\n/// Event generated by the [`NetInterfaceState::next_event`] function.\n#[derive(Debug)]\npub enum NetInterfaceEvent<'a, TSockUd> {\n    /// Data is available to be sent out by the Ethernet cable.\n    EthernetCableOut,\n    /// A TCP/IP socket has connected to its target.\n    TcpConnected {\n        socket: TcpSocket<'a, TSockUd>,\n        local_endpoint: SocketAddr,\n        remote_endpoint: SocketAddr,\n    },\n    /// A TCP/IP socket has been closed. It is either in the \"TIME WAIT\" or \"CLOSED\" states.\n    ///\n    /// > **Note**: This does *not* destroy the socket. You must call [`TcpSocket::reset`] to\n    /// >           actually destroy it.\n    TcpClosed(TcpSocket<'a, TSockUd>),\n    /// A TCP/IP socket has data ready to be read.\n    TcpReadReady(TcpSocket<'a, TSockUd>),\n    /// A TCP/IP socket has finished writing the data that we passed to it, and is now ready to\n    /// accept more.\n    TcpWriteFinished(TcpSocket<'a, TSockUd>),\n\n    /// The DHCP client has configured the interface.\n    DhcpDiscovery {\n        /// IP assigned to the interface.\n        ip: Ipv4Addr,\n        /// Length in bits of the subnet mask. Always inferior or equal to 32.\n        prefix_len: u8,\n        /// Default gateway when sending requests outside of the subnet mask.\n        gateway: Ipv4Addr,\n        /// Addresses of DNS servers reported by the DHCP server.\n        dns_servers: Vec<Ipv4Addr>,\n    },\n}\n\n/// Internal enum similar to [`NetInterfaceEvent`], except that it is `'static`.\n///\n/// Necessary because of borrow checker issue.\n// TODO: remove this once Polonius lands in Rust\n#[derive(Debug)]\nenum NetInterfaceEventStatic {\n    EthernetCableOut,\n    TcpConnected(SocketId, SocketAddr, SocketAddr),\n    TcpClosed(SocketId),\n    TcpReadReady(SocketId),\n    TcpWriteFinished(SocketId),\n    DhcpDiscovery {\n        ip: Ipv4Addr,\n        prefix_len: u8,\n        gateway: Ipv4Addr,\n        dns_servers: Vec<Ipv4Addr>,\n    },\n}\n\n/// Active TCP socket within a [`NetInterfaceState`].\npub struct TcpSocket<'a, TSockUd> {\n    /// Reference to the interface.\n    interface: &'a mut NetInterfaceState<TSockUd>,\n    /// Identifier of that socket within [`NetInterfaceState::sockets`].\n    id: SocketId,\n}\n\n/// State of a socket that we maintain in parallel to its actual state.\nstruct SocketState<TSockUd> {\n    user_data: TSockUd,\n    is_connected: bool,\n    // TODO: a bit stupid, since we destroy the socket asap?\n    is_closed: bool,\n    close_called: bool,\n    read_ready: bool,\n    write_ready: bool,\n    write_remaining: Vec<u8>,\n}\n\n/// Error when building a TCP socket.\n#[derive(Debug, thiserror::Error)]\npub enum ConnectError {\n    #[error(\"No port available\")]\n    NoPortAvailable,\n    #[error(\"The specific port requested isn't available\")]\n    PortNotAvailable,\n    #[error(\"The destination IP cannot be 0.0.0.0 or [::]\")]\n    UnspecifiedDestinationIp,\n    #[error(\"The destination port cannot be 0\")]\n    UnspecifiedDestinationPort,\n}\n\n/// Opaque identifier of a socket within a [`NetInterfaceState`].\n#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub struct SocketId(smoltcp::socket::SocketHandle);\n\nimpl<TSockUd> NetInterfaceState<TSockUd> {\n    /// Initializes the state machine of a new interface.\n    pub async fn new(config: Config) -> Self {\n        let device = RawDevice {\n            device_out_buffer: Vec::new(),\n            device_in_buffer: Vec::with_capacity(4096),\n        };\n\n        let mut routes = smoltcp::iface::Routes::new(BTreeMap::new());\n        let mut ip_addresses = Vec::new();\n\n        match config.ip_address {\n            ConfigIpAddr::FixedIpv4 {\n                ip_address,\n                prefix_len,\n                gateway,\n            } => {\n                routes.add_default_ipv4_route(From::from(gateway)).unwrap();\n                assert!(prefix_len <= 32);\n                ip_addresses.push(From::from(smoltcp::wire::Ipv4Cidr::new(\n                    From::from(ip_address),\n                    prefix_len,\n                )));\n            }\n            ConfigIpAddr::FixedIpv6 {\n                ip_address,\n                prefix_len,\n                gateway,\n            } => {\n                routes.add_default_ipv6_route(From::from(gateway)).unwrap();\n                assert!(prefix_len <= 128);\n                ip_addresses.push(From::from(smoltcp::wire::Ipv6Cidr::new(\n                    From::from(ip_address),\n                    prefix_len,\n                )));\n            }\n            ConfigIpAddr::DHCPv4 => {\n                // We need to \"reserve\" one unspecified IP address, as specified in the\n                // documentation of the DHCP client. It is unclear whether this is a strict\n                // requirement or an optimization.\n                ip_addresses.push(From::from(smoltcp::wire::Ipv4Cidr::new(\n                    smoltcp::wire::Ipv4Address::UNSPECIFIED,\n                    0,\n                )));\n            }\n        }\n\n        let interface = smoltcp::iface::EthernetInterfaceBuilder::new(device)\n            .ethernet_addr(smoltcp::wire::EthernetAddress(config.mac_address))\n            .ip_addrs(ip_addresses)\n            .routes(routes)\n            .neighbor_cache(smoltcp::iface::NeighborCache::new(BTreeMap::new()))\n            .finalize();\n\n        let mut sockets = smoltcp::socket::SocketSet::new(Vec::new());\n\n        // Build the DHCP client, if relevant.\n        // This inserts an entry in `sockets`.\n        let dhcp_v4_client = if matches!(config.ip_address, ConfigIpAddr::DHCPv4) {\n            let dhcp_rx_buffer = smoltcp::socket::RawSocketBuffer::new(\n                [smoltcp::socket::RawPacketMetadata::EMPTY; 1],\n                vec![0; 600],\n            );\n\n            let dhcp_tx_buffer = smoltcp::socket::RawSocketBuffer::new(\n                [smoltcp::socket::RawPacketMetadata::EMPTY; 1],\n                vec![0; 600],\n            );\n\n            Some(Dhcpv4Client::new(\n                &mut sockets,\n                dhcp_rx_buffer,\n                dhcp_tx_buffer,\n                now().await,\n            ))\n        } else {\n            None\n        };\n\n        NetInterfaceState {\n            ethernet: interface,\n            reported_available_data: false,\n            sockets,\n            sockets_state: HashMap::default(),\n            tcp_ports_assign: port_assign::PortAssign::new(),\n            check_sockets_required: false,\n            ethernet_poll_delay: None,\n            dhcp_v4_client,\n        }\n    }\n\n    /// Returns the IP address and prefix of the interface, or `None` if DHCP hasn't configured\n    /// the interface yet.\n    pub fn local_ip_prefix(&self) -> Option<(IpAddr, u8)> {\n        assert_eq!(self.ethernet.ip_addrs().len(), 1);\n        let addr = &self.ethernet.ip_addrs()[0];\n\n        let ip = match addr.address() {\n            smoltcp::wire::IpAddress::Unspecified => return None,\n            smoltcp::wire::IpAddress::Ipv4(ip) => IpAddr::from(Ipv4Addr::from(ip)),\n            smoltcp::wire::IpAddress::Ipv6(ip) => IpAddr::from(Ipv6Addr::from(ip)),\n            _ => unimplemented!(),\n        };\n\n        let prefix = addr.prefix_len();\n        Some((ip, prefix))\n    }\n\n    /// Initializes a new TCP connection which tries to connect to the given\n    /// [`SocketAddr`](std::net::SocketAddr).\n    pub fn build_tcp_socket(\n        &mut self,\n        listen: bool,\n        addr: &SocketAddr,\n        user_data: TSockUd,\n    ) -> Result<TcpSocket<TSockUd>, (ConnectError, TSockUd)> {\n        let mut socket = {\n            let rx_buf = smoltcp::socket::TcpSocketBuffer::new(vec![0; 1024]);\n            let tx_buf = smoltcp::socket::TcpSocketBuffer::new(vec![0; 1024]);\n            smoltcp::socket::TcpSocket::new(rx_buf, tx_buf)\n        };\n\n        if listen {\n            let mut addr = addr.clone();\n            assert!(!addr.ip().is_multicast()); // TODO: ?\n            if addr.port() == 0 {\n                addr.set_port(match self.tcp_ports_assign.reserve_any(1024) {\n                    Some(p) => p,\n                    None => return Err((ConnectError::NoPortAvailable, user_data)),\n                });\n            } else {\n                if let Err(()) = self.tcp_ports_assign.reserve(addr.port()) {\n                    return Err((ConnectError::PortNotAvailable, user_data));\n                }\n            }\n            // `listen` can only fail if the socket was misconfigured.\n            socket.listen(addr).unwrap();\n        } else {\n            if addr.port() == 0 {\n                return Err((ConnectError::UnspecifiedDestinationPort, user_data));\n            }\n            if addr.ip().is_unspecified() {\n                return Err((ConnectError::UnspecifiedDestinationIp, user_data));\n            }\n            assert!(!addr.ip().is_multicast()); // TODO: not supported? or is it?\n            let port = match self.tcp_ports_assign.reserve_any(1024) {\n                Some(p) => p,\n                None => return Err((ConnectError::NoPortAvailable, user_data)),\n            };\n            // `connect` can only fail if the socket was misconfigured.\n            socket.connect(addr.clone(), port).unwrap();\n        }\n\n        let id = SocketId(self.sockets.add(socket));\n        self.sockets_state.insert(\n            id,\n            SocketState {\n                user_data,\n                is_connected: false,\n                is_closed: false,\n                close_called: false,\n                read_ready: false,\n                write_ready: true,\n                write_remaining: Vec::new(),\n            },\n        );\n        self.ethernet_poll_delay = None;\n\n        Ok(TcpSocket {\n            interface: self,\n            id,\n        })\n    }\n\n    /// Returns an existing TCP socket by its ID.\n    pub fn tcp_socket_by_id(&mut self, id: SocketId) -> Option<TcpSocket<TSockUd>> {\n        if !self.sockets_state.contains_key(&id) {\n            return None;\n        }\n\n        Some(TcpSocket {\n            interface: self,\n            id,\n        })\n    }\n\n    /// Extract the data to transmit out of the Ethernet cable.\n    ///\n    /// Returns an empty buffer if nothing is ready.\n    pub fn read_ethernet_cable_out(&mut self) -> Vec<u8> {\n        let device_out_buffer = &mut self.ethernet.device_mut().device_out_buffer;\n        self.reported_available_data = false;\n        mem::replace(&mut *device_out_buffer, Vec::new())\n    }\n\n    /// Injects some data coming from the Ethernet cable.\n    ///\n    /// Call [`NetInterfaceState::next_event`] in order to obtain the result.\n    pub fn inject_interface_data(&mut self, data: impl AsRef<[u8]>) {\n        self.ethernet\n            .device_mut()\n            .device_in_buffer\n            .extend_from_slice(data.as_ref());\n        self.ethernet_poll_delay = None;\n    }\n\n    /// Wait until an event happens on the network.\n    pub async fn next_event<'a>(&'a mut self) -> NetInterfaceEvent<'a, TSockUd> {\n        match self.next_event_static().await {\n            NetInterfaceEventStatic::EthernetCableOut => NetInterfaceEvent::EthernetCableOut,\n            NetInterfaceEventStatic::TcpConnected(id, local_endpoint, remote_endpoint) => {\n                NetInterfaceEvent::TcpConnected {\n                    socket: self.tcp_socket_by_id(id).unwrap(),\n                    local_endpoint,\n                    remote_endpoint,\n                }\n            }\n            NetInterfaceEventStatic::TcpClosed(id) => {\n                NetInterfaceEvent::TcpClosed(self.tcp_socket_by_id(id).unwrap())\n            }\n            NetInterfaceEventStatic::TcpReadReady(id) => {\n                NetInterfaceEvent::TcpReadReady(self.tcp_socket_by_id(id).unwrap())\n            }\n            NetInterfaceEventStatic::TcpWriteFinished(id) => {\n                NetInterfaceEvent::TcpWriteFinished(self.tcp_socket_by_id(id).unwrap())\n            }\n            NetInterfaceEventStatic::DhcpDiscovery {\n                ip,\n                prefix_len,\n                gateway,\n                dns_servers,\n            } => NetInterfaceEvent::DhcpDiscovery {\n                ip,\n                prefix_len,\n                gateway,\n                dns_servers,\n            },\n        }\n    }\n\n    async fn next_event_static(&mut self) -> NetInterfaceEventStatic {\n        loop {\n            // First, check the out buffer.\n            if !self.reported_available_data {\n                if !self.ethernet.device_mut().device_out_buffer.is_empty() {\n                    self.reported_available_data = true;\n                    return NetInterfaceEventStatic::EthernetCableOut;\n                }\n            }\n\n            // Check whether any socket has changed state by comparing the latest known state\n            // with what `smoltcp` tells us.\n            // TODO: make changes in smoltcp to make this better?\n            if self.check_sockets_required {\n                for (socket_id, socket_state) in &mut self.sockets_state {\n                    let mut smoltcp_socket =\n                        self.sockets.get::<smoltcp::socket::TcpSocket>(socket_id.0);\n\n                    // Check if this socket got connected.\n                    if !socket_state.is_connected && smoltcp_socket.may_send() {\n                        socket_state.is_connected = true;\n\n                        let local_endpoint = {\n                            let endpoint = smoltcp_socket.local_endpoint();\n                            debug_assert_ne!(endpoint.port, 0);\n                            let ip = match endpoint.addr {\n                                smoltcp::wire::IpAddress::Ipv4(addr) => {\n                                    IpAddr::from(Ipv4Addr::from(addr))\n                                }\n                                smoltcp::wire::IpAddress::Ipv6(addr) => {\n                                    IpAddr::from(Ipv6Addr::from(addr))\n                                }\n                                _ => unreachable!(),\n                            };\n                            SocketAddr::from((ip, endpoint.port))\n                        };\n\n                        let remote_endpoint = {\n                            let endpoint = smoltcp_socket.remote_endpoint();\n                            debug_assert_ne!(endpoint.port, 0);\n                            let ip = match endpoint.addr {\n                                smoltcp::wire::IpAddress::Ipv4(addr) => {\n                                    IpAddr::from(Ipv4Addr::from(addr))\n                                }\n                                smoltcp::wire::IpAddress::Ipv6(addr) => {\n                                    IpAddr::from(Ipv6Addr::from(addr))\n                                }\n                                _ => unreachable!(),\n                            };\n                            SocketAddr::from((ip, endpoint.port))\n                        };\n\n                        return NetInterfaceEventStatic::TcpConnected(\n                            *socket_id,\n                            local_endpoint,\n                            remote_endpoint,\n                        );\n                    }\n\n                    // Check if this socket got closed.\n                    if !socket_state.is_closed && !smoltcp_socket.is_open() {\n                        socket_state.is_closed = true;\n                        return NetInterfaceEventStatic::TcpClosed(*socket_id);\n                    }\n\n                    // Check if this socket has data for reading.\n                    if !socket_state.read_ready && smoltcp_socket.can_recv() {\n                        socket_state.read_ready = true;\n                        return NetInterfaceEventStatic::TcpReadReady(*socket_id);\n                    }\n\n                    // Continue writing `write_remaining`.\n                    while smoltcp_socket.can_send() && !socket_state.write_remaining.is_empty() {\n                        let written = smoltcp_socket\n                            .send_slice(&socket_state.write_remaining)\n                            .unwrap();\n                        assert_ne!(written, 0);\n                        self.ethernet_poll_delay = None;\n                        socket_state.write_remaining =\n                            socket_state.write_remaining.split_off(written);\n                    }\n\n                    // Report when this socket is available for writing.\n                    if smoltcp_socket.may_send()\n                        && !socket_state.write_ready\n                        && socket_state.write_remaining.is_empty()\n                    {\n                        socket_state.write_ready = true;\n                        return NetInterfaceEventStatic::TcpWriteFinished(*socket_id);\n                    }\n                }\n\n                // Only set `check_sockets_required` to false here, when we have iterated through\n                // all the sockets and made sure that nothing could be reported anymore.\n                self.check_sockets_required = false;\n            }\n\n            // Perform an active wait if any is going on.\n            {\n                if let Some(ethernet_poll_delay) = self.ethernet_poll_delay.as_mut() {\n                    ethernet_poll_delay.await;\n                }\n                self.ethernet_poll_delay = None;\n            }\n\n            // We don't want to query `now` too often, so do it only once, here.\n            let now = now().await;\n\n            // Errors other than `Unrecognized` are meant to be logged and ignored.\n            match self.ethernet.poll(&mut self.sockets, now) {\n                Ok(true) => self.check_sockets_required = true,\n                Ok(false) => {}\n                // The documentation of smoltcp recommends to *not* log any `Unrecognized`\n                // error, as such errors happen very frequently.\n                Err(smoltcp::Error::Unrecognized) => {}\n                Err(err) => {\n                    log::trace!(\"Error while polling interface: {:?}\", err);\n                }\n            };\n\n            // Process the DHCPv4 client.\n            // The documentation mentions that this must be done *after* polling the interface.\n            if let Some(dhcp_v4_client) = &mut self.dhcp_v4_client {\n                match dhcp_v4_client.poll(&mut self.ethernet, &mut self.sockets, now) {\n                    Err(smoltcp::Error::Unrecognized) => {}\n                    Err(err) => {\n                        log::trace!(\"Error while polling DHCP client: {:?}\", err);\n                    }\n                    Ok(None) => {}\n                    Ok(Some(config)) => {\n                        // Update the configuration of the Ethernet state machine with the DHCP\n                        // discovery.\n                        if let Some(address) = config.address.as_ref() {\n                            self.ethernet.update_ip_addrs(|addrs| {\n                                *addrs.iter_mut().nth(0).unwrap() = address.clone().into();\n                            });\n                        }\n                        if let Some(router) = config.router.as_ref() {\n                            self.ethernet\n                                .routes_mut()\n                                .add_default_ipv4_route(router.clone().into())\n                                .unwrap();\n                        }\n\n                        // Report that to the user.\n                        // TODO: is it possible to get multiple independent reports in such as\n                        // way that we never emit the DhcpDiscovery event?\n                        if let (Some(address), Some(router)) =\n                            (config.address.as_ref(), config.router.as_ref())\n                        {\n                            // Now that the DHCP request is complete, drop the client.\n                            // TODO: added as a hack, is that correct?\n                            self.dhcp_v4_client = None;\n\n                            return NetInterfaceEventStatic::DhcpDiscovery {\n                                ip: address.address().into(),\n                                prefix_len: address.prefix_len(),\n                                gateway: router.clone().into(),\n                                dns_servers: config\n                                    .dns_servers\n                                    .iter()\n                                    .filter_map(|d| d.clone())\n                                    .map(Ipv4Addr::from)\n                                    .collect(),\n                            };\n                        }\n                    }\n                }\n            }\n\n            // Update `ethernet_poll_delay`.\n            debug_assert!(self.ethernet_poll_delay.is_none());\n            self.ethernet_poll_delay = Some({\n                let when_iface = self.ethernet.poll_delay(&mut self.sockets, now);\n                let when_dchp = self.dhcp_v4_client.as_ref().map(|c| c.next_poll(now));\n                let combined = match (when_iface, when_dchp) {\n                    (Some(a), Some(b)) => cmp::min(a, b),\n                    (Some(a), None) => a,\n                    (None, Some(b)) => b,\n                    // `(None, None)` means \"no deadline\", other words \"infinite\". For convenience,\n                    // we instead set an arbitrary deadline.\n                    (None, None) => smoltcp::time::Duration::from_secs(20),\n                };\n\n                redshirt_time_interface::Delay::new(combined.into())\n            });\n        }\n    }\n}\n\nimpl<TSockUd> fmt::Debug for NetInterfaceState<TSockUd> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_struct(\"NetInterfaceState\").finish()\n    }\n}\n\nimpl<'a, TSockUd> TcpSocket<'a, TSockUd> {\n    /// Returns the unique identifier of this socket.\n    pub fn id(&self) -> SocketId {\n        self.id\n    }\n\n    /// Starts the process of closing the TCP socket.\n    ///\n    /// Returns an error if `closed` had been called earlier on this socket. This error is benign.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the socket is still in the connecting stage.\n    pub fn close(&mut self) -> Result<(), ()> {\n        let mut state = &mut self.interface.sockets_state.get_mut(&self.id).unwrap();\n        assert!(state.is_connected);\n        if state.close_called {\n            return Err(());\n        }\n        state.close_called = true;\n\n        let mut socket = self\n            .interface\n            .sockets\n            .get::<smoltcp::socket::TcpSocket<'static>>(self.id.0);\n        socket.close();\n        self.interface.ethernet_poll_delay = None;\n\n        Ok(())\n    }\n\n    /// Returns true if `close` has successfully been called earlier.\n    pub fn close_called(&self) -> bool {\n        self.interface\n            .sockets_state\n            .get(&self.id)\n            .unwrap()\n            .close_called\n    }\n\n    /// Returns true if the socket has been closed.\n    ///\n    /// > **Note**: This indicates whether the socket is entirely closed, including by the remote,\n    /// >           and isn't directly related to the `close` method.\n    pub fn closed(&self) -> bool {\n        self.interface\n            .sockets_state\n            .get(&self.id)\n            .unwrap()\n            .is_closed\n    }\n\n    /// Instantly drops the socket without a proper shutdown.\n    pub fn reset(self) {\n        let smoltcp_socket = self.interface.sockets.remove(self.id.0);\n        self.interface.sockets_state.remove(&self.id);\n\n        let local_port = match smoltcp_socket {\n            smoltcp::socket::Socket::Tcp(s) => s.local_endpoint().port,\n            _ => unreachable!(),\n        };\n\n        // Free the port if it is no longer in use by any other socket.\n        let port_still_in_use = self.interface.sockets.iter().any(|s| match s {\n            smoltcp::socket::Socket::Tcp(s) => s.local_endpoint().port == local_port,\n            _ => false,\n        });\n        if !port_still_in_use {\n            self.interface.tcp_ports_assign.free(local_port).unwrap();\n        }\n    }\n\n    /// Reads the data that has been received on the TCP socket.\n    ///\n    /// Returns an empty `Vec` if there is no data available.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the socket is still in the connecting stage.\n    pub fn read(&mut self) -> Vec<u8> {\n        let mut state = &mut self.interface.sockets_state.get_mut(&self.id).unwrap();\n        assert!(state.is_connected);\n\n        let mut socket = self\n            .interface\n            .sockets\n            .get::<smoltcp::socket::TcpSocket<'static>>(self.id.0);\n        if !socket.can_recv() {\n            return Vec::new();\n        }\n\n        state.read_ready = false;\n\n        let recv_queue_len = socket.recv_queue();\n        let mut out = Vec::with_capacity(recv_queue_len);\n        unsafe {\n            out.set_len(recv_queue_len);\n        }\n        let n_recved = socket.recv_slice(&mut out).unwrap();\n        debug_assert_eq!(n_recved, recv_queue_len);\n        debug_assert_eq!(socket.recv_queue(), 0);\n        out\n    }\n\n    /// Passes a buffer that the socket will encode into Ethernet frames.\n    ///\n    /// Only one buffer can be active at any given point in time. If a buffer is already active,\n    /// returns `Err(buffer)`.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the socket is still in the connecting stage.\n    pub fn set_write_buffer(&mut self, mut buffer: Vec<u8>) -> Result<(), Vec<u8>> {\n        let mut state = self.interface.sockets_state.get_mut(&self.id).unwrap();\n        assert!(state.is_connected);\n        if !state.write_remaining.is_empty() {\n            return Err(buffer);\n        }\n\n        let mut socket = self\n            .interface\n            .sockets\n            .get::<smoltcp::socket::TcpSocket<'static>>(self.id.0);\n\n        if socket.can_send() {\n            let written = socket.send_slice(&buffer).unwrap();\n            self.interface.ethernet_poll_delay = None;\n            buffer = buffer.split_off(written);\n        }\n\n        state.write_ready = false;\n        state.write_remaining = buffer;\n        self.interface.check_sockets_required = true;\n        Ok(())\n    }\n\n    /// Returns a reference to the user data stored within the socket state.\n    pub fn user_data(&self) -> &TSockUd {\n        let state = self.interface.sockets_state.get(&self.id).unwrap();\n        &state.user_data\n    }\n\n    /// Returns a reference to the user data stored within the socket state.\n    pub fn into_user_data(self) -> &'a mut TSockUd {\n        let state = self.interface.sockets_state.get_mut(&self.id).unwrap();\n        &mut state.user_data\n    }\n\n    /// Returns a reference to the user data stored within the socket state.\n    pub fn user_data_mut(&mut self) -> &mut TSockUd {\n        let state = self.interface.sockets_state.get_mut(&self.id).unwrap();\n        &mut state.user_data\n    }\n}\n\nimpl<'a, TSockUd> fmt::Debug for TcpSocket<'a, TSockUd> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"TcpSocket\").field(&self.id()).finish()\n    }\n}\n\n// TODO: remove?\nasync fn now() -> smoltcp::time::Instant {\n    let now = redshirt_time_interface::monotonic_clock().await;\n    smoltcp::time::Instant::from_millis(i64::try_from(now / 1_000_000).unwrap())\n}\n\n/// Implementation of `smoltcp::phy::Device`.\nstruct RawDevice {\n    /// Buffer of data to send out to the virtual Ethernet cable.\n    device_out_buffer: Vec<u8>,\n\n    /// Buffer of data received from the virtual Ethernet cable.\n    device_in_buffer: Vec<u8>,\n}\n\nimpl<'a> smoltcp::phy::Device<'a> for RawDevice {\n    type RxToken = RawDeviceRxToken<'a>;\n    type TxToken = RawDeviceTxToken<'a>;\n\n    fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {\n        if self.device_in_buffer.is_empty() {\n            return None;\n        }\n\n        if !self.device_out_buffer.is_empty() {\n            return None;\n        }\n\n        let rx = RawDeviceRxToken {\n            buffer: &mut self.device_in_buffer,\n        };\n        let tx = RawDeviceTxToken {\n            buffer: &mut self.device_out_buffer,\n        };\n        Some((rx, tx))\n    }\n\n    fn transmit(&'a mut self) -> Option<Self::TxToken> {\n        if !self.device_out_buffer.is_empty() {\n            return None;\n        }\n\n        Some(RawDeviceTxToken {\n            buffer: &mut self.device_out_buffer,\n        })\n    }\n\n    fn capabilities(&self) -> phy::DeviceCapabilities {\n        let mut caps: phy::DeviceCapabilities = Default::default();\n        caps.max_transmission_unit = 9216; // FIXME:\n        caps.max_burst_size = None;\n        caps.checksum = phy::ChecksumCapabilities::ignored();\n        caps.checksum.ipv4 = phy::Checksum::Both;\n        caps.checksum.udp = phy::Checksum::Both;\n        caps.checksum.tcp = phy::Checksum::Both;\n        caps.checksum.icmpv4 = phy::Checksum::Both;\n        caps.checksum.icmpv6 = phy::Checksum::Both;\n        caps\n    }\n}\n\nstruct RawDeviceRxToken<'a> {\n    buffer: &'a mut Vec<u8>,\n}\n\nimpl<'a> phy::RxToken for RawDeviceRxToken<'a> {\n    fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> Result<R, smoltcp::Error>\n    where\n        F: FnOnce(&mut [u8]) -> Result<R, smoltcp::Error>,\n    {\n        let result = f(&mut self.buffer);\n        self.buffer.clear();\n        result\n    }\n}\n\nstruct RawDeviceTxToken<'a> {\n    buffer: &'a mut Vec<u8>,\n}\n\nimpl<'a> phy::TxToken for RawDeviceTxToken<'a> {\n    fn consume<R, F>(mut self, _timestamp: Instant, len: usize, f: F) -> Result<R, smoltcp::Error>\n    where\n        F: FnOnce(&mut [u8]) -> Result<R, smoltcp::Error>,\n    {\n        debug_assert!(self.buffer.is_empty());\n        *self.buffer = Vec::with_capacity(len);\n        unsafe {\n            self.buffer.set_len(len);\n        }\n        f(&mut self.buffer)\n    }\n}\n"
  },
  {
    "path": "programs/network-manager/src/lib.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nmod interface;\nmod manager;\nmod port_assign;\n\npub use manager::{NetworkManager, NetworkManagerEvent, SocketId, TcpSocket};\n"
  },
  {
    "path": "programs/network-manager/src/main.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n#![recursion_limit = \"2048\"]\n\nuse futures::prelude::*;\nuse hashbrown::HashMap;\nuse network_manager::{NetworkManager, NetworkManagerEvent};\nuse redshirt_ethernet_interface::ffi as eth_ffi;\nuse redshirt_interface_interface::DecodedInterfaceOrDestroyed;\nuse redshirt_syscalls::{Decode as _, MessageId};\nuse redshirt_tcp_interface::ffi as tcp_ffi;\nuse std::{\n    collections::VecDeque,\n    net::{IpAddr, Ipv6Addr, SocketAddr},\n};\n\nfn main() {\n    redshirt_log_interface::init();\n    redshirt_syscalls::block_on(async_main())\n}\n\nstruct SocketState {\n    id: u32,\n    connected_message: Option<MessageId>,\n    read_message: Option<MessageId>,\n    write_finished_message: Option<MessageId>,\n}\n\nasync fn async_main() {\n    // Register the ethernet and TCP interfaces.\n    let mut eth_registration = redshirt_interface_interface::register_interface(eth_ffi::INTERFACE)\n        .await\n        .unwrap();\n    let mut tcp_registration = redshirt_interface_interface::register_interface(tcp_ffi::INTERFACE)\n        .await\n        .unwrap();\n\n    let mut network = NetworkManager::<_, VecDeque<MessageId>, SocketState>::new();\n    let mut sockets = HashMap::with_capacity_and_hasher(0, fnv::FnvBuildHasher::default());\n    let mut next_socket_id = 0u32;\n\n    // TODO: re-review all this code\n\n    loop {\n        futures::select! {\n            interface_event = eth_registration.next_message_raw().fuse() => {\n                match interface_event {\n                    DecodedInterfaceOrDestroyed::Interface(msg) => {\n                        let msg_data = eth_ffi::NetworkMessage::decode(msg.actual_data).unwrap();\n                        match msg_data {\n                            eth_ffi::NetworkMessage::RegisterInterface { id, mac_address } => {\n                                network\n                                    .register_interface((msg.emitter_pid, id), mac_address, VecDeque::new())\n                                    .await\n                                    .unwrap(); // TODO: don't unwrap\n                            }\n                            eth_ffi::NetworkMessage::UnregisterInterface(id) => {\n                                network.interface_by_id((msg.emitter_pid, id)).unwrap().unregister();\n                            }\n                            eth_ffi::NetworkMessage::InterfaceOnData(id, buf) => {\n                                // TODO: back-pressure here as well?\n                                network.interface_by_id((msg.emitter_pid, id)).unwrap().inject_data(buf);\n                                if let Some(message_id) = msg.message_id {\n                                    redshirt_interface_interface::emit_answer(message_id, &());\n                                }\n                            }\n                            eth_ffi::NetworkMessage::InterfaceWaitData(id) => {\n                                let data = network\n                                .interface_by_id((msg.emitter_pid, id)).unwrap().read_ethernet_cable_out();\n                                if !data.is_empty() {\n                                    // TODO: don't unwrap message_id\n                                    redshirt_interface_interface::emit_answer(msg.message_id.unwrap(), &data);\n                                } else {\n                                    // TODO: don't unwrap message_id\n                                    network\n                                        .interface_by_id((msg.emitter_pid, id)).unwrap()\n                                        .user_data()\n                                        .push_back(msg.message_id.unwrap());\n                                }\n                            }\n                        }\n                    },\n                    DecodedInterfaceOrDestroyed::ProcessDestroyed(_) => {\n                        continue;\n                        // TODO: unimplemented\n                    }\n                }\n            }\n            interface_event = tcp_registration.next_message_raw().fuse() => {\n                match interface_event {\n                    DecodedInterfaceOrDestroyed::Interface(msg) => {\n                        // TODO: don't unwrap\n                        let msg_data = tcp_ffi::TcpMessage::decode(msg.actual_data).unwrap();\n                        match msg_data {\n                            tcp_ffi::TcpMessage::Open(open_msg) => {\n                                let message_id = match msg.message_id {\n                                    Some(m) => m,\n                                    None => continue,\n                                };\n\n                                let new_id = next_socket_id;\n                                next_socket_id += 1;\n\n                                let inner_id = network\n                                    .build_tcp_socket(\n                                        open_msg.listen,\n                                        &{\n                                            let ip_addr = Ipv6Addr::from(open_msg.ip);\n                                            if let Some(ip_addr) = ip_addr.to_ipv4() {\n                                                SocketAddr::new(ip_addr.into(), open_msg.port)\n                                            } else {\n                                                SocketAddr::new(ip_addr.into(), open_msg.port)\n                                            }\n                                        },\n                                        SocketState {\n                                            id: new_id,\n                                            connected_message: Some(message_id),\n                                            read_message: None,\n                                            write_finished_message: None,\n                                        },\n                                    )\n                                    .id();\n\n                                sockets.insert(new_id, inner_id);\n                            }\n                            tcp_ffi::TcpMessage::Close(close) => {\n                                if let Some(inner_id) = sockets.get_mut(&close.socket_id) {\n                                    let mut socket = network.tcp_socket_by_id(&inner_id).unwrap();\n                                    if socket.closed() {\n                                        if let Some(message_id) = msg.message_id {\n                                            redshirt_interface_interface::emit_answer(\n                                                message_id,\n                                                &tcp_ffi::TcpCloseResponse {\n                                                    result: Err(tcp_ffi::TcpCloseError::ConnectionFinished),\n                                                },\n                                            );\n                                        }\n                                        continue;\n                                    }\n\n                                    if socket.close().is_ok() {\n                                        if let Some(message_id) = msg.message_id {\n                                            redshirt_interface_interface::emit_answer(\n                                                message_id,\n                                                &tcp_ffi::TcpCloseResponse { result: Ok(()) },\n                                            );\n                                        }\n                                    } else if let Some(message_id) = msg.message_id {\n                                        redshirt_interface_interface::emit_answer(\n                                            message_id,\n                                            &tcp_ffi::TcpCloseResponse {\n                                                result: Err(tcp_ffi::TcpCloseError::FinAlreaySent),\n                                            },\n                                        );\n                                    }\n                                } else if let Some(message_id) = msg.message_id {\n                                    redshirt_interface_interface::emit_answer(\n                                        message_id,\n                                        &tcp_ffi::TcpCloseResponse {\n                                            result: Err(tcp_ffi::TcpCloseError::InvalidSocket),\n                                        },\n                                    );\n                                }\n                            }\n                            tcp_ffi::TcpMessage::Read(read) => {\n                                let message_id = match msg.message_id {\n                                    Some(m) => m,\n                                    None => continue,\n                                };\n\n                                if let Some(inner_socket_id) = sockets.get_mut(&read.socket_id) {\n                                    let mut inner_socket = network.tcp_socket_by_id(inner_socket_id).unwrap();\n                                    if inner_socket.closed() {\n                                        redshirt_interface_interface::emit_answer(\n                                            message_id,\n                                            &tcp_ffi::TcpReadResponse {\n                                                result: Err(tcp_ffi::TcpReadError::ConnectionFinished),\n                                            },\n                                        );\n                                        continue;\n                                    }\n\n                                    // TODO: handle errors\n                                    let available = inner_socket.read();\n                                    if !available.is_empty() {\n                                        redshirt_interface_interface::emit_answer(\n                                            message_id,\n                                            &tcp_ffi::TcpReadResponse {\n                                                result: Ok(available),\n                                            },\n                                        );\n                                    } else {\n                                        inner_socket.user_data_mut().read_message = Some(message_id);\n                                    }\n                                } else {\n                                    redshirt_interface_interface::emit_answer(\n                                        message_id,\n                                        &tcp_ffi::TcpReadResponse {\n                                            result: Err(tcp_ffi::TcpReadError::InvalidSocket),\n                                        },\n                                    );\n                                }\n                            }\n                            tcp_ffi::TcpMessage::Write(write) => {\n                                if let Some(inner_socket_id) = sockets.get_mut(&write.socket_id) {\n                                    let mut inner_socket = network.tcp_socket_by_id(inner_socket_id).unwrap();\n                                    if inner_socket.closed() {\n                                        if let Some(message_id) = msg.message_id {\n                                            redshirt_interface_interface::emit_answer(\n                                                message_id,\n                                                &tcp_ffi::TcpWriteResponse {\n                                                    result: Err(tcp_ffi::TcpWriteError::ConnectionFinished),\n                                                },\n                                            );\n                                        }\n                                        continue;\n                                    }\n                                    if inner_socket.close_called() {\n                                        if let Some(message_id) = msg.message_id {\n                                            redshirt_interface_interface::emit_answer(\n                                                message_id,\n                                                &tcp_ffi::TcpWriteResponse {\n                                                    result: Err(tcp_ffi::TcpWriteError::FinAlreaySent),\n                                                },\n                                            );\n                                        }\n                                        continue;\n                                    }\n\n                                    // TODO: handle errors\n                                    let _ = inner_socket.set_write_buffer(write.data);\n                                    inner_socket.user_data_mut().write_finished_message = msg.message_id;\n                                } else if let Some(message_id) = msg.message_id {\n                                    redshirt_interface_interface::emit_answer(\n                                        message_id,\n                                        &tcp_ffi::TcpWriteResponse {\n                                            result: Err(tcp_ffi::TcpWriteError::InvalidSocket),\n                                        },\n                                    );\n                                }\n                            }\n                            tcp_ffi::TcpMessage::Destroy(socket_id) => {\n                                if let Some(inner_id) = sockets.remove(&socket_id) {\n                                    let mut socket = network.tcp_socket_by_id(&inner_id).unwrap();\n                                    let local_state = socket.user_data_mut();\n                                    // TODO: connected_message should be None, or the user\n                                    // managed to guess an ID that hasn't been reported yet\n                                    if let Some(message_id) = local_state.read_message.take() {\n                                        redshirt_interface_interface::emit_answer(\n                                            message_id,\n                                            &tcp_ffi::TcpReadResponse {\n                                                result: Err(tcp_ffi::TcpReadError::InvalidSocket),\n                                            },\n                                        );\n                                    }\n                                    if let Some(message_id) = local_state.write_finished_message.take() {\n                                        redshirt_interface_interface::emit_answer(\n                                            message_id,\n                                            &tcp_ffi::TcpWriteResponse {\n                                                result: Err(tcp_ffi::TcpWriteError::InvalidSocket),\n                                            },\n                                        );\n                                    }\n                                    socket.reset();\n                                }\n                            }\n                        }\n                    },\n                    DecodedInterfaceOrDestroyed::ProcessDestroyed(_) => {\n                        continue;\n                        // TODO: unimplemented\n                    }\n                }\n            }\n            net_event = network.next_event().fuse() => {\n                match net_event {\n                    NetworkManagerEvent::EthernetCableOut(mut interface) => {\n                        // There is data available for sending to the network. We only actually\n                        // send data if there is a `InterfaceWaitData` message available to\n                        // respond to.\n                        // If that is not the case, then we don't pull any data, which also causes\n                        // the interface to not emit any data, and propagates the back-pressure to\n                        // the sockets. When a `InterfaceWaitData` later arrives, we try to call\n                        // `read_ethernet_cable_out` again.\n                        if let Some(msg_id) = interface.user_data().pop_front() {\n                            let buffer = interface.read_ethernet_cable_out();\n                            debug_assert!(!buffer.is_empty());\n                            redshirt_interface_interface::emit_answer(msg_id, &buffer);\n                        }\n                    }\n                    NetworkManagerEvent::TcpConnected {\n                        mut socket,\n                        local_endpoint,\n                        remote_endpoint,\n                    } => {\n                        let state = socket.user_data_mut();\n                        let message_id = state.connected_message.take().unwrap();\n                        redshirt_interface_interface::emit_answer(\n                            message_id,\n                            &tcp_ffi::TcpOpenResponse {\n                                result: Ok(tcp_ffi::TcpSocketOpen {\n                                    socket_id: state.id,\n                                    local_ip: match local_endpoint.ip() {\n                                        IpAddr::V4(ip) => ip.to_ipv6_mapped().segments(),\n                                        IpAddr::V6(ip) => ip.segments(),\n                                    },\n                                    local_port: local_endpoint.port(),\n                                    remote_ip: match remote_endpoint.ip() {\n                                        IpAddr::V4(ip) => ip.to_ipv6_mapped().segments(),\n                                        IpAddr::V6(ip) => ip.segments(),\n                                    },\n                                    remote_port: remote_endpoint.port(),\n                                }),\n                            },\n                        );\n                    }\n                    NetworkManagerEvent::TcpClosed(mut socket) => {\n                        let state = socket.user_data_mut();\n                        if let Some(message_id) = state.connected_message.take() {\n                            redshirt_interface_interface::emit_answer(\n                                message_id,\n                                &tcp_ffi::TcpOpenResponse { result: Err(()) },\n                            );\n                        }\n                        if let Some(message_id) = state.read_message.take() {\n                            redshirt_interface_interface::emit_answer(\n                                message_id,\n                                &tcp_ffi::TcpReadResponse {\n                                    result: Err(tcp_ffi::TcpReadError::ConnectionFinished),\n                                },\n                            );\n                        }\n                        if let Some(message_id) = state.write_finished_message.take() {\n                            redshirt_interface_interface::emit_answer(\n                                message_id,\n                                &tcp_ffi::TcpWriteResponse {\n                                    result: Err(tcp_ffi::TcpWriteError::ConnectionFinished),\n                                },\n                            );\n                        }\n                    }\n                    NetworkManagerEvent::TcpReadReady(mut socket) => {\n                        let state = socket.user_data_mut();\n                        if let Some(message_id) = state.read_message.take() {\n                            let data = socket.read();\n                            debug_assert!(!data.is_empty());\n                            redshirt_interface_interface::emit_answer(\n                                message_id,\n                                &tcp_ffi::TcpReadResponse { result: Ok(data) },\n                            );\n                        }\n                    }\n                    NetworkManagerEvent::TcpWriteFinished(mut socket) => {\n                        let state = socket.user_data_mut();\n                        if let Some(message_id) = state.write_finished_message.take() {\n                            redshirt_interface_interface::emit_answer(\n                                message_id,\n                                &tcp_ffi::TcpWriteResponse { result: Ok(()) },\n                            );\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "programs/network-manager/src/manager.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Manages a collection of network interfaces.\n//!\n//! This module manages the state of all the network interfaces together. Most of the\n//! implementation is delegated to the [`interface`] module, and the primary role of this code\n//! is to aggregate interfaces and assign new sockets to the correct interface based on the\n//! available routes.\n\nuse crate::interface;\n\nuse fnv::FnvBuildHasher;\nuse futures::prelude::*;\nuse hashbrown::{hash_map::Entry, HashMap};\nuse std::{fmt, hash::Hash, iter, mem, net::SocketAddr, pin::Pin};\n\n/// State machine managing all the network interfaces and sockets.\n///\n/// The `TIfId` generic parameter is an identifier for network interfaces.\n/// The `TSockUd` generic parameter is user data to store alongside with each socket.\npub struct NetworkManager<TIfId, TIfUser, TSockUd> {\n    /// List of devices that have been registered.\n    devices: HashMap<TIfId, Device<TIfUser, TSockUd>, FnvBuildHasher>,\n    /// Id to assign to the next socket.\n    next_socket_id: u64,\n    /// List of sockets open in the manager.\n    sockets: HashMap<u64, SocketState<TIfId, TSockUd>, FnvBuildHasher>,\n}\n\n/// State of a socket.\n#[derive(Debug)]\nenum SocketState<TIfId, TSockUd> {\n    /// Socket is waiting to be assigned to an interface.\n    Pending {\n        /// `listen` parameter passed to the socket constructor.\n        listen: bool,\n        /// Socket address parameter passed to the socket constructor.\n        addr: SocketAddr,\n        /// User data for this socket.\n        user_data: TSockUd,\n    },\n    /// Socket has been assigned to a specific interface.\n    Assigned {\n        /// Interface it's been assigned to.\n        interface: TIfId,\n        /// Id of the socket within the interface.\n        inner_id: interface::SocketId,\n    },\n}\n\n/// State of a device.\nstruct Device<TIfUser, TSockUd> {\n    /// Inner state.\n    inner: interface::NetInterfaceState<(u64, TSockUd)>,\n    /// Additional user data.\n    user_data: TIfUser,\n}\n\n/// Event generated by the [`NetworkManager::next_event`] function.\n#[derive(Debug)]\npub enum NetworkManagerEvent<'a, TIfId, TIfUser, TSockUd> {\n    /// Data to be sent out by the Ethernet cable is available.\n    EthernetCableOut(Interface<'a, TIfId, TIfUser, TSockUd>),\n    /// A TCP/IP socket has connected to its target.\n    TcpConnected {\n        socket: TcpSocket<'a, TIfId, TIfUser, TSockUd>,\n        local_endpoint: SocketAddr,\n        remote_endpoint: SocketAddr,\n    },\n    /// A TCP/IP socket has been closed by the remote.\n    ///\n    /// > **Note**: This does *not* destroy the socket. You must call [`TcpSocket::reset`] to\n    /// >           actually destroy it.\n    TcpClosed(TcpSocket<'a, TIfId, TIfUser, TSockUd>),\n    /// A TCP/IP socket has data ready to be read.\n    TcpReadReady(TcpSocket<'a, TIfId, TIfUser, TSockUd>),\n    /// A TCP/IP socket has finished writing the data that we passed to it, and is now ready to\n    /// accept more.\n    TcpWriteFinished(TcpSocket<'a, TIfId, TIfUser, TSockUd>),\n}\n\n/// Internal enum similar to [`NetworkManagerEvent`], except that it is `'static`.\n///\n/// Necessary because of borrow checker issue.\n// TODO: remove this once Polonius lands in Rust\n#[derive(Debug)]\nenum NetworkManagerEventStatic {\n    EthernetCableOut,\n    TcpConnected(interface::SocketId, SocketAddr, SocketAddr),\n    TcpClosed(interface::SocketId),\n    TcpReadReady(interface::SocketId),\n    TcpWriteFinished(interface::SocketId),\n    DhcpDiscovery,\n}\n\n/// Identifier of a socket within the [`NetworkManager`]. Common between all types of sockets.\n#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]\npub struct SocketId {\n    id: u64,\n}\n\nimpl<TIfId, TIfUser, TSockUd> NetworkManager<TIfId, TIfUser, TSockUd>\nwhere\n    TIfId: Clone + Hash + PartialEq + Eq,\n{\n    /// Initializes a new `NetworkManager`.\n    pub fn new() -> Self {\n        NetworkManager {\n            devices: HashMap::default(),\n            next_socket_id: 1,\n            sockets: HashMap::default(),\n        }\n    }\n\n    /// Adds a new TCP socket to the state of the network manager.\n    ///\n    /// If `listen` is `true`, then `addr` is a local address that the socket will listen on.\n    pub fn build_tcp_socket(\n        &mut self,\n        listen: bool,\n        addr: &SocketAddr,\n        user_data: TSockUd,\n    ) -> TcpSocket<TIfId, TIfUser, TSockUd> {\n        let socket_id = self.next_socket_id;\n        self.next_socket_id += 1;\n\n        let mut user_data = Some(user_data);\n\n        for (device_id, device) in self.devices.iter_mut() {\n            // TODO: naive\n            match device.inner.build_tcp_socket(\n                listen,\n                addr,\n                (socket_id, user_data.take().unwrap()),\n            ) {\n                Ok(socket) => {\n                    self.sockets.insert(\n                        socket_id,\n                        SocketState::Assigned {\n                            interface: device_id.clone(),\n                            inner_id: socket.id(),\n                        },\n                    );\n\n                    return TcpSocket {\n                        parent: self,\n                        id: socket_id,\n                    };\n                }\n                Err((_, (_, ud))) => {\n                    user_data = Some(ud);\n                }\n            }\n        }\n\n        self.sockets.insert(\n            socket_id,\n            SocketState::Pending {\n                listen,\n                user_data: user_data.take().unwrap(),\n                addr: addr.clone(),\n            },\n        );\n\n        TcpSocket {\n            parent: self,\n            id: socket_id,\n        }\n    }\n\n    /// Returns an accesss to the TCP socket with the given id.\n    pub fn tcp_socket_by_id(\n        &mut self,\n        id: &SocketId,\n    ) -> Option<TcpSocket<TIfId, TIfUser, TSockUd>> {\n        if !self.sockets.contains_key(&id.id) {\n            return None;\n        }\n\n        Some(TcpSocket {\n            parent: self,\n            id: id.id,\n        })\n    }\n\n    /// Registers an interface with the given ID. Returns an error if an interface with that ID\n    /// already exists.\n    pub async fn register_interface<'a>(\n        &'a mut self,\n        id: TIfId,\n        mac_address: [u8; 6],\n        user_data: TIfUser,\n    ) -> Result<Interface<'a, TIfId, TIfUser, TSockUd>, ()> {\n        let entry = match self.devices.entry(id.clone()) {\n            Entry::Occupied(_) => return Err(()),\n            Entry::Vacant(e) => e,\n        };\n\n        log::debug!(\n            \"Registering interface with MAC {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\",\n            mac_address[0],\n            mac_address[1],\n            mac_address[2],\n            mac_address[3],\n            mac_address[4],\n            mac_address[5]\n        );\n\n        let interface = interface::NetInterfaceState::new(interface::Config {\n            ip_address: interface::ConfigIpAddr::DHCPv4,\n            mac_address,\n        })\n        .await;\n\n        entry.insert(Device {\n            inner: interface,\n            user_data,\n        });\n\n        Ok(Interface { parent: self, id })\n    }\n\n    /// Returns an accesss to the interface with the given id.\n    pub fn interface_by_id(&mut self, id: TIfId) -> Option<Interface<TIfId, TIfUser, TSockUd>> {\n        if !self.devices.contains_key(&id) {\n            return None;\n        }\n\n        Some(Interface { parent: self, id })\n    }\n\n    /// Returns the next event generated by the [`NetworkManager`].\n    pub async fn next_event<'a>(&'a mut self) -> NetworkManagerEvent<'a, TIfId, TIfUser, TSockUd> {\n        loop {\n            let (device_id, event) = self.next_event_inner().await;\n            match event {\n                NetworkManagerEventStatic::EthernetCableOut => {\n                    let device = self.devices.get_mut(&device_id).unwrap();\n                    return NetworkManagerEvent::EthernetCableOut(Interface {\n                        parent: self,\n                        id: device_id,\n                    });\n                }\n                NetworkManagerEventStatic::TcpConnected(\n                    socket,\n                    local_endpoint,\n                    remote_endpoint,\n                ) => {\n                    let device = self.devices.get_mut(&device_id).unwrap();\n                    let inner = device.inner.tcp_socket_by_id(socket).unwrap();\n                    let id = inner.user_data().0;\n                    return NetworkManagerEvent::TcpConnected {\n                        socket: TcpSocket { parent: self, id },\n                        local_endpoint,\n                        remote_endpoint,\n                    };\n                }\n                NetworkManagerEventStatic::TcpClosed(socket) => {\n                    let device = self.devices.get_mut(&device_id).unwrap();\n                    let inner = device.inner.tcp_socket_by_id(socket).unwrap();\n                    let id = inner.user_data().0;\n                    return NetworkManagerEvent::TcpClosed(TcpSocket { parent: self, id });\n                }\n                NetworkManagerEventStatic::TcpReadReady(socket) => {\n                    let device = self.devices.get_mut(&device_id).unwrap();\n                    let inner = device.inner.tcp_socket_by_id(socket).unwrap();\n                    let id = inner.user_data().0;\n                    return NetworkManagerEvent::TcpReadReady(TcpSocket { parent: self, id });\n                }\n                NetworkManagerEventStatic::TcpWriteFinished(socket) => {\n                    let device = self.devices.get_mut(&device_id).unwrap();\n                    let inner = device.inner.tcp_socket_by_id(socket).unwrap();\n                    let id = inner.user_data().0;\n                    return NetworkManagerEvent::TcpWriteFinished(TcpSocket { parent: self, id });\n                }\n                NetworkManagerEventStatic::DhcpDiscovery => {\n                    let interface = self.devices.get_mut(&device_id).unwrap();\n\n                    // Take all the pending sockets and try to assign them to that new interface.\n                    // TODO: that's O(n)\n                    let sockets = {\n                        let cap = self.sockets.capacity();\n                        mem::replace(\n                            &mut self.sockets,\n                            HashMap::with_capacity_and_hasher(cap, Default::default()),\n                        )\n                    };\n\n                    for (socket_id, socket) in sockets {\n                        let (listen, addr, user_data) = match socket {\n                            SocketState::Pending {\n                                listen,\n                                addr,\n                                user_data,\n                            } => (listen, addr, user_data),\n                            s @ SocketState::Assigned { .. } => {\n                                self.sockets.insert(socket_id, s);\n                                continue;\n                            }\n                        };\n\n                        // TODO: naive\n                        match interface.inner.build_tcp_socket(\n                            listen,\n                            &addr,\n                            (socket_id, user_data),\n                        ) {\n                            Ok(inner_socket) => {\n                                self.sockets.insert(\n                                    socket_id,\n                                    SocketState::Assigned {\n                                        interface: device_id.clone(),\n                                        inner_id: inner_socket.id(),\n                                    },\n                                );\n                            }\n                            Err((_, (_, user_data))) => {\n                                self.sockets.insert(\n                                    socket_id,\n                                    SocketState::Pending {\n                                        listen,\n                                        addr,\n                                        user_data,\n                                    },\n                                );\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    async fn next_event_inner<'a>(&'a mut self) -> (TIfId, NetworkManagerEventStatic) {\n        // TODO: optimize?\n        let next_event = future::select_all(\n            self.devices\n                .iter_mut()\n                .map(move |(n, d)| {\n                    let user_data = &mut d.user_data;\n                    Box::pin(\n                        d.inner\n                            .next_event()\n                            .map(move |ev| (n.clone(), user_data, ev)),\n                    ) as Pin<Box<dyn Future<Output = _>>>\n                })\n                .chain(iter::once(Box::pin(future::pending()) as Pin<Box<_>>)),\n        );\n\n        match next_event.await.0 {\n            (device_id, _, interface::NetInterfaceEvent::EthernetCableOut) => {\n                (device_id, NetworkManagerEventStatic::EthernetCableOut)\n            }\n            (\n                device_id,\n                _,\n                interface::NetInterfaceEvent::TcpConnected {\n                    socket,\n                    local_endpoint,\n                    remote_endpoint,\n                },\n            ) => (\n                device_id,\n                NetworkManagerEventStatic::TcpConnected(\n                    socket.id(),\n                    local_endpoint,\n                    remote_endpoint,\n                ),\n            ),\n            (device_id, _, interface::NetInterfaceEvent::TcpClosed(inner)) => {\n                (device_id, NetworkManagerEventStatic::TcpClosed(inner.id()))\n            }\n            (device_id, _, interface::NetInterfaceEvent::TcpReadReady(inner)) => (\n                device_id,\n                NetworkManagerEventStatic::TcpReadReady(inner.id()),\n            ),\n            (device_id, _, interface::NetInterfaceEvent::TcpWriteFinished(inner)) => (\n                device_id,\n                NetworkManagerEventStatic::TcpWriteFinished(inner.id()),\n            ),\n            (device_id, _, interface::NetInterfaceEvent::DhcpDiscovery { .. }) => {\n                (device_id, NetworkManagerEventStatic::DhcpDiscovery)\n            }\n        }\n    }\n}\n\nimpl<'a, TIfId, TIfUser, TSockUd> fmt::Debug for NetworkManager<TIfId, TIfUser, TSockUd> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        // TODO: better impl?\n        f.debug_tuple(\"NetworkManager\").finish()\n    }\n}\n\n/// Access to an interface within the manager.\npub struct Interface<'a, TIfId, TIfUser, TSockUd> {\n    parent: &'a mut NetworkManager<TIfId, TIfUser, TSockUd>,\n    id: TIfId,\n}\n\nimpl<'a, TIfId, TIfUser, TSockUd> Interface<'a, TIfId, TIfUser, TSockUd>\nwhere\n    TIfId: Clone + Hash + PartialEq + Eq,\n{\n    pub fn unregister(self) {\n        //let device = self.devices.remove(id);\n        todo!();\n        // TODO: this is far from trivial, as one has to kill all sockets\n    }\n\n    /// Extract the data to transmit out of the Ethernet cable.\n    ///\n    /// Returns an empty buffer if nothing is ready.\n    pub fn user_data(&mut self) -> &mut TIfUser {\n        &mut self.parent.devices.get_mut(&self.id).unwrap().user_data\n    }\n\n    /// Extract the data to transmit out of the Ethernet cable.\n    ///\n    /// Returns an empty buffer if nothing is ready.\n    pub fn read_ethernet_cable_out(&mut self) -> Vec<u8> {\n        self.parent\n            .devices\n            .get_mut(&self.id)\n            .unwrap()\n            .inner\n            .read_ethernet_cable_out()\n    }\n\n    /// Injects some data coming from the Ethernet cable.\n    pub fn inject_data(&mut self, data: impl AsRef<[u8]>) {\n        self.parent\n            .devices\n            .get_mut(&self.id)\n            .unwrap()\n            .inner\n            .inject_interface_data(data)\n    }\n}\n\nimpl<'a, TIfId, TIfUser, TSockUd> fmt::Debug for Interface<'a, TIfId, TIfUser, TSockUd>\nwhere\n    TIfId: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        // TODO: better impl\n        f.debug_tuple(\"Interface\").finish()\n    }\n}\n\n/// Access to a socket within the manager.\npub struct TcpSocket<'a, TIfId, TIfUser, TSockUd> {\n    parent: &'a mut NetworkManager<TIfId, TIfUser, TSockUd>,\n    id: u64,\n}\n\nimpl<'a, TIfId, TIfUser, TSockUd> TcpSocket<'a, TIfId, TIfUser, TSockUd>\nwhere\n    TIfId: Clone + Hash + PartialEq + Eq,\n{\n    /// Returns the identifier of the socket, for later retrieval.\n    pub fn id(&self) -> SocketId {\n        SocketId { id: self.id }\n    }\n\n    /// Returns a reference to the user data stored within this TCP socket.\n    pub fn user_data_mut(&mut self) -> &mut TSockUd {\n        match self.parent.sockets.get_mut(&self.id).unwrap() {\n            SocketState::Pending { user_data, .. } => user_data,\n            SocketState::Assigned {\n                interface,\n                inner_id,\n            } => {\n                &mut self\n                    .parent\n                    .devices\n                    .get_mut(interface)\n                    .unwrap()\n                    .inner\n                    .tcp_socket_by_id(*inner_id)\n                    .unwrap()\n                    .into_user_data()\n                    .1\n            }\n        }\n    }\n\n    /// Reads the data that has been received on the TCP socket.\n    ///\n    /// Returns an empty `Vec` if there is no data available.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the socket is still in the connecting stage.\n    pub fn read(&mut self) -> Vec<u8> {\n        match self.parent.sockets.get_mut(&self.id).unwrap() {\n            SocketState::Pending { .. } => panic!(),\n            SocketState::Assigned {\n                interface,\n                inner_id,\n            } => self\n                .parent\n                .devices\n                .get_mut(interface)\n                .unwrap()\n                .inner\n                .tcp_socket_by_id(*inner_id)\n                .unwrap()\n                .read(),\n        }\n    }\n\n    /// Passes a buffer that the socket will encode into Ethernet frames.\n    ///\n    /// Only one buffer can be active at any given point in time. If a buffer is already active,\n    /// returns `Err(buffer)`.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the socket is still in the connecting stage.\n    pub fn set_write_buffer(&mut self, buffer: Vec<u8>) -> Result<(), Vec<u8>> {\n        match self.parent.sockets.get_mut(&self.id).unwrap() {\n            SocketState::Pending { .. } => panic!(),\n            SocketState::Assigned {\n                interface,\n                inner_id,\n            } => self\n                .parent\n                .devices\n                .get_mut(interface)\n                .unwrap()\n                .inner\n                .tcp_socket_by_id(*inner_id)\n                .unwrap()\n                .set_write_buffer(buffer),\n        }\n    }\n\n    /// Starts the process of closing the TCP socket.\n    ///\n    /// Returns an error if `closed` had been called earlier on this socket. This error is benign.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the socket is still in the connecting stage.\n    pub fn close(&mut self) -> Result<(), ()> {\n        match self.parent.sockets.get_mut(&self.id).unwrap() {\n            SocketState::Pending { .. } => panic!(),\n            SocketState::Assigned {\n                interface,\n                inner_id,\n            } => self\n                .parent\n                .devices\n                .get_mut(interface)\n                .unwrap()\n                .inner\n                .tcp_socket_by_id(*inner_id)\n                .unwrap()\n                .close(),\n        }\n    }\n\n    /// Returns true if `close` has successfully been called earlier.\n    pub fn close_called(&mut self) -> bool {\n        match self.parent.sockets.get(&self.id).unwrap() {\n            SocketState::Pending { .. } => false,\n            SocketState::Assigned {\n                interface,\n                inner_id,\n            } => self\n                .parent\n                .devices\n                .get_mut(interface)\n                .unwrap()\n                .inner\n                .tcp_socket_by_id(*inner_id)\n                .unwrap()\n                .close_called(),\n        }\n    }\n\n    /// Returns true if the socket has been closed.\n    ///\n    /// > **Note**: This indicates whether the socket is entirely closed, including by the remote,\n    /// >           and isn't directly related to the `close` method.\n    pub fn closed(&mut self) -> bool {\n        match self.parent.sockets.get(&self.id).unwrap() {\n            SocketState::Pending { .. } => false,\n            SocketState::Assigned {\n                interface,\n                inner_id,\n            } => self\n                .parent\n                .devices\n                .get_mut(interface)\n                .unwrap()\n                .inner\n                .tcp_socket_by_id(*inner_id)\n                .unwrap()\n                .closed(),\n        }\n    }\n\n    /// Destroys the socket. If it was open, instantly drops everything.\n    pub fn reset(self) {\n        match self.parent.sockets.remove(&self.id).unwrap() {\n            SocketState::Pending { .. } => {}\n            SocketState::Assigned {\n                interface,\n                inner_id,\n            } => self\n                .parent\n                .devices\n                .get_mut(&interface)\n                .unwrap()\n                .inner\n                .tcp_socket_by_id(inner_id)\n                .unwrap()\n                .reset(),\n        }\n    }\n}\n\nimpl<'a, TIfId, TIfUser, TSockUd> fmt::Debug for TcpSocket<'a, TIfId, TIfUser, TSockUd>\nwhere\n    TIfId: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        // TODO: better impl\n        f.debug_tuple(\"TcpSocket\").finish()\n    }\n}\n"
  },
  {
    "path": "programs/network-manager/src/port_assign.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse hashbrown::HashSet;\nuse rand::distributions::{Distribution as _, Uniform};\n\n/// Port assignment system. Keeps track of which port is used.\n///\n/// This struct doesn't know and doesn't care whether it is used by TCP, UDP, or something else.\n/// It is expected that one instance of this struct exists for each protocol.\npub struct PortAssign {\n    occupied: HashSet<u16, fnv::FnvBuildHasher>,\n}\n\nimpl PortAssign {\n    /// Builds a new [`PortAssign`] with no port assigned.\n    pub fn new() -> PortAssign {\n        PortAssign {\n            occupied: Default::default(),\n        }\n    }\n\n    /// Try to reserve a specific port. Returns an error if the port was already reserved.\n    pub fn reserve(&mut self, port: u16) -> Result<(), ()> {\n        if self.occupied.insert(port) {\n            Ok(())\n        } else {\n            Err(())\n        }\n    }\n\n    /// Reserves a port whose value is superior to `min`. Returns `None` if no port is available.\n    pub fn reserve_any(&mut self, min: u16) -> Option<u16> {\n        if (min..=u16::max_value()).all(|p| self.occupied.contains(&p)) {\n            return None;\n        }\n\n        loop {\n            let attempt =\n                Uniform::new_inclusive(min, u16::max_value()).sample(&mut rand::thread_rng());\n            if self.occupied.insert(attempt) {\n                debug_assert!(attempt >= min);\n                return Some(attempt);\n            }\n        }\n    }\n\n    /// Un-reserves a port. Returns an error if the port wasn't reserved.\n    pub fn free(&mut self, port: u16) -> Result<(), ()> {\n        if self.occupied.remove(&port) {\n            Ok(())\n        } else {\n            Err(())\n        }\n    }\n}\n"
  },
  {
    "path": "programs/pci-printer/Cargo.toml",
    "content": "[package]\nname = \"pci-printer\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[dependencies]\nfnv = { version = \"1.0.7\", default-features = false }\nhashbrown = { version = \"0.12.0\", default-features = false }\nlazy_static = \"1\"\nlog = \"0.4\"\nredshirt-pci-interface = { path = \"../../interface-wrappers/pci\" }\nredshirt-log-interface = { path = \"../../interface-wrappers/log\" }\nredshirt-syscalls = { path = \"../../interface-wrappers/syscalls\" }\nparity-scale-codec = { version = \"1.3.6\", default-features = false }\n\n[build-dependencies]\nregex = \"1.4.6\"\n"
  },
  {
    "path": "programs/pci-printer/build/pci.ids",
    "content": "#\n#\tList of PCI ID's\n#\n#\tVersion: 2019.12.11\n#\tDate:    2019-12-11 03:15:01\n#\n#\tMaintained by Albert Pool, Martin Mares, and other volunteers from\n#\tthe PCI ID Project at https://pci-ids.ucw.cz/.\n#\n#\tNew data are always welcome, especially if they are accurate. If you have\n#\tanything to contribute, please follow the instructions at the web site.\n#\n#\tThis file can be distributed under either the GNU General Public License\n#\t(version 2 or higher) or the 3-clause BSD License.\n#\n#\tThe database is a compilation of factual data, and as such the copyright\n#\tonly covers the aggregation and formatting. The copyright is held by\n#\tMartin Mares and Albert Pool.\n#\n\n# Vendors, devices and subsystems. Please keep sorted.\n\n# Syntax:\n# vendor  vendor_name\n#\tdevice  device_name\t\t\t\t<-- single tab\n#\t\tsubvendor subdevice  subsystem_name\t<-- two tabs\n\n0001  SafeNet (wrong ID)\n0010  Allied Telesis, Inc (Wrong ID)\n# This is a relabelled RTL-8139\n\t8139  AT-2500TX V3 Ethernet\n0014  Loongson Technology LLC\n\t7a00  Hyper Transport Bridge Controller\n\t7a02  APB (Advanced Peripheral Bus) Controller\n\t7a03  Gigabit Ethernet Controller\n\t7a04  OTG USB Controller\n\t7a05  Vivante GPU (Graphics Processing Unit)\n\t7a06  DC (Display Controller)\n\t7a07  HDA (High Definition Audio) Controller\n\t7a08  SATA AHCI Controller\n\t7a09  PCI-to-PCI Bridge\n\t7a0b  SPI Controller\n\t7a0c  LPC Controller\n\t7a0f  DMA (Direct Memory Access) Controller\n\t7a14  EHCI USB Controller\n\t7a15  Vivante GPU (Graphics Processing Unit)\n\t7a19  PCI-to-PCI Bridge\n\t7a24  OHCI USB Controller\n\t7a29  PCI-to-PCI Bridge\n001c  PEAK-System Technik GmbH\n\t0001  PCAN-PCI CAN-Bus controller\n\t\t001c 0004  2 Channel CAN Bus SJC1000\n\t\t001c 0005  2 Channel CAN Bus SJC1000 (Optically Isolated)\n003d  Lockheed Martin-Marietta Corp\n# Real TJN ID is e159, but they got it wrong several times --mj\n0059  Tiger Jet Network Inc. (Wrong ID)\n0070  Hauppauge computer works Inc.\n\t7801  WinTV HVR-1800 MCE\n0071  Nebula Electronics Ltd.\n0095  Silicon Image, Inc. (Wrong ID)\n\t0680  Ultra ATA/133 IDE RAID CONTROLLER CARD\n# Wrong ID used in subsystem ID of the TELES.S0/PCI 2.x ISDN adapter\n00a7  Teles AG (Wrong ID)\n0100  nCipher Security\n0123  General Dynamics\n0128  Dell (wrong ID)\n# 018a is not LevelOne but there is a board misprogrammed\n018a  LevelOne\n\t0106  FPC-0106TX misprogrammed [RTL81xx]\n# 021b is not Compaq but there is a board misprogrammed\n021b  Compaq Computer Corporation\n\t8139  HNE-300 (RealTek RTL8139c) [iPaq Networking]\n0270  Hauppauge computer works Inc. (Wrong ID)\n0291  Davicom Semiconductor, Inc. (Wrong ID)\n# SpeedStream is Efficient Networks, Inc, a Siemens Company\n02ac  SpeedStream\n\t1012  1012 PCMCIA 10/100 Ethernet Card [RTL81xx]\n02e0  XFX Pine Group Inc. (Wrong ID)\n0303  Hewlett-Packard Company (Wrong ID)\n0308  ZyXEL Communications Corporation (Wrong ID)\n0315  SK-Electronics Co., Ltd.\n0357  TTTech Computertechnik AG (Wrong ID)\n\t000a  TTP-Monitoring Card V2.0\n0432  SCM Microsystems, Inc.\n\t0001  Pluto2 DVB-T Receiver for PCMCIA [EasyWatch MobilSet]\n0497  Dell Inc. (wrong ID)\n0675  Dynalink\n\t1700  IS64PH ISDN Adapter\n\t1702  IS64PH ISDN Adapter\n\t1703  ISDN Adapter (PCI Bus, DV, W)\n\t1704  ISDN Adapter (PCI Bus, D, C)\n0721  Sapphire, Inc.\n0777  Ubiquiti Networks, Inc.\n0795  Wired Inc.\n\t6663  Butane II (MPEG2 encoder board)\n\t6666  MediaPress (MPEG2 encoder board)\n07d1  D-Link System Inc\n0824  T1042 [Freescale]\n0925  VIA Technologies, Inc. (Wrong ID)\n0a89  BREA Technologies Inc\n0b0b  Rhino Equipment Corp.\n\t0105  R1T1\n\t0205  R4FXO\n\t0206  RCB4FXO 4-channel FXO analog telephony card\n\t0305  R4T1\n\t0405  R8FXX\n\t0406  RCB8FXX 8-channel modular analog telephony card\n\t0505  R24FXX\n\t0506  RCB24FXS 24-Channel FXS analog telephony card\n\t0605  R2T1\n\t0705  R24FXS\n\t0706  RCB24FXO 24-Channel FXO analog telephony card\n\t0905  R1T3 Single T3 Digital Telephony Card\n\t0906  RCB24FXX 24-channel modular analog telephony card\n\t0a06  RCB672FXX 672-channel modular analog telephony card\n0e11  Compaq Computer Corporation\n\t0001  PCI to EISA Bridge\n\t0002  PCI to ISA Bridge\n\t0046  Smart Array 64xx\n\t\t0e11 4091  Smart Array 6i\n\t\t0e11 409a  Smart Array 641\n\t\t0e11 409b  Smart Array 642\n\t\t0e11 409c  Smart Array 6400\n\t\t0e11 409d  Smart Array 6400 EM\n\t0049  NC7132 Gigabit Upgrade Module\n\t004a  NC6136 Gigabit Server Adapter\n\t005a  Remote Insight II board - Lights-Out\n\t007c  NC7770 1000BaseTX\n\t007d  NC6770 1000BaseTX\n\t0085  NC7780 1000BaseTX\n\t00b1  Remote Insight II board - PCI device\n\t00bb  NC7760\n\t00ca  NC7771\n\t00cb  NC7781\n\t00cf  NC7772\n\t00d0  NC7782\n\t00d1  NC7783\n\t00e3  NC7761\n\t0508  Netelligent 4/16 Token Ring\n\t1000  Triflex/Pentium Bridge, Model 1000\n\t2000  Triflex/Pentium Bridge, Model 2000\n\t3032  QVision 1280/p\n\t3033  QVision 1280/p\n\t3034  QVision 1280/p\n\t4000  4000 [Triflex]\n\t4040  Integrated Array\n\t4048  Compaq Raid LC2\n\t4050  Smart Array 4200\n\t4051  Smart Array 4250ES\n\t4058  Smart Array 431\n\t4070  Smart Array 5300\n\t4080  Smart Array 5i\n\t4082  Smart Array 532\n\t4083  Smart Array 5312\n\t4091  Smart Array 6i\n\t409a  Smart Array 641\n\t409b  Smart Array 642\n\t409c  Smart Array 6400\n\t409d  Smart Array 6400 EM\n\t6010  HotPlug PCI Bridge 6010\n\t7020  USB Controller\n\ta0ec  Fibre Channel Host Controller\n\ta0f0  Advanced System Management Controller\n\t\t0e11 b0f3  ProLiant DL360\n\ta0f3  Triflex PCI to ISA Bridge\n\ta0f7  PCI Hotplug Controller\n\t\t8086 002a  PCI Hotplug Controller A\n\t\t8086 002b  PCI Hotplug Controller B\n\ta0f8  ZFMicro Chipset USB\n\ta0fc  FibreChannel HBA Tachyon\n\tae10  Smart-2/P RAID Controller\n\t\t0e11 4030  Smart-2/P Array Controller\n\t\t0e11 4031  Smart-2SL Array Controller\n\t\t0e11 4032  Smart Array 3200 Controller\n\t\t0e11 4033  Smart Array 3100ES Controller\n\t\t0e11 4034  Smart Array 221 Controller\n\tae29  MIS-L\n\tae2a  MPC\n\tae2b  MIS-E\n\tae31  System Management Controller\n\tae32  Netelligent 10/100 TX PCI UTP\n\tae33  Triflex Dual EIDE Controller\n\tae34  Netelligent 10 T PCI UTP\n\tae35  Integrated NetFlex-3/P\n\tae40  Netelligent Dual 10/100 TX PCI UTP\n\tae43  Netelligent Integrated 10/100 TX UTP\n\tae69  CETUS-L\n\tae6c  Northstar\n\tae6d  NorthStar CPU to PCI Bridge\n\tb011  Netelligent 10/100 TX Embedded UTP\n\tb012  Netelligent 10 T/2 PCI UTP/Coax\n\tb01e  NC3120 Fast Ethernet NIC\n\tb01f  NC3122 Fast Ethernet NIC\n\tb02f  NC1120 Ethernet NIC\n\tb030  Netelligent 10/100 TX UTP\n\tb04a  10/100 TX PCI Intel WOL UTP Controller\n\tb060  Smart Array 5300 Controller\n\tb0c6  NC3161 Fast Ethernet NIC\n\tb0c7  NC3160 Fast Ethernet NIC\n\tb0d7  NC3121 Fast Ethernet NIC\n\tb0dd  NC3131 Fast Ethernet NIC\n\tb0de  NC3132 Fast Ethernet Module\n\tb0df  NC6132 Gigabit Module\n\tb0e0  NC6133 Gigabit Module\n\tb0e1  NC3133 Fast Ethernet Module\n\tb123  NC6134 Gigabit NIC\n\tb134  NC3163 Fast Ethernet NIC\n\tb13c  NC3162 Fast Ethernet NIC\n\tb144  NC3123 Fast Ethernet NIC\n\tb163  NC3134 Fast Ethernet NIC\n\tb164  NC3165 Fast Ethernet Upgrade Module\n\tb178  Smart Array 5i/532\n\t\t0e11 4080  Smart Array 5i\n\t\t0e11 4082  Smart Array 532\n\t\t0e11 4083  Smart Array 5312\n\tb1a4  NC7131 Gigabit Server Adapter\n\tb200  Memory Hot-Plug Controller\n\tb203  Integrated Lights Out Controller\n\tb204  Integrated Lights Out  Processor\n\tc000  Remote Insight Lights-Out Edition\n\tf130  NetFlex-3/P ThunderLAN 1.0\n\tf150  NetFlex-3/P ThunderLAN 2.3\n0e55  HaSoTec GmbH\n0eac  SHF Communication Technologies AG\n\t0008  Ethernet Powerlink Managing Node 01\n0f62  Acrox Technologies Co., Ltd.\n1000  Broadcom / LSI\n\t0001  53c810\n\t\t1000 1000  LSI53C810AE PCI to SCSI I/O Processor\n\t0002  53c820\n\t0003  53c825\n\t\t1000 1000  LSI53C825AE PCI to SCSI I/O Processor (Ultra Wide)\n\t0004  53c815\n\t0005  53c810AP\n\t0006  53c860\n\t\t1000 1000  LSI53C860E PCI to Ultra SCSI I/O Processor\n\t000a  53c1510\n\t\t0e11 b143  Integrated Dual Channel Wide Ultra2 SCSI Controller\n\t\t1000 1000  LSI53C1510 PCI to Dual Channel Wide Ultra2 SCSI Controller (Nonintelligent mode)\n\t000b  53C896/897\n\t\t0e11 6004  EOB003 Series SCSI host adapter\n\t\t1000 1000  LSI53C896/7 PCI to Dual Channel Ultra2 SCSI Multifunction Controller\n\t\t1000 1010  LSI22910 PCI to Dual Channel Ultra2 SCSI host adapter\n\t\t1000 1020  LSI21002 PCI to Dual Channel Ultra2 SCSI host adapter\n\t\t13e9 1000  6221L-4U (Dual U2W SCSI, dual 10/100TX, graphics)\n\t000c  53c895\n\t\t1000 1010  LSI8951U PCI to Ultra2 SCSI host adapter\n\t\t1000 1020  LSI8952U PCI to Ultra2 SCSI host adapter\n\t\t1de1 3906  DC-390U2B SCSI adapter\n\t\t1de1 3907  DC-390U2W\n\t000d  53c885\n\t000f  53c875\n\t\t0e11 7004  Embedded Ultra Wide SCSI Controller\n\t\t1000 1000  LSI53C876/E PCI to Dual Channel SCSI Controller\n\t\t1000 1010  LSI22801 PCI to Dual Channel Ultra SCSI host adapter\n\t\t1000 1020  LSI22802 PCI to Dual Channel Ultra SCSI host adapter\n\t\t1092 8760  FirePort 40 Dual SCSI Controller\n\t\t1775 10d0  V5D Single Board Computer Wide Ultra SCSI\n\t\t1775 10d1  V5D Single Board Computer Ultra SCSI\n\t\t1de1 3904  DC390F/U Ultra Wide SCSI Adapter\n\t\t4c53 1000  CC7/CR7/CP7/VC7/VP7/VR7 mainboard\n\t\t4c53 1050  CT7 mainboard\n\t0010  53C1510\n\t\t0e11 4040  Integrated Smart Array Controller\n\t\t0e11 4048  RAID LC2 Controller\n\t\t1000 1000  53C1510 PCI to Dual Channel Wide Ultra2 SCSI Controller (Intelligent mode)\n\t0012  53c895a\n\t\t1000 1000  LSI53C895A PCI to Ultra2 SCSI Controller\n\t0013  53c875a\n\t\t1000 1000  LSI53C875A PCI to Ultra SCSI Controller\n\t0014  MegaRAID Tri-Mode SAS3516\n\t\t1028 1f3a  PERC H745 Adapter\n\t\t1028 1f3b  PERC H745 Front\n\t\t1028 1fd4  PERC H745P MX\n\t\t1137 020e  UCSC-RAID-M5 12G Modular RAID Controller\n\t\t1d49 0602  ThinkSystem RAID 930-16i 4GB Flash PCIe 12Gb Adapter\n\t\t1d49 0604  ThinkSystem RAID 930-8e 4GB Flash PCIe 12Gb Adapter\n\t\t1d49 0607  ThinkSystem RAID 930-16i 8GB Flash PCIe 12Gb Adapter\n\t\t8086 352d  Integrated RAID Module RMSP3AD160F\n\t\t8086 9460  RAID Controller RSP3TD160F\n\t\t8086 9480  RAID Controller RSP3MD088F\n\t0015  MegaRAID Tri-Mode SAS3416\n\t\t1028 1f3c  PERC H345 Adapter\n\t\t1028 1f3d  PERC H345 Front\n\t\t1d49 0503  ThinkSystem RAID 530-16i PCIe 12Gb Adapter\n\t0016  MegaRAID Tri-Mode SAS3508\n\t\t1028 1fc9  PERC H840 Adapter\n\t\t1028 1fcb  PERC H740P Adapter\n\t\t1028 1fcd  PERC H740P Mini\n\t\t1028 1fcf  PERC H740P Mini\n\t\t1d49 0601  ThinkSystem RAID 930-8i 2GB Flash PCIe 12Gb Adapter\n\t\t1d49 0603  ThinkSystem RAID 930-24i 4GB Flash PCIe 12Gb Adapter\n\t\t8086 352e  Integrated RAID Module RMSP3CD080F\n\t\t8086 352f  Integrated RAID Module RMSP3HD080E\n\t\t8086 9461  RAID Controller RSP3DD080F\n\t0017  MegaRAID Tri-Mode SAS3408\n\t\t1d49 0500  ThinkSystem RAID 530-8i PCIe 12Gb Adapter\n\t\t1d49 0502  ThinkSystem RAID 530-8i Dense Adapter\n\t\t8086 3528  Integrated RAID RMSP3LD060\n\t\t8086 3529  Integrated RAID RMSP3LD060\n\t\t8086 9441  RAID Controller RSP3WD080E\n\t001b  MegaRAID Tri-Mode SAS3504\n\t\t1d49 0605  ThinkSystem RAID 930-4i 2GB Flash Flex Adapter\n\t001c  MegaRAID Tri-Mode SAS3404\n\t\t1d49 0501  ThinkSystem RAID 530-4i Flex Adapter\n\t0020  53c1010 Ultra3 SCSI Adapter\n\t\t1000 1000  LSI53C1010-33 PCI to Dual Channel Ultra160 SCSI Controller\n\t\t107b 1040  Server Onboard 53C1010-33\n\t\t1de1 1020  DC-390U3W\n\t0021  53c1010 66MHz  Ultra3 SCSI Adapter\n\t\t1000 1000  LSI53C1000/1000R/1010R/1010-66 PCI to Ultra160 SCSI Controller\n\t\t1000 1010  Asus TR-DLS onboard 53C1010-66\n\t\t103c 1300  Ultra160 SCSI [AB306A]\n\t\t103c 1310  Ultra160 SCSI [A9918A]\n\t\t103c 1330  Ultra160 SCSI [A7059A]\n\t\t103c 1340  Ultra160 SCSI [A7060A]\n\t\t124b 1070  PMC-USCSI3\n\t\t4c53 1080  CT8 mainboard\n\t\t4c53 1300  P017 mezzanine (32-bit PMC)\n\t\t4c53 1310  P017 mezzanine (64-bit PMC)\n\t002f  MegaRAID SAS 2208 IOV [Thunderbolt]\n\t\t1028 1f39  SPERC8-e\n\t\t1028 1f3e  SPERC 8\n\t0030  53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI\n\t\t0e11 00da  ProLiant ML 350\n\t\t1028 0123  LSI Logic 1020/1030\n\t\t1028 014a  LSI Logic 1020/1030\n\t\t1028 016c  PowerEdge 1850 MPT Fusion SCSI/RAID (Perc 4)\n\t\t1028 0183  LSI Logic 1020/1030\n\t\t1028 018a  PERC 4/IM\n\t\t1028 1010  LSI U320 SCSI Controller\n\t\t103c 12c5  Ultra320 SCSI [A7173A]\n\t\t103c 1323  Core I/O LAN/SCSI Combo [AB314A]\n\t\t103c 3108  Single Channel Ultra320 SCSI HBA G2\n\t\t103c 322a  SC11Xe Ultra320 Single Channel PCIe x4 SCSI Host Bus Adapter (412911-B21)\n\t\t124b 1170  PMC-USCSI320\n# VMware's emulation of this device. Was missing from the list.\n\t\t15ad 1976  LSI Logic Parallel SCSI Controller\n\t\t1734 1052  PRIMERGY BX/RX/TX S2 series onboard SCSI(IME)\n\t0031  53c1030ZC PCI-X Fusion-MPT Dual Ultra320 SCSI\n\t0032  53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI\n\t\t1000 1000  LSI53C1020/1030 PCI-X to Ultra320 SCSI Controller\n\t0033  1030ZC_53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI\n\t0040  53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI\n\t\t1000 0033  MegaRAID SCSI 320-2XR\n\t\t1000 0066  MegaRAID SCSI 320-2XRWS\n\t0041  53C1035ZC PCI-X Fusion-MPT Dual Ultra320 SCSI\n\t0050  SAS1064 PCI-X Fusion-MPT SAS\n\t\t1028 1f04  SAS 5/E\n\t\t1028 1f09  SAS 5i/R\n\t0052  MegaRAID SAS-3 3216/3224 [Cutlass]\n\t0053  MegaRAID SAS-3 3216/3224 [Cutlass]\n\t\t1000 9350  MegaRAID SAS 9341-16i\n\t\t1000 9351  MegaRAID SAS 9341-24i\n\t0054  SAS1068 PCI-X Fusion-MPT SAS\n\t\t1028 1f04  SAS 5/E Adapter Controller\n\t\t1028 1f05  SAS 5/i Adapter Controller\n\t\t1028 1f06  SAS 5/i Integrated Controller\n\t\t1028 1f07  SAS 5/iR Integrated RAID Controller\n\t\t1028 1f08  SAS 5/iR Integrated RAID Controller\n\t\t1028 1f09  SAS 5/iR Adapter RAID Controller\n\t\t15ad 1976  SAS Controller\n\t0055  SAS1068 PCI-X Fusion-MPT SAS\n\t\t1033 8336  SAS1068\n\t0056  SAS1064ET PCI-Express Fusion-MPT SAS\n\t\t1014 03bb  ServeRAID BR10il SAS/SATA Controller v2\n\t\t8086 34dc  AXX4SASMOD RAID Controller\n\t0057  M1064E MegaRAID SAS\n\t\t8086 346c  Embedded Software RAID Technology II (ESTRII)\n\t0058  SAS1068E PCI-Express Fusion-MPT SAS\n\t\t1000 3140  SAS3081E-R 8-Port SAS/SATA Host Bus Adapter\n\t\t1028 021d  SAS 6/iR Integrated Workstations RAID Controller\n\t\t1028 1f0e  SAS 6/iR Adapter RAID Controller\n\t\t1028 1f0f  SAS 6/iR Integrated Blades RAID Controller\n\t\t1028 1f10  SAS 6/iR Integrated RAID Controller\n\t\t103c 3229  SC44Ge Host Bus Adapter\n\t0059  MegaRAID SAS 8208ELP/8208ELP\n\t005a  SAS1066E PCI-Express Fusion-MPT SAS\n\t005b  MegaRAID SAS 2208 [Thunderbolt]\n\t\t1000 9265  MegaRAID SAS 9265-8i\n\t\t1000 9266  MegaRAID SAS 9266-8i\n\t\t1000 9267  MegaRAID SAS 9267-8i\n\t\t1000 9268  MegaRAID SAS 9265CV-8i / 9270CV-8i\n\t\t1000 9269  MegaRAID SAS 9266-4i\n\t\t1000 9270  MegaRAID SAS 9270-8i\n\t\t1000 9271  MegaRAID SAS 9271-8i\n\t\t1000 9272  MegaRAID SAS 9272-8i\n\t\t1000 9273  MegaRAID SAS 9270CV-8i\n\t\t1000 9274  MegaRAID SAS 9270-4i\n\t\t1000 9275  MegaRAID SAS 9271-8iCC\n\t\t1000 9276  MegaRAID SAS 9271-4i\n\t\t1000 9285  MegaRAID SAS 9285-8e\n\t\t1000 9288  MegaRAID SAS 9285CV-8e\n\t\t1000 9290  MegaRAID SAS 9286-8e\n\t\t1000 9291  MegaRAID SAS 9286CV-8e\n\t\t1000 9295  MegaRAID SAS 9286CV-8eCC\n\t\t1014 040b  ServeRAID M5110 SAS/SATA Controller\n\t\t1014 040c  ServeRAID M5120 SAS/SATA Controller\n\t\t1014 0412  ServeRAID M5110e SAS/SATA Controller\n\t\t1028 1f2d  PERC H810 Adapter\n\t\t1028 1f30  PERC H710 Embedded\n\t\t1028 1f31  PERC H710P Adapter\n\t\t1028 1f33  PERC H710P Mini (for blades)\n\t\t1028 1f34  PERC H710P Mini (for monolithics)\n\t\t1028 1f35  PERC H710 Adapter\n\t\t1028 1f37  PERC H710 Mini (for blades)\n\t\t1028 1f38  PERC H710 Mini (for monolithics)\n\t\t15d9 0690  LSI MegaRAID ROMB\n\t\t8086 3510  RMS25PB080 RAID Controller\n\t\t8086 3511  RMS25PB040 RAID Controller\n\t\t8086 3512  RMT3PB080 RAID Controller\n\t\t8086 3513  Integrated RAID Module RMS25CB080\n\t\t8086 3514  RMS25CB040 RAID Controller\n\t\t8086 351c  RMS25PB080N RAID Controller\n\t\t8086 351d  RMS25CB080N RAID Controller\n\t\t8086 9265  RS25DB080 RAID Controller\n\t\t8086 9268  RS25AB080 RAID Controller\n\t\t8086 9285  RS25NB008 RAID Controller\n\t\t8086 9288  RS25SB008 RAID Controller\n\t005c  SAS1064A PCI-X Fusion-MPT SAS\n\t005d  MegaRAID SAS-3 3108 [Invader]\n\t\t1000 9361  MegaRAID SAS 9361-8i\n\t\t1000 9363  MegaRAID SAS 9361-4i\n\t\t1000 9364  MegaRAID SAS 9364-8i\n\t\t1000 936a  MegaRAID SAS 9364-8i\n\t\t1028 1f41  PERC H830 Adapter\n\t\t1028 1f42  PERC H730P Adapter\n\t\t1028 1f43  PERC H730 Adapter\n\t\t1028 1f47  PERC H730P Mini\n\t\t1028 1f48  PERC H730P Mini (for blades)\n\t\t1028 1f49  PERC H730 Mini\n\t\t1028 1f4a  PERC H730 Mini (for blades)\n\t\t1028 1f4d  PERC FD33xS\n\t\t1028 1f4f  PERC H730P Slim\n\t\t1028 1f54  PERC FD33xD\n\t\t1028 1fd1  PERC H730P MX\n\t\t17aa 1052  ThinkServer RAID 720i\n\t\t17aa 1053  ThinkServer RAID 720ix\n\t\t1d49 0600  ThinkSystem RAID 730-8i 1GB Cache PCIe 12Gb Adapter\n\t\t1d49 0608  ThinkSystem RAID 730-8i 2GB Flash PCIe 12Gb Adapter\n\t\t1d49 0609  ThinkSystem RAID 730-8i 4GB Flash PCIe 12Gb Adapter\n\t\t8086 351e  RMS3CC080 RAID Controller\n\t\t8086 351f  RMS3CC040 RAID Controller\n\t\t8086 9360  RS3DC080 RAID Controller\n\t\t8086 9362  RS3DC040 RAID Controller\n\t\t8086 9380  RS3SC008 RAID Controller\n\t\t8086 9381  RS3MC044 RAID Controller\n\t005e  SAS1066 PCI-X Fusion-MPT SAS\n\t005f  MegaRAID SAS-3 3008 [Fury]\n\t\t1028 1f44  PERC H330 Adapter\n\t\t1028 1f4b  PERC H330 Mini\n\t\t1028 1f4c  PERC H330 Mini (for blades)\n\t\t1028 1f4d  PERC H330 Embedded (for monolithic)\n\t\t1054 306a  SAS 3004 iMR ROMB\n\t\t1d49 04db  ServeRAID M1210 SAS/SATA Controller\n\t\t1d49 0504  ThinkSystem RAID 520-8i PCIe 12Gb Adapter\n\t0060  MegaRAID SAS 1078\n\t\t1000 1006  MegaRAID SAS 8888ELP\n\t\t1000 100a  MegaRAID SAS 8708ELP\n\t\t1000 100e  MegaRAID SAS 8884E\n\t\t1000 100f  MegaRAID SAS 8708E\n\t\t1000 1010  MegaRAID SATA 350-8ELP\n\t\t1000 1011  MegaRAID SATA 350-4ELP\n\t\t1000 1012  MegaRAID SAS 8704ELP\n\t\t1000 1016  MegaRAID SAS 8880EM2\n\t\t1014 0363  MegaRAID SAS PCI Express ROMB\n\t\t1014 0364  SystemX MegaRAID SAS 8808E\n\t\t1014 0365  SystemX MegaRAID SAS 8884E\n\t\t1014 0379  SystemX MegaRAID SAS 8880EM2\n\t\t1028 1f0a  PERC 6/E Adapter RAID Controller\n\t\t1028 1f0b  PERC 6/i Adapter RAID Controller\n\t\t1028 1f0c  PERC 6/i Integrated RAID Controller\n\t\t1028 1f0d  PERC 6/i Integrated RAID Controller\n\t\t1028 1f11  CERC 6/i Integrated RAID Controller\n\t\t1033 835a  MegaRAID SAS PCI Express ROMB\n\t\t1043 824d  MegaRAID SAS PCI Express ROMB\n\t\t1170 002f  MegaRAID SAS PCI Express ROMB\n\t\t1170 0036  MegaRAID SAS PCI Express ROMB\n\t\t15d9 c080  MegaRAID SAS PCI Express ROMB\n\t\t17aa 6b7c  MegaRAID SAS PCI Express ROMB\n\t\t18a1 0003  LSI MegaRAID SAS PCI Express ROMB\n\t\t8086 1006  RAID Controller SRCSAS28EP\n\t\t8086 100a  RAID Controller SRCSAS28EV\n\t\t8086 1010  RAID Controller SRCSATA28E\n\t\t8086 34cc  Integrated RAID Controller SROMBSAS28E\n\t\t8086 34cd  Integrated RAID Controller SROMBSAS28E\n\t\t8086 3505  Integrated RAID Controller SROMBSASMP2\n\t0062  SAS1078 PCI-Express Fusion-MPT SAS\n\t\t1000 0062  SAS1078 PCI-Express Fusion-MPT SAS\n\t0064  SAS2116 PCI-Express Fusion-MPT SAS-2 [Meteor]\n\t\t1000 3030  9200-16e 6Gb/s SAS/SATA PCIe x8 External HBA\n\t\t1000 30c0  SAS 9201-16i\n\t\t1000 30d0  9201-16e 6Gb/s SAS/SATA PCIe x8 External HBA\n\t0065  SAS2116 PCI-Express Fusion-MPT SAS-2 [Meteor]\n\t006e  SAS2308 PCI-Express Fusion-MPT SAS-2\n\t0070  SAS2004 PCI-Express Fusion-MPT SAS-2 [Spitfire]\n\t\t1000 3010  SAS9211-4i\n\t\t1014 040e  ServeRAID H1110\n\t0071  MR SAS HBA 2004\n\t0072  SAS2008 PCI-Express Fusion-MPT SAS-2 [Falcon]\n\t\t1000 3040  9210-8i\n\t\t1000 3080  9200-8e [LSI SAS 6Gb/s SAS/SATA PCIe x8 External HBA]\n\t\t1000 30b0  9200-8e [LSI SAS 6Gb/s SAS/SATA PCIe x8 External HBA]\n\t\t1028 1f1c  6Gbps SAS HBA Adapter\n\t\t1028 1f1d  PERC H200 Adapter\n\t\t1028 1f1e  PERC H200 Integrated\n\t\t1028 1f1f  PERC H200 Modular\n\t\t1028 1f20  PERC H200 Embedded\n\t\t1028 1f22  PERC H200 Internal Tape Adapter\n\t\t8086 350f  RMS2LL040 RAID Controller\n\t\t8086 3700  SSD 910 Series\n\t0073  MegaRAID SAS 2008 [Falcon]\n\t\t1000 9240  MegaRAID SAS 9240-8i\n\t\t1000 9241  MegaRAID SAS 9240-4i\n\t\t1000 92a0  MegaRAID SAS 9220-8i\n\t\t1014 03b1  ServeRAID M1015 SAS/SATA Controller\n\t\t1014 040d  ServeRAID M1115 SAS/SATA Controller\n\t\t1028 1f4e  PERC H310 Adapter\n\t\t1028 1f4f  PERC H310 Integrated\n\t\t1028 1f50  PERC H310 Mini Blades\n\t\t1028 1f51  PERC H310 Mini Monolithics\n\t\t1028 1f52  PERC H310 Embedded1\n\t\t1028 1f53  PERC H310 Embedded2\n\t\t1028 1f54  PERC H310 Reserved\n\t\t1028 1f78  PERC H310\n\t\t1054 3035  LSI MegaRAID SAS 9240-8i\n\t\t1137 0072  2004 iMR ROMB\n\t\t1137 0073  2008 ROMB\n\t\t1137 00b0  UCSC RAID SAS 2008M-8i\n\t\t1137 00b1  UCSC RAID SAS 2008M-8i\n\t\t1137 00c2  UCS E-Series Double Wide\n\t\t1137 00c3  UCS E-Series Single Wide\n\t\t15d9 0400  Supermicro SMC2008-iMR\n\t\t1734 1177  RAID Ctrl SAS 6G 0/1 (D2607)\n\t\t17aa 1051  ThinkServer RAID 510i\n\t\t8086 350d  RMS2AF040 RAID Controller\n\t\t8086 9240  RAID Controller RS2WC080\n\t\t8086 9241  RAID Controller RS2WC040\n\t0074  SAS2108 PCI-Express Fusion-MPT SAS-2 [Liberator]\n\t0076  SAS2108 PCI-Express Fusion-MPT SAS-2 [Liberator]\n\t0077  SAS2108 PCI-Express Fusion-MPT SAS-2 [Liberator]\n\t0079  MegaRAID SAS 2108 [Liberator]\n\t\t1000 9251  MegaRAID SAS 9260-4ix\n\t\t1000 9256  MegaRAID SAS 9260-8ix\n\t\t1000 9260  MegaRAID SAS 9260-4i\n\t\t1000 9261  MegaRAID SAS 9260-8i\n\t\t1000 9262  MegaRAID SAS 9262-8i\n\t\t1000 9263  MegaRAID SAS 9261-8i\n\t\t1000 9264  MegaRAID SAS 9264-8i\n\t\t1000 9267  MegaRAID SAS 9260CV-4i\n\t\t1000 9268  MegaRAID SAS 9260CV-8i\n\t\t1000 9275  MegaRAID SAS 9280-8ex\n\t\t1000 9276  MR9260-16i\n\t\t1000 9280  MegaRAID SAS 9280-8e\n\t\t1000 9281  MegaRAID SAS 9281-8E\n\t\t1000 9282  MegaRAID SAS 9280-4i4e\n\t\t1000 9290  MegaRAID SAS 9280DE-24i4e\n\t\t1014 03b2  ServeRAID M5015 SAS/SATA Controller\n\t\t1014 03b3  ServeRAID M5025 SAS/SATA Controller\n\t\t1028 1f15  PERC H800 Adapter\n\t\t1028 1f16  PERC H700 Adapter\n\t\t1028 1f17  PERC H700 Integrated\n\t\t1028 1f18  PERC H700 Modular\n\t\t1028 1f1a  PERC H800 Proto Adapter\n\t\t1028 1f1b  PERC H700 Integrated\n\t\t1043 8480  PIKE-2108 16PD\n\t\t1734 1176  RAID Ctrl SAS 6G 5/6 512MB (D2616)\n\t\t1734 1177  RAID Ctrl SAS 6G 0/1 (D2607)\n\t\t8086 350b  RMS2MH080 RAID Controller\n\t\t8086 9256  MegaRAID SAS 9260DE-8i RS2BL080DE\n\t\t8086 9260  RAID Controller RS2BL040\n\t\t8086 9261  RAID Controller RS2BL080\n\t\t8086 9264  RAID Controller RT3WB080 Warm Beach (Caster Lite)\n\t\t8086 9267  RAID Controller RS2VB040\n\t\t8086 9268  RAID Controller RS2VB080\n\t\t8086 9275  RAID Controller RS2PI008DE\n\t\t8086 9276  RAID Controller RS2WG160\n\t\t8086 9280  RAID Controller RS2PI008\n\t\t8086 9282  RAID Controller RS2MB044\n\t\t8086 9290  RAID Controller RS2SG244\n\t007c  MegaRAID SAS 1078DE\n\t\t1014 0395  ServeRAID-AR10is SAS/SATA Controller\n\t007e  SSS6200 PCI-Express Flash SSD\n\t\t1000 0504  Nytro NWD-BLP4-800\n\t\t1000 0507  Nytro NWD-BLP4-1600\n\t\t1000 0581  Nytro NWD-BLP4-400\n\t\t1000 100d  Nytro NWD-BFH6-1200\n\t\t1000 100e  Nytro NWD-BFH8-1600\n\t\t1000 107e  Nytro NWD-BFH8-3200\n\t\t1000 1310  Nytro XP6302-8B1536\n\t\t1000 1311  Nytro XP6302-8B2048\n\t\t1000 1314  Nytro XP6302-8B4096\n\t\t1000 150c  Nytro XP6210-4A2048\n\t\t1000 150f  Nytro XP6210-4B2048\n\t\t1000 160b  Nytro XP6209-4A1024\n\t\t1000 1613  Nytro XP6209-4B2048\n\t\t108e 050a  Nytro ELP4x200_4d_n\n\t\t108e 0581  Nytro ELP4x100_4d_n\n\t0080  SAS2208 PCI-Express Fusion-MPT SAS-2\n\t0081  SAS2208 PCI-Express Fusion-MPT SAS-2\n\t0082  SAS2208 PCI-Express Fusion-MPT SAS-2\n\t0083  SAS2208 PCI-Express Fusion-MPT SAS-2\n\t0084  SAS2208 PCI-Express Fusion-MPT SAS-2\n\t0085  SAS2208 PCI-Express Fusion-MPT SAS-2\n\t0086  SAS2308 PCI-Express Fusion-MPT SAS-2\n\t\t15d9 0690  Onboard MegaRAID SAS2208 [Thunderbolt]\n\t\t15d9 0691  Onboard SAS2308 PCI-Express Fusion-MPT SAS-2\n\t0087  SAS2308 PCI-Express Fusion-MPT SAS-2\n\t\t1000 3020  9207-8i SAS2.1 HBA\n\t\t1000 3030  SAS9207-4i4e\n\t\t1000 3040  9207-8e SAS2.1 HBA\n\t\t1000 3050  SAS9217-8i\n\t\t1000 3060  SAS9217-4i4e\n\t\t1014 0472  N2125 External Host Bus Adapter\n\t\t1590 0041  H220i\n\t\t1590 0042  H221 / 9207-8e\n\t\t1590 0044  H220i\n\t\t8086 3000  RS25GB008 RAID Controller\n\t\t8086 3060  RS25FB044 RAID Controller\n\t\t8086 3516  RMS25JB080 RAID Controller\n\t\t8086 3517  RMS25JB040 RAID Controller\n\t\t8086 3518  RMS25KB080 RAID Controller\n\t\t8086 3519  RMS25KB040 RAID Controller\n\t\t8086 351a  RMS25LB040 RAID Controller\n\t\t8086 351b  RMS25LB080 RAID Controller\n\t008f  53c875J\n\t\t1092 8000  FirePort 40 SCSI Controller\n\t\t1092 8760  FirePort 40 Dual SCSI Host Adapter\n\t0090  SAS3108 PCI-Express Fusion-MPT SAS-3\n\t0091  SAS3108 PCI-Express Fusion-MPT SAS-3\n\t0094  SAS3108 PCI-Express Fusion-MPT SAS-3\n\t0095  SAS3108 PCI-Express Fusion-MPT SAS-3\n\t0096  SAS3004 PCI-Express Fusion-MPT SAS-3\n\t0097  SAS3008 PCI-Express Fusion-MPT SAS-3\n\t\t1000 3090  SAS9311-8i\n\t\t1000 30a0  SAS9300-8e\n\t\t1000 30e0  SAS9300-8i\n\t\t1000 3130  SAS 9300-16i\n\t\t1028 1f45  HBA330 Adapter\n\t\t1028 1f46  12Gbps HBA\n\t\t1028 1f53  HBA330 Mini\n\t\t1028 1fd2  HBA330 MX\n\t\t1028 1fd3  HBA330 MMZ\n# Supermicro AOC-S3008L-L8e uses 0808 for their SAS3008 SAS controller\n\t\t15d9 0808  AOC-S3008L-L8e\n\t\t1bd4 0011  Inspur 12Gb 8i-3008 IT SAS HBA\n\t00ab  SAS3516 Fusion-MPT Tri-Mode RAID On Chip (ROC)\n# 8 Internal and 8 External port channel 9400 HBA\n\t\t1000 3040  HBA 9400-8i8e\n\t\t8086 3530  Integrated RAID Module RMSP3JD160J\n\t00ac  SAS3416 Fusion-MPT Tri-Mode I/O Controller Chip (IOC)\n# Channel 16 internal port HBA\n\t\t1000 3000  HBA 9400-16i\n# Channel 16 external port HBA\n\t\t1000 3020  HBA 9400-16e\n\t\t1028 1fe3  HBA345 Adapter\n\t\t1028 1fe4  HBA345 Front\n\t\t1d49 0201  ThinkSystem 430-16i SAS/SATA 12Gb HBA\n\t\t1d49 0203  ThinkSystem 430-16e SAS/SATA 12Gb HBA\n\t\t8086 3000  RAID Controller RSP3QD160J\n\t\t8086 3020  RAID Controller RSP3GD016J\n\t00ae  SAS3508 Fusion-MPT Tri-Mode RAID On Chip (ROC)\n\t00af  SAS3408 Fusion-MPT Tri-Mode I/O Controller Chip (IOC)\n\t\t1000 3010  HBA 9400-8i\n# 9400 Channel 8 external port HBA\n\t\t1000 3030  HBA 9400-8e\n\t\t1d49 0200  ThinkSystem 430-8i SAS/SATA 12Gb HBA\n\t\t1d49 0202  ThinkSystem 430-8e SAS/SATA 12Gb HBA\n\t\t1d49 0204  ThinkSystem 430-8i SAS/SATA 12Gb Dense HBA\n\t00be  SAS3504 Fusion-MPT Tri-Mode RAID On Chip (ROC)\n\t00bf  SAS3404 Fusion-MPT Tri-Mode I/O Controller Chip (IOC)\n\t00c0  SAS3324 PCI-Express Fusion-MPT SAS-3\n\t00c1  SAS3324 PCI-Express Fusion-MPT SAS-3\n\t00c2  SAS3324 PCI-Express Fusion-MPT SAS-3\n\t00c3  SAS3324 PCI-Express Fusion-MPT SAS-3\n\t00c4  SAS3224 PCI-Express Fusion-MPT SAS-3\n\t00c5  SAS3316 PCI-Express Fusion-MPT SAS-3\n\t00c6  SAS3316 PCI-Express Fusion-MPT SAS-3\n\t00c7  SAS3316 PCI-Express Fusion-MPT SAS-3\n\t00c8  SAS3316 PCI-Express Fusion-MPT SAS-3\n\t00c9  SAS3216 PCI-Express Fusion-MPT SAS-3\n\t00ce  MegaRAID SAS-3 3316 [Intruder]\n\t\t1000 9371  MegaRAID SAS 9361-16i\n\t\t1000 9390  MegaRAID SAS 9380-8i8e\n\t00cf  MegaRAID SAS-3 3324 [Intruder]\n\t\t1000 9370  MegaRAID SAS 9361-24i\n\t00d0  SAS3716 Fusion-MPT Tri-Mode RAID Controller Chip (ROC)\n# 9405W 16 internal port channel HBA\n\t\t1000 3050  HBA 9405W-16i\n# 9405W 8 internal and 8 external port channel HBA\n\t\t1000 3070  HBA 9405W-8i8e\n\t00d1  SAS3616 Fusion-MPT Tri-Mode I/O Controller Chip (IOC)\n# 9405W 16 external port Channel HBA\n\t\t1000 3080  HBA 9405W-16e\n# 9405W 16 internal port Channel HBA\n\t\t1000 3090  HBA 9405W-16i\n\t00d3  MegaRAID Tri-Mode SAS3716W\n\t00e0  Fusion-MPT 12GSAS/PCIe Unsupported SAS39xx\n\t00e1  Fusion-MPT 12GSAS/PCIe SAS39xx\n\t00e2  Fusion-MPT 12GSAS/PCIe Secure SAS39xx\n\t00e3  Fusion-MPT 12GSAS/PCIe Unsupported SAS39xx\n\t00e4  Fusion-MPT 12GSAS/PCIe Unsupported SAS38xx\n# Invalid part\n\t\t1028 200b  HBA355i Adapter Invalid\n# Invalid part\n\t\t1028 200c  HBA355i Front Invalid\n# Invalid part\n\t\t1028 200d  HBA355e Adapter Invalid\n# Invalid part\n\t\t1028 200e  HBA350i MX Invalid\n# Soft Secure\n\t00e5  Fusion-MPT 12GSAS/PCIe SAS38xx\n# Soft Secure\n\t\t1028 200b  HBA355i Adapter\n# Soft Secure\n\t\t1028 200c  HBA355i Front\n# Soft Secure\n\t\t1028 200d  HBA355e Adapter\n# Soft Secure\n\t\t1028 200e  HBA350i MX\n\t\t1d49 0205  ThinkSystem 440-16i SAS/SATA PCIe Gen4 12Gb Internal HBA\n\t\t1d49 0206  ThinkSystem 440-16e SAS/SATA PCIe Gen4 12Gb HBA\n\t00e6  Fusion-MPT 12GSAS/PCIe Secure SAS38xx\n\t\t1028 200b  HBA355i Adapter\n\t\t1028 200c  HBA355i Front\n\t\t1028 200d  HBA355e Adapter\n\t\t1028 200e  HBA355i MX\n\t\t1d49 0205  ThinkSystem 440-16i SAS/SATA PCIe Gen4 12Gb Internal HBA\n\t\t1d49 0206  ThinkSystem 440-16e SAS/SATA PCIe Gen4 12Gb HBA\n\t00e7  Fusion-MPT 12GSAS/PCIe Unsupported SAS38xx\n# Tampered part\n\t\t1028 200b  HBA355i Adapter Tampered\n# Tampered part\n\t\t1028 200c  HBA355i Front Tampered\n# Tampered part\n\t\t1028 200d  HBA355e Adapter Tampered\n# Tampered part\n\t\t1028 200e  HBA350i MX Tampered\n\t02b0  Virtual Endpoint on PCIe Switch\n\t\t1d49 0001  ThinkSystem 1610-4P NVMe Switch Adapter\n\t\t1d49 0002  ThinkSystem 810-4P NVMe Switch Adapter\n\t02b1  Virtual Endpoint on PCIe Switch (9749)\n\t\t1d49 0004  ThinkSystem 1610-8P NVMe Switch Adapter\n\t0407  MegaRAID\n\t\t1000 0530  MegaRAID 530 SCSI 320-0X RAID Controller\n\t\t1000 0531  MegaRAID 531 SCSI 320-4X RAID Controller\n\t\t1000 0532  MegaRAID 532 SCSI 320-2X RAID Controller\n\t\t1028 0531  PowerEdge Expandable RAID Controller 4/QC\n\t\t1028 0533  PowerEdge Expandable RAID Controller 4/QC\n\t\t8086 0530  MegaRAID Intel RAID Controller SRCZCRX\n\t\t8086 0532  MegaRAID Intel RAID Controller SRCU42X\n\t0408  MegaRAID\n\t\t1000 0001  MegaRAID SCSI 320-1E RAID Controller\n\t\t1000 0002  MegaRAID SCSI 320-2E RAID Controller\n\t\t1025 004d  MegaRAID ACER ROMB-2E RAID Controller\n\t\t1028 0001  PowerEdge RAID Controller PERC4e/SC\n\t\t1028 0002  PowerEdge RAID Controller PERC4e/DC\n\t\t1028 0012  PowerEdge RAID Controller RAC4\n\t\t1028 0015  PowerEdge RAID Controller PERC5\n\t\t1028 1f03  PowerEdge RAID Controller PERC5\n\t\t1734 1065  FSC MegaRAID PCI Express ROMB\n\t\t8086 0002  MegaRAID Intel RAID Controller SRCU42E\n\t\t8086 3449  MegaRAID Intel RAID Controller SROMBU\n\t0409  MegaRAID\n\t\t1000 3004  MegaRAID SATA 300-4X RAID Controller\n\t\t1000 3008  MegaRAID SATA 300-8X RAID Controller\n\t\t8086 3008  MegaRAID RAID Controller SRCS28X\n\t\t8086 3431  MegaRAID RAID Controller Alief SROMBU42E\n\t\t8086 3499  MegaRAID RAID Controller Harwich SROMBU42E\n\t0411  MegaRAID SAS 1068\n\t\t1000 1001  MegaRAID SAS 8408E\n\t\t1000 1002  MegaRAID SAS 8480E\n\t\t1000 1003  MegaRAID SAS 8344ELP\n\t\t1000 1004  MegaRAID SAS 8308ELP\n\t\t1000 1008  MegaRAID SAS 84016E\n\t\t1000 100c  MegaRAID SATA 300-12E\n\t\t1000 100d  MegaRAID SATA 300-16E\n\t\t1000 2004  MegaRAID SATA 300-8ELP\n\t\t1000 2005  MegaRAID SATA 300-4ELP\n\t\t1033 8287  MegaRAID SAS PCI Express ROMB\n\t\t1054 3016  MegaRAID SAS RoMB Server\n\t\t1734 1081  MegaRAID SAS PCI Express ROMB\n\t\t1734 10a3  MegaRAID SAS PCI Express ROMB\n\t\t8086 1001  RAID Controller SRCSAS18E\n\t\t8086 1003  RAID Controller SRCSAS144E\n\t\t8086 3500  SROMBSAS18E RAID Controller\n\t\t8086 3501  SROMBSAS18E RAID Controller\n\t\t8086 3504  SROMBSAS18E RAID Controller\n\t0413  MegaRAID SAS 1068 [Verde ZCR]\n\t\t1000 1005  MegaRAID SAS 8300XLP\n\t0621  FC909 Fibre Channel Adapter\n\t0622  FC929 Fibre Channel Adapter\n\t\t1000 1020  44929 O Dual Fibre Channel card\n\t0623  FC929 LAN\n\t0624  FC919 Fibre Channel Adapter\n\t0625  FC919 LAN\n\t0626  FC929X Fibre Channel Adapter\n\t\t1000 1010  7202-XP-LC Dual Fibre Channel card\n\t0627  FC929X LAN\n\t0628  FC919X Fibre Channel Adapter\n\t0629  FC919X LAN\n\t0640  FC949X Fibre Channel Adapter\n\t0642  FC939X Fibre Channel Adapter\n\t0646  FC949ES Fibre Channel Adapter\n\t0701  83C885 NT50 DigitalScape Fast Ethernet\n\t0702  Yellowfin G-NIC gigabit ethernet\n\t\t1318 0000  PEI100X\n\t0804  SA2010\n\t0805  SA2010ZC\n\t0806  SA2020\n\t0807  SA2020ZC\n\t0901  61C102\n\t1000  63C815\n\t10e0  MegaRAID 12GSAS/PCIe Unsupported SAS39xx\n\t\t1028 1ae0  PERC H755 Adapter - Invalid Device\n\t\t1028 1ae1  PERC H755 Front - Invalid Device\n\t\t1028 1ae2  PERC H755N Front - Invalid Device\n\t\t1028 1ae3  PERC H755 MX - Invalid Device\n\t10e1  MegaRAID 12GSAS/PCIe SAS39xx\n\t\t1028 1ae0  PERC H755 Adapter\n\t\t1028 1ae1  PERC H755 Front\n\t\t1028 1ae2  PERC H755N Front\n\t\t1028 1ae3  PERC H755 MX\n\t\t1d49 060a  ThinkSystem RAID 940-8i 4GB Flash PCIe Gen4 12Gb Adapter\n\t\t1d49 060b  ThinkSystem RAID 940-8i 8GB Flash PCIe Gen4 12Gb Adapter\n\t\t1d49 060c  ThinkSystem RAID 940-16i 8GB Flash PCIe Gen4 12Gb Adapter\n\t\t1d49 060d  ThinkSystem RAID 940-16i 8GB Flash PCIe Gen4 12Gb Internal Adapter\n\t\t1d49 060e  ThinkSystem RAID 940-32i 8GB Flash PCIe Gen4 12Gb Adapter\n\t\t1d49 060f  ThinkSystem RAID 940-8e 4GB Flash PCIe Gen4 12Gb Adapter\n\t10e2  MegaRAID 12GSAS/PCIe Secure SAS39xx\n\t\t1028 1ae0  PERC H755 Adapter\n\t\t1028 1ae1  PERC H755 Front\n\t\t1028 1ae2  PERC H755N Front\n\t\t1028 1ae3  PERC H755 MX\n\t\t1d49 060a  ThinkSystem RAID 940-8i 4GB Flash PCIe Gen4 12Gb Adapter\n\t\t1d49 060b  ThinkSystem RAID 940-8i 8GB Flash PCIe Gen4 12Gb Adapter\n\t\t1d49 060c  ThinkSystem RAID 940-16i 8GB Flash PCIe Gen4 12Gb Adapter\n\t\t1d49 060d  ThinkSystem RAID 940-16i 8GB Flash PCIe Gen4 12Gb Internal Adapter\n\t\t1d49 060e  ThinkSystem RAID 940-32i 8GB Flash PCIe Gen4 12Gb Adapter\n\t\t1d49 060f  ThinkSystem RAID 940-8e 4GB Flash PCIe Gen4 12Gb Adapter\n\t10e3  MegaRAID 12GSAS/PCIe Unsupported SAS39xx\n\t\t1028 1ae0  PERC H755 Adapter - Tampered Device\n\t\t1028 1ae1  PERC H755 Front - Tampered Device\n\t\t1028 1ae2  PERC H755N Front - Tampered Device\n\t\t1028 1ae3  PERC H755 MX - Tampered Device\n\t10e4  MegaRAID 12GSAS/PCIe Unsupported SAS38xx\n\t10e5  MegaRAID 12GSAS/PCIe SAS38xx\n\t10e6  MegaRAID 12GSAS/PCIe Secure SAS38xx\n\t10e7  MegaRAID 12GSAS/PCIe Unsupported SAS38xx\n\t1960  MegaRAID\n\t\t1000 0518  MegaRAID 518 SCSI 320-2 Controller\n\t\t1000 0520  MegaRAID 520 SCSI 320-1 Controller\n\t\t1000 0522  MegaRAID 522 i4 133 RAID Controller\n\t\t1000 0523  MegaRAID SATA 150-6 RAID Controller\n\t\t1000 4523  MegaRAID SATA 150-4 RAID Controller\n\t\t1000 a520  MegaRAID ZCR SCSI 320-0 Controller\n\t\t1028 0518  MegaRAID 518 DELL PERC 4/DC RAID Controller\n\t\t1028 0520  MegaRAID 520 DELL PERC 4/SC RAID Controller\n\t\t1028 0531  PowerEdge Expandable RAID Controller 4/QC\n\t\t1028 0533  PowerEdge Expandable RAID Controller 4/QC\n\t\t8086 0520  MegaRAID RAID Controller SRCU41L\n\t\t8086 0523  MegaRAID RAID Controller SRCS16\n\t3050  SAS2008 PCI-Express Fusion-MPT SAS-2\n\t6001  DX1 Multiformat Broadcast HD/SD Encoder/Decoder\n1001  Kolter Electronic\n\t0010  PCI 1616 Measurement card with 32 digital I/O lines\n\t0011  OPTO-PCI Opto-Isolated digital I/O board\n\t0012  PCI-AD/DA Analogue I/O board\n\t0013  PCI-OPTO-RELAIS Digital I/O board with relay outputs\n\t0014  PCI-Counter/Timer Counter Timer board\n\t0015  PCI-DAC416 Analogue output board\n\t0016  PCI-MFB Analogue I/O board\n\t0017  PROTO-3 PCI Prototyping board\n\t9100  INI-9100/9100W SCSI Host\n# nee ATI Technologies, Inc.\n1002  Advanced Micro Devices, Inc. [AMD/ATI]\n\t1304  Kaveri\n\t1305  Kaveri\n\t1306  Kaveri\n\t1307  Kaveri\n\t1308  Kaveri HDMI/DP Audio Controller\n\t1309  Kaveri [Radeon R6/R7 Graphics]\n\t130a  Kaveri [Radeon R6 Graphics]\n\t130b  Kaveri [Radeon R4 Graphics]\n\t130c  Kaveri [Radeon R7 Graphics]\n\t130d  Kaveri [Radeon R6 Graphics]\n\t130e  Kaveri [Radeon R5 Graphics]\n\t130f  Kaveri [Radeon R7 Graphics]\n\t1310  Kaveri\n\t1311  Kaveri\n\t1312  Kaveri\n\t1313  Kaveri [Radeon R7 Graphics]\n\t1314  Wrestler HDMI Audio\n\t\t174b 1001  PURE Fusion Mini\n\t1315  Kaveri [Radeon R5 Graphics]\n\t1316  Kaveri [Radeon R5 Graphics]\n\t1317  Kaveri\n\t1318  Kaveri [Radeon R5 Graphics]\n\t131b  Kaveri [Radeon R4 Graphics]\n\t131c  Kaveri [Radeon R7 Graphics]\n\t131d  Kaveri [Radeon R6 Graphics]\n\t13e9  Ariel\n\t1478  Navi 10 XL Upstream Port of PCI Express Switch\n\t1479  Navi 10 XL Downstream Port of PCI Express Switch\n\t154c  Kryptos\n\t154e  Garfield\n\t1551  Arlene\n\t1552  Pooky\n\t1561  Anubis\n\t15d8  Picasso\n\t\t103c 8615  Pavilion Laptop 15-cw1xxx\n\t15dd  Raven Ridge [Radeon Vega Series / Radeon Vega Mobile Series]\n\t\t103c 83c6  Radeon Vega 8 Mobile\n\t\t1458 d000  Radeon RX Vega 11\n\t15de  Raven/Raven2/Fenghuang HDMI/DP Audio Controller\n\t\t103c 8615  Pavilion Laptop 15-cw1xxx\n\t15df  Raven/Raven2/Fenghuang/Renoir Cryptographic Coprocessor\n\t\t103c 8615  Pavilion Laptop 15-cw1xxx\n\t15ff  Fenghuang [Zhongshan Subor Z+]\n\t1607  Arden\n\t1636  Renoir\n\t1714  BeaverCreek HDMI Audio [Radeon HD 6500D and 6400G-6600G series]\n\t\t103c 168b  ProBook 4535s\n\t3150  RV380/M24 [Mobility Radeon X600]\n\t\t103c 0934  nx8220\n\t3151  RV380 GL [FireMV 2400]\n\t3152  RV370/M22 [Mobility Radeon X300]\n\t3154  RV380/M24 GL [Mobility FireGL V3200]\n\t3155  RV380 GL [FireMV 2400]\n\t3171  RV380 GL [FireMV 2400] (Secondary)\n\t3e50  RV380 [Radeon X600]\n\t3e54  RV380 GL [FireGL V3200]\n\t3e70  RV380 [Radeon X600] (Secondary)\n\t4136  RS100 [Mobility IGP 320M]\n\t4137  RS200 [Radeon IGP 340]\n\t4144  R300 [Radeon 9500]\n\t4146  R300 [Radeon 9700 PRO]\n\t4147  R300 GL [FireGL Z1]\n\t4148  R350 [Radeon 9800/9800 SE]\n\t4150  RV350 [Radeon 9550/9600/X1050 Series]\n\t\t1002 0002  R9600 Pro primary (Asus OEM for HP)\n\t\t1002 0003  R9600 Pro secondary (Asus OEM for HP)\n\t\t1002 4722  All-in-Wonder 2006 AGP Edition\n\t\t1458 4024  GV-R96128D\n\t\t148c 2064  R96A-C3N\n\t\t148c 2066  R96A-C3N\n\t\t174b 7c19  Atlantis Radeon 9600 Pro\n\t\t174b 7c29  GC-R9600PRO\n\t\t17ee 2002  Radeon 9600 256Mb Primary\n\t\t18bc 0101  GC-R9600PRO (Primary)\n\t4151  RV350 [Radeon 9600 Series]\n\t\t1043 c004  A9600SE\n\t\t174b 7c37  Radeon 9600SE 128M DDR V/D/VO\n\t4152  RV360 [Radeon 9600/X1050 Series]\n\t\t1002 0002  Radeon 9600XT\n\t\t1002 4772  All-in-Wonder 9600 XT\n\t\t1043 c002  Radeon 9600 XT TVD\n\t\t1043 c01a  A9600XT/TD\n\t\t1462 9510  RX9600XT (MS-8951)\n\t\t174b 7c29  Radeon 9600XT\n\t\t1787 4002  Radeon 9600 XT\n\t4153  RV350 [Radeon 9550]\n\t\t1043 010c  A9550GE/TD\n\t\t1462 932c  RX9550SE-TD128 (MS-8932)\n\t4154  RV350 GL [FireGL T2]\n\t4155  RV350 [Radeon 9600]\n\t4157  RV350 GL [FireGL T2]\n\t4158  68800AX [Graphics Ultra Pro PCI]\n\t4164  R300 [Radeon 9500 PRO] (Secondary)\n\t4165  R300 [Radeon 9700 PRO] (Secondary)\n\t4166  R300 [Radeon 9700 PRO] (Secondary)\n\t4168  RV350 [Radeon 9800 SE] (Secondary)\n\t4170  RV350 [Radeon 9550/9600/X1050 Series] (Secondary)\n\t\t1002 0003  R9600 Pro secondary (Asus OEM for HP)\n\t\t1002 4723  All-in-Wonder 2006 AGP Edition (Secondary)\n\t\t1458 4025  GV-R96128D (Secondary)\n\t\t148c 2067  R96A-C3N (Secondary)\n\t\t174b 7c28  GC-R9600PRO (Secondary)\n\t\t17ee 2003  Radeon 9600 256Mb (Secondary)\n\t\t18bc 0100  GC-R9600PRO (Secondary)\n\t4171  RV350 [Radeon 9600] (Secondary)\n\t\t1043 c005  A9600SE (Secondary)\n\t\t174b 7c36  Radeon 9600SE 128M DDR V/D/VO (secondary)\n\t4172  RV350 [Radeon 9600/X1050 Series] (Secondary)\n\t\t1002 0003  Radeon 9600XT (Secondary)\n\t\t1002 4773  All-in-Wonder 9600 XT (Secondary)\n\t\t1043 c003  A9600XT (Secondary)\n\t\t1043 c01b  A9600XT/TD (Secondary)\n\t\t174b 7c28  Radeon 9600XT (Secondary)\n\t\t1787 4003  Radeon 9600 XT (Secondary)\n\t4173  RV350 [Radeon 9550] (Secondary)\n\t\t1043 010d  A9550GE/TD (Secondary)\n\t4242  R200 [All-In-Wonder Radeon 8500 DV]\n\t\t1002 02aa  Radeon 8500 AIW DV Edition\n\t4243  R200 PCI Bridge [All-in-Wonder Radeon 8500DV]\n\t4336  RS100 [Radeon IGP 320M]\n\t\t1002 4336  Pavilion ze4300 ATI Radeon Mobility U1 (IGP 320 M)\n\t\t103c 0024  Pavilion ze4400 builtin Video\n\t\t161f 2029  eMachines M5312 builtin Video\n\t4337  RS200M [Radeon IGP 330M/340M/345M/350M]\n\t\t1014 053a  ThinkPad R40e\n\t\t103c 0850  Radeon IGP 345M\n\t4341  SB200 AC97 Audio Controller\n\t4342  SB200 PCI to PCI Bridge\n\t4345  SB200 EHCI USB Controller\n\t4346  Crayola 6 [XENOS Parent Die (XBOX 360)]\n\t4347  SB200 OHCI USB Controller #1\n\t4348  SB200 OHCI USB Controller #2\n\t4349  SB200 IDE Controller\n\t434c  SB200 PCI to LPC Bridge\n\t434d  SB200 AC97 Modem Controller\n\t4353  SB200 SMBus Controller\n\t4354  215CT [Mach64 CT PCI]\n\t4358  Mach64 CX [Graphics Xpression]\n\t4361  SB300 AC'97 Audio Controller\n\t4362  SB300 PCI to PCI Bridge\n\t4363  SB300 SMBus Controller\n\t4365  SB300 USB Controller (EHCI)\n\t4367  SB300 USB Controller (EHCI)\n\t4368  SB300 USB Controller (EHCI)\n\t4369  SB300 IDE Controller\n\t436c  SB300 PCI to LPC Bridge\n\t436d  SB300 AC97 Modem Controller\n\t436e  SB300 Serial ATA Controller\n\t4370  IXP SB400 AC'97 Audio Controller\n\t\t1025 0079  Aspire 5024WLMMi\n\t\t1025 0091  Aspire 5032WXMi\n\t\t103c 2a05  Pavilion t3030.de Desktop PC\n\t\t103c 308b  MX6125\n\t\t105b 0c81  Realtek ALC 653\n\t\t107b 0300  MX6421\n\t\t1462 0131  MS-1013 Notebook\n\t4371  IXP SB4x0 PCI-PCI Bridge\n\t\t103c 308b  MX6125\n\t\t1462 7217  Aspire L250\n\t4372  IXP SB4x0 SMBus Controller\n\t\t1025 0080  Aspire 5024WLMMi\n\t\t103c 2a20  Pavilion t3030.de Desktop PC\n\t\t103c 308b  MX6125\n\t\t1462 0131  MS-1013 Notebook\n\t\t1462 7217  Aspire L250\n\t4373  IXP SB4x0 USB2 Host Controller\n\t\t1025 0080  Aspire 5024WLMMi\n\t\t103c 2a20  Pavilion t3030.de Desktop PC\n\t\t103c 308b  MX6125\n\t\t1462 7217  Aspire L250\n\t4374  IXP SB4x0 USB Host Controller\n\t\t103c 2a20  Pavilion t3030.de Desktop PC\n\t\t103c 308b  MX6125\n\t\t1462 7217  Aspire L250\n\t4375  IXP SB4x0 USB Host Controller\n\t\t1025 0080  Aspire 5024WLMMi\n\t\t103c 2a20  Pavilion t3030.de Desktop PC\n\t\t103c 308b  MX6125\n\t\t1462 7217  Aspire L250\n\t4376  IXP SB4x0 IDE Controller\n\t\t1025 0080  Aspire 5024WLMMi\n\t\t103c 2a20  Pavilion t3030.de Desktop PC\n\t\t103c 308b  MX6125\n\t\t1462 0131  MS-1013 Notebook\n\t\t1462 7217  Aspire L250\n\t4377  IXP SB4x0 PCI-ISA Bridge\n\t\t1025 0080  Aspire 5024WLMi\n\t\t103c 2a20  Pavilion t3030.de Desktop PC\n\t\t103c 308b  MX6125\n\t\t1462 7217  Aspire L250\n\t4378  IXP SB400 AC'97 Modem Controller\n\t\t1025 0080  Aspire 5024WLMMi\n\t\t103c 308b  MX6125\n\t\t1462 0131  MS-1013 Notebook\n\t4379  IXP SB4x0 Serial ATA Controller\n\t\t1462 7141  Aspire L250\n\t437a  IXP SB400 Serial ATA Controller\n\t\t1002 4379  4379 Serial ATA Controller\n\t\t1002 437a  437A Serial ATA Controller\n\t\t1462 7141  Aspire L250\n\t\t14f1 8800  Leadtek WinFast TV2000XP Expert\n\t437b  IXP SB4x0 High Definition Audio Controller\n\t\t1002 437b  IXP SB4x0 High Definition Audio Controller\n\t\t10cf 1326  Fujitsu Lifebook A3040\n\t\t1734 10b8  Realtek High Definition Audio\n\t4380  SB600 Non-Raid-5 SATA\n\t\t103c 2813  DC5750 Microtower\n\t\t1179 ff50  Satellite P305D-S8995E\n\t\t1458 b003  GA-MA790FX-DS5 (rev. 1.0)\n\t\t1458 b005  Gigabyte GA-MA69G-S3H Motherboard\n\t\t1462 7327  K9AG Neo2\n\t\t17f2 5999  KI690-AM2 Motherboard\n\t4381  SB600 SATA Controller (RAID 5 mode)\n\t4382  SB600 AC97 Audio\n\t4383  SBx00 Azalia (Intel HDA)\n\t\t1019 2120  A785GM-M\n\t\t103c 1611  Pavilion DM1Z-3000\n\t\t103c 280a  DC5750 Microtower\n\t\t1043 8230  M3A78-EH Motherboard\n\t\t1043 836c  M4A785TD Motherboard\n\t\t1043 8410  M4A89GTD PRO/USB3 Motherboard\n\t\t1043 841b  M5A88-V EVO\n\t\t1043 8445  M5A78L LE\n\t\t105b 0e13  N15235/A74MX mainboard / AMD SB700\n\t\t1179 ff50  Satellite P305D-S8995E\n\t\t1458 a022  GA-MA770-DS3rev2.0 Motherboard\n\t\t17f2 5000  KI690-AM2 Motherboard\n\t4384  SBx00 PCI to PCI Bridge\n\t4385  SBx00 SMBus Controller\n\t\t1019 2120  A785GM-M\n\t\t103c 1611  Pavilion DM1Z-3000\n\t\t103c 280a  DC5750 Microtower\n\t\t1043 82ef  M3A78-EH Motherboard\n\t\t1043 8389  M4A785TD Motherboard\n\t\t105b 0e13  N15235/A74MX mainboard / AMD SB700\n\t\t1179 ff50  Satellite P305D-S8995E\n\t\t1458 4385  GA-MA770-DS3rev2.0 Motherboard\n\t\t1462 7368  K9AG Neo2\n\t\t15d9 a811  H8DGU\n\t\t174b 1001  PURE Fusion Mini\n\t\t17f2 5000  KI690-AM2 Motherboard\n\t4386  SB600 USB Controller (EHCI)\n\t\t103c 280a  DC5750 Microtower\n\t\t1179 ff50  Satellite P305D-S8995E\n\t\t1462 7368  K9AG Neo2\n\t\t17f2 5000  KI690-AM2 Motherboard\n\t4387  SB600 USB (OHCI0)\n\t\t103c 280a  DC5750 Microtower\n\t\t1179 ff50  Satellite P305D-S8995E\n\t\t1462 7368  K9AG Neo2\n\t\t17f2 5000  KI690-AM2 Motherboard\n\t4388  SB600 USB (OHCI1)\n\t\t103c 280a  DC5750 Microtower\n\t\t1179 ff50  Satellite P305D-S8995E\n\t\t1462 7368  K9AG Neo2\n\t\t17f2 5000  KI690-AM2 Motherboard\n\t4389  SB600 USB (OHCI2)\n\t\t103c 280a  DC5750 Microtower\n\t\t1179 ff50  Satellite P305D-S8995E\n\t\t1462 7368  K9AG Neo2\n\t\t17f2 5000  KI690-AM2 Motherboard\n\t438a  SB600 USB (OHCI3)\n\t\t103c 280a  DC5750 Microtower\n\t\t1179 ff50  Satellite P305D-S8995E\n\t\t1462 7368  K9AG Neo2\n\t\t17f2 5000  KI690-AM2 Motherboard\n\t438b  SB600 USB (OHCI4)\n\t\t103c 280a  DC5750 Microtower\n\t\t1179 ff50  Satellite P305D-S8995E\n\t\t1462 7368  K9AG Neo2\n\t\t17f2 5000  KI690-AM2 Motherboard\n\t438c  SB600 IDE\n\t\t103c 280a  DC5750 Microtower\n\t\t1179 ff50  Satellite P305D-S8995E\n\t\t1458 5002  Gigabyte GA-MA69G-S3H Motherboard\n\t\t1462 7368  K9AG Neo2\n\t\t17f2 5000  KI690-AM2 Motherboard\n\t438d  SB600 PCI to LPC Bridge\n\t\t103c 280a  DC5750 Microtower\n\t\t1179 ff50  Satellite P305D-S8995E\n\t\t1462 7368  K9AG Neo2\n\t\t17f2 5000  KI690-AM2 Motherboard\n\t438e  SB600 AC97 Modem\n\t4390  SB7x0/SB8x0/SB9x0 SATA Controller [IDE mode]\n\t\t1043 82ef  M3A78-EH Motherboard\n\t\t1043 8389  M4A785TD Motherboard\n\t\t105b 0e13  N15235/A74MX mainboard / AMD SB700\n\t\t1458 b002  GA-MA770-DS3rev2.0 Motherboard\n\t\t1849 4390  Motherboard (one of many)\n\t4391  SB7x0/SB8x0/SB9x0 SATA Controller [AHCI mode]\n\t\t103c 1611  Pavilion DM1Z-3000\n\t\t1043 82ef  M3A78-EH Motherboard\n\t\t1043 8443  M5A88-V EVO\n\t\t1043 84dd  M5A99X EVO (R1.0) SB950\n\t\t105b 0e13  N15235/A74MX mainboard / AMD SB700\n\t\t174b 1001  PURE Fusion Mini\n\t4392  SB7x0/SB8x0/SB9x0 SATA Controller [Non-RAID5 mode]\n\t\t105b 0e13  N15235/A74MX mainboard / AMD SB700\n\t4393  SB7x0/SB8x0/SB9x0 SATA Controller [RAID5 mode]\n\t4394  SB7x0/SB8x0/SB9x0 SATA Controller [AHCI mode]\n\t4395  SB8x0/SB9x0 SATA Controller [Storage mode]\n\t4396  SB7x0/SB8x0/SB9x0 USB EHCI Controller\n\t\t1019 2120  A785GM-M\n\t\t103c 1611  Pavilion DM1Z-3000\n\t\t1043 82ef  M3A78-EH Motherboard\n\t\t1043 8443  M5A88-V EVO\n\t\t105b 0e13  N15235/A74MX mainboard / AMD SB700\n\t\t15d9 a811  H8DGU\n\t\t174b 1001  PURE Fusion Mini\n\t4397  SB7x0/SB8x0/SB9x0 USB OHCI0 Controller\n\t\t1019 2120  A785GM-M\n\t\t103c 1611  Pavilion DM1Z-3000\n\t\t1043 82ef  M3A78-EH Motherboard\n\t\t1043 8443  M5A88-V EVO\n\t\t105b 0e13  N15235/A74MX mainboard / AMD SB700\n\t\t15d9 a811  H8DGU\n\t\t174b 1001  PURE Fusion Mini\n\t4398  SB7x0 USB OHCI1 Controller\n\t\t1019 2120  A785GM-M\n\t\t1043 82ef  M3A78-EH Motherboard\n\t\t105b 0e13  N15235/A74MX mainboard / AMD SB700\n\t\t15d9 a811  H8DGU\n\t4399  SB7x0/SB8x0/SB9x0 USB OHCI2 Controller\n\t\t1019 2120  A785GM-M\n\t\t1043 82ef  M3A78-EH Motherboard\n\t\t1043 8443  M5A88-V EVO\n\t\t105b 0e13  N15235/A74MX mainboard / AMD SB700\n\t\t174b 1001  PURE Fusion Mini\n\t439c  SB7x0/SB8x0/SB9x0 IDE Controller\n\t\t1002 4392  MSI MS-7713 motherboard\n\t\t1019 2120  A785GM-M\n\t\t1043 82ef  M3A78-EH Motherboard\n\t\t105b 0e13  N15235/A74MX mainboard / AMD SB700\n\t439d  SB7x0/SB8x0/SB9x0 LPC host controller\n\t\t1019 2120  A785GM-M\n\t\t103c 1611  Pavilion DM1Z-3000\n\t\t1043 82ef  M3A78-EH Motherboard\n\t\t1043 8443  M5A88-V EVO\n\t\t105b 0e13  N15235/A74MX mainboard / AMD SB700\n\t\t174b 1001  PURE Fusion Mini\n\t43a0  SB700/SB800/SB900 PCI to PCI bridge (PCIE port 0)\n\t43a1  SB700/SB800/SB900 PCI to PCI bridge (PCIE port 1)\n\t43a2  SB900 PCI to PCI bridge (PCIE port 2)\n\t43a3  SB900 PCI to PCI bridge (PCIE port 3)\n\t4437  RS250 [Mobility Radeon 7000 IGP]\n\t4554  210888ET [Mach64 ET]\n\t4630  XENOS Parent Die (XBOX 360)\n\t4631  XENOS Daughter Die (XBOX 360)\n\t4654  Mach64 VT\n\t4742  Rage 3 [3D Rage PRO AGP 2X]\n\t\t1002 0040  Rage Pro Turbo AGP 2X\n\t\t1002 0044  Rage Pro Turbo AGP 2X\n\t\t1002 0061  Rage Pro AIW AGP 2X\n\t\t1002 0062  Rage Pro AIW AGP 2X\n\t\t1002 0063  Rage Pro AIW AGP 2X\n\t\t1002 0080  Rage Pro Turbo AGP 2X\n\t\t1002 0084  Rage Pro Turbo AGP 2X\n\t\t1002 4742  Rage Pro Turbo AGP 2X\n\t\t1002 8001  Rage Pro Turbo AGP 2X\n\t\t1028 0082  Rage Pro Turbo AGP 2X\n\t\t1028 4082  Optiplex GX1 Onboard Display Adapter\n\t\t1028 8082  Rage Pro Turbo AGP 2X\n\t\t1028 c082  Rage Pro Turbo AGP 2X\n\t\t8086 4152  Xpert 98D AGP 2X\n\t\t8086 464a  Rage Pro Turbo AGP 2X\n\t4744  Rage 3 [3D Rage PRO AGP 1X]\n\t\t1002 4744  Rage Pro Turbo AGP\n\t\t8086 4d55  Rage 3D Pro AGP 1X [Intel MU440EX]\n\t4749  3D Rage PRO PCI\n\t\t1002 0061  Rage Pro AIW\n\t\t1002 0062  Rage Pro AIW\n\t474d  Rage XL AGP 2X\n\t\t1002 0004  Xpert 98 RXL AGP 2X\n\t\t1002 0008  Xpert 98 RXL AGP 2X\n\t\t1002 0080  Rage XL AGP 2X\n\t\t1002 0084  Xpert 98 AGP 2X\n\t\t1002 474d  Rage XL AGP\n\t\t1033 806a  Rage XL AGP\n\t474e  Rage XC AGP\n\t\t1002 474e  Rage XC AGP\n\t474f  Rage XL\n\t\t1002 0008  Rage XL\n\t\t1002 474f  Rage XL\n\t4750  3D Rage Pro PCI\n\t\t1002 0040  Rage Pro Turbo\n\t\t1002 0044  Rage Pro Turbo\n\t\t1002 0080  Rage Pro Turbo\n\t\t1002 0084  Rage Pro Turbo\n\t\t1002 4750  Rage Pro Turbo\n\t4752  Rage 3 [Rage XL PCI]\n\t\t0e11 001e  Proliant Rage XL\n\t\t1002 0008  Rage XL\n\t\t1002 4752  Proliant Rage XL\n\t\t1002 8008  Rage XL\n\t\t1014 0240  eServer xSeries server mainboard\n\t\t1028 00ce  PowerEdge 1400\n\t\t1028 00d1  PowerEdge 2550\n\t\t1028 00d9  PowerEdge 2500\n\t\t1028 0134  PowerEdge 600SC\n\t\t1028 014a  PowerEdge 1750\n\t\t1028 0165  PowerEdge 750\n\t\t103c 10e1  NetServer Rage XL\n\t\t103c 3208  ProLiant DL140 G2\n\t\t107b 6400  6400 Server\n\t\t1734 007a  PRIMERGY RX/TX series onboard VGA\n\t\t1734 1073  Primergy Econel 200 D2020 mainboard\n\t\t8086 3411  SDS2 Mainboard\n\t\t8086 3427  S875WP1-E mainboard\n\t\t8086 5744  S845WD1-E mainboard\n\t4753  Rage XC\n\t\t1002 4753  Rage XC\n\t4754  Mach64 GT/GT-B [3D Rage I/II]\n\t4755  Mach64 GT-B [3D Rage II+ DVD]\n\t4756  Rage 2 [3D Rage IIC PCI]\n\t\t1002 4756  Rage IIC\n\t4757  Rage 2 [3D Rage IIC AGP]\n\t\t1002 4757  Rage IIC AGP\n\t\t1028 0089  Rage 3D IIC\n\t\t1028 008e  PowerEdge 1300 onboard video\n\t\t1028 4082  Rage 3D IIC\n\t\t1028 8082  Rage 3D IIC\n\t\t1028 c082  Rage 3D IIC\n\t4758  Mach64 GX [WinTurbo]\n\t4759  Rage 3 [3D Rage IIC PCI]\n\t475a  3D Rage IIC AGP\n\t\t1002 0084  Rage 3D Pro AGP 2x XPERT 98\n\t\t1002 0087  Rage 3D IIC\n\t\t1002 475a  Rage IIC AGP\n\t4845  Xilleon 220 HBIU for HDTV2\n\t4846  Xilleon 220 IDE for HDTV2\n\t4847  Xilleon 220 USB for HDTV2\n\t4848  Xilleon 220 DAIO-0 for HDTV2\n\t4849  Xilleon 220 DAIO-1 for HDTV2\n\t484a  Xilleon 220 LPC for HDTV2\n\t4850  Xilleon 215 HBIU for X215\n\t4851  Xilleon 215 IDE for X215\n\t4852  Xilleon 215 USB for X215\n\t4853  Xilleon 215 DAIO-0 for X215\n\t4854  Xilleon 215 DAIO-1 for X215\n\t4855  Xilleon 225 HBIU for X225\n\t4856  Xilleon 225 IDE for X225\n\t4857  Xilleon 225 USB for X225\n\t4858  Xilleon 225 DAIO-0 for X225\n\t4859  Xilleon 225 DAIO-1 for X225\n\t4860  Xilleon 210 HBIU for X210\n\t4861  Xilleon 210 IDE for X210\n\t4862  Xilleon 210 USB for X210\n\t4863  Xilleon 210 DAIO-0 for X210\n\t4864  Xilleon 210 DAIO-1 for X210\n\t4865  Xilleon 226 HBIU for X226\n\t4866  Xilleon 226 IDE for X226\n\t4867  Xilleon 226 USB for X226\n\t4868  Xilleon 226 DAIO-0 for X226\n\t4869  Xilleon 226 DAIO-1 for X226\n\t486a  Xilleon 240S HBIU for X240S\n\t486b  Xilleon 240H HBIU for X240H\n\t486c  Xilleon 240S USB for X240S\n\t486d  Xilleon 240H USB for X240H\n\t486e  Xilleon 250 USB 1.1 for X250\n\t486f  Xilleon 260 USB 1.1 for X260\n\t4870  Xilleon 250 HBIU for X250\n\t4871  Xilleon 250 IDE for X250\n\t4872  Xilleon 234/235 HBIU for X234/X235\n\t4873  Xilleon 244/245 HBIU for X244/X245\n\t4874  Xilleon 234/235 USB 1.1 for X234/X235\n\t4875  Xilleon 260 HBIU for X260\n\t4876  Xilleon 260 IDE for X260\n\t4877  Xilleon 244/245 USB 1.1 for X244/X245\n\t4878  Xilleon 270 HBIU for X270\n\t487b  Xilleon 242 HBIU for X242\n\t487d  Xilleon 242 USB 1.1 for X242\n\t4880  Xilleon 254 HBIU for X254\n\t4881  Xilleon 254 USB 1.1 for X254\n\t4882  Xilleon 255 HBIU for X255\n\t4883  Xilleon 255 USB 1.1 for X255\n\t4884  Xilleon 243 HBIU for X243\n\t4885  Xilleon 243 USB 1.1 for X243\n\t4886  Xilleon 233 HBIU for X233\n\t4887  Xilleon 233 USB 1.1 for X233\n\t4888  Xilleon 143 HBIU for X143\n\t4889  Xilleon 143 HBIU for X143L\n\t488a  Xilleon 143 HBIU for X143S\n\t4966  RV250 [Radeon 9000 Series]\n\t\t10f1 0002  RV250 If [Tachyon G9000 PRO]\n\t\t148c 2039  RV250 If [Radeon 9000 Pro \"Evil Commando\"]\n\t\t1509 9a00  RV250 If [Radeon 9000 \"AT009\"]\n\t\t1681 0040  RV250 If [3D prophet 9000]\n\t\t174b 7176  Radeon 9000 Pro\n\t\t174b 7192  RV250 If [Radeon 9000 \"Atlantis\"]\n\t\t17af 2005  RV250 If [Excalibur Radeon 9000 Pro]\n\t\t17af 2006  RV250 If [Excalibur Radeon 9000]\n\t496e  RV250 [Radeon 9000] (Secondary)\n\t4a49  R420 [Radeon X800 PRO/GTO AGP]\n\t\t174b 2620  R420 [Radeon X800 GTO AGP]\n\t4a4a  R420 [Radeon X800 GT AGP]\n\t4a4b  R420 [Radeon X800 AGP Series]\n\t4a4d  R420 GL [FireGL X3-256]\n\t4a4e  RV420/M18 [Mobility Radeon 9800]\n\t4a4f  R420 [Radeon X850 AGP]\n\t4a50  R420 [Radeon X800 XT Platinum Edition AGP]\n\t4a54  R420 [Radeon X800 VE AGP]\n\t\t1002 4422  All-In-Wonder X800 VE AGP\n\t4a69  R420 [Radeon X800 PRO/GTO] (Secondary)\n\t4a6a  R420 [Radeon X800] (Secondary)\n\t4a6b  R420 [Radeon X800 XT AGP] (Secondary)\n\t4a70  R420 [Radeon X800 XT Platinum Edition AGP] (Secondary)\n\t4a74  R420 [Radeon X800 VE] (Secondary)\n\t4b49  R481 [Radeon X850 XT AGP]\n\t4b4b  R481 [Radeon X850 PRO AGP]\n\t4b4c  R481 [Radeon X850 XT Platinum Edition AGP]\n\t4b69  R481 [Radeon X850 XT AGP] (Secondary)\n\t4b6b  R481 [Radeon X850 PRO AGP] (Secondary)\n\t4b6c  R481 [Radeon X850 XT Platinum Edition AGP] (Secondary)\n\t4c42  Mach64 LT [3D Rage LT PRO AGP]\n\t\t0e11 b0e7  Rage LT Pro (Compaq Presario 5240)\n\t\t0e11 b0e8  Rage 3D LT Pro\n\t\t0e11 b10e  3D Rage LT Pro (Compaq Armada 1750)\n\t\t1002 0040  Rage LT Pro AGP 2X\n\t\t1002 0044  Rage LT Pro AGP 2X\n\t\t1002 4c42  Rage LT Pro AGP 2X\n\t\t1002 8001  Rage LT Pro AGP 2X\n\t\t1028 0085  Rage 3D LT Pro\n\t4c46  Rage Mobility 128 AGP 2X/Mobility M3\n\t\t1002 0155  IBM Thinkpad A22p\n\t\t1014 0155  Thinkpad A22p\n\t\t1028 00b1  Latitude C600\n\t4c47  3D Rage IIC PCI / Mobility Radeon 7500/7500C\n\t4c49  3D Rage LT PRO PCI\n\t\t1002 0004  Rage LT Pro\n\t\t1002 0040  Rage LT Pro\n\t\t1002 0044  Rage LT Pro\n\t\t1002 4c49  Rage LT Pro\n\t4c4d  Rage Mobility AGP 2x Series\n\t\t0e11 b111  Armada M700\n\t\t0e11 b160  Armada E500\n\t\t1002 0084  Xpert 98 AGP 2X (Mobility)\n\t\t1014 0154  ThinkPad A20m/A21m\n\t\t1028 00aa  Latitude CPt\n\t\t1028 00bb  Latitude CPx\n\t\t1179 ff00  Satellite 1715XCDS laptop\n\t\t13bd 1019  PC-AR10\n\t4c50  Rage 3 LT [3D Rage LT PRO PCI]\n\t\t1002 4c50  Rage LT Pro\n\t4c52  M1 [Rage Mobility-M1 PCI]\n\t\t1033 8112  Versa Note VXi\n\t4c54  264LT [Mach64 LT]\n\t4c57  RV200/M7 [Mobility Radeon 7500]\n\t\t1014 0517  ThinkPad T30\n\t\t1014 0530  ThinkPad T4x Series\n\t\t1028 00e6  Radeon Mobility M7 LW (Dell Inspiron 8100)\n\t\t1028 012a  Latitude C640\n\t\t1043 1622  Mobility Radeon M7 (L3C/S)\n\t\t144d c006  Radeon Mobility M7 LW in vpr Matrix 170B4\n\t4c58  RV200/M7 GL [Mobility FireGL 7800]\n\t4c59  RV100/M6 [Rage/Radeon Mobility Series]\n\t\t0e11 b111  Evo N600c\n\t\t1014 0235  ThinkPad A30/A30p (2652/2653)\n\t\t1014 0239  ThinkPad X22/X23/X24\n\t\t103c 0025  XE4500 Notebook\n\t\t104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP\n\t\t104d 8140  PCG-Z1SP laptop\n\t\t1509 1930  Medion MD9703\n\t4c66  RV250/M9 GL [Mobility FireGL 9000/Radeon 9000]\n\t\t1014 054d  ThinkPad T41\n\t4c6e  RV250/M9 [Mobility Radeon 9000] (Secondary)\n\t4d46  Rage Mobility 128 AGP 4X/Mobility M4\n\t4d52  Theater 550 PRO PCI [ATI TV Wonder 550]\n\t4d53  Theater 550 PRO PCIe\n\t4e44  R300 [Radeon 9700/9700 PRO]\n\t\t1002 515e  Radeon ES1000\n\t\t1002 5965  Radeon ES1000\n\t4e45  R300 [Radeon 9500 PRO/9700]\n\t\t1002 0002  Radeon R300 NE [Radeon 9500 Pro]\n\t\t1681 0002  Hercules 3D Prophet 9500 PRO [Radeon 9500 Pro]\n\t4e46  R300 [Radeon 9600 TX]\n\t4e47  R300 GL [FireGL X1]\n\t4e48  R350 [Radeon 9800 Series]\n\t4e49  R350 [Radeon 9800]\n\t4e4a  R360 [Radeon 9800 XXL/XT]\n\t\t1002 4e4a  R360 [Radeon 9800 XT]\n\t4e4b  R350 GL [FireGL X2 AGP Pro]\n\t4e50  RV350/M10 / RV360/M11 [Mobility Radeon 9600 (PRO) / 9700]\n\t\t1025 005a  TravelMate 290\n\t\t1025 0064  Extensa 3000 series laptop: ATI RV360/M11 [Mobility Radeon 9700]\n\t\t103c 088c  NC8000 laptop\n\t\t103c 0890  NC6000 laptop\n\t\t144d c00c  P35 notebook\n\t\t1462 0311  MSI M510A\n\t\t1734 1055  Amilo M1420W\n\t4e51  RV350 [Radeon 9550/9600/X1050 Series]\n\t4e52  RV350/M10 [Mobility Radeon 9500/9700 SE]\n\t\t144d c00c  P35 notebook\n\t4e54  RV350/M10 GL [Mobility FireGL T2]\n\t4e56  RV360/M12 [Mobility Radeon 9550]\n\t4e64  R300 [Radeon 9700 PRO] (Secondary)\n\t4e65  R300 [Radeon 9500 PRO] (Secondary)\n\t\t1002 0003  Radeon R300 NE [Radeon 9500 Pro]\n\t\t1681 0003  Hercules 3D Prophet 9500 PRO [Radeon 9500 Pro] (Secondary)\n\t4e66  RV350 [Radeon 9600] (Secondary)\n\t4e67  R300 GL [FireGL X1] (Secondary)\n\t4e68  R350 [Radeon 9800 PRO] (Secondary)\n\t4e69  R350 [Radeon 9800] (Secondary)\n\t4e6a  RV350 [Radeon 9800 XT] (Secondary)\n\t\t1002 4e6a  R360 [Radeon 9800 XT] (Secondary)\n\t\t1002 4e71  M10 NQ [Radeon Mobility 9600]\n\t4e71  RV350/M10 [Mobility Radeon 9600] (Secondary)\n\t4f72  RV250 [Radeon 9000 Series]\n\t4f73  RV250 [Radeon 9000 Series] (Secondary)\n\t5044  All-In-Wonder 128 PCI\n\t\t1002 0028  Rage 128 AIW\n\t\t1002 0029  Rage 128 AIW\n\t5046  Rage 4 [Rage 128 PRO AGP 4X TMDS]\n\t\t1002 0004  Rage Fury Pro\n\t\t1002 0008  Rage Fury Pro/Xpert 2000 Pro\n\t\t1002 0014  Rage Fury Pro\n\t\t1002 0018  Rage Fury Pro/Xpert 2000 Pro\n\t\t1002 0028  Rage 128 Pro AIW AGP\n\t\t1002 002a  Rage 128 Pro AIW AGP\n\t\t1002 0048  Rage Fury Pro\n\t\t1002 2000  Rage Fury MAXX AGP 4x (TMDS) (VGA device)\n\t\t1002 2001  Rage Fury MAXX AGP 4x (TMDS) (Extra device?!)\n\t5050  Rage128 [Xpert 128 PCI]\n\t\t1002 0008  Xpert 128\n\t5052  Rage 128 PRO AGP 4X TMDS\n\t5144  R100 [Radeon 7200 / All-In-Wonder Radeon]\n\t\t1002 0008  Radeon 7000/Radeon VE\n\t\t1002 0009  Radeon 7000/Radeon\n\t\t1002 000a  Radeon 7000/Radeon\n\t\t1002 001a  Radeon 7000/Radeon\n\t\t1002 0029  Radeon AIW\n\t\t1002 0038  Radeon 7000/Radeon\n\t\t1002 0039  Radeon 7000/Radeon\n\t\t1002 008a  Radeon 7000/Radeon\n\t\t1002 00ba  Radeon 7000/Radeon\n\t\t1002 0139  Radeon 7000/Radeon\n\t\t1002 028a  Radeon 7000/Radeon\n\t\t1002 02aa  Radeon AIW\n\t\t1002 053a  Radeon 7000/Radeon\n\t5148  R200 GL [FireGL 8800]\n\t\t1002 010a  FireGL 8800 64Mb\n\t\t1002 0152  FireGL 8800 128Mb\n\t\t1002 0162  FireGL 8700 32Mb\n\t\t1002 0172  FireGL 8700 64Mb\n\t514c  R200 [Radeon 8500/8500 LE]\n\t\t1002 003a  Radeon R200 QL [Radeon 8500 LE]\n\t\t1002 013a  Radeon 8500\n\t\t148c 2026  R200 QL [Radeon 8500 Evil Master II Multi Display Edition]\n\t\t1681 0010  Radeon 8500 [3D Prophet 8500 128Mb]\n\t\t174b 7149  Radeon 8500 LE\n\t\t1787 0f08  Radeon R200 QL [PowerMagic Radeon 8500]\n\t514d  R200 [Radeon 9100]\n\t5157  RV200 [Radeon 7500/7500 LE]\n\t\t1002 013a  Radeon 7500\n\t\t1002 0f2b  ALL-IN-WONDER VE PCI\n\t\t1002 103a  Dell Optiplex GX260\n\t\t1458 4000  RV200 QW [RADEON 7500 PRO MAYA AR]\n\t\t148c 2024  RV200 QW [Radeon 7500LE Dual Display]\n\t\t148c 2025  RV200 QW [Radeon 7500 Evil Master Multi Display Edition]\n\t\t148c 2036  RV200 QW [Radeon 7500 PCI Dual Display]\n\t\t174b 7146  RV200 QW [Radeon 7500 LE]\n\t\t174b 7147  Radeon 7500 LE\n\t\t174b 7161  Radeon RV200 QW [Radeon 7500 LE]\n\t\t17af 0202  RV200 QW [Excalibur Radeon 7500LE]\n\t5159  RV100 [Radeon 7000 / Radeon VE]\n\t\t1002 000a  Radeon 7000/Radeon VE\n\t\t1002 000b  Radeon 7000\n\t\t1002 0038  Radeon 7000/Radeon VE\n\t\t1002 003a  Radeon 7000/Radeon VE\n\t\t1002 00ba  Radeon 7000/Radeon VE\n\t\t1002 013a  Radeon 7000/Radeon VE\n\t\t1002 0908  XVR-100 (supplied by Sun)\n# The IBM card doubles as an ATI PCI video adapter\n\t\t1014 029a  Remote Supervisor Adapter II (RSA2)\n\t\t1014 02c8  eServer xSeries server mainboard\n\t\t1028 016c  PowerEdge 1850 Embedded Radeon 7000/VE\n\t\t1028 016d  PowerEdge 2850 Embedded Radeon 7000-M\n\t\t1028 0170  PowerEdge 6850 Embedded Radeon 7000/VE\n\t\t1028 019a  PowerEdge SC1425\n\t\t103c 1292  Radeon 7000\n\t\t1043 c00a  A7000/T/64M\n\t\t1458 4002  RV100 QY [RADEON 7000 PRO MAYA AV Series]\n\t\t148c 2003  RV100 QY [Radeon 7000 Multi-Display Edition]\n\t\t148c 2023  RV100 QY [Radeon 7000 Evil Master Multi-Display]\n\t\t148c 2081  RV6DE\n\t\t174b 0280  Radeon RV100 QY [Radeon 7000/VE]\n\t\t174b 7112  Radeon VE 7000\n\t\t174b 7c28  Radeon VE 7000 DDR\n\t\t1787 0202  RV100 QY [Excalibur Radeon 7000]\n\t\t17ee 1001  Radeon 7000 64MB DDR + DVI\n\t515e  ES1000\n\t\t1028 01bb  PowerEdge 1955 Embedded ATI ES1000\n\t\t1028 01df  PowerEdge SC440\n\t\t1028 01e6  PowerEdge 860\n\t\t1028 01f0  PowerEdge R900 Embedded ATI ES1000\n\t\t1028 0205  PowerEdge 2970 Embedded ATI ES1000\n\t\t1028 020b  PowerEdge T605 Embedded ATI ES1000\n\t\t1028 020f  PowerEdge R300 Embedded ATI ES1000\n\t\t1028 0210  PowerEdge T300 Embedded ATI ES1000\n\t\t1028 0221  PowerEdge R805 Embedded ATI ES1000\n\t\t1028 0223  PowerEdge R905 Embedded ATI ES1000\n\t\t1028 0225  PowerEdge T105 Embedded ATI ES1000\n\t\t1028 023c  PowerEdge R200 Embedded ATI ES1000\n\t\t103c 1304  Integrity iLO2 Advanced KVM VGA [AD307A]\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t5245  Rage 128 GL PCI\n\t\t1002 0008  Xpert 128\n\t\t1002 0028  Rage 128 AIW\n\t\t1002 0029  Rage 128 AIW\n\t\t1002 0068  Rage 128 AIW\n\t5246  Rage 128 (Rage 4) series\n\t\t1002 0004  Magnum/Xpert 128/Xpert 99\n\t\t1002 0008  Rage 128 AGP 2x\n\t\t1002 0028  Rage 128 AIW AGP\n\t\t1002 0044  Rage Fury/Xpert 128/Xpert 2000\n\t\t1002 0068  Rage 128 AIW AGP\n\t\t1002 0448  Rage Fury\n\t524b  Rage 128 VR PCI\n\t524c  Rage 128 VR AGP\n\t\t1002 0008  Xpert 99/Xpert 2000\n\t\t1002 0088  Xpert 99\n\t5346  Rage 128 SF/4x AGP 2x\n\t\t1002 0048  RAGE 128 16MB VGA TVOUT AMC PAL\n\t534d  Rage 128 4X AGP 4x\n\t\t1002 0008  Xpert 99/Xpert 2000\n\t\t1002 0018  Xpert 2000\n\t5354  Mach 64 VT\n\t\t1002 5654  Mach 64 reference\n\t5446  Rage 128 PRO Ultra AGP 4x\n\t\t1002 0004  Rage Fury Pro\n\t\t1002 0008  Rage Fury Pro/Xpert 2000 Pro\n\t\t1002 0018  Rage Fury Pro/Xpert 2000 Pro\n\t\t1002 0028  Rage 128 AIW Pro AGP\n\t\t1002 0029  Rage 128 AIW\n\t\t1002 002a  Rage 128 AIW Pro AGP\n\t\t1002 002b  Rage 128 AIW\n\t\t1002 0048  Xpert 2000 Pro\n\t5452  Rage 128 PRO Ultra4XL VR-R AGP\n\t\t1002 001c  Rage 128 Pro 4XL\n\t\t103c 1279  Rage 128 Pro 4XL\n\t5460  RV370/M22 [Mobility Radeon X300]\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t5461  RV370/M22 [Mobility Radeon X300]\n\t5462  RV380/M24C [Mobility Radeon X600 SE]\n\t5464  RV370/M22 GL [Mobility FireGL V3100]\n\t5549  R423 [Radeon X800 GTO]\n\t554a  R423 [Radeon X800 XT Platinum Edition]\n\t554b  R423 [Radeon X800 GT/SE]\n\t\t1002 0302  Radeon X800 SE\n\t554d  R430 [Radeon X800 XL]\n\t\t1002 0322  All-In-Wonder X800 XL\n\t\t1458 2124  GV-R80L256V-B (AGP)\n\t554e  R430 [All-In-Wonder X800 GT]\n\t554f  R430 [Radeon X800]\n\t5550  R423 GL [FireGL V7100]\n\t5551  R423 GL [FireGL V5100]\n\t5569  R423 [Radeon X800 PRO] (Secondary)\n\t556b  R423 [Radeon X800 GT] (Secondary)\n\t556d  R430 [Radeon X800 XL] (Secondary)\n\t\t1458 2125  GV-R80L256V-B (AGP)\n\t556f  R430 [Radeon X800] (Secondary)\n\t5571  R423 GL [FireGL V5100] (Secondary)\n\t564b  RV410/M26 GL [Mobility FireGL V5000]\n\t564f  RV410/M26 [Mobility Radeon X700 XL]\n\t5652  RV410/M26 [Mobility Radeon X700]\n\t5653  RV410/M26 [Mobility Radeon X700]\n\t\t1025 0080  Aspire 5024WLMi\n\t\t103c 0940  Compaq NW8240 Mobile Workstation\n\t5654  Mach64 VT [Video Xpression]\n\t\t1002 5654  Mach64VT Reference\n\t5655  264VT3 [Mach64 VT3]\n\t5656  Mach64 VT4 [Video Xpression+]\n\t5657  RV410 [Radeon X550 XTX / X700]\n\t5830  RS300 Host Bridge\n\t5831  RS300 Host Bridge\n\t5832  RS300 Host Bridge\n\t5833  RS300 Host Bridge\n\t5834  RS300 [Radeon 9100 IGP]\n\t5835  RS300M [Mobility Radeon 9100 IGP]\n\t5838  RS300 AGP Bridge\n\t5854  RS480 [Radeon Xpress 200 Series] (Secondary)\n\t5874  RS480 [Radeon Xpress 1150] (Secondary)\n\t5940  RV280 [Radeon 9200 PRO] (Secondary)\n\t\t17af 2021  Excalibur Radeon 9250 (Secondary)\n\t5941  RV280 [Radeon 9200] (Secondary)\n\t\t1458 4019  Radeon 9200\n\t\t174b 7c12  Radeon 9200\n\t\t17af 200d  Excalibur Radeon 9200\n\t\t18bc 0050  GC-R9200-C3 (Secondary)\n\t5944  RV280 [Radeon 9200 SE PCI]\n\t5950  RS480/RS482/RS485 Host Bridge\n\t\t1025 0080  Aspire 5024WLMMi\n\t\t103c 280a  DC5750 Microtower\n\t\t103c 2a20  Pavilion t3030.de Desktop PC\n\t\t103c 308b  MX6125\n\t\t1462 0131  MS-1013 Notebook\n\t\t1462 7217  Aspire L250\n\t5951  RX480/RX482 Host Bridge\n\t5952  RD580 Host Bridge\n\t5954  RS480 [Radeon Xpress 200 Series]\n\t\t1002 5954  RV370 [Radeon Xpress 200G Series]\n\t5955  RS480M [Mobility Radeon Xpress 200]\n\t\t1002 5955  RS480 0x5955 [Radeon XPRESS 200M 5955 (PCIE)]\n\t\t103c 308b  MX6125\n\t\t1462 0131  MS-1013 Notebook\n\t5956  RD790 Host Bridge\n\t5957  RX780/RX790 Host Bridge\n\t\t1849 5957  A770CrossFire Motherboard\n\t5958  RD780 Host Bridge\n\t5960  RV280 [Radeon 9200 PRO]\n\t\t17af 2020  Excalibur Radeon 9250\n\t5961  RV280 [Radeon 9200]\n\t\t1002 2f72  All-in-Wonder 9200 Series\n\t\t1019 4c30  Radeon 9200 VIVO\n\t\t12ab 5961  YUAN SMARTVGA Radeon 9200\n\t\t1458 4018  Radeon 9200\n\t\t174b 7c13  Radeon 9200\n\t\t17af 200c  Excalibur Radeon 9200\n\t\t18bc 0050  Radeon 9200 Game Buster\n\t\t18bc 0051  GC-R9200-C3\n\t\t18bc 0053  Radeon 9200 Game Buster VIVO\n\t5962  RV280 [Radeon 9200]\n\t5964  RV280 [Radeon 9200 SE]\n\t\t1002 5964  Radeon 9200 SE, 64-bit 128MB DDR, 200/166MHz\n\t\t1043 c006  Radeon 9200 SE / TD / 128M\n\t\t1458 4018  Radeon 9200 SE\n\t\t1458 4032  Radeon 9200 SE 128MB\n\t\t147b 6191  R9200SE-DT\n\t\t148c 2073  CN-AG92E\n\t\t174b 7c13  Radeon 9200 SE\n\t\t1787 5964  Excalibur 9200SE VIVO 128M\n\t\t17af 2012  Radeon 9200 SE Excalibur\n\t\t18bc 0170  Sapphire Radeon 9200 SE 128MB Game Buster\n\t\t18bc 0173  GC-R9200L(SE)-C3H [Radeon 9200 Game Buster]\n\t5965  RV280 GL [FireMV 2200 PCI]\n\t5974  RS482/RS485 [Radeon Xpress 1100/1150]\n\t\t103c 280a  DC5750 Microtower\n\t\t1462 7141  Aspire L250\n\t5975  RS482M [Mobility Radeon Xpress 200]\n\t5978  RX780/RD790 PCI to PCI bridge (external gfx0 port A)\n\t\t1849 5957  A770CrossFire Motherboard\n\t5979  RD790 PCI to PCI bridge (external gfx0 port B)\n\t597a  RD790 PCI to PCI bridge (PCI express gpp port A)\n\t597b  RX780/RD790 PCI to PCI bridge (PCI express gpp port B)\n\t597c  RD790 PCI to PCI bridge (PCI express gpp port C)\n\t597d  RX780/RD790 PCI to PCI bridge (PCI express gpp port D)\n\t597e  RD790 PCI to PCI bridge (PCI express gpp port E)\n\t\t1849 5957  A770CrossFire Motherboard\n\t597f  RD790 PCI to PCI bridge (PCI express gpp port F)\n\t\t1849 5957  A770CrossFire Motherboard\n\t5980  RD790 PCI to PCI bridge (external gfx1 port A)\n\t5981  RD790 PCI to PCI bridge (external gfx1 port B)\n\t5982  RD790 PCI to PCI bridge (NB-SB link)\n\t5a10  RD890 Northbridge only dual slot (2x16) PCI-e GFX Hydra part\n\t5a11  RD890 Northbridge only single slot PCI-e GFX Hydra part\n\t5a12  RD890 Northbridge only dual slot (2x8) PCI-e GFX Hydra part\n\t\t15d9 a811  H8DGU\n\t5a13  RD890S/SR5650 Host Bridge\n\t5a14  RD9x0/RX980 Host Bridge\n\t5a15  RD890 PCI to PCI bridge (PCI express gpp port A)\n\t5a16  RD890/RD9x0/RX980 PCI to PCI bridge (PCI Express GFX port 0)\n\t5a17  RD890/RD9x0 PCI to PCI bridge (PCI Express GFX port 1)\n\t5a18  RD890/RD9x0/RX980 PCI to PCI bridge (PCI Express GPP Port 0)\n\t\t15d9 a811  H8DGU\n\t5a19  RD890/RD9x0/RX980 PCI to PCI bridge (PCI Express GPP Port 1)\n\t5a1a  RD890/RD9x0/RX980 PCI to PCI bridge (PCI Express GPP Port 2)\n\t5a1b  RD890/RD9x0/RX980 PCI to PCI bridge (PCI Express GPP Port 3)\n\t5a1c  RD890/RD9x0/RX980 PCI to PCI bridge (PCI Express GPP Port 4)\n\t5a1d  RD890/RD9x0/RX980 PCI to PCI bridge (PCI Express GPP Port 5)\n\t5a1e  RD890/RD9x0/RX980 PCI to PCI bridge (PCI Express GPP2 Port 0)\n\t5a1f  RD890/RD990 PCI to PCI bridge (PCI Express GFX2 port 0)\n\t\t15d9 a811  H8DGU\n\t5a20  RD890/RD990 PCI to PCI bridge (PCI Express GFX2 port 1)\n\t5a23  RD890S/RD990 I/O Memory Management Unit (IOMMU)\n\t5a31  RC410 Host Bridge\n\t5a33  RS400 Host Bridge\n\t5a34  RS4xx PCI Express Port [ext gfx]\n\t5a36  RC4xx/RS4xx PCI Express Port 1\n\t5a37  RC4xx/RS4xx PCI Express Port 2\n\t5a38  RC4xx/RS4xx PCI Express Port 3\n\t5a39  RC4xx/RS4xx PCI Express Port 4\n\t5a3f  RC4xx/RS4xx PCI Bridge [int gfx]\n\t\t1462 7217  Aspire L250\n\t5a41  RS400 [Radeon Xpress 200]\n\t5a42  RS400M [Radeon Xpress 200M]\n\t5a61  RC410 [Radeon Xpress 200/1100]\n\t5a62  RC410M [Mobility Radeon Xpress 200M]\n\t5b60  RV370 [Radeon X300]\n\t\t1043 002a  Extreme AX300SE-X\n\t\t1043 032e  Extreme AX300/TD\n\t\t1458 2102  GV-RX30S128D (X300SE)\n\t\t1462 0400  RX300SE-TD128E (MS-8940 REV:200)\n\t\t1462 0402  RX300SE-TD128E (MS-8940)\n\t\t174b 0500  Radeon X300 (PCIE)\n\t\t196d 1086  X300SE HM\n\t5b62  RV370 [Radeon X600/X600 SE]\n\t5b63  RV370 [Radeon X300/X550/X1050 Series]\n\t5b64  RV370 GL [FireGL V3100]\n\t5b65  RV370 GL [FireMV 2200]\n\t5b66  RV370X\n\t5b70  RV370 [Radeon X300 SE]\n# RX300SE-TD128E\n\t\t1462 0403  Radeon X300 SE 128MB DDR\n\t\t174b 0501  Radeon X300 SE\n\t\t196d 1087  Radeon X300 SE HyperMemory\n\t5b72  RV380 [Radeon X300/X550/X1050 Series] (Secondary)\n\t5b73  RV370 [Radeon X300/X550/X1050 Series] (Secondary)\n\t5b74  RV370 GL [FireGL V3100] (Secondary)\n\t5b75  RV370 GL [FireMV 2200] (Secondary)\n\t5c61  RV280/M9+ [Mobility Radeon 9200 AGP]\n\t5c63  RV280/M9+ [Mobility Radeon 9200 AGP]\n\t\t1002 5c63  Apple iBook G4 2004\n\t\t144d c00c  P30 notebook\n\t5d44  RV280 [Radeon 9200 SE] (Secondary)\n\t\t1458 4019  Radeon 9200 SE (Secondary)\n\t\t1458 4032  Radeon 9200 SE 128MB\n\t\t147b 6190  R9200SE-DT (Secondary)\n\t\t174b 7c12  Radeon 9200 SE (Secondary)\n\t\t1787 5965  Excalibur 9200SE VIVO 128M (Secondary)\n\t\t17af 2013  Radeon 9200 SE Excalibur (Secondary)\n\t\t18bc 0171  Radeon 9200 SE 128MB Game Buster (Secondary)\n\t\t18bc 0172  GC-R9200L(SE)-C3H [Radeon 9200 Game Buster]\n\t5d45  RV280 GL [FireMV 2200 PCI] (Secondary)\n\t5d48  R423/M28 [Mobility Radeon X800 XT]\n\t5d49  R423/M28 GL [Mobility FireGL V5100]\n\t5d4a  R423/M28 [Mobility Radeon X800]\n\t5d4d  R480 [Radeon X850 XT Platinum Edition]\n\t5d4e  R480 [Radeon X850 SE]\n\t5d4f  R480 [Radeon X800 GTO]\n\t5d50  R480 GL [FireGL V7200]\n\t5d52  R480 [Radeon X850 XT]\n\t\t1002 0b12  PowerColor X850XT PCIe (Primary)\n\t5d57  R423 [Radeon X800 XT]\n\t5d6d  R480 [Radeon X850 XT Platinum Edition] (Secondary)\n\t5d6f  R480 [Radeon X800 GTO] (Secondary)\n\t5d72  R480 [Radeon X850 XT] (Secondary)\n\t\t1002 0b13  PowerColor X850XT PCIe (Secondary)\n\t5d77  R423 [Radeon X800 XT] (Secondary)\n\t5e48  RV410 GL [FireGL V5000]\n\t5e49  RV410 [Radeon X700 Series]\n\t5e4a  RV410 [Radeon X700 XT]\n\t5e4b  RV410 [Radeon X700 PRO]\n\t5e4c  RV410 [Radeon X700 SE]\n\t5e4d  RV410 [Radeon X700]\n\t\t148c 2116  Bravo X700\n\t5e4f  RV410 [Radeon X700]\n\t\t1569 1e4f  Radeon X550 XT\n\t5e6b  RV410 [Radeon X700 PRO] (Secondary)\n\t5e6d  RV410 [Radeon X700] (Secondary)\n\t\t148c 2117  Bravo X700 (Secondary)\n\t5f57  R423 [Radeon X800 XT]\n\t6600  Mars [Radeon HD 8670A/8670M/8750M]\n\t\t103c 1952  ProBook 455 G1\n\t6601  Mars [Radeon HD 8730M]\n\t\t103c 2100  FirePro M4100\n\t6604  Opal XT [Radeon R7 M265/M365X/M465]\n\t\t1025 0776  Aspire V5 Radeon R7 M265\n\t\t103c 8006  FirePro M4170\n\t\t103c 814f  Litho XT [Radeon R7 M365X]\n\t\t103c 82aa  Litho XT [Radeon R7 M465]\n\t\t17aa 3643  Radeon R7 A360\n\t6605  Opal PRO [Radeon R7 M260X]\n\t\t103c 2259  FirePro M4150\n\t6606  Mars XTX [Radeon HD 8790M]\n\t\t1028 0684  FirePro W4170M\n\t6607  Mars LE [Radeon HD 8530M / R5 M240]\n\t6608  Oland GL [FirePro W2100]\n\t\t13cc 3d28  MXRT-2600\n\t6610  Oland XT [Radeon HD 8670 / R7 250/350]\n\t\t1019 0030  Radeon HD 8670\n\t\t1028 2120  Radeon R7 250\n\t\t1028 2322  Radeon R7 250\n\t\t1462 2910  Radeon HD 8670\n\t\t1462 2911  Radeon HD 8670\n\t\t148c 7350  Radeon R7 350\n\t\t1642 3c81  Radeon HD 8670\n\t\t1642 3c91  Radeon HD 8670\n\t\t1642 3f09  Radeon R7 350\n\t6611  Oland [Radeon HD 8570 / R7 240/340 OEM]\n\t\t1028 210b  Radeon R5 240 OEM\n\t\t174b 4248  Radeon R7 240 OEM\n\t\t174b a240  Radeon R7 240 OEM\n\t\t174b d340  Radeon R7 340 OEM\n\t\t1b0a 90d3  Radeon R7 240 OEM\n\t6613  Oland PRO [Radeon R7 240/340]\n\t\t148c 7340  Radeon R7 340\n\t\t1682 7240  R7 240 2048 MB\n\t6631  Oland\n\t6640  Saturn XT [FirePro M6100]\n\t\t106b 014b  Tropo XT [Radeon R9 M380 Mac Edition]\n\t6641  Saturn PRO [Radeon HD 8930M]\n\t6646  Bonaire XT [Radeon R9 M280X]\n\t6647  Saturn PRO/XT [Radeon R9 M270X/M280X]\n\t\t1043 223d  N551ZU laptop Radeon R9 M280X\n\t6649  Bonaire [FirePro W5100]\n\t\t1002 0b0c  FirePro W4300\n\t\t103c 0b0c  Bonaire [FirePro W4300]\n\t\t103c 230c  FirePro W5100\n\t\t13cc 3d2a  MXRT-5600\n\t6650  Bonaire\n\t6651  Bonaire\n\t6658  Bonaire XTX [Radeon R7 260X/360]\n\t\t1043 04d3  AMD Radeon R7 260X\n\t\t148c 0907  Radeon R7 360\n\t\t1682 0907  Radeon R7 360\n\t\t1682 7360  Radeon R7 360\n\t665c  Bonaire XT [Radeon HD 7790/8770 / R7 360 / R9 260/360 OEM]\n\t\t1043 0452  Radeon HD 7790 DirectCU II OC\n# R7790-1GD5/OC\n\t\t1462 2930  Radeon HD 7790 OC\n\t\t1462 2932  Radeon HD 8770\n\t\t1462 2934  Radeon R9 260 OEM\n\t\t1462 2938  Radeon R9 360 OEM\n\t\t148c 0907  Radeon R7 360\n\t\t148c 9260  Radeon R9 260 OEM\n\t\t148c 9360  Radeon R9 360 OEM\n\t\t1682 0907  Radeon R7 360\n# FX-779A-CDB4 / FX-779A-CDBC\n\t\t1682 3310  Radeon HD 7790 Black Edition 2 GB\n# 100356OCL / 11210-01-20G\n\t\t174b e253  Radeon HD 7790 Dual-X OC\n\t\t1787 2329  Radeon HD 7790 TurboDuo\n\t665d  Bonaire [Radeon R7 200 Series]\n\t665f  Tobago PRO [Radeon R7 360 / R9 360 OEM]\n\t\t1028 0b04  Radeon R9 360 OEM\n\t\t1462 2938  Radeon R9 360 OEM\n\t\t1462 3271  Radeon R9 360 OEM\n\t\t1682 7360  Radeon R7 360\n\t6660  Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330 / M430 / Radeon 520 Mobile]\n\t\t1028 05ea  Radeon HD 8670M\n\t\t1028 06bf  Radeon R5 M335\n\t\t103c 1970  Radeon HD 8670M\n\t\t103c 80be  Radeon R5 M330\n\t\t103c 8136  Radeon R5 M330\n\t\t103c 8329  Radeon R7 M520\n\t\t17aa 3633  Radeon R5 A330\n\t\t17aa 3804  Radeon R5 M330\n\t\t17aa 3809  Radeon R5 M330\n\t\t17aa 381a  Radeon R5 M430\n\t\t17aa 390c  Radeon R5 M330\n\t6663  Sun PRO [Radeon HD 8570A/8570M]\n\t\t1025 0846  Radeon HD 8570A\n\t\t17aa 3805  Radeon HD 8570M\n\t6664  Jet XT [Radeon R5 M240]\n\t6665  Jet PRO [Radeon R5 M230 / R7 M260DX / Radeon 520 Mobile]\n\t\t17aa 1309  Radeon R7 M260DX\n\t\t17aa 368f  Radeon R5 A230\n\t6667  Jet ULT [Radeon R5 M230]\n\t666f  Sun LE [Radeon HD 8550M / R5 M230]\n\t66a0  Vega 20 [Radeon Instinct]\n\t66a1  Vega 20\n\t66a2  Vega 20\n\t66a3  Vega 20\n\t66a7  Vega 20 [Radeon Pro Vega 20]\n\t66af  Vega 20 [Radeon VII]\n\t6704  Cayman PRO GL [FirePro V7900]\n\t6707  Cayman LE GL [FirePro V5900]\n\t6718  Cayman XT [Radeon HD 6970]\n\t6719  Cayman PRO [Radeon HD 6950]\n\t671c  Antilles [Radeon HD 6990]\n\t671d  Antilles [Radeon HD 6990]\n\t671f  Cayman CE [Radeon HD 6930]\n\t6720  Blackcomb [Radeon HD 6970M/6990M]\n\t\t1028 048f  Radeon HD 6990M\n\t\t1028 0490  Alienware M17x R3 Radeon HD 6970M\n\t\t1028 04a4  FirePro M8900\n\t\t1028 04ba  Radeon HD 6990M\n\t\t1028 053f  FirePro M8900\n\t\t106b 0b00  Radeon HD 6970M\n\t\t1558 5102  Radeon HD 6970M\n\t\t1558 5104  Radeon HD 6990M\n\t\t1558 7201  Radeon HD 6990M\n\t\t174b e188  Radeon HD 6970M\n\t6738  Barts XT [Radeon HD 6870]\n# HD-687A-ZDFC\n\t\t1682 3103  Radeon HD 8670\n\t\t1787 201a  Barts XT [Radeon HD 6870 X2]\n\t\t1787 201b  Barts XT [Radeon HD 6870 X2]\n\t6739  Barts PRO [Radeon HD 6850]\n\t\t1043 03b4  EAH6850 [Radeon HD 6850]\n\t673e  Barts LE [Radeon HD 6790]\n\t\t148c 7720  Radeon HD 7720 OEM\n\t6740  Whistler [Radeon HD 6730M/6770M/7690M XT]\n\t\t1019 238c  Radeon HD 6730M\n\t\t1019 238e  Radeon HD 6730M\n\t\t1019 2391  Radeon HD 6730M\n\t\t1019 2392  Radeon HD 6770M\n\t\t1028 04a3  Precision M4600\n\t\t1028 053e  FirePro M5950\n\t\t103c 1630  FirePro M5950\n\t\t103c 1631  FirePro M5950\n\t\t103c 164b  Radeon HD 6730M\n\t\t103c 164e  Radeon HD 6730M\n\t\t103c 1657  Radeon HD 6770M\n\t\t103c 1658  Radeon HD 6770M\n\t\t103c 165a  Radeon HD 6770M\n\t\t103c 165b  Radeon HD 6770M\n\t\t103c 1688  Radeon HD 6770M\n\t\t103c 1689  Radeon HD 6770M\n\t\t103c 168a  Radeon HD 6770M\n\t\t103c 185e  Radeon HD 7690M XT\n\t\t103c 3388  Radeon HD 6770M\n\t\t103c 3389  Radeon HD 6770M\n\t\t103c 3582  Radeon HD 6770M\n\t\t103c 366c  Radeon HD 6730M\n\t\t1043 1d02  Radeon HD 6730M\n\t\t1043 1d12  Radeon HD 6730M\n\t\t104d 9084  Radeon HD 6730M\n\t\t104d 9085  Radeon HD 6730M\n\t\t144d b074  Radeon HD 6730M\n\t\t144d b077  Radeon HD 6730M\n\t\t144d b084  Radeon HD 6730M\n\t\t144d b088  Radeon HD 6730M\n\t\t17aa 3982  Radeon HD 6730M\n\t6741  Whistler [Radeon HD 6630M/6650M/6750M/7670M/7690M]\n\t\t1019 238e  Radeon HD 6650M\n\t\t1019 238f  Radeon HD 6650M\n\t\t1025 0379  Radeon HD 6650M\n\t\t1025 037b  Radeon HD 6650M\n\t\t1025 037e  Radeon HD 6650M\n\t\t1025 0382  Radeon HD 6650M\n\t\t1025 0384  Radeon HD 6650M\n\t\t1025 0385  Radeon HD 6650M\n\t\t1025 0386  Radeon HD 6650M\n\t\t1025 0387  Radeon HD 6650M\n\t\t1025 0388  Radeon HD 6650M\n\t\t1025 0442  Radeon HD 6650M\n\t\t1025 0451  Radeon HD 6650M\n\t\t1025 0489  Radeon HD 6650M\n\t\t1025 048b  Radeon HD 6650M\n\t\t1025 048c  Radeon HD 6650M\n\t\t1025 050a  Radeon HD 6650M\n\t\t1025 050b  Radeon HD 6650M\n\t\t1025 050c  Radeon HD 6650M\n\t\t1025 050e  Radeon HD 6650M\n\t\t1025 050f  Radeon HD 6650M\n\t\t1025 0513  Radeon HD 6650M\n\t\t1025 0514  Radeon HD 6650M\n\t\t1025 0515  Radeon HD 6650M\n\t\t1025 0516  Radeon HD 6650M\n\t\t1025 051e  Radeon HD 6650M\n\t\t1025 051f  Radeon HD 6650M\n\t\t1025 0520  Radeon HD 6650M\n\t\t1025 0521  Radeon HD 6650M\n\t\t1025 052a  Radeon HD 6650M\n\t\t1025 0555  Radeon HD 6650M\n\t\t1025 0556  Radeon HD 6650M\n\t\t1025 055d  Radeon HD 6650M\n\t\t1025 055e  Radeon HD 6650M\n\t\t1025 056d  Radeon HD 6650M\n\t\t1025 059a  Radeon HD 6650M\n\t\t1025 059b  Radeon HD 6650M\n\t\t1025 059e  Radeon HD 6650M\n\t\t1025 059f  Radeon HD 6650M\n\t\t1025 0600  Radeon HD 6650M\n\t\t1025 0605  Radeon HD 6650M\n\t\t1025 0606  Radeon HD 6650M\n\t\t1025 0619  Radeon HD 6650M\n\t\t1028 04c1  Radeon HD 6630M\n\t\t1028 04c5  Radeon HD 6630M\n\t\t1028 04cd  Radeon HD 6630M\n\t\t1028 04d7  Radeon HD 6630M\n\t\t1028 04d9  Radeon HD 6630M\n\t\t1028 052d  Radeon HD 6630M\n\t\t103c 1617  Radeon HD 6650M\n\t\t103c 1646  Radeon HD 6750M\n\t\t103c 1647  Radeon HD 6650M\n\t\t103c 164b  Radeon HD 6650M\n\t\t103c 164e  Radeon HD 6650M\n\t\t103c 1688  Radeon HD 6750M\n\t\t103c 1689  Radeon HD 6750M\n\t\t103c 168a  Radeon HD 6750M\n\t\t103c 1860  Radeon HD 7690M\n\t\t103c 3385  Radeon HD 6630M\n\t\t103c 3560  Radeon HD 6750M\n\t\t103c 358d  Radeon HD 6750M\n\t\t103c 3590  Radeon HD 6750M\n\t\t103c 3593  Radeon HD 6750M\n\t\t103c 366c  Radeon HD 6650M\n\t\t1043 1cd2  Radeon HD 6650M\n\t\t1043 2121  Radeon HD 6650M\n\t\t1043 2122  Radeon HD 6650M\n\t\t1043 2123  Radeon HD 6650M\n\t\t1043 2125  Radeon HD 7670M\n\t\t1043 2127  Radeon HD 7670M\n\t\t104d 907b  Radeon HD 6630M\n\t\t104d 9080  Radeon HD 6630M\n\t\t104d 9081  Radeon HD 6630M\n\t\t106b 00e2  MacBookPro8,2 [Core i7, 15\", Late 2011]\n\t\t1179 fd63  Radeon HD 6630M\n\t\t1179 fd65  Radeon HD 6630M\n\t\t144d c093  Radeon HD 6650M\n\t\t144d c0ac  Radeon HD 6650M\n\t\t144d c0b3  Radeon HD 6750M\n\t\t144d c539  Radeon HD 6630M\n\t\t144d c609  Radeon HD 6630M\n\t\t152d 0914  Radeon HD 6650M\n\t\t17aa 21e1  Radeon HD 6630M\n\t\t17aa 3970  Radeon HD 6650M\n\t\t17aa 3976  Radeon HD 6650M\n\t\t1854 0907  Radeon HD 6650M\n\t6742  Whistler LE [Radeon HD 6610M/7610M]\n\t\t1002 6570  Turks [Radeon HD 6570]\n\t\t1019 2393  Radeon HD 6610M\n\t\t1043 1d82  K53SK Laptop Radeon HD 7610M\n\t\t1179 fb22  Radeon HD 7610M\n\t\t1179 fb23  Radeon HD 7610M\n\t\t1179 fb27  Radeon HD 7610M\n\t\t1179 fb2a  Radeon HD 7610M\n\t\t1179 fb2c  Radeon HD 7610M\n\t\t1179 fb30  Radeon HD 7610M\n\t\t1179 fb31  Radeon HD 7610M\n\t\t1179 fb32  Radeon HD 7610M\n\t\t1179 fb38  Radeon HD 7610M\n\t\t1179 fb39  Radeon HD 7610M\n\t\t1179 fb3a  Radeon HD 7610M\n\t\t1179 fb3b  Radeon HD 7610M\n\t\t1179 fb40  Radeon HD 7610M\n\t\t1179 fb41  Radeon HD 7610M\n\t\t1179 fb47  Radeon HD 7610M\n\t\t1179 fb48  Radeon HD 7610M\n\t\t1179 fb49  Radeon HD 7610M\n\t\t1179 fb51  Radeon HD 7610M\n\t\t1179 fb52  Radeon HD 7610M\n\t\t1179 fb53  Radeon HD 7610M\n\t\t1179 fb56  Radeon HD 7610M\n\t\t1179 fb81  Radeon HD 7610M\n\t\t1179 fb82  Radeon HD 7610M\n\t\t1179 fb83  Radeon HD 7610M\n\t\t1179 fc56  Radeon HD 7610M\n\t\t1179 fcd4  Radeon HD 7610M\n\t\t1179 fcee  Radeon HD 7610M\n\t\t1458 6570  Turks [Radeon HD 6570]\n\t\t1462 6570  Turks [Radeon HD 6570]\n\t\t148c 6570  Turks [Radeon HD 6570]\n\t\t1682 6570  Turks [Radeon HD 6570]\n\t\t174b 5570  Turks [Radeon HD 5570]\n\t\t174b 6570  Turks [Radeon HD 6570]\n\t\t174b 7570  Turks [Radeon HD 7570]\n\t\t174b 8510  Turks [Radeon HD 8510]\n\t\t174b 8570  Turks [Radeon HD 8570]\n\t\t1787 6570  Turks [Radeon HD 6570]\n\t\t17af 6570  Turks [Radeon HD 6570]\n\t\t8086 2111  Radeon HD 6625M\n\t6743  Whistler [Radeon E6760]\n\t6749  Turks GL [FirePro V4900]\n\t\t15c3 2b06  MED-X4900\n\t674a  Turks GL [FirePro V3900]\n\t\t13cc 3d22  MXRT-2500\n\t\t15c3 0106  MED-X3900\n\t6750  Onega [Radeon HD 6650A/7650A]\n\t\t1462 2670  Radeon HD 6670A\n\t\t17aa 3079  Radeon HD 7650A\n\t\t17aa 307a  Radeon HD 6650A\n\t\t17aa 3087  Radeon HD 7650A\n\t\t17aa 3618  Radeon HD 6650A\n\t\t17aa 3623  Radeon HD 6650A\n\t\t17aa 3627  Radeon HD 6650A\n\t6751  Turks [Radeon HD 7650A/7670A]\n\t\t1028 0548  Radeon HD 7650A\n\t\t1462 2671  Radeon HD 7670A\n\t\t1462 2672  Radeon HD 7670A\n\t\t1462 2680  Radeon HD 7650A\n\t\t1462 2681  Radeon HD 7650A\n\t\t17aa 3087  Radeon HD 7650A\n\t6758  Turks XT [Radeon HD 6670/7670]\n\t\t1028 0b0e  Radeon HD 6670\n\t\t103c 6882  Radeon HD 6670\n\t\t1462 250a  Radeon HD 7670\n\t\t148c 7670  Radeon HD 7670\n\t\t1545 7670  Radeon HD 7670\n\t\t1682 3300  Radeon HD 7670\n\t\t174b 7670  Radeon HD 7670\n\t\t174b e181  Radeon HD 6670\n\t\t1787 2309  Radeon HD 6670\n\t6759  Turks PRO [Radeon HD 6570/7570/8550]\n\t\t103c 3130  Radeon HD 6570\n\t\t1043 0403  Radeon HD 6570\n\t\t1462 2500  Radeon HD 6570\n\t\t1462 2509  Radeon HD 7570\n\t\t148c 7570  Radeon HD 7570\n\t\t1642 3a67  Radeon HD 6570\n\t\t1682 3280  Radeon HD 7570\n\t\t1682 3530  Radeon HD 8550\n\t\t174b 7570  Radeon HD 7570\n\t\t174b e142  Radeon HD 6570\n\t\t174b e181  Radeon HD 6570\n\t\t1b0a 908f  Radeon HD 6570\n\t\t1b0a 9090  Radeon HD 6570\n\t\t1b0a 9091  Radeon HD 6570\n\t\t1b0a 9092  Radeon HD 6570\n\t\t1b0a 909e  Radeon HD 6570\n\t\t1b0a 90b5  Radeon HD 7570\n\t\t1b0a 90b6  Radeon HD 7570\n\t675b  Turks [Radeon HD 7600 Series]\n\t675d  Turks PRO [Radeon HD 7570]\n\t675f  Turks LE [Radeon HD 5570/6510/7510/8510]\n\t\t148c 6510  Radeon HD 6510\n\t\t148c 6530  Radeon HD 6530\n\t\t148c 7510  Radeon HD 7510\n\t\t1545 7570  Radeon HD 7570\n\t\t174b 6510  Radeon HD 6510\n\t\t174b 7510  Radeon HD 7510\n\t\t174b 8510  Radeon HD 8510\n\t\t1787 2012  Radeon HD 5570 2GB GDDR3\n\t\t1787 2314  Radeon HD 5570 1GB DDR2/GDDR3\n\t6760  Seymour [Radeon HD 6400M/7400M Series]\n\t\t1002 0124  Radeon HD 6470M\n\t\t1002 0134  Radeon HD 6470M\n\t\t1019 238b  Radeon HD 6470M\n\t\t1019 238e  Radeon HD 6470M\n\t\t1019 2390  Radeon HD 6470M\n\t\t1019 9985  Radeon HD 6470M\n\t\t1028 04c1  Radeon HD 6470M\n\t\t1028 04c3  Radeon HD 6470M\n\t\t1028 04ca  Radeon HD 6470M\n\t\t1028 04cb  Radeon HD 6470M\n\t\t1028 04cc  Vostro 3350\n\t\t1028 04d1  Radeon HD 6470M\n\t\t1028 04d3  Radeon HD 6470M\n\t\t1028 04d7  Radeon HD 6470M\n\t\t1028 0502  Radeon HD 6470M\n\t\t1028 0503  Radeon HD 6470M\n\t\t1028 0506  Radeon HD 6470M\n\t\t1028 0507  Radeon HD 6470M\n\t\t1028 0514  Radeon HD 6470M\n\t\t1028 051c  Radeon HD 6450M\n\t\t1028 051d  Radeon HD 6450M\n\t\t103c 161a  Radeon HD 6470M\n\t\t103c 161b  Radeon HD 6470M\n\t\t103c 161e  Radeon HD 6470M\n\t\t103c 161f  Radeon HD 6470M\n\t\t103c 1622  Radeon HD 6450M\n\t\t103c 1623  Radeon HD 6450M\n\t\t103c 164a  Radeon HD 6470M\n\t\t103c 164d  Radeon HD 6470M\n\t\t103c 1651  Radeon HD 6470M\n\t\t103c 1656  Radeon HD 6490M\n\t\t103c 1658  Radeon HD 6490M\n\t\t103c 1659  Radeon HD 6490M\n\t\t103c 165b  Radeon HD 6490M\n\t\t103c 165d  Radeon HD 6470M\n\t\t103c 165f  Radeon HD 6470M\n\t\t103c 1661  Radeon HD 6470M\n\t\t103c 1663  Radeon HD 6470M\n\t\t103c 1665  Radeon HD 6470M\n\t\t103c 1667  Radeon HD 6470M\n\t\t103c 1669  Radeon HD 6470M\n\t\t103c 166b  Radeon HD 6470M\n\t\t103c 166c  Radeon HD 6470M\n\t\t103c 166e  Radeon HD 6470M\n\t\t103c 1670  Radeon HD 6470M\n\t\t103c 1672  Radeon HD 6470M\n\t\t103c 167a  Radeon HD 6470M\n\t\t103c 167b  Radeon HD 6470M\n\t\t103c 167d  Radeon HD 6490M\n\t\t103c 167f  Radeon HD 6490M\n\t\t103c 168c  Radeon HD 6470M\n\t\t103c 168f  Radeon HD 6470M\n\t\t103c 1694  Radeon HD 6470M\n\t\t103c 1696  Radeon HD 6470M\n\t\t103c 1698  Radeon HD 6470M\n\t\t103c 169a  Radeon HD 6470M\n\t\t103c 169c  Radeon HD 6490M\n\t\t103c 1855  Radeon HD 7450M\n\t\t103c 1859  Radeon HD 7450M\n\t\t103c 185c  Radeon HD 7450M\n\t\t103c 185d  Radeon HD 7470M\n\t\t103c 185f  Radeon HD 7470M\n\t\t103c 1863  Radeon HD 7450M\n\t\t103c 355c  Radeon HD 6490M\n\t\t103c 355f  Radeon HD 6490M\n\t\t103c 3563  Radeon HD 6470M\n\t\t103c 3565  Radeon HD 6470M\n\t\t103c 3567  Radeon HD 6470M\n\t\t103c 3569  Radeon HD 6470M\n\t\t103c 3581  Radeon HD 6490M\n\t\t103c 3584  Radeon HD 6470M\n\t\t103c 358c  Radeon HD 6490M\n\t\t103c 358f  Radeon HD 6490M\n\t\t103c 3592  Radeon HD 6490M\n\t\t103c 3596  Radeon HD 6490M\n\t\t103c 366b  Radeon HD 6470M\n\t\t103c 3671  FirePro M3900\n\t\t103c 3673  Radeon HD 6470M\n\t\t1043 100a  Radeon HD 7470M\n\t\t1043 100c  Radeon HD 6470M\n\t\t1043 101b  Radeon HD 6470M\n\t\t1043 101c  Radeon HD 6470M\n\t\t1043 102a  Radeon HD 7450M\n\t\t1043 102c  Radeon HD 6470M\n\t\t1043 104b  Radeon HD 7470M\n\t\t1043 105d  Radeon HD 7470M\n\t\t1043 106b  Radeon HD 7470M\n\t\t1043 106d  Radeon HD 7470M\n\t\t1043 107d  Radeon HD 7470M\n\t\t1043 1cb2  Radeon HD 6470M\n\t\t1043 1d22  Radeon HD 6470M\n\t\t1043 1d32  Radeon HD 6470M\n\t\t1043 2001  Radeon HD 6470M\n\t\t1043 2002  Radeon HD 7470M\n\t\t1043 2107  Radeon HD 7470M\n\t\t1043 2108  Radeon HD 7470M\n\t\t1043 2109  Radeon HD 7470M\n\t\t1043 84a0  Radeon HD 6470M\n\t\t1043 84e9  Radeon HD 6470M\n\t\t1043 8515  Radeon HD 7470M\n\t\t1043 8517  Radeon HD 7470M\n\t\t1043 855a  Radeon HD 7470M\n\t\t104d 907b  Radeon HD 6470M\n\t\t104d 9081  Radeon HD 6470M\n\t\t104d 9084  Radeon HD 6470M\n\t\t104d 9085  Radeon HD 6470M\n\t\t1179 0001  Radeon HD 6450M\n\t\t1179 0003  Radeon HD 6450M\n\t\t1179 0004  Radeon HD 6450M\n\t\t1179 fb22  Radeon HD 7470M\n\t\t1179 fb23  Radeon HD 7470M\n\t\t1179 fb2c  Radeon HD 7470M\n\t\t1179 fb31  Radeon HD 7470M\n\t\t1179 fb32  Radeon HD 7470M\n\t\t1179 fb33  Radeon HD 7470M\n\t\t1179 fb38  Radeon HD 7470M\n\t\t1179 fb39  Radeon HD 7470M\n\t\t1179 fb3a  Radeon HD 7470M\n\t\t1179 fb40  Radeon HD 7470M\n\t\t1179 fb41  Radeon HD 7470M\n\t\t1179 fb42  Radeon HD 7470M\n\t\t1179 fb47  Radeon HD 7470M\n\t\t1179 fb48  Radeon HD 7470M\n\t\t1179 fb51  Radeon HD 7470M\n\t\t1179 fb52  Radeon HD 7470M\n\t\t1179 fb53  Radeon HD 7470M\n\t\t1179 fb81  Radeon HD 7470M\n\t\t1179 fb82  Radeon HD 7470M\n\t\t1179 fb83  Radeon HD 7470M\n\t\t1179 fc51  Radeon HD 6470M\n\t\t1179 fc52  Radeon HD 7470M\n\t\t1179 fc56  Radeon HD 7470M\n\t\t1179 fcd3  Radeon HD 7470M\n\t\t1179 fcd4  Radeon HD 7470M\n\t\t1179 fcee  Radeon HD 7470M\n\t\t1179 fdee  Radeon HD 7470M\n\t\t144d b074  Radeon HD 6470M\n\t\t144d b084  Radeon HD 6470M\n\t\t144d c095  Radeon HD 6470M\n\t\t144d c0b3  Radeon HD 6490M\n\t\t144d c538  Radeon HD 6470M\n\t\t144d c581  Radeon HD 6470M\n\t\t144d c589  Radeon HD 6470M\n\t\t144d c609  Radeon HD 7470M\n\t\t144d c625  Radeon HD 7470M\n\t\t144d c636  Radeon HD 7450M\n\t\t1462 10ac  Radeon HD 6470M\n\t\t152d 0916  Radeon HD 6470M\n\t\t17aa 21e5  Radeon HD 6470M\n\t\t17aa 3900  Radeon HD 7450M\n\t\t17aa 3902  Radeon HD 7450M\n\t\t17aa 3969  Radeon HD 6470M\n\t\t17aa 3970  Radeon HD 7450M\n\t\t17aa 3976  Radeon HD 6470M\n\t\t17aa 397b  Radeon HD 6470M\n\t\t17aa 397d  Radeon HD 6470M\n\t\t17aa 5101  Radeon HD 7470M\n\t\t17aa 5102  Radeon HD 7450M\n\t\t17aa 5103  Radeon HD 7450M\n\t\t17aa 5106  Radeon HD 7450M\n\t\t1854 0897  Radeon HD 6470M\n\t\t1854 0900  Radeon HD 6470M\n\t\t1854 0908  Radeon HD 6470M\n\t\t1854 2015  Radeon HD 6470M\n\t6761  Seymour LP [Radeon HD 6430M]\n\t6763  Seymour [Radeon E6460]\n\t6764  Seymour [Radeon HD 6400M Series]\n\t6765  Seymour [Radeon HD 6400M Series]\n\t6766  Caicos\n\t6767  Caicos\n\t6768  Caicos\n\t6770  Caicos [Radeon HD 6450A/7450A]\n\t\t17aa 308d  Radeon HD 7450A\n\t\t17aa 3623  Radeon HD 6450A\n\t\t17aa 3627  Radeon HD 6450A\n\t\t17aa 3629  Radeon HD 6450A\n\t\t17aa 363c  Radeon HD 6450A\n\t\t17aa 3658  Radeon HD 7470A\n\t6771  Caicos XTX [Radeon HD 8490 / R5 235X OEM]\n\t6772  Caicos [Radeon HD 7450A]\n\t6778  Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM]\n\t\t1019 0024  Radeon HD 7470\n\t\t1019 0027  Radeon HD 8470\n\t\t1028 2120  Radeon HD 7470\n\t\t1462 b491  Radeon HD 8470\n\t\t1462 b492  Radeon HD 8470\n\t\t1462 b493  Radeon HD 8470 OEM\n\t\t1462 b499  Radeon R5 235 OEM\n\t\t1642 3c65  Radeon HD 8470\n\t\t1642 3c75  Radeon HD 8470\n\t\t174b 8145  Radeon HD 8470\n\t\t174b d145  Radeon R5 235 OEM\n\t\t174b d335  Radeon R5 310 OEM\n\t\t174b e145  Radeon HD 7470\n\t\t17aa 3694  Radeon R5 A220\n\t6779  Caicos [Radeon HD 6450/7450/8450 / R5 230 OEM]\n\t\t1019 0016  Radeon HD 6450\n\t\t1019 0017  Radeon HD 6450\n\t\t1019 0018  Radeon HD 6450\n\t\t1028 2120  Radeon HD 6450\n\t\t103c 2128  Radeon HD 6450\n\t\t103c 2aee  Radeon HD 7450A\n\t\t1092 6450  Radeon HD 6450\n\t\t1462 2125  Radeon HD 6450\n\t\t1462 2346  Radeon HD 7450\n\t\t1462 2490  Radeon HD 6450\n\t\t1462 2494  Radeon HD 6450\n\t\t1462 2496  Radeon HD 7450\n\t\t148c 7450  Radeon HD 7450\n\t\t148c 8450  Radeon HD 8450 OEM\n\t\t1545 7470  Radeon HD 7470\n\t\t1642 3a65  Radeon HD 6450\n\t\t1642 3a66  Radeon HD 7450\n\t\t1642 3a75  Radeon HD 6450\n\t\t1642 3a76  Radeon HD 7450\n\t\t1682 3200  Radeon HD 7450\n\t\t174b 7450  Radeon HD 7450\n\t\t174b e127  Radeon HD 6450\n\t\t174b e153  Radeon HD 6450\n\t\t174b e164  Radeon HD 6450 1 GB DDR3\n\t\t174b e180  Radeon HD 6450\n\t\t174b e201  Radeon HD 6450\n\t\t17af 8450  Radeon HD 8450 OEM\n\t\t1b0a 9096  Radeon HD 6450\n\t\t1b0a 9097  Radeon HD 6450\n\t\t1b0a 90a8  Radeon HD 6450A\n\t\t1b0a 90b1  Radeon HD 6450\n\t\t1b0a 90b3  Radeon HD 7450A\n\t\t1b0a 90bb  Radeon HD 7450A\n\t677b  Caicos PRO [Radeon HD 7450]\n\t6780  Tahiti XT GL [FirePro W9000]\n\t6784  Tahiti [FirePro Series Graphics Adapter]\n\t6788  Tahiti [FirePro Series Graphics Adapter]\n\t678a  Tahiti PRO GL [FirePro Series]\n\t\t1002 030c  FirePro W8000\n\t\t1002 0310  FirePro S9000\n\t\t1002 0420  Radeon Sky 700\n\t\t1002 0422  Radeon Sky 900\n\t\t1002 0710  FirePro S9050\n\t\t1002 0b0e  FirePro S10000 Passive\n\t\t1002 0b2a  FirePro S10000\n\t\t1028 030c  FirePro W8000\n\t\t1028 0710  FirePro S9000\n\t6798  Tahiti XT [Radeon HD 7970/8970 OEM / R9 280X]\n\t\t1002 3000  Tahiti XT2 [Radeon HD 7970 GHz Edition]\n\t\t1002 3001  Tahiti XTL [Radeon R9 280X]\n\t\t1002 4000  Radeon HD 8970 OEM\n\t\t1043 041c  HD 7970 DirectCU II\n\t\t1043 0420  HD 7970 DirectCU II TOP\n\t\t1043 0444  HD 7970 DirectCU II TOP\n\t\t1043 0448  HD 7970 DirectCU II TOP\n\t\t1043 044a  Tahiti XT2 [Matrix HD 7970]\n\t\t1043 044c  Tahiti XT2 [Matrix HD 7970 Platinum]\n\t\t1043 3001  Tahiti XTL [ROG Matrix R9 280X]\n\t\t1043 3006  Tahiti XTL [Radeon R9 280X DirectCU II TOP]\n\t\t1043 9999  ARES II\n\t\t106b 0127  FirePro D700\n\t\t106b 0128  FirePro D700\n\t\t1092 3000  Tahiti XT2 [Radeon HD 7970 GHz Edition]\n\t\t1458 2261  Tahiti XT2 [Radeon HD 7970 GHz Edition OC]\n# GV-R928XOC-3GD\n\t\t1458 3001  Tahiti XTL [Radeon R9 280X OC]\n\t\t1462 2774  HD 7970 TwinFrozr III Boost Edition OC\n\t\t1682 3001  Tahiti XTL [Radeon R9 280X]\n\t\t1682 3211  Double D HD 7970 Black Edition\n# FX-797A-TNBC\n\t\t1682 3213  HD 7970 Black Edition\n\t\t1682 3214  Double D HD 7970\n\t\t1787 201c  HD 7970 IceQ X²\n# Radeon HD 7970 X2\n\t\t1787 2317  Radeon HD 7990\n\t\t1787 3000  Tahiti XT2 [Radeon HD 7970 GHz Edition]\n\t679a  Tahiti PRO [Radeon HD 7950/8950 OEM / R9 280]\n\t\t1002 0b01  Radeon HD 8950 OEM\n\t\t1002 3000  Tahiti PRO2 [Radeon HD 7950 Boost]\n\t\t1462 3000  Radeon HD 8950 OEM\n\t\t174b a003  Radeon R9 280\n\t679b  Malta [Radeon HD 7990/8990 OEM]\n\t\t1002 0b28  Radeon HD 8990 OEM\n\t\t1002 0b2a  Radeon HD 7990\n\t\t1462 8036  Radeon HD 8990 OEM\n\t\t148c 8990  Radeon HD 8990 OEM\n\t679e  Tahiti LE [Radeon HD 7870 XT]\n\t\t106b 0125  FirePro D500\n\t\t106b 0126  FirePro D500\n\t\t1787 2328  Radeon HD 7870 Black Edition 2 GB GDDR5 [2GBD5-2DHV3E]\n\t679f  Tahiti\n\t67a0  Hawaii XT GL [FirePro W9100]\n\t\t1002 0335  FirePro S9150\n\t\t1002 0735  FirePro S9170\n\t\t1028 031f  FirePro W9100\n\t\t1028 0335  FirePro S9150\n\t67a1  Hawaii PRO GL [FirePro W8100]\n\t\t1002 0335  FirePro S9100\n\t\t1028 0335  FirePro S9100\n\t67a2  Hawaii GL\n\t67a8  Hawaii\n\t67a9  Hawaii\n\t67aa  Hawaii\n\t67b0  Hawaii XT / Grenada XT [Radeon R9 290X/390X]\n\t\t1028 0b00  Grenada XT [Radeon R9 390X]\n\t\t103c 6566  Radeon R9 390X\n\t\t1043 046a  R9 290X DirectCU II\n\t\t1043 046c  R9 290X DirectCU II OC\n\t\t1043 0474  Matrix R9 290X Platinum\n\t\t1043 0476  ARES III\n\t\t1043 04d7  Radeon R9 390X\n\t\t1043 04db  Radeon R9 390X\n\t\t1043 04df  Radeon R9 390X\n\t\t1043 04e9  Radeon R9 390X\n\t\t1458 227c  R9 290X WindForce 3X OC\n\t\t1458 2281  R9 290X WindForce 3X OC\n\t\t1458 228c  R9 290X WindForce 3X\n\t\t1458 228d  R9 290X WindForce 3X OC\n\t\t1458 2290  R9 290X WindForce 3X\n\t\t1458 22bc  Radeon R9 390X\n\t\t1458 22c1  Grenada PRO [Radeon R9 390]\n\t\t1462 2015  Radeon R9 390X\n\t\t1462 3070  R9 290X Lightning\n\t\t1462 3071  R9 290X Lightning\n\t\t1462 3072  R9 290X Lightning LE\n\t\t1462 3080  R9 290X Gaming\n\t\t1462 3082  R9 290X Gaming OC\n\t\t148c 2347  Devil 13 Dual Core R9 290X\n\t\t148c 2357  Grenada XT [Radeon R9 390X]\n\t\t1682 9290  Double Dissipation R9 290X\n\t\t1682 9395  Grenada XT [Radeon R9 390X]\n\t\t174b 0e34  Radeon R9 390X\n\t\t174b e282  Vapor-X R9 290X Tri-X OC\n\t\t174b e285  R9 290X Tri-X OC\n\t\t174b e324  Grenada XT2 [Radeon R9 390X]\n\t\t1787 2020  R9 290X IceQ X² Turbo\n\t\t1787 2357  Grenada XT [Radeon R9 390X]\n\t67b1  Hawaii PRO [Radeon R9 290/390]\n\t\t1043 04dd  STRIX R9 390\n\t\t148c 2358  Radeon R9 390\n\t\t174b e324  Sapphire Nitro R9 390\n\t67b9  Vesuvius [Radeon R9 295X2]\n\t67be  Hawaii LE\n\t67c0  Ellesmere [Radeon Pro WX 7100 Mobile]\n\t67c2  Ellesmere [Radeon Pro V7300X / V7350x2]\n\t67c4  Ellesmere [Radeon Pro WX 7100]\n\t\t1002 0336  Radeon Pro Duo\n\t\t1002 1336  Radeon Pro Duo\n\t67c7  Ellesmere [Radeon Pro WX 5100]\n\t67ca  Ellesmere [Polaris10]\n\t67cc  Ellesmere [Polaris10]\n\t67cf  Ellesmere [Polaris10]\n\t67d0  Ellesmere [Radeon Pro V7300X / V7350x2]\n\t67df  Ellesmere [Radeon RX 470/480/570/570X/580/580X/590]\n\t\t1002 0b37  Radeon RX 480\n\t\t1028 1722  Radeon RX 570X\n\t\t1028 1723  Radeon RX 580X\n\t\t1043 04a8  Radeon RX 480\n\t\t1043 04b0  Radeon RX 470\n\t\t1043 04fb  Radeon RX 480\n\t\t1043 04fd  Radeon RX 480 8GB\n\t\t1043 056a  Radeon RX 590\n\t\t106b 0161  Radeon Pro 580\n\t\t106b 0162  Radeon Pro 575\n\t\t106b 0163  Radeon Pro 570\n\t\t1458 22f0  Radeon RX 570\n\t\t1458 22f7  Radeon RX 570 Gaming 4G\n\t\t1462 3411  Radeon RX 470\n\t\t1462 3413  Radeon RX 480 Gaming X 8GB\n\t\t1462 3416  Radeon RX 570\n\t\t1462 3418  Radeon RX 580 Armor 4G OC\n\t\t1462 341e  Radeon RX 570 Armor 4G OC\n\t\t1462 8a92  Radeon RX 580\n\t\t148c 2372  Radeon RX 480\n\t\t148c 2373  Radeon RX 470\n\t\t1682 9470  Radeon RX 470\n\t\t1682 9480  Radeon RX 480\n\t\t1682 9588  Radeon RX 580 XTR\n\t\t1682 c570  Radeon RX 570\n\t\t174b e347  Radeon RX 470/480\n\t\t174b e349  Radeon RX 470\n\t\t1787 a470  Radeon RX 470\n\t\t1787 a480  Radeon RX 480\n\t\t1849 5001  Phantom Gaming X RX 580 OC\n\t\t1849 5030  Phantom Gaming D Radeon RX580 8G OC\n\t\t1da2 e353  Radeon RX 570 Pulse 4GB\n\t\t1da2 e366  Nitro+ Radeon RX 570/580/590\n\t67e0  Baffin [Radeon Pro WX 4170]\n\t\t103c 8270  Radeon Pro WX 4170\n\t\t103c 8272  Radeon Pro WX 4170\n\t67e1  Baffin [Polaris11]\n\t67e3  Baffin [Radeon Pro WX 4100]\n\t67e8  Baffin [Radeon Pro WX 4130/4150]\n\t\t1028 075d  Radeon Pro WX 4150\n\t\t1028 07b0  Radeon Pro WX 4130/4150\n\t\t1028 07b1  Radeon Pro WX 4130\n\t\t1028 175d  Radeon Pro WX 4150\n\t\t1028 17b0  Radeon Pro WX 4130/4150\n\t\t1028 17b1  Radeon Pro WX 4130\n\t\t103c 8275  Radeon Pro WX 4150\n\t\t103c 8277  Radeon Pro WX 4150\n\t67e9  Baffin [Polaris11]\n\t67eb  Baffin [Radeon Pro V5300X]\n\t67ef  Baffin [Radeon RX 460/560D / Pro 450/455/460/555/555X/560/560X]\n\t\t1028 1703  RX 560D OEM OC 2 GB\n\t\t103c 3421  Radeon RX 460\n\t\t106b 0160  Radeon Pro 460\n\t\t106b 0166  Radeon Pro 455\n\t\t106b 0167  Radeon Pro 450\n\t\t106b 0179  Radeon Pro 560\n\t\t106b 017a  Radeon Pro 555\n\t\t106b 018f  Radeon Pro 560X\n\t\t106b 0190  Radeon Pro 555X\n\t\t1642 1727  Polaris 21 XL [Radeon RX 560D]\n\t\t1682 956d  Polaris 21 XL [Radeon RX 560D]\n\t67ff  Baffin [Radeon RX 550 640SP / RX 560/560X]\n\t\t1002 0b04  Radeon RX 560\n\t\t1028 1721  Radeon RX 560X\n\t\t1028 1726  Radeon RX 560DX\n\t\t103c 8479  Radeon RX 560X Mobile\n\t\t1043 04bc  Radeon RX 560\n\t\t1043 052f  Radeon RX 560\n\t\t1458 22ed  Radeon RX 560\n\t\t148c 2381  Radeon RX 560\n\t\t1682 9560  Radeon RX 560\n\t\t1da2 e348  Radeon RX 560\n\t\t1da2 e367  Radeon RX 550 640SP\n\t6800  Wimbledon XT [Radeon HD 7970M]\n\t\t1002 0124  Radeon HD 7970M\n\t\t8086 2110  Radeon HD 7970M\n\t\t8086 2111  Radeon HD 7970M\n\t6801  Neptune XT [Radeon HD 8970M]\n\t\t1002 0124  Radeon HD 8970M\n\t\t1462 1117  Radeon R9 M290X\n\t\t8086 2110  Radeon HD 8970M\n\t\t8086 2111  Radeon HD 8970M\n\t6802  Wimbledon\n\t6806  Neptune\n\t6808  Pitcairn XT GL [FirePro W7000]\n\t\t1002 0310  FirePro S7000\n\t\t1002 0420  Radeon Sky 500\n\t\t103c 030c  MED-X7000\n\t\t13cc 3d25  MXRT-7500\n\t\t15c3 030c  MED-X7000\n\t6809  Pitcairn LE GL [FirePro W5000]\n\t\t13cc 3d23  MXRT-5500\n\t\t13cc 3d24  MXRT-5550\n\t\t15c3 0b06  MED-X5000\n\t6810  Curacao XT / Trinidad XT [Radeon R7 370 / R9 270X/370X]\n\t\t106b 012a  FirePro D300\n\t\t106b 012b  FirePro D300\n\t\t148c 0908  Radeon R9 370 OEM\n\t\t1682 7370  Radeon R7 370\n\t6811  Curacao PRO [Radeon R7 370 / R9 270/370 OEM]\n\t\t1028 0b00  Trinidad PRO [Radeon R9 370 OEM]\n\t\t1043 2016  Trinidad PRO [Radeon R9 370 OEM]\n\t\t1458 2016  Trinidad PRO [Radeon R9 370 OEM]\n\t\t1462 2016  Trinidad PRO [Radeon R9 370 OEM]\n\t\t1462 3050  R9 270 Gaming OC\n\t\t148c 2016  Trinidad PRO [Radeon R9 370 OEM]\n\t\t1682 2015  Trinidad PRO [Radeon R7 370]\n\t\t174b 2015  NITRO Radeon R7 370\n\t\t174b 2016  Trinidad PRO [Radeon R9 370 OEM]\n\t\t1787 2016  Trinidad PRO [Radeon R9 370 OEM]\n\t6816  Pitcairn\n\t6817  Pitcairn\n\t6818  Pitcairn XT [Radeon HD 7870 GHz Edition]\n\t\t1002 0b05  Radeon HD 8870 OEM\n\t\t174b 8b04  Radeon HD 8860\n\t6819  Pitcairn PRO [Radeon HD 7850 / R7 265 / R9 270 1024SP]\n\t\t1043 042c  Radeon HD 7850\n\t\t1682 7269  Radeon R9 270 1024SP\n\t\t1682 9278  Radeon R9 270 1024SP\n\t\t174b a008  Radeon R9 270 1024SP\n\t\t174b e221  Radeon HD 7850 2GB GDDR5 DVI-I/DVI-D/HDMI/DP\n\t6820  Venus XTX [Radeon HD 8890M / R9 M275X/M375X]\n\t\t103c 1851  Radeon HD 7750M\n\t\t17aa 3643  Radeon R9 A375\n\t\t17aa 3801  Radeon R9 M275\n\t\t17aa 3824  Radeon R9 M375\n\t6821  Venus XT [Radeon HD 8870M / R9 M270X/M370X]\n\t\t1002 031e  FirePro SX4000\n\t\t1028 05cc  FirePro M5100\n\t\t1028 15cc  FirePro M5100\n\t\t106b 0149  Radeon R9 M370X Mac Edition\n\t6822  Venus PRO [Radeon E8860]\n\t6823  Venus PRO [Radeon HD 8850M / R9 M265X]\n\t6825  Heathrow XT [Radeon HD 7870M]\n\t\t1028 053f  FirePro M6000\n\t\t1028 05cd  FirePro M6000\n\t\t1028 15cd  FirePro M6000\n\t\t103c 176c  FirePro M6000\n\t\t8086 2111  Chelsea PRO\n\t6826  Chelsea LP [Radeon HD 7700M Series]\n\t6827  Heathrow PRO [Radeon HD 7850M/8850M]\n\t6828  Cape Verde PRO [FirePro W600]\n\t\t15c3 2b1e  MED-X6000\n\t6829  Cape Verde\n\t682a  Venus PRO\n\t682b  Cape Verde PRO / Venus LE / Tropo PRO-L [Radeon HD 8830M / R7 250 / R7 M465X]\n\t\t0128 079c  Radeon R7 465X\n\t\t1462 3012  Radeon R7 250\n\t682c  Cape Verde GL [FirePro W4100]\n\t682d  Chelsea XT GL [FirePro M4000]\n\t682f  Chelsea LP [Radeon HD 7730M]\n\t\t103c 1851  Radeon HD 7750M\n\t6835  Cape Verde PRX [Radeon R9 255 OEM]\n\t6837  Cape Verde LE [Radeon HD 7730/8730]\n\t\t1462 2796  Radeon HD 8730\n\t\t1462 8092  Radeon HD 8730\n\t\t148c 8730  Radeon HD 8730\n\t\t1787 3000  Radeon HD 6570\n\t683d  Cape Verde XT [Radeon HD 7770/8760 / R7 250X]\n\t\t1002 0030  Radeon HD 8760 OEM\n\t\t1019 0030  Radeon HD 8760 OEM\n\t\t103c 6890  Radeon HD 8760 OEM\n\t\t1043 8760  Radeon HD 8760 OEM\n\t\t1462 2710  R7770-PMD1GD5\n\t\t174b 8304  Radeon HD 8760 OEM\n\t683f  Cape Verde PRO [Radeon HD 7750/8740 / R7 250E]\n\t\t1462 2790  Radeon HD 8740\n\t\t1462 2791  Radeon HD 8740\n\t\t1642 3b97  Radeon HD 8740\n\t6840  Thames [Radeon HD 7500M/7600M Series]\n\t\t1025 050e  Radeon HD 7670M\n\t\t1025 050f  Radeon HD 7670M\n\t\t1025 0513  Radeon HD 7670M\n\t\t1025 0514  Radeon HD 7670M\n\t\t1025 056d  Radeon HD 7670M\n\t\t1025 059a  Radeon HD 7670M\n\t\t1025 059b  Radeon HD 7670M\n\t\t1025 059e  Radeon HD 7670M\n\t\t1025 0600  Radeon HD 7670M\n\t\t1025 0606  Radeon HD 7670M\n\t\t1025 0696  Radeon HD 7650M\n\t\t1025 0697  Radeon HD 7650M\n\t\t1025 0698  Radeon HD 7650M\n\t\t1025 0699  Radeon HD 7650M\n\t\t1025 0757  Radeon HD 7670M\n\t\t1028 056a  Radeon HD 7670M\n\t\t1028 056e  Radeon HD 7670M\n\t\t1028 0598  Radeon HD 7670M\n\t\t1028 059d  Radeon HD 7670M\n\t\t1028 05a3  Radeon HD 7670M\n\t\t1028 05b9  Radeon HD 7670M\n\t\t1028 05bb  Radeon HD 7670M\n\t\t103c 1789  FirePro M2000\n\t\t103c 17f1  Radeon HD 7570M\n\t\t103c 17f4  Radeon HD 7650M\n\t\t103c 1813  Radeon HD 7590M\n\t\t103c 182f  Radeon HD 7670M\n\t\t103c 1830  Radeon HD 7670M\n\t\t103c 1835  Radeon HD 7670M\n\t\t103c 183a  Radeon HD 7670M\n\t\t103c 183c  Radeon HD 7670M\n\t\t103c 183e  Radeon HD 7670M\n\t\t103c 1840  Radeon HD 7670M\n\t\t103c 1842  Radeon HD 7670M\n\t\t103c 1844  Radeon HD 7670M\n\t\t103c 1848  Radeon HD 7670M\n\t\t103c 184a  Radeon HD 7670M\n\t\t103c 184c  Radeon HD 7670M\n\t\t103c 1895  Radeon HD 7670M\n\t\t103c 1897  Radeon HD 7670M\n\t\t103c 18a5  Radeon HD 7670M\n\t\t103c 18a7  Radeon HD 7670M\n\t\t103c 18f4  Radeon HD 7670M\n\t\t1043 100a  Radeon HD 7670M\n\t\t1043 104b  Radeon HD 7670M\n\t\t1043 10dc  Radeon HD 7670M\n\t\t1043 2121  Radeon HD 7670M\n\t\t1043 2122  Radeon HD 7670M\n\t\t1043 2123  Radeon HD 7670M\n\t\t1043 2125  Radeon HD 7670M\n\t\t1043 2127  Radeon HD 7670M\n\t\t1179 fb11  Radeon HD 7670M\n\t\t1179 fb22  Radeon HD 7670M\n\t\t1179 fb23  Radeon HD 7670M\n\t\t1179 fb2c  Radeon HD 7670M\n\t\t1179 fb31  Radeon HD 7670M\n\t\t1179 fb32  Radeon HD 7670M\n\t\t1179 fb38  Radeon HD 7670M\n\t\t1179 fb39  Radeon HD 7670M\n\t\t1179 fb3a  Radeon HD 7670M\n\t\t1179 fb40  Radeon HD 7670M\n\t\t1179 fb41  Radeon HD 7670M\n\t\t1179 fb47  Radeon HD 7670M\n\t\t1179 fb48  Radeon HD 7670M\n\t\t1179 fb51  Radeon HD 7670M\n\t\t1179 fb52  Radeon HD 7670M\n\t\t1179 fb53  Radeon HD 7670M\n\t\t1179 fb81  Radeon HD 7670M\n\t\t1179 fb82  Radeon HD 7670M\n\t\t1179 fb83  Radeon HD 7670M\n\t\t1179 fc56  Radeon HD 7670M\n\t\t1179 fcd4  Radeon HD 7670M\n\t\t1179 fcee  Radeon HD 7670M\n\t\t144d c0c5  Radeon HD 7690M\n\t\t144d c0ce  Radeon HD 7670M\n\t\t144d c0da  Radeon HD 7670M\n\t\t17aa 3970  Radeon HD 7670M\n\t\t17aa 397b  Radeon HD 7670M\n\t\t17aa 5101  Radeon HD 7670M\n\t\t17aa 5102  Radeon HD 7670M\n\t\t17aa 5103  Radeon HD 7670M\n\t6841  Thames [Radeon HD 7550M/7570M/7650M]\n\t\t1028 0561  Radeon HD 7650M\n\t\t1028 056c  Radeon HD 7650M\n\t\t1028 057f  Radeon HD 7570M\n\t\t103c 17f1  Radeon HD 7570M\n\t\t103c 17f4  Radeon HD 7650M\n\t\t103c 1813  Radeon HD 7570M\n\t\t103c 183a  Radeon HD 7650M\n\t\t103c 183c  Radeon HD 7650M\n\t\t103c 183e  Radeon HD 7650M\n\t\t103c 1840  Radeon HD 7650M\n\t\t103c 1842  Radeon HD 7650M\n\t\t103c 1844  Radeon HD 7650M\n\t\t1043 100a  Radeon HD 7650M\n\t\t1043 104b  Radeon HD 7650M\n\t\t1043 10dc  Radeon HD 7650M\n\t\t1043 2134  Radeon HD 7650M\n\t\t1179 0001  Radeon HD 7570M\n\t\t1179 0002  Radeon HD 7570M\n\t\t1179 fb43  Radeon HD 7550M\n\t\t1179 fb91  Radeon HD 7550M\n\t\t1179 fb92  Radeon HD 7550M\n\t\t1179 fb93  Radeon HD 7550M\n\t\t1179 fba2  Radeon HD 7550M\n\t\t1179 fba3  Radeon HD 7550M\n\t\t144d c0c7  Radeon HD 7550M\n\t6842  Thames LE [Radeon HD 7000M Series]\n\t6843  Thames [Radeon HD 7670M]\n\t6860  Vega 10 [Radeon Instinct MI25]\n\t\t1002 0c35  Radeon PRO V320\n\t\t1002 6c75  Radeon PRO V320\n\t\t106b 017c  Radeon Pro Vega 64\n\t6861  Vega 10 XT [Radeon PRO WX 9100]\n\t6862  Vega 10 XT [Radeon PRO SSG]\n\t6863  Vega 10 XTX [Radeon Vega Frontier Edition]\n\t6864  Vega\n\t6867  Vega 10 XL [Radeon Pro Vega 56]\n\t6868  Vega 10 [Radeon PRO WX 8100/8200]\n\t686c  Vega 10 [Radeon Instinct MI25 MxGPU]\n\t687f  Vega 10 XL/XT [Radeon RX Vega 56/64]\n\t\t1002 0b36  RX Vega64\n\t\t1002 6b76  RX Vega56\n\t6880  Lexington [Radeon HD 6550M]\n\t\t103c 163c  Pavilion dv6 Radeon HD 6550M\n\t6888  Cypress XT [FirePro V8800]\n\t6889  Cypress PRO [FirePro V7800]\n\t\t1002 0301  FirePro V7800P\n\t\t13cc 3d1f  MXRT-7400\n\t688a  Cypress XT [FirePro V9800]\n\t\t1002 030c  FirePro V9800P\n\t688c  Cypress XT GL [FireStream 9370]\n\t688d  Cypress PRO GL [FireStream 9350]\n\t6898  Cypress XT [Radeon HD 5870]\n\t\t1002 0b00  Radeon HD 5870 Eyefinity⁶ Edition\n\t\t106b 00d0  Radeon HD 5870 Mac Edition\n# R5870-PM2D1G\n\t\t1462 8032  Radeon HD 5870 1 GB GDDR5\n\t\t174b 6870  Radeon HD 6870 1600SP Edition\n\t6899  Cypress PRO [Radeon HD 5850]\n# EAH5850\n\t\t1043 0330  Radeon HD 5850\n\t\t174b 237b  Radeon HD 5850 X2\n\t\t174b 6850  Radeon HD 6850 1440SP Edition\n\t689b  Cypress PRO [Radeon HD 6800 Series]\n\t689c  Hemlock [Radeon HD 5970]\n\t\t1043 0352  ARES\n\t689d  Hemlock [Radeon HD 5970]\n\t689e  Cypress LE [Radeon HD 5830]\n\t68a0  Broadway XT [Mobility Radeon HD 5870]\n\t\t1028 12ef  FirePro M7820\n\t\t103c 1520  FirePro M7820\n\t68a1  Broadway PRO [Mobility Radeon HD 5850]\n\t\t106b 00cc  iMac MC511 Mobility Radeon HD 5850 MXM Module\n\t68a8  Granville [Radeon HD 6850M/6870M]\n\t\t1025 0442  Radeon HD 6850M\n\t\t1025 0451  Radeon HD 6850M\n\t\t1025 050a  Radeon HD 6850M\n\t\t1025 050b  Radeon HD 6850M\n\t\t1025 050c  Radeon HD 6850M\n\t\t1025 050e  Radeon HD 6850M\n\t\t1025 050f  Radeon HD 6850M\n\t\t1025 0513  Radeon HD 6850M\n\t\t1025 0514  Radeon HD 6850M\n\t\t1025 0515  Radeon HD 6850M\n\t\t1025 0516  Radeon HD 6850M\n\t\t1025 0525  Radeon HD 6850M\n\t\t1025 0526  Radeon HD 6850M\n\t\t1025 056d  Radeon HD 6850M\n\t\t1028 048f  Radeon HD 6870M\n\t\t1028 0490  Radeon HD 6870M\n\t\t1028 04b9  Radeon HD 6870M\n\t\t1028 04ba  Radeon HD 6870M\n\t\t103c 159b  Radeon HD 6850M\n\t\t144d c0ad  Radeon HD 6850M\n\t68a9  Juniper XT [FirePro V5800]\n\t\t13cc 3d1e  MXRT-5400\n\t\t13cc 3d20  MXRT-5450\n\t68b8  Juniper XT [Radeon HD 5770]\n\t\t106b 00cf  MacPro5,1 [Mac Pro 2.8GHz DDR3]\n\t68b9  Juniper LE [Radeon HD 5670 640SP Edition]\n\t68ba  Juniper XT [Radeon HD 6770]\n\t68be  Juniper PRO [Radeon HD 5750]\n\t\t148c 3000  Radeon HD 6750\n\t68bf  Juniper PRO [Radeon HD 6750]\n\t\t174b 6750  Radeon HD 6750\n\t68c0  Madison [Mobility Radeon HD 5730 / 6570M]\n\t\t1019 2383  Mobility Radeon HD 5730\n\t\t1028 02a2  Mobility Radeon HD 5730\n\t\t1028 02fe  Mobility Radeon HD 5730\n\t\t1028 0419  Mobility Radeon HD 5730\n\t\t103c 147d  Mobility Radeon HD 5730\n\t\t103c 1521  Madison XT [FirePro M5800]\n\t\t103c 1593  Mobility Radeon HD 6570\n\t\t103c 1596  Mobility Radeon HD 6570\n\t\t103c 1599  Mobility Radeon HD 6570\n\t\t1043 1c22  Mobility Radeon HD 5730\n\t\t17aa 3927  Mobility Radeon HD 5730\n\t\t17aa 3952  Mobility Radeon HD 5730\n\t\t17aa 3978  Radeon HD 6570M\n\t68c1  Madison [Mobility Radeon HD 5650/5750 / 6530M/6550M]\n\t\t1025 0205  Mobility Radeon HD 5650\n\t\t1025 0293  Mobility Radeon HD 5650\n\t\t1025 0294  Mobility Radeon HD 5650\n\t\t1025 0296  Mobility Radeon HD 5650\n\t\t1025 0308  Mobility Radeon HD 5650\n\t\t1025 030a  Mobility Radeon HD 5650\n\t\t1025 0311  Mobility Radeon HD 5650\n\t\t1025 0312  Mobility Radeon HD 5650\n\t\t1025 031c  Mobility Radeon HD 5650\n\t\t1025 031d  Mobility Radeon HD 5650\n\t\t1025 033d  Mobility Radeon HD 5650\n\t\t1025 033e  Mobility Radeon HD 5650\n\t\t1025 033f  Mobility Radeon HD 5650\n\t\t1025 0346  Mobility Radeon HD 5650\n\t\t1025 0347  Aspire 7740G\n\t\t1025 0348  Mobility Radeon HD 5650\n\t\t1025 0356  Mobility Radeon HD 5650\n\t\t1025 0357  Mobility Radeon HD 5650\n\t\t1025 0358  Mobility Radeon HD 5650\n\t\t1025 0359  Mobility Radeon HD 5650\n\t\t1025 035a  Mobility Radeon HD 5650\n\t\t1025 035b  Mobility Radeon HD 5650\n\t\t1025 035c  Mobility Radeon HD 5650\n\t\t1025 035d  Mobility Radeon HD 5650\n\t\t1025 035e  Mobility Radeon HD 5650\n\t\t1025 0360  Mobility Radeon HD 5650\n\t\t1025 0362  Mobility Radeon HD 5650\n\t\t1025 0364  Mobility Radeon HD 5650\n\t\t1025 0365  Mobility Radeon HD 5650\n\t\t1025 0366  Mobility Radeon HD 5650\n\t\t1025 0367  Mobility Radeon HD 5650\n\t\t1025 0368  Mobility Radeon HD 5650\n\t\t1025 036c  Mobility Radeon HD 5650\n\t\t1025 036d  Mobility Radeon HD 5650\n\t\t1025 036e  Mobility Radeon HD 5650\n\t\t1025 036f  Mobility Radeon HD 5650\n\t\t1025 0372  Mobility Radeon HD 5650\n\t\t1025 0373  Mobility Radeon HD 5650\n\t\t1025 0377  Mobility Radeon HD 5650\n\t\t1025 0378  Mobility Radeon HD 5650\n\t\t1025 0379  Mobility Radeon HD 5650\n\t\t1025 037a  Mobility Radeon HD 5650\n\t\t1025 037b  Mobility Radeon HD 5650\n\t\t1025 037e  Mobility Radeon HD 5650\n\t\t1025 037f  Mobility Radeon HD 5650\n\t\t1025 0382  Mobility Radeon HD 5650\n\t\t1025 0383  Mobility Radeon HD 5650\n\t\t1025 0384  Mobility Radeon HD 5650\n\t\t1025 0385  Mobility Radeon HD 5650\n\t\t1025 0386  Mobility Radeon HD 5650\n\t\t1025 0387  Mobility Radeon HD 5650\n\t\t1025 0388  Mobility Radeon HD 5650\n\t\t1025 038b  Mobility Radeon HD 5650\n\t\t1025 038c  Mobility Radeon HD 5650\n\t\t1025 039a  Mobility Radeon HD 5650\n\t\t1025 0411  Mobility Radeon HD 5650\n\t\t1025 0412  Mobility Radeon HD 5650\n\t\t1025 0418  Mobility Radeon HD 5650\n\t\t1025 0419  Mobility Radeon HD 5650\n\t\t1025 0420  Mobility Radeon HD 5650\n\t\t1025 0421  Mobility Radeon HD 5650\n\t\t1025 0425  Mobility Radeon HD 5650\n\t\t1025 042a  Mobility Radeon HD 5650\n\t\t1025 042e  Mobility Radeon HD 5650\n\t\t1025 042f  Mobility Radeon HD 5650\n\t\t1025 0432  Mobility Radeon HD 5650\n\t\t1025 0433  Mobility Radeon HD 5650\n\t\t1025 0442  Mobility Radeon HD 5650\n\t\t1025 044c  Mobility Radeon HD 5650\n\t\t1025 044e  Mobility Radeon HD 5650\n\t\t1025 0451  Mobility Radeon HD 5650\n\t\t1025 0454  Mobility Radeon HD 5650\n\t\t1025 0455  Mobility Radeon HD 5650\n\t\t1025 0475  Mobility Radeon HD 5650\n\t\t1025 0476  Mobility Radeon HD 5650\n\t\t1025 0487  Mobility Radeon HD 5650\n\t\t1025 0489  Mobility Radeon HD 5650\n\t\t1025 0498  Mobility Radeon HD 5650\n\t\t1025 0517  Radeon HD 6550M\n\t\t1025 051a  Radeon HD 6550M\n\t\t1025 051b  Radeon HD 6550M\n\t\t1025 051c  Radeon HD 6550M\n\t\t1025 051d  Radeon HD 6550M\n\t\t1025 0525  Radeon HD 6550M\n\t\t1025 0526  Radeon HD 6550M\n\t\t1025 052b  Radeon HD 6550M\n\t\t1025 052c  Radeon HD 6550M\n\t\t1025 053c  Radeon HD 6550M\n\t\t1025 053d  Radeon HD 6550M\n\t\t1025 053e  Radeon HD 6550M\n\t\t1025 053f  Radeon HD 6550M\n\t\t1025 0607  Radeon HD 6550M\n\t\t1028 041b  Mobility Radeon HD 5650\n\t\t1028 0447  Mobility Radeon HD 5650\n\t\t1028 0448  Mobility Radeon HD 5650\n\t\t1028 0456  Mobility Radeon HD 5650\n\t\t1028 0457  Mobility Radeon HD 5650\n\t\t103c 1436  Mobility Radeon HD 5650\n\t\t103c 1437  Mobility Radeon HD 5650\n\t\t103c 1440  Mobility Radeon HD 5650\n\t\t103c 1448  Mobility Radeon HD 5650\n\t\t103c 1449  Mobility Radeon HD 5650\n\t\t103c 144a  Mobility Radeon HD 5650\n\t\t103c 144b  Mobility Radeon HD 5650\n\t\t103c 147b  Mobility Radeon HD 5650\n\t\t103c 149c  Mobility Radeon HD 5650\n\t\t103c 149e  Mobility Radeon HD 5650\n\t\t103c 1521  Madison Pro [FirePro M5800]\n\t\t1043 1bc2  Mobility Radeon HD 5650\n\t\t104d 9071  Mobility Radeon HD 5650\n\t\t104d 9077  Mobility Radeon HD 5650\n\t\t104d 9081  Mobility Radeon HD 5650\n\t\t1179 fd00  Mobility Radeon HD 5650\n\t\t1179 fd12  Mobility Radeon HD 5650\n\t\t1179 fd1a  Mobility Radeon HD 5650\n\t\t1179 fd30  Mobility Radeon HD 5650\n\t\t1179 fd31  Mobility Radeon HD 5650\n\t\t1179 fd50  Mobility Radeon HD 5650\n\t\t1179 fd52  Radeon HD 6530M\n\t\t1179 fd63  Radeon HD 6530M\n\t\t1179 fd65  Radeon HD 6530M\n\t\t1179 fdd0  Mobility Radeon HD 5650\n\t\t1179 fdd2  Radeon HD 6530M\n\t\t144d c07e  Mobility Radeon HD 5650\n\t\t144d c085  Mobility Radeon HD 5650\n\t\t14c0 0043  Mobility Radeon HD 5650\n\t\t14c0 004d  Mobility Radeon HD 5650\n\t\t17aa 3928  Mobility Radeon HD 5650\n\t\t17aa 3951  Mobility Radeon HD 5650\n\t\t17aa 3977  Radeon HD 6550M\n\t68c7  Pinewood [Mobility Radeon HD 5570/6550A]\n\t\t1462 2241  Mobility Radeon HD 5570\n\t\t1462 2243  Mobility Radeon HD 5570\n\t\t1462 2244  Mobility Radeon HD 5570\n\t\t1462 2245  Radeon HD 6550A\n\t\t1462 2246  Radeon HD 6550A\n\t68c8  Redwood XT GL [FirePro V4800]\n\t68c9  Redwood PRO GL [FirePro V3800]\n\t\t13cc 3d1d  MXRT-2400\n\t68d8  Redwood XT [Radeon HD 5670/5690/5730]\n\t\t1028 68e0  Radeon HD 5670\n\t\t174b 5690  Radeon HD 5690\n\t\t174b 5730  Radeon HD 5730\n\t\t174b e151  Radeon HD 5670\n\t\t1787 3000  Radeon HD 5730\n\t\t17af 3010  Radeon HD 5730\n\t\t17af 3011  Radeon HD 5690\n\t68d9  Redwood PRO [Radeon HD 5550/5570/5630/6510/6610/7570]\n\t\t103c 6870  Radeon HD 5570\n\t\t103c 6872  Radeon HD 5570\n\t\t1043 03ce  Radeon HD 5550\n\t\t1462 2151  Radeon HD 5570\n\t\t1462 2240  Radeon HD 5570\n\t\t148c 3000  Radeon HD 6510\n\t\t148c 3001  Radeon HD 6610\n\t\t1545 5550  Radeon HD 5550\n\t\t1545 7570  Radeon HD 7570\n\t\t1642 3985  Radeon HD 5570\n\t\t1642 3996  Radeon HD 5570\n\t\t174b 3000  Radeon HD 6510\n\t\t174b 6510  Radeon HD 6510\n\t\t174b 6610  Radeon HD 6610\n\t\t174b e142  Radeon HD 5570\n\t\t1787 3000  Radeon HD 6510\n\t\t17af 3000  Radeon HD 6510\n\t\t17af 3010  Radeon HD 5630\n\t68da  Redwood LE [Radeon HD 5550/5570/5630/6390/6490/7570]\n\t\t148c 3000  Radeon HD 6390\n\t\t148c 3001  Radeon HD 6490\n\t\t1545 7570  Radeon HD 7570\n\t\t174b 3000  Radeon HD 6390\n\t\t174b 5570  Radeon HD 5570\n\t\t174b 5630  Radeon HD 5630\n\t\t174b 6490  Radeon HD 6490\n\t\t1787 3000  Radeon HD 5630\n\t\t17af 3000  Radeon HD 6390\n\t\t17af 3010  Radeon HD 5630\n\t68de  Redwood\n\t68e0  Park [Mobility Radeon HD 5430/5450/5470]\n\t\t1028 0404  Mobility Radeon HD 5450\n\t\t1028 0414  Mobility Radeon HD 5450\n\t\t1028 0434  Mobility Radeon HD 5450\n\t\t103c 1433  Mobility Radeon HD 5450\n\t\t103c 1434  Mobility Radeon HD 5450\n\t\t103c 1469  Mobility Radeon HD 5450\n\t\t103c 146b  Mobility Radeon HD 5450\n\t\t103c 1486  TouchSmart tm2-2050er discrete GPU (Mobility Radeon HD 5450)\n\t\t103c 1622  Mobility Radeon HD 5450\n\t\t103c 1623  Mobility Radeon HD 5450\n\t\t103c eeee  Mobility Radeon HD 5450\n\t\t104d 9076  Mobility Radeon HD 5450\n\t\t1682 304e  Caicos [Radeon HD 5450]\n\t\t1682 6000  Caicos [Radeon HD 5450]\n\t\t17aa 9e52  FirePro M3800\n\t\t17aa 9e53  FirePro M3800\n\t68e1  Park [Mobility Radeon HD 5430]\n\t\t1043 041f  Caicos [Radeon HD 7350]\n\t\t1043 3000  Caicos [Radeon HD 5450]\n\t\t148c 3000  Caicos [Radeon HD 5450]\n\t\t148c 3001  Caicos [Radeon HD 6230]\n\t\t148c 3002  Caicos [Radeon HD 6250]\n\t\t148c 3003  Caicos [Radeon HD 6350]\n\t\t148c 7350  Caicos [Radeon HD 7350]\n\t\t148c 8350  Caicos [Radeon HD 8350]\n\t\t1545 5450  Caicos [Radeon HD 5450]\n\t\t1545 7350  Caicos [Radeon HD 7350]\n\t\t1682 3000  Caicos [Radeon HD 5450]\n\t\t1682 6000  Caicos [Radeon HD 5450]\n\t\t1682 7350  Caicos [Radeon HD 7350]\n\t\t174b 3000  Caicos [Radeon HD 5450]\n\t\t174b 5470  Caicos [Radeon HD 5470]\n\t\t174b 6000  Caicos [Radeon HD 5450]\n\t\t174b 6230  Caicos [Radeon HD 6230]\n\t\t174b 6350  Caicos [Radeon HD 6350]\n\t\t174b 7350  Caicos [Radeon HD 7350]\n\t\t1787 3000  Caicos [Radeon HD 5450]\n\t\t17af 3000  Caicos [Radeon HD 5450]\n\t\t17af 3001  Caicos [Radeon HD 6230]\n\t\t17af 3014  Caicos [Radeon HD 6350]\n\t\t17af 3015  Caicos [Radeon HD 7350]\n\t\t17af 8350  Caicos [Radeon HD 8350 OEM]\n\t68e4  Robson CE [Radeon HD 6370M/7370M]\n\t\t1019 2386  Radeon HD 6350M\n\t\t1019 2387  Radeon HD 6350M\n\t\t1019 238d  Radeon HD 6370M\n\t\t1019 238e  Radeon HD 6370M\n\t\t1025 0382  Radeon HD 6370M\n\t\t1025 0489  Radeon HD 6370M\n\t\t1025 048a  Radeon HD 6370M\n\t\t1025 048b  Radeon HD 6370M\n\t\t1025 048c  Radeon HD 6370M\n\t\t1028 04c1  Radeon HD 6370M\n\t\t1028 04ca  Radeon HD 6370M\n\t\t1028 04cc  Radeon HD 6370M\n\t\t1028 04cd  Radeon HD 6370M\n\t\t1028 04d7  Radeon HD 6370M\n\t\t103c 1411  Radeon HD 6370M\n\t\t103c 1421  Radeon HD 6370M\n\t\t103c 1426  Radeon HD 6370M\n\t\t103c 1428  Radeon HD 6370M\n\t\t103c 142a  Radeon HD 6370M\n\t\t103c 142b  Radeon HD 6370M\n\t\t103c 143a  Radeon HD 6370M\n\t\t103c 143c  Radeon HD 6370M\n\t\t103c 1445  Radeon HD 6370M\n\t\t103c 162c  Radeon HD 6370M\n\t\t103c 162d  Radeon HD 6370M\n\t\t103c 162e  Radeon HD 6370M\n\t\t103c 162f  Radeon HD 6370M\n\t\t103c 1639  Radeon HD 6370M\n\t\t103c 163a  Radeon HD 6370M\n\t\t103c 163b  Radeon HD 6370M\n\t\t103c 163c  Radeon HD 6370M\n\t\t103c 163d  Radeon HD 6370M\n\t\t103c 163e  Radeon HD 6370M\n\t\t103c 163f  Radeon HD 6370M\n\t\t103c 1641  Radeon HD 6370M\n\t\t103c 1643  Radeon HD 6370M\n\t\t103c 3578  Radeon HD 6370M\n\t\t103c 357a  Radeon HD 6370M\n\t\t103c 3673  Radeon HD 6370M\n\t\t103c 3675  Radeon HD 6370M\n\t\t1043 1c92  Radeon HD 6370M\n\t\t1043 84a1  Radeon HD 6370M\n\t\t1043 84ad  Radeon HD 6370M\n\t\t104d 9081  Radeon HD 6370M\n\t\t1545 7350  Cedar [Radeon HD 7350]\n\t\t1558 4510  Radeon HD 6370M\n\t\t1558 5505  Radeon HD 6370M\n\t\t174b 5450  Cedar [Radeon HD 5450]\n\t\t17aa 21dd  Radeon HD 6370M\n\t\t17aa 21e9  Radeon HD 6370M\n\t\t17aa 3971  Radeon HD 6370M\n\t\t17aa 3972  Radeon HD 7370M\n\t\t17aa 397a  Radeon HD 6370M/7370M\n\t\t17aa 397b  Radeon HD 6370M/7370M\n\t\t17aa 397f  Radeon HD 7370M\n\t68e5  Robson LE [Radeon HD 6330M]\n\t\t1179 fd3c  Radeon HD 6330M\n\t\t1179 fd50  Radeon HD 6330M\n\t\t1179 fd52  Radeon HD 6330M\n\t\t1179 fd63  Radeon HD 6330M\n\t\t1179 fd65  Radeon HD 6330M\n\t\t1179 fd73  Radeon HD 6330M\n\t\t1179 fd75  Radeon HD 6330M\n\t\t1179 fdd0  Radeon HD 6330M\n\t\t1179 fdd2  Radeon HD 6330M\n\t\t1179 fdea  Radeon HD 6330M\n\t\t1179 fdf8  Radeon HD 6330M\n\t\t148c 5450  Cedar [Radeon HD 5450]\n\t\t148c 6350  Cedar [Radeon HD 6350]\n\t\t148c 7350  Cedar [Radeon HD 7350]\n\t\t148c 8350  Cedar [Radeon HD 8350]\n\t\t1545 7350  Cedar [Radeon HD 7350]\n\t68e8  Cedar\n\t68e9  Cedar [ATI FirePro (FireGL) Graphics Adapter]\n\t68f1  Cedar GL [FirePro 2460]\n\t68f2  Cedar GL [FirePro 2270]\n\t68f8  Cedar [Radeon HD 7300 Series]\n\t68f9  Cedar [Radeon HD 5000/6000/7350/8350 Series]\n\t\t1019 0001  Radeon HD 5450\n\t\t1019 0002  Radeon HD 5450\n\t\t1019 0019  Radeon HD 6350\n\t\t1025 0518  Radeon HD 5450\n\t\t1025 0519  Radeon HD 5450\n\t\t1028 010e  XPS 8300\n\t\t1028 2126  Radeon HD 6350\n\t\t103c 2126  Radeon HD 6350\n\t\t103c 2aac  Radeon HD 5450\n\t\t103c 2aae  Radeon HD 5450\n\t\t103c 3580  Radeon HD 5450\n\t\t1043 0386  Radeon HD 5450\n\t\t1043 03c2  EAH5450 SILENT/DI/512MD2 (LP)\n\t\t1462 2130  Radeon HD 5450\n\t\t1462 2131  Radeon HD 5450\n\t\t1462 2133  Radeon HD 6350\n\t\t1462 2180  Radeon HD 5450\n\t\t1462 2181  Radeon HD 5450\n\t\t1462 2182  Radeon HD 6350\n\t\t1462 2183  Radeon HD 6350\n\t\t1462 2230  Radeon HD 5450\n\t\t1462 2231  Radeon HD 5450\n\t\t1462 2495  Radeon HD 6350\n\t\t148c 3001  Radeon HD 5530/6250\n\t\t148c 3002  Radeon HD 6290\n\t\t148c 3003  Radeon HD 6230\n\t\t148c 3004  Radeon HD 6350\n\t\t148c 7350  Radeon HD 7350\n\t\t148c 8350  Radeon HD 8350\n\t\t1545 7350  Radeon HD 7350\n\t\t1642 3983  Radeon HD 5450\n\t\t1642 3984  Radeon HD 6350\n\t\t1642 3987  Radeon HD 6350\n\t\t1642 3997  Radeon HD 5450\n\t\t1642 3a05  Radeon HD 5450\n\t\t1642 3b31  Radeon HD 6350A\n\t\t1682 3270  Radeon HD 7350\n\t\t174b 3000  Radeon HD 6230\n\t\t174b 3987  Radeon HD 6350\n\t\t174b 5470  Radeon HD 5470\n\t\t174b 5490  Radeon HD 5490\n\t\t174b 5530  Radeon HD 5530\n\t\t174b 6230  Radeon HD 6230\n\t\t174b 6250  Radeon HD 6250\n\t\t174b 6290  Radeon HD 6290\n\t\t174b 6350  Radeon HD 6350\n\t\t174b 7350  Radeon HD 7350\n\t\t174b 8350  Radeon HD 8350\n\t\t174b e127  Radeon HD 5450\n\t\t174b e145  Radeon HD 5450\n\t\t174b e153  Radeon HD 5450\n\t\t1787 3000  Radeon HD 5470\n\t\t1787 3001  Radeon HD 5530\n\t\t1787 3002  Radeon HD 5490\n\t\t17aa 3602  Radeon HD 5450\n\t\t17aa 3603  Radeon HD 5450\n\t\t17aa 360f  Radeon HD 5450\n\t\t17aa 3619  Radeon HD 5450\n\t\t17af 3000  Radeon HD 6250\n\t\t17af 3001  Radeon HD 6230\n\t\t17af 3002  Radeon HD 6290\n\t\t17af 3011  Radeon HD 5470\n\t\t17af 3012  Radeon HD 5490\n\t\t17af 3013  Radeon HD 5470\n\t\t17af 3014  Radeon HD 6350\n\t68fa  Cedar [Radeon HD 7350/8350 / R5 220]\n\t\t1019 0019  Radeon HD 7350\n\t\t1019 0021  Radeon HD 7350\n\t\t1019 0022  Radeon HD 7350\n\t\t1019 0026  Radeon HD 8350\n\t\t103c 2adf  Radeon HD 7350A\n\t\t103c 2ae8  Radeon HD 7350A\n\t\t1043 8350  Radeon HD 8350\n\t\t1462 2128  Radeon HD 7350\n\t\t1462 2184  Radeon HD 7350\n\t\t1462 2186  Radeon HD 7350\n\t\t1462 2495  Radeon HD 7350\n\t\t1462 b490  Radeon HD 7350\n\t\t1642 3985  Radeon HD 7350\n\t\t174b 3510  Radeon HD 8350\n\t\t174b 3521  Radeon R5 220\n\t\t174b 3522  Radeon R5 220\n\t\t174b 7350  Radeon HD 7350\n\t\t174b 8153  Radeon HD 8350\n\t\t174b e127  Radeon HD 7350\n\t\t174b e153  Radeon HD 7350\n\t\t174b e180  Radeon HD 7350\n\t\t17af 3015  Radeon HD 7350\n\t68fe  Cedar LE\n\t6900  Topaz XT [Radeon R7 M260/M265 / M340/M360 / M440/M445 / 530/535 / 620/625 Mobile]\n\t\t1025 1056  Radeon R7 M360 / R8 M365DX\n\t\t1028 0640  Radeon R7 M260/M265\n\t\t1028 0643  Radeon R7 M260/M265\n\t\t1028 067f  Radeon R7 M260\n\t\t1028 0767  Radeon R7 M445\n\t\t1028 0810  Radeon 530\n\t\t1028 130a  Radeon R7 M260\n\t\t103c 2263  Radeon R7 M260\n\t\t103c 2269  Radeon R7 M260\n\t\t103c 22c6  Radeon R7 M260\n\t\t103c 22c8  Radeon R7 M260\n\t\t103c 2b45  Radeon R7 A360\n\t\t103c 808c  Radeon R7 M260\n\t\t103c 8099  Radeon R7 M360\n\t\t103c 80b5  Radeon R7 M360\n\t\t103c 80b9  Radeon R7 M360\n\t\t103c 811c  Radeon R7 M340\n\t\t103c 8226  Radeon R7 M440\n\t\t10cf 1906  Radeon R7 M260\n\t\t1170 9979  Radeon R7 M360\n\t\t1179 f903  Radeon R7 M260\n\t\t1179 f922  Radeon R7 M260\n\t\t1179 f923  Radeon R7 M260\n\t\t1179 f934  Radeon R7 M260\n\t\t17aa 3822  Radeon R7 M360\n\t\t17aa 3824  Radeon R7 M360\n\t\t17aa 5021  Radeon R7 M260\n\t6901  Topaz PRO [Radeon R5 M255]\n\t\t103c 1318  Radeon R6 M255DX\n\t6907  Meso XT [Radeon R5 M315]\n\t6921  Amethyst XT [Radeon R9 M295X]\n\t6929  Tonga XT GL [FirePro S7150]\n\t692b  Tonga PRO GL [FirePro W7100]\n\t\t13cc 3d2b  MXRT-7600\n\t692f  Tonga XTV GL [FirePro S7150V]\n\t6938  Tonga XT / Amethyst XT [Radeon R9 380X / R9 M295X]\n\t\t1043 04f5  Radeon R9 380X\n\t\t1043 04f7  Radeon R9 380X\n\t\t106b 013a  Radeon R9 M295X Mac Edition\n\t\t1458 22c8  Radeon R9 380X\n\t\t148c 2350  Radeon R9 380X\n\t\t1682 9385  Radeon R9 380X\n\t\t174b e308  Radeon R9 380X Nitro 4G D5\n\t\t17af 2006  Radeon R9 380X\n\t6939  Tonga PRO [Radeon R9 285/380]\n\t\t148c 9380  Radeon R9 380\n# Make naming scheme consistent\n\t\t174b e308  Radeon R9 380 Nitro 4G D5\n\t694c  Polaris 22 XT [Radeon RX Vega M GH]\n\t694e  Polaris 22 XL [Radeon RX Vega M GL]\n\t694f  Polaris 22 MGL XL [Radeon Pro WX Vega M GL]\n\t6980  Polaris12\n\t6981  Lexa XT [Radeon PRO WX 3200]\n\t6985  Lexa XT [Radeon PRO WX 3100]\n\t6986  Polaris12\n\t6987  Lexa [Radeon 540X/550X/630 / RX 640 / E9171 MCM]\n\t6995  Lexa XT [Radeon PRO WX 2100]\n\t699f  Lexa PRO [Radeon 540/540X/550/550X / RX 540X/550/550X]\n\t\t1028 1720  Radeon RX 550X\n\t\t148c 2380  Lexa XL [Radeon RX 550]\n\t\t1da2 e367  Lexa PRO [Radeon RX 550]\n\t69a0  Vega 12\n\t69a1  Vega 12\n\t69a2  Vega 12\n\t69a3  Vega 12\n\t69af  Vega 12 [Radeon Pro Vega 20]\n\t6fdf  Polaris 20 XL [Radeon RX 580 2048SP]\n\t700f  RS100 AGP Bridge\n\t7010  RS200/RS250 AGP Bridge\n\t7100  R520 [Radeon X1800 XT]\n\t7101  R520/M58 [Mobility Radeon X1800 XT]\n\t7102  R520/M58 [Mobility Radeon X1800]\n\t7104  R520 GL [FireGL V7200]\n\t\t13cc 3d0a  MXRT-5100\n\t7109  R520 [Radeon X1800 XL]\n\t\t1002 0322  All-in-Wonder X1800XL\n\t\t1002 0d02  Radeon X1800 CrossFire Edition\n\t710a  R520 [Radeon X1800 GTO]\n\t\t1002 0b12  Radeon X1800 GTO²\n\t710b  R520 [Radeon X1800 GTO]\n\t710e  R520 GL [FireGL V7300]\n\t\t13cc 3d0c  MXRT-5150\n\t710f  R520 GL [FireGL V7350]\n\t\t13cc 3d0e  MXRT-7100\n\t7120  R520 [Radeon X1800] (Secondary)\n\t7124  R520 GL [FireGL V7200] (Secondary)\n\t\t13cc 3d0b  MXRT-5100 (Secondary)\n\t7129  R520 [Radeon X1800] (Secondary)\n\t\t1002 0323  All-In-Wonder X1800 XL (Secondary)\n\t\t1002 0d03  Radeon X1800 CrossFire Edition (Secondary)\n\t712e  R520 GL [FireGL V7300] (Secondary)\n\t\t13cc 3d0d  MXRT-5150 (Secondary)\n\t712f  R520 GL [FireGL V7350] (Secondary)\n\t\t13cc 3d0f  MXRT-7100 (Secondary)\n\t7140  RV515 [Radeon X1300/X1550/X1600 Series]\n\t7142  RV515 PRO [Radeon X1300/X1550 Series]\n\t\t1002 0322  All-in-Wonder 2006 PCI-E Edition\n\t\t1043 0142  EAX1300PRO/TD/256M\n\t7143  RV505 [Radeon X1300/X1550 Series]\n\t7145  RV515/M54 [Mobility Radeon X1400]\n\t\t17aa 2006  Thinkpad T60 model 2007\n\t7146  RV515 [Radeon X1300/X1550]\n\t\t1002 0322  All-in-Wonder 2006 PCI-E Edition\n\t\t1545 1996  Radeon X1300 512MB PCI-e\n\t7147  RV505 [Radeon X1550 64-bit]\n\t7149  RV515/M52 [Mobility Radeon X1300]\n\t714a  RV515/M52 [Mobility Radeon X1300]\n\t7152  RV515 GL [FireGL V3300]\n\t7153  RV515 GL [FireGL V3350]\n\t715f  RV505 CE [Radeon X1550 64-bit]\n\t7162  RV515 PRO [Radeon X1300/X1550 Series] (Secondary)\n\t\t1002 0323  All-in-Wonder 2006 PCI-E Edition (Secondary)\n\t7163  RV505 [Radeon X1550 Series] (Secondary)\n\t7166  RV515 [Radeon X1300/X1550 Series] (Secondary)\n\t\t1002 0323  All-in-Wonder 2006 PCI-E Edition (Secondary)\n\t\t1545 1997  Radeon X1300 512MB PCI-e (Secondary)\n\t7167  RV515 [Radeon X1550 64-bit] (Secondary)\n\t7172  RV515 GL [FireGL V3300] (Secondary)\n\t7173  RV515 GL [FireGL V3350] (Secondary)\n\t7181  RV516 [Radeon X1600/X1650 Series]\n\t7183  RV516 [Radeon X1300/X1550 Series]\n\t7186  RV516/M64 [Mobility Radeon X1450]\n\t7187  RV516 [Radeon X1300/X1550 Series]\n\t7188  RV516/M64-S [Mobility Radeon X2300]\n\t\t103c 30c1  6910p\n\t718a  RV516/M64 [Mobility Radeon X2300]\n\t718b  RV516/M62 [Mobility Radeon X1350]\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t718c  RV516/M62-CSP64 [Mobility Radeon X1350]\n\t718d  RV516/M64-CSP128 [Mobility Radeon X1450]\n\t7193  RV516 [Radeon X1550 Series]\n\t7196  RV516/M62-S [Mobility Radeon X1350]\n\t719b  RV516 GL [FireMV 2250]\n\t\t13cc 3d12  MXRT-1150\n\t\t13cc 3d14  MXRT-2150\n\t719f  RV516 [Radeon X1550 Series]\n\t71a0  RV516 [Radeon X1300/X1550 Series] (Secondary)\n\t71a1  RV516 [Radeon X1600/X1650 Series] (Secondary)\n\t71a3  RV516 [Radeon X1300/X1550 Series] (Secondary)\n\t71a7  RV516 [Radeon X1300/X1550 Series] (Secondary)\n\t71bb  RV516 GL [FireMV 2250] (Secondary)\n\t\t13cc 3d13  MXRT-1150 (Secondary)\n\t\t13cc 3d15  MXRT-2150 (Secondary)\n\t71c0  RV530 [Radeon X1600 XT/X1650 GTO]\n\t\t1002 e160  Radeon X1650 GTO\n\t\t174b e160  Radeon X1650 GTO\n\t71c1  RV535 [Radeon X1650 PRO]\n\t\t174b 0880  Radeon X1700 FSC\n\t71c2  RV530 [Radeon X1600 PRO]\n\t71c4  RV530/M56 GL [Mobility FireGL V5200]\n\t\t17aa 2007  ThinkPad T60p\n\t71c5  RV530/M56-P [Mobility Radeon X1600]\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a3  Compaq NW8440\n\t\t1043 10b2  A6J-Q008\n\t\t106b 0080  MacBook Pro\n\t71c6  RV530LE [Radeon X1600/X1650 PRO]\n\t71c7  RV535 [Radeon X1650 PRO]\n\t\t1787 3000  PowerColor X1650 PRO AGP\n\t71ce  RV530 [Radeon X1300 XT/X1600 PRO]\n\t71d2  RV530 GL [FireGL V3400]\n\t\t13cc 3d08  MXRT-2100\n\t71d4  RV530/M66 GL [Mobility FireGL V5250]\n\t71d5  RV530/M66-P [Mobility Radeon X1700]\n\t71d6  RV530/M66-XT [Mobility Radeon X1700]\n\t71de  RV530/M66 [Mobility Radeon X1700/X2500]\n\t71e0  RV530 [Radeon X1600] (Secondary)\n\t\t174b e161  Radeon X1600 GTO (Secondary)\n\t71e1  RV535 [Radeon X1650 PRO] (Secondary)\n\t\t174b 0881  Radeon X1700 FSC (Secondary)\n\t71e2  RV530 [Radeon X1600] (Secondary)\n\t71e6  RV530 [Radeon X1650] (Secondary)\n\t71e7  RV535 [Radeon X1650 PRO] (Secondary)\n\t\t1787 3001  Radeon X1650 PRO AGP\n\t71f2  RV530 GL [FireGL V3400] (Secondary)\n\t\t13cc 3d09  MXRT-2100 (Secondary)\n\t7210  RV550/M71 [Mobility Radeon HD 2300]\n\t7211  RV550/M71 [Mobility Radeon X2300 HD]\n\t7240  R580+ [Radeon X1950 XTX]\n\t\t1002 0d02  Radeon X1950 CrossFire Edition\n\t7244  R580+ [Radeon X1950 XT]\n\t7248  R580 [Radeon X1950]\n\t7249  R580 [Radeon X1900 XT]\n\t\t1002 0412  All-In-Wonder X1900\n\t\t1002 0b12  Radeon X1900 XT/XTX\n\t\t1002 0d02  Radeon X1900 CrossFire Edition\n\t\t1043 0160  Radeon X1900 XTX 512 MB GDDR3\n\t724b  R580 [Radeon X1900 GT]\n\t\t1002 0b12  Radeon X1900 (Primary)\n\t\t1002 0b13  Radeon X1900 (Secondary)\n\t724e  R580 GL [FireGL V7350]\n\t7269  R580 [Radeon X1900 XT] (Secondary)\n\t726b  R580 [Radeon X1900 GT] (Secondary)\n\t726e  R580 [AMD Stream Processor] (Secondary)\n\t7280  RV570 [Radeon X1950 PRO]\n\t7288  RV570 [Radeon X1950 GT]\n\t7291  RV560 [Radeon X1650 XT]\n\t\t1462 0810  Radeon X1700 SE\n\t7293  RV560 [Radeon X1650 GT]\n\t72a0  RV570 [Radeon X1950 PRO] (Secondary)\n\t72a8  RV570 [Radeon X1950 GT] (Secondary)\n\t72b1  RV560 [Radeon X1650 XT] (Secondary)\n\t72b3  RV560 [Radeon X1650 GT] (Secondary)\n\t7300  Fiji [Radeon R9 FURY / NANO Series]\n\t\t1002 0b36  Radeon R9 FURY X / NANO\n\t\t1002 1b36  Radeon Pro Duo\n\t\t1043 049e  Radeon R9 FURY\n\t\t1043 04a0  Radeon R9 FURY X\n\t\t174b e329  Radeon R9 FURY\n\t7310  Navi 10\n\t731f  Navi 10 [Radeon RX 5700 / 5700 XT]\n\t7340  Navi 14 [Radeon RX 5500 / 5500M]\n\t7833  RS350 Host Bridge\n\t7834  RS350 [Radeon 9100 PRO/XT IGP]\n\t7835  RS350M [Mobility Radeon 9000 IGP]\n\t7838  RS350 AGP Bridge\n\t7910  RS690 Host Bridge\n\t\t1179 ff50  Satellite P305D-S8995E\n\t\t17f2 5000  KI690-AM2 Motherboard\n\t7911  RS690/RS740 Host Bridge\n\t\t1002 7910  RS690/RS740 Host Bridge\n\t7912  RS690/RS740 PCI to PCI Bridge (Internal gfx)\n\t7913  RS690 PCI to PCI Bridge (PCI Express Graphics Port 0)\n\t7915  RS690 PCI to PCI Bridge (PCI Express Port 1)\n\t7916  RS690 PCI to PCI Bridge (PCI Express Port 2)\n\t7917  RS690 PCI to PCI Bridge (PCI Express Port 3)\n\t\t1002 7910  RS690 PCI to PCI Bridge\n\t7919  RS690 HDMI Audio [Radeon Xpress 1200 Series]\n\t\t1179 7919  Satellite P305D-S8995E\n\t\t17f2 5000  KI690-AM2 Motherboard\n\t791e  RS690 [Radeon X1200]\n\t\t1462 7327  K9AG Neo2\n\t\t17f2 5000  KI690-AM2 Motherboard\n\t791f  RS690M [Radeon Xpress 1200/1250/1270]\n\t\t1179 ff50  Satellite P305D-S8995E\n\t7930  RS600 Host Bridge\n\t7932  RS600 PCI to PCI Bridge (Internal gfx)\n\t7933  RS600 PCI to PCI Bridge (PCI Express Graphics Port 0)\n\t7935  RS600 PCI to PCI Bridge (PCI Express Port 1)\n\t7936  RS600 PCI to PCI Bridge (PCI Express Port 2)\n\t7937  RS690 PCI to PCI Bridge (PCI Express Port 3)\n\t793b  RS600 HDMI Audio [Radeon Xpress 1250]\n\t793f  RS690M [Radeon Xpress 1200/1250/1270] (Secondary)\n\t7941  RS600 [Radeon Xpress 1250]\n\t7942  RS600M [Radeon Xpress 1250]\n\t796e  RS740 [Radeon 2100]\n\t\t105b 0e13  N15235/A74MX mainboard\n\t9400  R600 [Radeon HD 2900 PRO/XT]\n\t\t1002 2552  Radeon HD 2900 XT\n\t\t1002 3000  Radeon HD 2900 PRO\n\t\t1002 3142  HIS Radeon HD 2900XT 512MB GDDR3 VIVO PCIe\n\t9401  R600 [Radeon HD 2900 XT]\n\t9403  R600 [Radeon HD 2900 PRO]\n\t9405  R600 [Radeon HD 2900 GT]\n\t940a  R600 GL [FireGL V8650]\n\t\t13cc 3d16  MXRT-7200\n\t940b  R600 GL [FireGL V8600]\n\t940f  R600 GL [FireGL V7600]\n\t9440  RV770 [Radeon HD 4870]\n\t9441  R700 [Radeon HD 4870 X2]\n\t9442  RV770 [Radeon HD 4850]\n\t\t1002 0502  MSI Radeon HD 4850 512MB GDDR3\n\t\t174b e810  Radeon HD 4850 512MB GDDR3\n\t9443  R700 [Radeon HD 4850 X2]\n\t9444  RV770 GL [FirePro V8750]\n\t9446  RV770 GL [FirePro V7760]\n\t944a  RV770/M98L [Mobility Radeon HD 4850]\n\t944b  RV770/M98 [Mobility Radeon HD 4850 X2]\n\t944c  RV770 LE [Radeon HD 4830]\n\t944e  RV770 CE [Radeon HD 4710]\n\t\t174b 3261  Radeon HD 4810\n\t9450  RV770 GL [FireStream 9270]\n\t9452  RV770 GL [FireStream 9250]\n\t9456  RV770 GL [FirePro V8700]\n\t945a  RV770/M98-XT [Mobility Radeon HD 4870]\n\t9460  RV790 [Radeon HD 4890]\n\t9462  RV790 [Radeon HD 4860]\n\t946a  RV770 GL [FirePro M7750]\n\t9480  RV730/M96 [Mobility Radeon HD 4650/5165]\n\t\t103c 3628  Mobility Radeon HD 4650 [dv6-1190en]\n\t9488  RV730/M96-XT [Mobility Radeon HD 4670]\n\t9489  RV730/M96 GL [Mobility FireGL V5725]\n\t9490  RV730 XT [Radeon HD 4670]\n\t\t174b e880  Radeon HD 4670 512MB GDDR3 Dual DVI-I/TVO\n\t9491  RV730/M96-CSP [Radeon E4690]\n\t9495  RV730 [Radeon HD 4600 AGP Series]\n\t\t1002 0028  Radeon HD 4650/4670 AGP\n\t\t1092 0028  Radeon HD 4670 AGP 512MB DDR2\n\t\t1458 0028  Radeon HD 4650 AGP\n\t\t1682 0028  Radeon HD 4650 AGP\n\t\t174b 0028  Radeon HD 4650 AGP DDR2\n\t9498  RV730 PRO [Radeon HD 4650]\n\t949c  RV730 GL [FirePro V7750]\n\t\t13cc 3d1b  MXRT-7300\n\t949e  RV730 GL [FirePro V5700]\n\t949f  RV730 GL [FirePro V3750]\n\t94a0  RV740/M97 [Mobility Radeon HD 4830]\n\t94a1  RV740/M97-XT [Mobility Radeon HD 4860]\n\t94a3  RV740/M97 GL [FirePro M7740]\n\t94b3  RV740 PRO [Radeon HD 4770]\n\t94b4  RV740 PRO [Radeon HD 4750]\n\t94c1  RV610 [Radeon HD 2400 PRO/XT]\n\t\t1028 0211  Optiplex 755\n\t\t1028 0d02  Optiplex 755\n\t94c3  RV610 [Radeon HD 2400 PRO]\n\t\t1028 0302  Radeon HD 2400 Pro\n\t\t174b e400  Radeon HD 2400 PRO\n\t\t18bc 3550  Radeon HD 2400 PRO\n\t94c4  RV610 LE [Radeon HD 2400 PRO AGP]\n\t94c5  RV610 [Radeon HD 2400 LE]\n\t94c7  RV610 [Radeon HD 2350]\n\t94c8  RV610/M74 [Mobility Radeon HD 2400 XT]\n\t94c9  RV610/M72-S [Mobility Radeon HD 2400]\n\t\t1002 94c9  Radeon HD2400\n\t94cb  RV610 [Radeon E2400]\n\t94cc  RV610 LE [Radeon HD 2400 PRO PCI]\n\t9500  RV670 [Radeon HD 3850 X2]\n\t9501  RV670 [Radeon HD 3870]\n\t\t174b e620  Radeon HD 3870\n\t9504  RV670/M88 [Mobility Radeon HD 3850]\n\t9505  RV670 [Radeon HD 3690/3850]\n\t\t148c 3000  Radeon HD 3850\n\t\t174b 3000  Radeon HD 3690/3850\n\t\t1787 3000  Radeon HD 3690\n\t9506  RV670/M88 [Mobility Radeon HD 3850 X2]\n\t9507  RV670 [Radeon HD 3830]\n\t9508  RV670/M88-XT [Mobility Radeon HD 3870]\n\t9509  RV670/M88 [Mobility Radeon HD 3870 X2]\n\t950f  R680 [Radeon HD 3870 X2]\n\t9511  RV670 GL [FireGL V7700]\n\t9513  RV670 [Radeon HD 3850 X2]\n\t9515  RV670 PRO [Radeon HD 3850 AGP]\n\t9519  RV670 GL [FireStream 9170]\n\t9540  RV710 [Radeon HD 4550]\n\t954f  RV710 [Radeon HD 4350/4550]\n\t\t1462 1618  R4350 MD512H (MS-V161)\n\t9552  RV710/M92 [Mobility Radeon HD 4330/4350/4550]\n\t\t1028 1103  M92 [Mobility Radeon HD 4330]\n# GV-R435OC-512I/FF1\n\t\t1458 21ac  Radeon HD 4350\n# GV-R455HM-512I/F41\n\t\t1458 21ed  Radeon HD 4550\n# 113-100928-J01\n\t\t148c 3000  Radeon HD 4350 Go! Green 512MB GDDR3\n# 113-2E172001-003\n\t\t174b 3000  Radeon HD 4350/4550 HyperMemory DDR2\n\t9553  RV710/M92 [Mobility Radeon HD 4530/4570/545v]\n\t\t1025 015e  Mobility Radeon HD 4570\n\t\t1025 017d  Mobility Radeon HD 4570\n\t\t1025 0205  Mobility Radeon HD 4570 / 545v\n\t\t1025 0206  Mobility Radeon HD 4570\n\t\t1025 0237  Mobility Radeon HD 4570\n\t\t1028 02be  Mobility Radeon HD 4570 / 545v\n\t\t1028 02e8  Mobility Radeon HD 4530\n\t\t103c 143c  Mobility Radeon HD 545v\n\t\t103c 1446  Mobility Radeon HD 545v\n\t\t103c 3624  Mobility Radeon HD 4530\n\t\t103c 3628  Mobility Radeon HD 4530\n\t\t103c 3636  Mobility Radeon HD 4530\n\t\t1043 1b32  Mobility Radeon HD 4570\n\t\t1043 1b42  Mobility Radeon HD 4570\n\t\t104d 9056  Mobility Radeon HD 4570\n\t\t1179 ff82  Satellite L505-13T GPU (Mobility Radeon HD 5145)\n\t\t144d c07f  Mobility Radeon HD 545v\n\t\t144d c571  Mobility Radeon HD 545v\n\t\t1462 1006  Mobility Radeon HD 545v\n\t\t17aa 2129  Mobility Radeon HD 545v\n\t\t17aa 215b  Mobility Radeon HD 545v\n\t\t17aa 21bb  Mobility Radeon HD 545v\n\t9555  RV710/M92 [Mobility Radeon HD 4350/4550]\n\t\t103c 1411  ProBook 4720s GPU (Mobility Radeon HD 4350)\n\t9557  RV711 GL [FirePro RG220]\n\t955f  RV710/M92 [Mobility Radeon HD 4330]\n\t9580  RV630 [Radeon HD 2600 PRO]\n\t9581  RV630/M76 [Mobility Radeon HD 2600]\n\t9583  RV630/M76 [Mobility Radeon HD 2600 XT/2700]\n\t\t106b 0083  iMac 7,1\n\t\t1734 1107  Mobility Radeon HD 2700\n\t9586  RV630 XT [Radeon HD 2600 XT AGP]\n\t9587  RV630 PRO [Radeon HD 2600 PRO AGP]\n\t9588  RV630 XT [Radeon HD 2600 XT]\n\t\t1458 216c  Radeon HD 2600 XT, 256MB GDDR3, 2x DVI, TV-out, PCIe (GV-RX26T256H)\n\t9589  RV630 PRO [Radeon HD 2600 PRO]\n# Rebranded HD 2600 PRO\n\t\t1787 3000  Radeon HD 3610\n\t958a  RV630 [Radeon HD 2600 X2]\n\t958b  RV630/M76 [Mobility Radeon HD 2600 XT]\n\t958c  RV630 GL [FireGL V5600]\n\t\t13cc 3d18  MXRT-5200\n\t958d  RV630 GL [FireGL V3600]\n\t9591  RV635/M86 [Mobility Radeon HD 3650]\n\t\t1002 9591  Mobility Radeon HD 3650\n\t9593  RV635/M86 [Mobility Radeon HD 3670]\n\t9595  RV635/M86 GL [Mobility FireGL V5700]\n\t9596  RV635 PRO [Radeon HD 3650 AGP]\n\t\t1043 0028  EAH3650 SILENT/HTDI/512M/A\n\t9597  RV635 PRO [Radeon HD 3650 AGP]\n\t9598  RV635 [Radeon HD 3650/3750/4570/4580]\n\t\t1002 9598  Mobility Radeon HD 3600\n\t\t1043 01d6  EAH3650 Silent\n\t\t1043 3001  Radeon HD 4570\n\t\t174b 3001  Radeon HD 3750\n\t\t174b 4580  RV635 PRO [Radeon HD 4580]\n\t\t17af 3011  RV635 PRO [Radeon HD 4580]\n\t9599  RV635 PRO [Radeon HD 3650 AGP]\n\t95c0  RV620 PRO [Radeon HD 3470]\n\t\t1002 95c0  Mobility Radeon HD 3470\n\t95c2  RV620/M82 [Mobility Radeon HD 3410/3430]\n\t95c4  RV620/M82 [Mobility Radeon HD 3450/3470]\n\t\t1002 95c4  Mobility Radeon HD 3400\n\t95c5  RV620 LE [Radeon HD 3450]\n\t\t1028 0342  OptiPlex 980\n\t95c6  RV620 LE [Radeon HD 3450 AGP]\n\t95c9  RV620 LE [Radeon HD 3450 PCI]\n\t95cc  RV620 GL [FirePro V3700]\n\t95cd  RV620 GL [FirePro 2450]\n\t95cf  RV620 GL [FirePro 2260]\n\t960f  RS780 HDMI Audio [Radeon 3000/3100 / HD 3200/3300]\n\t9610  RS780 [Radeon HD 3200]\n\t\t1458 d000  GA-MA78GM-S2H Motherboard\n\t9611  RS780C [Radeon 3100]\n\t9612  RS780M [Mobility Radeon HD 3200]\n\t9613  RS780MC [Mobility Radeon HD 3100]\n\t9614  RS780D [Radeon HD 3300]\n\t9616  RS780L [Radeon 3000]\n\t9640  Sumo [Radeon HD 6550D]\n\t9641  Sumo [Radeon HD 6620G]\n\t9642  SuperSumo [Radeon HD 6370D]\n\t9643  SuperSumo [Radeon HD 6380G]\n\t9644  SuperSumo [Radeon HD 6410D]\n\t9645  SuperSumo [Radeon HD 6410D]\n\t9647  Sumo [Radeon HD 6520G]\n\t9648  Sumo [Radeon HD 6480G]\n\t9649  SuperSumo [Radeon HD 6480G]\n\t964a  Sumo [Radeon HD 6530D]\n\t964b  Sumo\n\t964c  Sumo\n\t964e  Sumo\n\t964f  Sumo\n\t970f  RS880 HDMI Audio [Radeon HD 4200 Series]\n\t\t1019 2120  A785GM-M\n\t\t1043 83a2  M4A785TD Motherboard\n\t\t1043 843e  M5A88-V EVO\n\t9710  RS880 [Radeon HD 4200]\n\t\t1019 2120  A785GM-M\n\t\t1043 83a2  M4A785TD Motherboard\n\t9712  RS880M [Mobility Radeon HD 4225/4250]\n\t9713  RS880M [Mobility Radeon HD 4100]\n\t9714  RS880 [Radeon HD 4290]\n\t9715  RS880 [Radeon HD 4250]\n\t\t1043 843e  M5A88-V EVO\n# Radeon HD 6250 too?\n\t9802  Wrestler [Radeon HD 6310]\n\t\t174b 1001  PURE Fusion Mini\n\t9803  Wrestler [Radeon HD 6310]\n\t9804  Wrestler [Radeon HD 6250]\n\t9805  Wrestler [Radeon HD 6250]\n\t9806  Wrestler [Radeon HD 6320]\n\t9807  Wrestler [Radeon HD 6290]\n\t9808  Wrestler [Radeon HD 7340]\n\t9809  Wrestler [Radeon HD 7310]\n\t980a  Wrestler [Radeon HD 7290]\n\t9830  Kabini [Radeon HD 8400 / R3 Series]\n\t9831  Kabini [Radeon HD 8400E]\n\t9832  Kabini [Radeon HD 8330]\n\t9833  Kabini [Radeon HD 8330E]\n\t9834  Kabini [Radeon HD 8210]\n\t9835  Kabini [Radeon HD 8310E]\n\t9836  Kabini [Radeon HD 8280 / R3 Series]\n\t9837  Kabini [Radeon HD 8280E]\n\t9838  Kabini [Radeon HD 8240 / R3 Series]\n\t9839  Kabini [Radeon HD 8180]\n\t983d  Temash [Radeon HD 8250/8280G]\n\t9840  Kabini HDMI/DP Audio\n\t9850  Mullins [Radeon R3 Graphics]\n\t9851  Mullins [Radeon R4/R5 Graphics]\n\t\t1179 f928  Beema [Radeon R5 Graphics]\n\t9852  Mullins [Radeon R2 Graphics]\n\t9853  Mullins [Radeon R2 Graphics]\n\t9854  Mullins [Radeon R3E Graphics]\n\t9855  Mullins [Radeon R6 Graphics]\n\t9856  Mullins [Radeon R1E/R2E Graphics]\n\t9857  Mullins [Radeon APU XX-2200M with R2 Graphics]\n\t9858  Mullins\n\t9859  Mullins\n\t985a  Mullins\n\t985b  Mullins\n\t985c  Mullins\n\t985d  Mullins\n\t985e  Mullins\n\t985f  Mullins\n\t9874  Wani [Radeon R5/R6/R7 Graphics]\n\t\t1002 1871  Radeon R5 Graphics\n\t\t1002 1e20  Radeon R7 Graphics\n\t\t1028 06bd  Radeon R6 Graphics\n\t\t103c 2b44  Radeon R6 Graphics\n\t\t103c 8221  Radeon R5 Graphics\n\t\t103c 8223  Radeon R5 Graphics\n\t\t103c 8238  Radeon R7 Graphics\n\t\t103c 8353  Radeon R7 Graphics\n\t\t1458 d000  Radeon R7 Graphics\n\t\t17aa 5113  Radeon R6 Graphics\n\t\t17aa 5116  Radeon R6 Graphics\n\t\t17aa 5118  Radeon R5 Graphics\n\t9890  Amur\n\t98c0  Nolan\n\t98e4  Stoney [Radeon R2/R3/R4/R5 Graphics]\n\t9900  Trinity [Radeon HD 7660G]\n\t\t103c 1985  Pavilion 17-e163sg Notebook PC\n# AMD A10-5800K CPU\n\t9901  Trinity [Radeon HD 7660D]\n\t9902  Trinity HDMI Audio Controller\n\t\t103c 194e  ProBook 455 G1 Notebook\n\t\t103c 1985  Pavilion 17-e163sg Notebook PC\n\t9903  Trinity [Radeon HD 7640G]\n\t\t103c 194e  ProBook 455 G1 Notebook\n\t\t103c 1952  ProBook 455 G1 Notebook\n\t9904  Trinity [Radeon HD 7560D]\n\t9905  Trinity GL [FirePro A300]\n\t9906  Trinity GL [FirePro A320]\n\t9907  Trinity [Radeon HD 7620G]\n\t9908  Trinity [Radeon HD 7600G]\n\t9909  Trinity [Radeon HD 7500G]\n\t990a  Trinity [Radeon HD 7500G]\n\t990b  Richland [Radeon HD 8650G]\n\t990c  Richland [Radeon HD 8670D]\n\t990d  Richland [Radeon HD 8550G]\n\t990e  Richland [Radeon HD 8570D]\n\t990f  Richland [Radeon HD 8610G]\n\t9910  Trinity [Radeon HD 7660G]\n\t9913  Trinity [Radeon HD 7640G]\n\t9917  Trinity [Radeon HD 7620G]\n\t9918  Trinity [Radeon HD 7600G]\n\t9919  Trinity [Radeon HD 7500G]\n\t991e  Bishop\n\t9920  Liverpool [Playstation 4 APU]\n\t9921  Liverpool HDMI/DP Audio Controller\n\t9922  Starshp\n\t9923  Starsha2 [Kingston/Clayton]\n\t9924  Gladius\n\t9925  Kingston/Clayton/Jupiter/Gladius/Montego HDMI Controller\n\t9926  Jupiter\n\t9990  Trinity 2 [Radeon HD 7520G]\n\t9991  Trinity 2 [Radeon HD 7540D]\n\t9992  Trinity 2 [Radeon HD 7420G]\n\t9993  Trinity 2 [Radeon HD 7480D]\n\t9994  Trinity 2 [Radeon HD 7400G]\n\t9995  Richland [Radeon HD 8450G]\n\t9996  Richland [Radeon HD 8470D]\n\t9997  Richland [Radeon HD 8350G]\n\t9998  Richland [Radeon HD 8370D]\n\t9999  Richland [Radeon HD 8510G]\n\t999a  Richland [Radeon HD 8410G]\n\t999b  Richland [Radeon HD 8310G]\n\t999c  Richland [Radeon HD 8650D]\n# AMD Quad-Core A8-Series APU A8-6500T with Radeon HD 8550D\n\t999d  Richland [Radeon HD 8550D]\n\t99a0  Trinity 2 [Radeon HD 7520G]\n\t99a2  Trinity 2 [Radeon HD 7420G]\n\t99a4  Trinity 2 [Radeon HD 7400G]\n\taa00  R600 HDMI Audio [Radeon HD 2900 GT/PRO/XT]\n\taa01  RV635 HDMI Audio [Radeon HD 3650/3730/3750]\n\taa08  RV630 HDMI Audio [Radeon HD 2600 PRO/XT / HD 3610]\n\taa10  RV610 HDMI Audio [Radeon HD 2350 PRO / 2400 PRO/XT / HD 3410]\n\t\t174b aa10  Radeon HD 2400 PRO\n\t\t18bc aa10  Radeon HD 2400 PRO\n\taa18  RV670/680 HDMI Audio [Radeon HD 3690/3800 Series]\n\taa20  RV635 HDMI Audio [Radeon HD 3650/3730/3750]\n\taa28  RV620 HDMI Audio [Radeon HD 3450/3470/3550/3570]\n\taa30  RV770 HDMI Audio [Radeon HD 4850/4870]\n\t\t174b aa30  Radeon HD 4850 512MB GDDR3 PCI-E Dual Slot Fansink\n\taa38  RV710/730 HDMI Audio [Radeon HD 4000 series]\n\t\t103c 3628  dv6-1190en\n\taa50  Cypress HDMI Audio [Radeon HD 5830/5850/5870 / 6850/6870 Rebrand]\n\taa58  Juniper HDMI Audio [Radeon HD 5700 Series]\n# 5500, 5600 and mobile 5700 series\n\taa60  Redwood HDMI Audio [Radeon HD 5000 Series]\n\t\t1025 033d  Mobility Radeon HD 5650\n\t\t1025 0347  Aspire 7740G\n\taa68  Cedar HDMI Audio [Radeon HD 5400/6300/7300 Series]\n\t\t1028 aa68  XPS 8300\n\taa80  Cayman/Antilles HDMI Audio [Radeon HD 6930/6950/6970/6990]\n\taa88  Barts HDMI Audio [Radeon HD 6790/6850/6870 / 7720 OEM]\n\taa90  Turks HDMI Audio [Radeon HD 6500/6600 / 6700M Series]\n\t\t1028 04a3  Precision M4600\n\taa98  Caicos HDMI Audio [Radeon HD 6450 / 7450/8450/8490 OEM / R5 230/235/235X OEM]\n\t\t174b aa98  Radeon HD 6450 1GB DDR3\n\taaa0  Tahiti HDMI Audio [Radeon HD 7870 XT / 7950/7970]\n\taab0  Oland/Hainan/Cape Verde/Pitcairn HDMI Audio [Radeon HD 7000 Series]\n\taab8  Tiran HDMI Audio\n\taac0  Tobago HDMI Audio [Radeon R7 360 / R9 360 OEM]\n\taac8  Hawaii HDMI Audio [Radeon R9 290/290X / 390/390X]\n\taad8  Tonga HDMI Audio [Radeon R9 285/380]\n\t\t174b aad8  Radeon R9 285/380 HDMI Audio\n\taae0  Baffin HDMI/DP Audio [Radeon RX 550 640SP / RX 560/560X]\n\taae8  Fiji HDMI/DP Audio [Radeon R9 Nano / FURY/FURY X]\n\taaf0  Ellesmere HDMI Audio [Radeon RX 470/480 / 570/580/590]\n\taaf8  Vega 10 HDMI Audio [Radeon Vega 56/64]\n\tab00  Baffin HDMI/DP Audio [Radeon RX 550 640SP / RX 560/560X]\n\tab08  Polaris 22 HDMI Audio\n\tab10  Lexa HDMI Audio\n\tab18  Vega 12 HDMI Audio\n\tab20  Vega 20 HDMI Audio [Radeon VII]\n\tab38  Navi 10 HDMI Audio\n\tac00  Theater 506 World-Wide Analog Decoder\n\tac01  Theater 506 World-Wide Analog Decoder\n\tac02  TV Wonder HD 600 PCIe\n\tac03  Theater 506 PCIe\n\tac04  Theater 506 USB\n\tac05  Theater 506 USB\n\tac06  Theater 506 External USB\n\tac07  Theater 506 External USB\n\tac08  Theater 506A World-Wide Analog Decoder + Demodulator\n\tac09  Theater 506A World-Wide Analog Decoder + Demodulator\n\tac0a  Theater 506A PCIe\n\tac0b  Theater 506A PCIe\n\tac0c  Theater 506A USB\n\tac0d  Theater 506A USB\n\tac0e  Theater 506A External USB\n\tac0f  Theater 506A External USB\n\tac12  Theater HD T507 (DVB-T) TV tuner/capture device\n\tcab0  RS100 Host Bridge\n\tcab2  RS200 Host Bridge\n\tcab3  RS250 Host Bridge\n\tcbb2  RS200 Host Bridge\n1003  ULSI Systems\n\t0201  US201\n1004  VLSI Technology Inc\n\t0005  82C592-FC1\n\t0006  82C593-FC1\n\t0007  82C594-AFC2\n\t0008  82C596/7 [Wildcat]\n\t0009  82C597-AFC2\n\t000c  82C541 [Lynx]\n\t000d  82C543 [Lynx]\n\t0101  82C532\n\t0102  82C534 [Eagle]\n\t0103  82C538\n\t0104  82C535\n\t0105  82C147\n\t0200  82C975\n\t0280  82C925\n\t0304  QSound ThunderBird PCI Audio\n\t\t1004 0304  QSound ThunderBird PCI Audio\n\t\t122d 1206  DSP368 Audio\n\t\t1483 5020  XWave Thunder 3D Audio\n\t0305  QSound ThunderBird PCI Audio Gameport\n\t\t1004 0305  QSound ThunderBird PCI Audio Gameport\n\t\t122d 1207  DSP368 Audio Gameport\n\t\t1483 5021  XWave Thunder 3D Audio Gameport\n\t0306  QSound ThunderBird PCI Audio Support Registers\n\t\t1004 0306  QSound ThunderBird PCI Audio Support Registers\n\t\t122d 1208  DSP368 Audio Support Registers\n\t\t1483 5022  XWave Thunder 3D Audio Support Registers\n\t0307  SAA7785 ThunderBird PCI Audio\n\t\t1004 0703  Philips Rhythmic Edge PSC703\n\t\t1004 0705  Philips Seismic Edge PSC705\n\t\t1004 0706  Philips Acoustic Edge PSC706\n\t0308  SAA7785 ThunderBird PCI Audio Gameport\n\t0702  VAS96011 [Golden Gate II]\n\t0703  Tollgate\n1005  Avance Logic Inc. [ALI]\n\t2064  ALG2032/2064\n\t2128  ALG2364A\n\t2301  ALG2301\n\t2302  ALG2302\n\t2364  ALG2364\n\t2464  ALG2364A\n\t2501  ALG2564A/25128A\n1006  Reply Group\n1007  NetFrame Systems Inc\n1008  Epson\n100a  Phoenix Technologies\n100b  National Semiconductor Corporation\n\t0001  DP83810\n\t0002  87415/87560 IDE\n\t000e  87560 Legacy I/O\n\t000f  FireWire Controller\n\t0011  NS87560 National PCI System I/O\n\t0012  USB Controller\n\t0020  DP83815 (MacPhyter) Ethernet Controller\n\t\t103c 0024  Pavilion ze4400 builtin Network\n\t\t12d9 000c  Aculab E1/T1 PMXc cPCI carrier card\n\t\t1385 f311  FA311 / FA312 (FA311 with WoL HW)\n\t\t1385 f312  FA312 (rev. A1) Fast Ethernet PCI Adapter\n\t0021  PC87200 PCI to ISA Bridge\n\t0022  DP83820 10/100/1000 Ethernet Controller\n\t\t1186 4900  DGE-500T\n\t\t1385 621a  GA621\n\t\t1385 622a  GA622T\n\t0028  Geode GX2 Host Bridge\n\t002a  CS5535 South Bridge\n\t002b  CS5535 ISA bridge\n\t002d  CS5535 IDE\n\t002e  CS5535 Audio\n\t002f  CS5535 USB\n\t0030  Geode GX2 Graphics Processor\n\t0035  DP83065 [Saturn] 10/100/1000 Ethernet Controller\n\t0500  SCx200 Bridge\n\t0501  SCx200 SMI\n\t0502  SCx200, SC1100 IDE controller\n\t\t100b 0502  IDE Controller\n\t0503  SCx200, SC1100 Audio Controller\n\t\t100b 0503  XpressAudio controller\n\t0504  SCx200 Video\n\t0505  SCx200 XBus\n\t0510  SC1100 Bridge\n\t\t100b 0500  GPIO and LPC support bridge\n\t0511  SC1100 SMI & ACPI\n\t\t100b 0501  SC1100 SMI & ACPI bridge\n\t0515  SC1100 XBus\n\t\t100b 0505  SC1100 PCI to XBus bridge\n\td001  87410 IDE\n100c  Tseng Labs Inc\n\t3202  ET4000/W32p rev A\n\t3205  ET4000/W32p rev B\n\t3206  ET4000/W32p rev C\n\t3207  ET4000/W32p rev D\n\t3208  ET6000\n\t4702  ET6300\n100d  AST Research Inc\n100e  Weitek\n\t9000  P9000 Viper\n\t9001  P9000 Viper\n\t9002  P9000 Viper\n\t9100  P9100 Viper Pro/SE\n1010  Video Logic, Ltd.\n1011  Digital Equipment Corporation\n\t0001  DECchip 21050\n\t0002  DECchip 21040 [Tulip]\n\t0004  DECchip 21030 [TGA]\n\t0007  NVRAM [Zephyr NVRAM]\n\t0008  KZPSA [KZPSA]\n\t0009  DECchip 21140 [FasterNet]\n\t\t1025 0310  21140 Fast Ethernet\n\t\t10b8 2001  SMC9332BDT EtherPower 10/100\n\t\t10b8 2002  SMC9332BVT EtherPower T4 10/100\n\t\t10b8 2003  SMC9334BDT EtherPower 10/100 (1-port)\n\t\t1109 2400  ANA-6944A/TX Fast Ethernet\n\t\t1112 2300  RNS2300 Fast Ethernet\n\t\t1112 2320  RNS2320 Fast Ethernet\n\t\t1112 2340  RNS2340 Fast Ethernet\n\t\t1113 1207  EN-1207-TX Fast Ethernet\n\t\t1186 1100  DFE-500TX Fast Ethernet\n\t\t1186 1112  DFE-570TX Fast Ethernet\n\t\t1186 1140  DFE-660 Cardbus Ethernet 10/100\n\t\t1186 1142  DFE-660 Cardbus Ethernet 10/100\n\t\t11f6 0503  Freedomline Fast Ethernet\n\t\t1282 9100  AEF-380TXD Fast Ethernet\n\t\t1385 1100  FA310TX Fast Ethernet\n\t\t2646 0001  KNE100TX Fast Ethernet\n\t000a  21230 Video Codec\n\t000d  PBXGB [TGA2]\n\t000f  DEFPA FDDI PCI-to-PDQ Interface Chip [PFI]\n\t\t1011 def1  FDDI controller (DEFPA)\n\t\t103c def1  FDDI controller (3X-DEFPA)\n\t0014  DECchip 21041 [Tulip Pass 3]\n\t\t1186 0100  DE-530+\n\t0016  DGLPB [OPPO]\n\t0017  PV-PCI Graphics Controller (ZLXp-L)\n\t0018  Memory Channel interface\n\t0019  DECchip 21142/43\n\t\t1011 500a  DE500A Fast Ethernet\n\t\t1011 500b  DE500B Fast Ethernet\n\t\t1014 0001  10/100 EtherJet Cardbus\n\t\t1025 0315  ALN315 Fast Ethernet\n\t\t1033 800c  PC-9821-CS01 100BASE-TX Interface Card\n\t\t1033 800d  PC-9821NR-B06 100BASE-TX Interface Card\n\t\t103c 125a  10/100Base-TX (PCI) [A5506B]\n\t\t108d 0016  Rapidfire 2327 10/100 Ethernet\n\t\t108d 0017  GoCard 2250 Ethernet 10/100 Cardbus\n\t\t10b8 2005  SMC8032DT Extreme Ethernet 10/100\n\t\t10b8 8034  SMC8034 Extreme Ethernet 10/100\n\t\t10ef 8169  Cardbus Fast Ethernet\n\t\t1109 2a00  ANA-6911A/TX Fast Ethernet\n\t\t1109 2b00  ANA-6911A/TXC Fast Ethernet\n\t\t1109 3000  ANA-6922/TX Fast Ethernet\n\t\t1113 1207  Cheetah Fast Ethernet\n\t\t1113 2220  Cardbus Fast Ethernet\n\t\t115d 0002  Cardbus Ethernet 10/100\n\t\t1179 0203  Fast Ethernet\n\t\t1179 0204  Cardbus Fast Ethernet\n\t\t1186 1100  DFE-500TX Fast Ethernet\n\t\t1186 1101  DFE-500TX Fast Ethernet\n\t\t1186 1102  DFE-500TX Fast Ethernet\n\t\t1186 1112  DFE-570TX Quad Fast Ethernet\n\t\t11f0 4235  21143 [FASTLine-II UTP 10/100]\n\t\t1259 2800  AT-2800Tx Fast Ethernet\n\t\t1266 0004  Eagle Fast EtherMAX\n\t\t12af 0019  NetFlyer Cardbus Fast Ethernet\n\t\t1374 0001  Cardbus Ethernet Card 10/100\n\t\t1374 0002  Cardbus Ethernet Card 10/100\n\t\t1374 0007  Cardbus Ethernet Card 10/100\n\t\t1374 0008  Cardbus Ethernet Card 10/100\n\t\t1385 2100  FA510\n\t\t1395 0001  10/100 Ethernet CardBus PC Card\n\t\t13d1 ab01  EtherFast 10/100 Cardbus (PCMPC200)\n\t\t1498 000a  TPMC880-10 10/100Base-T and 10Base2 PMC Ethernet Adapter\n\t\t1498 000b  TPMC880-11 Single 10/100Base-T PMC Ethernet Adapter\n\t\t1498 000c  TPMC880-12 Single 10Base2 PMC Ethernet Adapter\n\t\t14cb 0100  LNDL-100N 100Base-TX Ethernet PC Card\n\t\t1668 2000  FastNet Pro (PE2000)\n\t\t2646 0001  KNE100TX\n\t\t2646 0002  KNE-CB4TX\n\t\t8086 0001  EtherExpress PRO/100 Mobile CardBus 32\n\t001a  Farallon PN9000SX Gigabit Ethernet\n\t0021  DECchip 21052\n\t0022  DECchip 21150\n\t0023  DECchip 21150\n\t0024  DECchip 21152\n\t0025  DECchip 21153\n\t0026  DECchip 21154\n\t0034  56k Modem Cardbus\n\t\t1374 0003  56k Modem Cardbus\n\t0045  DECchip 21553\n\t0046  DECchip 21554\n\t\t0e11 4050  Smart Array 4200 Controller\n\t\t0e11 4051  Smart Array 4250ES Controller\n\t\t0e11 4058  Smart Array 431 Controller\n\t\t103c 10c2  NetRAID-4M\n\t\t12d9 000a  IP Telephony card\n\t\t4c53 1050  CT7 mainboard\n\t\t4c53 1051  CE7 mainboard\n\t\t9005 0364  5400S (Mustang)\n\t\t9005 0365  5400S (Mustang)\n\t\t9005 1364  Dell PowerEdge RAID Controller 2\n\t\t9005 1365  Dell PowerEdge RAID Controller 2\n\t\te4bf 1000  CC8-1-BLUES\n\t1065  StrongARM DC21285\n\t\t1069 0020  DAC960P / DAC1164P\n1012  Micronics Computers Inc\n1013  Cirrus Logic\n\t0038  GD 7548\n\t0040  GD 7555 Flat Panel GUI Accelerator\n\t004c  GD 7556 Video/Graphics LCD/CRT Ctrlr\n\t00a0  GD 5430/40 [Alpine]\n\t00a2  GD 5432 [Alpine]\n\t00a4  GD 5434-4 [Alpine]\n\t00a8  GD 5434-8 [Alpine]\n\t00ac  GD 5436 [Alpine]\n\t00b0  GD 5440\n\t00b8  GD 5446\n\t\t1af4 1100  QEMU Virtual Machine\n\t00bc  GD 5480\n\t\t1013 00bc  CL-GD5480\n\t00d0  GD 5462\n\t00d2  GD 5462 [Laguna I]\n\t00d4  GD 5464 [Laguna]\n\t00d5  GD 5464 BD [Laguna]\n\t00d6  GD 5465 [Laguna]\n\t\t13ce 8031  Barco Metheus 2 Megapixel, Dual Head\n\t\t13cf 8031  Barco Metheus 2 Megapixel, Dual Head\n\t00e8  GD 5436U\n\t1100  CL 6729\n\t1110  PD 6832 PCMCIA/CardBus Ctrlr\n\t1112  PD 6834 PCMCIA/CardBus Ctrlr\n\t1113  PD 6833 PCMCIA/CardBus Ctrlr\n\t1200  GD 7542 [Nordic]\n\t1202  GD 7543 [Viking]\n\t1204  GD 7541 [Nordic Light]\n\t4000  MD 5620 [CLM Data Fax Voice]\n\t4400  CD 4400\n\t6001  CS 4610/11 [CrystalClear SoundFusion Audio Accelerator]\n\t\t1014 1010  CS4610 SoundFusion Audio Accelerator\n\t6003  CS 4614/22/24/30 [CrystalClear SoundFusion Audio Accelerator]\n\t\t1013 4280  Crystal SoundFusion PCI Audio Accelerator\n\t\t1014 0153  ThinkPad 600X/A20m\n\t\t153b 112e  DMX XFire 1024\n\t\t153b 1136  SiXPack 5.1+\n\t\t1681 0050  Game Theater XP\n\t\t1681 a010  Gamesurround Fortissimo II\n\t\t1681 a011  Gamesurround Fortissimo III 7.1\n\t\t5053 3357  Santa Cruz\n\t6004  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]\n\t6005  Crystal CS4281 PCI Audio\n\t\t1013 4281  Crystal CS4281 PCI Audio\n\t\t10cf 10a8  Crystal CS4281 PCI Audio\n\t\t10cf 10a9  Crystal CS4281 PCI Audio\n\t\t10cf 10aa  Crystal CS4281 PCI Audio\n\t\t10cf 10ab  Crystal CS4281 PCI Audio\n\t\t10cf 10ac  Crystal CS4281 PCI Audio\n\t\t10cf 10ad  Crystal CS4281 PCI Audio\n\t\t10cf 10b4  Crystal CS4281 PCI Audio\n\t\t1179 0001  Crystal CS4281 PCI Audio\n\t\t14c0 000c  Crystal CS4281 PCI Audio\n1014  IBM\n\t0002  PCI to MCA Bridge\n\t0005  Processor to I/O Controller [Alta Lite]\n\t0007  Processor to I/O Controller [Alta MP]\n\t000a  PCI to ISA Bridge (IBM27-82376) [Fire Coral]\n\t0017  CPU to PCI Bridge\n\t0018  TR Auto LANstreamer\n\t001b  GXT-150P\n\t001c  Carrera\n\t001d  SCSI-2 FAST PCI Adapter (82G2675)\n\t0020  GXT1000 Graphics Adapter\n\t0022  PCI to PCI Bridge (IBM27-82351)\n\t002d  Processor to I/O Controller [Python]\n\t002e  SCSI RAID Adapter [ServeRAID]\n\t\t1014 002e  ServeRAID-3x\n\t\t1014 022e  ServeRAID-4H\n\t0031  2 Port Serial Adapter\n# AS400 iSeries PCI sync serial card\n\t\t1014 0031  2721 WAN IOA - 2 Port Sync Serial Adapter\n\t0036  PCI to 32-bit LocalBus Bridge [Miami]\n\t0037  PowerPC to PCI Bridge (IBM27-82660)\n\t003a  CPU to PCI Bridge\n\t003c  GXT250P/GXT255P Graphics Adapter\n\t003e  16/4 Token ring UTP/STP controller\n\t\t1014 003e  Token-Ring Adapter\n\t\t1014 00cd  Token-Ring Adapter + Wake-On-LAN\n\t\t1014 00ce  16/4 Token-Ring Adapter 2\n\t\t1014 00cf  16/4 Token-Ring Adapter Special\n\t\t1014 00e4  High-Speed 100/16/4 Token-Ring Adapter\n\t\t1014 00e5  16/4 Token-Ring Adapter 2 + Wake-On-LAN\n\t\t1014 016d  iSeries 2744 Card\n\t0045  SSA Adapter\n\t0046  MPIC interrupt controller\n\t0047  PCI to PCI Bridge\n\t0048  PCI to PCI Bridge\n\t0049  Warhead SCSI Controller\n\t004e  ATM Controller (14104e00)\n\t004f  ATM Controller (14104f00)\n\t0050  ATM Controller (14105000)\n\t0053  25 MBit ATM Controller\n\t0054  GXT500P/GXT550P Graphics Adapter\n\t0057  MPEG PCI Bridge\n\t0058  SSA Adapter [Advanced SerialRAID/X]\n\t005e  GXT800P Graphics Adapter\n\t007c  ATM Controller (14107c00)\n\t007d  3780IDSP [MWave]\n\t008b  EADS PCI to PCI Bridge\n\t008e  GXT3000P Graphics Adapter\n\t0090  GXT 3000P\n\t\t1014 008e  GXT-3000P\n\t0091  SSA Adapter\n\t0095  20H2999 PCI Docking Bridge\n\t0096  Chukar chipset SCSI controller\n\t\t1014 0097  iSeries 2778 DASD IOA\n\t\t1014 0098  iSeries 2763 DASD IOA\n\t\t1014 0099  iSeries 2748 DASD IOA\n\t009f  PCI 4758 Cryptographic Accelerator\n\t00a5  ATM Controller (1410a500)\n\t00a6  ATM 155MBPS MM Controller (1410a600)\n\t00b7  GXT2000P Graphics Adapter\n\t\t1092 00b8  FireGL1 AGP 32Mb\n\t00b8  GXT2000P Graphics Adapter\n\t00be  ATM 622MBPS Controller (1410be00)\n\t00dc  Advanced Systems Management Adapter (ASMA)\n\t00fc  CPC710 Dual Bridge and Memory Controller (PCI-64)\n\t0105  CPC710 Dual Bridge and Memory Controller (PCI-32)\n\t010f  Remote Supervisor Adapter (RSA)\n\t0142  Yotta Video Compositor Input\n\t\t1014 0143  Yotta Input Controller (ytin)\n\t0144  Yotta Video Compositor Output\n\t\t1014 0145  Yotta Output Controller (ytout)\n\t0156  405GP PLB to PCI Bridge\n\t015e  622Mbps ATM PCI Adapter\n\t0160  64bit/66MHz PCI ATM 155 MMF\n\t016e  GXT4000P Graphics Adapter\n\t0170  GXT6000P Graphics Adapter\n\t\t1092 0172  Fire GL2\n\t\t1092 0173  Fire GL3\n\t\t1092 0174  Fire GL4\n\t\t1092 0184  Fire GL4s\n\t017d  GXT300P Graphics Adapter\n\t0180  Snipe chipset SCSI controller\n\t\t1014 0241  iSeries 2757 DASD IOA\n\t\t1014 0264  Quad Channel PCI-X U320 SCSI RAID Adapter (2780)\n\t0188  EADS-X PCI-X to PCI-X Bridge\n\t01a7  PCI-X to PCI-X Bridge\n\t01bd  ServeRAID Controller\n\t\t1014 01bd  ServeRAID 4Lx\n\t\t1014 01be  ServeRAID-4M\n\t\t1014 01bf  ServeRAID-4L\n\t\t1014 0208  ServeRAID-4Mx\n\t\t1014 020e  ServeRAID-4Lx\n\t\t1014 022e  ServeRAID-4H\n\t\t1014 0258  ServeRAID-5i\n\t\t1014 0259  ServeRAID-5i\n\t01c1  64bit/66MHz PCI ATM 155 UTP\n\t01e6  Cryptographic Accelerator\n\t01ef  PowerPC 440GP PCI Bridge\n\t\t1734 102b  PCEAS PCI-X Dual Port ESCON Adapter\n\t\t1734 10f8  PCEAT PCI-Express Dual Port ESCON Adapter\n\t01ff  10/100 Mbps Ethernet\n\t0219  Multiport Serial Adapter\n\t\t1014 021a  Dual RVX\n\t\t1014 0251  Internal Modem/RVX\n\t\t1014 0252  Quad Internal Modem\n\t021b  GXT6500P Graphics Adapter\n\t021c  GXT4500P Graphics Adapter\n\t0233  GXT135P Graphics Adapter\n\t028c  Citrine chipset SCSI controller\n\t\t1014 028d  Dual Channel PCI-X DDR SAS RAID Adapter (572E)\n\t\t1014 02be  Dual Channel PCI-X DDR U320 SCSI RAID Adapter (571B)\n\t\t1014 02c0  Dual Channel PCI-X DDR U320 SCSI Adapter (571A)\n\t\t1014 030d  PCI-X DDR Auxiliary Cache Adapter (575B)\n\t02a1  Calgary PCI-X Host Bridge\n\t02bd  Obsidian chipset SCSI controller\n\t\t1014 02c1  PCI-X DDR 3Gb SAS Adapter (572A/572C)\n\t\t1014 02c2  PCI-X DDR 3Gb SAS RAID Adapter (572B/571D)\n\t\t1014 0338  PCI-X DDR Auxiliary Cache Adapter (575C)\n\t0302  Winnipeg PCI-X Host Bridge\n\t0308  CalIOC2 PCI-E Root Port\n\t0311  FC 5740/1954 4-Port 10/100/1000 Base-TX PCI-X Adapter for POWER\n\t0314  ZISC 036 Neural accelerator card\n\t032d  Axon - Cell Companion Chip\n\t\t1014 03a1  PCIe PowerXCell 8i Cell Accelerator Board\n\t0339  Obsidian-E PCI-E SCSI controller\n\t\t1014 030a  PCIe 3Gb SAS RAID Adapter (574E)\n\t\t1014 033a  PCIe 3Gb SAS Adapter (57B3)\n\t\t1014 035c  PCIe x8 Internal 3Gb SAS adapter (57CC)\n\t\t1014 0360  PCI-E Auxiliary Cache Adapter (57B7)\n\t033d  PCI-E IPR SAS Adapter (FPGA)\n\t\t1014 033c  PCIe2 1.8GB Cache 6Gb SAS RAID Adapter Tri-port (57B5)\n\t\t1014 0353  PCIe2 3.1GB Cache 6Gb SAS RAID Enclosure (57C3)\n\t\t1014 0354  PCIe2 6Gb SAS Adapter Dual-port (57C4)\n\t\t1014 0356  PCIe2 1.8GB Cache 6Gb SAS RAID & SSD Adapter (574D)\n\t\t1014 035f  PCIe2 6Gb SAS Adapter Quad-port (57B2)\n\t034a  PCI-E IPR SAS Adapter (ASIC)\n\t\t1014 033b  PCIe2 6Gb SAS RAID Adapter Quad-port (57B4)\n\t\t1014 0355  PCIe2 3.6GB Cache 6Gb SAS RAID Adapter Quad-port (57B1)\n\t\t1014 0357  PCIe2 6Gb SAS Adapter Quad-port (57C6)\n\t\t1014 035d  PCIe3 1.8GB Cache RAID SAS Adapter Quad-port 6GB (57C8)\n\t\t1014 035e  PCIe2 3.6GB Cache 6Gb SAS RAID Adapter Quad-port (57CE)\n\t\t1014 03fb  PCIe3 28GB Cache RAID SAS Enclosure 6Gb x 16 (57D5)\n\t\t1014 03fe  PCIe3 x8 Cache SAS RAID Internal Adapter 6Gb (57D8)\n\t\t1014 03ff  PCIe3 x8 SAS RAID Internal Adapter 6Gb (57D7)\n\t\t1014 0474  PCIe3 x16 Cache SAS RAID Internal Adapter 6Gb (57EB)\n\t\t1014 0475  PCIe3 x16 SAS RAID Internal Adapter 6Gb (57EC)\n\t\t1014 0499  PCIe3 x16 Cache SAS RAID Internal Adapter 6Gb (57ED)\n\t\t1014 049a  PCIe3 x16 SAS RAID Internal Adapter 6Gb (57EE)\n\t\t1014 04c7  PCIe3 x 8 Cache SAS RAID Internal Adapter 6GB(2CCA)\n\t\t1014 04c8  PCIe3 x 8 Cache SAS RAID Internal Adapter 6GB(2CD2)\n\t\t1014 04c9  PCIe3 x 8 Cache SAS RAID Internal Adapter 6GB(2CCD)\n\t03dc  POWER8 Host Bridge (PHB3)\n\t044b  GenWQE Accelerator Adapter\n\t04aa  Flash Adapter 90 (PCIe2 0.9TB)\n\t04c1  POWER9 Host Bridge (PHB4)\n\t04da  PCI-E IPR SAS+ Adapter (ASIC)\n\t\t1014 04fb  PCIe3 x16 20GB Cache 12Gb Quad SAS RAID+ Adapter(580B)\n\t\t1014 04fc  PCIe3 x8 12Gb Quad SAS RAID+ Adapter(580A)\n\t04ed  Internal Shared Memory (ISM) virtual PCI device\n\t3022  QLA3022 Network Adapter\n\t4022  QLA3022 Network Adapter\n\tffff  MPIC-2 interrupt controller\n1015  LSI Logic Corp of Canada\n1016  ICL Personal Systems\n1017  SPEA Software AG\n\t5343  SPEA 3D Accelerator\n1018  Unisys Systems\n1019  Elitegroup Computer Systems\n101a  AT&T GIS (NCR)\n\t0005  100VG ethernet\n\t0007  BYNET BIC4G/2C/2G\n\t\t101a 0019  BYNET BIC2C\n\t\t101a 001c  BYNET BIC2G\n\t\t101a 001f  BYNET BIC4G\n\t0009  PQS Memory Controller\n\t000a  BYNET BPCI Adapter\n\t000b  BYNET 4 Port BYA Switch (BYA4P)\n\t000c  BYNET 4 Port BYA Switch (BYA4G)\n\t0010  NCR AMC Memory Controller\n\t1dc1  BYNET BIC2M/BIC4M/BYA4M\n\t\t101a 0019  BIC2M\n\t\t101a 001f  BIC4M\n\t\t101a 0ece  BYA4M\n\t1fa8  BYNET Multi-port BIC Adapter (XBIC Based)\n\t\t101a 00c3  BYNET BIC2SE\n101b  Vitesse Semiconductor\n# Maxim VSC452 Super BMC Controller with Video\n\t0452  VSC452 [SuperBMC]\n101c  Western Digital\n\t0193  33C193A\n\t0196  33C196A\n\t0197  33C197A\n\t0296  33C296A\n\t3193  7193\n\t3197  7197\n\t3296  33C296A\n\t4296  34C296\n\t9710  Pipeline 9710\n\t9712  Pipeline 9712\n\tc24a  90C\n# ID for Newly Acquired Storage Products from Vitesse\n101d  Maxim Integrated Products\n101e  American Megatrends Inc.\n\t0009  MegaRAID 428 Ultra RAID Controller (rev 03)\n\t1960  MegaRAID\n\t\t101e 0471  MegaRAID 471 Enterprise 1600 RAID Controller\n\t\t101e 0475  MegaRAID 475 Express 500/500LC RAID Controller\n\t\t101e 0477  MegaRAID 477 Elite 3100 RAID Controller\n\t\t101e 0493  MegaRAID 493 Elite 1600 RAID Controller\n\t\t101e 0494  MegaRAID 494 Elite 1650 RAID Controller\n\t\t101e 0503  MegaRAID 503 Enterprise 1650 RAID Controller\n\t\t101e 0511  MegaRAID 511 i4 IDE RAID Controller\n\t\t101e 0522  MegaRAID 522 i4133 RAID Controller\n\t\t1028 0471  PowerEdge RAID Controller 3/QC\n\t\t1028 0475  PowerEdge RAID Controller 3/SC\n\t\t1028 0493  PowerEdge RAID Controller 3/DC\n\t\t1028 0511  PowerEdge Cost Effective RAID Controller ATA100/4Ch\n\t\t103c 60e7  NetRAID-1M\n\t\t103c 60e8  NetRaid 2M [AMI MegaRaid 493]\n\t9010  MegaRAID 428 Ultra RAID Controller\n\t9030  EIDE Controller\n\t9031  EIDE Controller\n\t9032  EIDE & SCSI Controller\n\t9033  SCSI Controller\n\t9040  Multimedia card\n\t9060  MegaRAID 434 Ultra GT RAID Controller\n\t9063  MegaRAC\n\t\t101e 0767  Dell Remote Assistant Card 2\n101f  PictureTel\n1020  Hitachi Computer Products\n1021  OKI Electric Industry Co. Ltd.\n1022  Advanced Micro Devices, Inc. [AMD]\n\t1100  K8 [Athlon64/Opteron] HyperTransport Technology Configuration\n\t1101  K8 [Athlon64/Opteron] Address Map\n\t1102  K8 [Athlon64/Opteron] DRAM Controller\n\t1103  K8 [Athlon64/Opteron] Miscellaneous Control\n\t1200  Family 10h Processor HyperTransport Configuration\n\t1201  Family 10h Processor Address Map\n\t1202  Family 10h Processor DRAM Controller\n\t1203  Family 10h Processor Miscellaneous Control\n\t1204  Family 10h Processor Link Control\n\t1300  Family 11h Processor HyperTransport Configuration\n\t1301  Family 11h Processor Address Map\n\t1302  Family 11h Processor DRAM Controller\n\t1303  Family 11h Processor Miscellaneous Control\n\t1304  Family 11h Processor Link Control\n\t1305  Griffin Function 5\n\t1306  Griffin Function 6\n\t1307  Griffin Function 7\n\t1308  Kaveri Audio Controller\n\t1314  Wrestler/Bheem/Ontario/Krishna Audio Controller\n\t13e0  Ariel Root Complex\n\t13e1  Ariel IOMMU\n\t13e2  Ariel PCIe Dummy Host Bridge\n\t13e3  Ariel PCIe GPP Bridge\n\t13e4  Ariel PCIe Dummy Host Bridge\n\t13e5  Ariel Internal PCIe GPP Bridge 0 to Bus A\n\t13e6  Ariel Internal PCIe GPP Bridge 0 to Bus B\n\t13e7  Ariel SMBus Controller\n\t13e8  Ariel LPC Bridge\n\t13e9  Ariel Internal GPU\n\t13ea  Ariel HD Audio Controller\n\t13eb  Ariel HD Audio Coprocessor\n\t13ec  Ariel Cryptographic Coprocessor\n\t13ed  Ariel USB 3.1 Type C: Gen2 x 1port + DP Alt Mode\n\t13ee  Ariel USB 3.1 Type A: Gen2 x 2 ports\n\t13ef  Ariel ZCN/MP4\n\t13f0  Ariel Device 24: Function 0\n\t13f1  Ariel Device 24: Function 1\n\t13f2  Ariel Device 24: Function 2\n\t13f3  Ariel Device 24: Function 3\n\t13f4  Ariel Device 24: Function 4\n\t13f5  Ariel Device 24: Function 5\n\t13f6  Ariel Device 24: Function 6\n\t13f7  Ariel Device 24: Function 7\n\t1400  Family 15h (Models 10h-1fh) Processor Function 0\n\t1401  Family 15h (Models 10h-1fh) Processor Function 1\n\t1402  Family 15h (Models 10h-1fh) Processor Function 2\n\t1403  Family 15h (Models 10h-1fh) Processor Function 3\n\t1404  Family 15h (Models 10h-1fh) Processor Function 4\n\t1405  Family 15h (Models 10h-1fh) Processor Function 5\n\t1410  Family 15h (Models 10h-1fh) Processor Root Complex\n\t\t103c 1985  Pavilion 17-e163sg Notebook PC\n\t1412  Family 15h (Models 10h-1fh) Processor Root Port\n\t\t1022 1234  Trinity A-series APU\n\t1413  Family 15h (Models 10h-1fh) Processor Root Port\n\t1414  Family 15h (Models 10h-1fh) Processor Root Port\n\t\t1022 1234  Trinity A-series APU\n\t1415  Family 15h (Models 10h-1fh) Processor Root Port\n\t1416  Family 15h (Models 10h-1fh) Processor Root Port\n\t1417  Family 15h (Models 10h-1fh) Processor Root Port\n\t1418  Family 15h (Models 10h-1fh) Processor Root Port\n\t1419  Family 15h (Models 10h-1fh) I/O Memory Management Unit\n\t141a  Family 15h (Models 30h-3fh) Processor Function 0\n\t141b  Family 15h (Models 30h-3fh) Processor Function 1\n\t141c  Family 15h (Models 30h-3fh) Processor Function 2\n\t141d  Family 15h (Models 30h-3fh) Processor Function 3\n\t141e  Family 15h (Models 30h-3fh) Processor Function 4\n\t141f  Family 15h (Models 30h-3fh) Processor Function 5\n\t1422  Family 15h (Models 30h-3fh) Processor Root Complex\n\t1423  Family 15h (Models 30h-3fh) I/O Memory Management Unit\n\t1424  Family 15h (Models 30h-3fh) Processor Root Port\n\t1425  Kaveri P2P Bridge for GFX PCIe Port [1:0]\n\t1426  Family 15h (Models 30h-3fh) Processor Root Port\n\t142e  Liverpool Processor HT configuration\n\t142f  Liverpool Processor Address Maps\n\t1430  Liverpool Processor DRAM configuration\n\t1431  Liverpool Processor Misc configuration\n\t1432  Liverpool Processor PM configuration\n\t1433  Liverpool Processor NB Performance Monitor\n\t1434  Liverpool Processor SPLL Configuration\n\t1436  Liverpool Processor Root Complex\n\t1437  Liverpool I/O Memory Management Unit\n\t1438  Liverpool UMI PCIe Dummy Host Bridge\n\t1439  Family 16h Processor Functions 5:1\n\t143a  Kingston/Clayton/Gladius/Montego Root Complex\n\t143b  Kingston/Clayton/Gladius/Montego P2P Bridge for UMI Link\n\t1440  Matisse Device 24: Function 0\n\t1441  Matisse Device 24: Function 1\n\t1442  Matisse Device 24: Function 2\n\t1443  Matisse Device 24: Function 3\n\t1444  Matisse Device 24: Function 4\n\t1445  Matisse Device 24: Function 5\n\t1446  Matisse Device 24: Function 6\n\t1447  Matisse Device 24: Function 7\n\t1448  Renoir Device 24: Function 0\n\t1449  Renoir Device 24: Function 1\n\t144a  Renoir Device 24: Function 2\n\t144b  Renoir Device 24: Function 3\n\t144c  Renoir Device 24: Function 4\n\t144d  Renoir Device 24: Function 5\n\t144e  Renoir Device 24: Function 6\n\t144f  Renoir Device 24: Function 7\n\t1450  Family 17h (Models 00h-0fh) Root Complex\n\t1451  Family 17h (Models 00h-0fh) I/O Memory Management Unit\n\t1452  Family 17h (Models 00h-1fh) PCIe Dummy Host Bridge\n\t1453  Family 17h (Models 00h-0fh) PCIe GPP Bridge\n\t1454  Family 17h (Models 00h-0fh) Internal PCIe GPP Bridge 0 to Bus B\n\t1455  Zeppelin/Renoir PCIe Dummy Function\n\t1456  Family 17h (Models 00h-0fh) Platform Security Processor\n\t1457  Family 17h (Models 00h-0fh) HD Audio Controller\n\t145a  Zeppelin/Raven/Raven2 PCIe Dummy Function\n\t145b  Zeppelin Non-Transparent Bridge\n\t145c  Family 17h (Models 00h-0fh) USB 3.0 Host Controller\n\t145d  Zeppelin Switch Upstream (PCIE SW.US)\n\t145e  Zeppelin Switch Downstream (PCIE SW.DS)\n\t145f  Zeppelin USB 3.0 Host controller\n\t1460  Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 0\n\t1461  Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 1\n\t1462  Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 2\n\t1463  Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 3\n\t1464  Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 4\n\t1465  Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 5\n\t1466  Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 6\n\t1467  Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 7\n\t1468  Zeppelin Cryptographic Coprocessor NTBCCP\n\t1480  Starship/Matisse Root Complex\n\t1481  Starship/Matisse IOMMU\n\t1482  Starship/Matisse PCIe Dummy Host Bridge\n\t1483  Starship/Matisse GPP Bridge\n\t1484  Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B]\n\t1485  Starship/Matisse Reserved SPP\n\t1486  Starship/Matisse Cryptographic Coprocessor PSPCPP\n\t1487  Starship/Matisse HD Audio Controller\n\t1488  Starship Reserved SSP\n\t1489  Starship Reserved SSP\n\t148a  Starship/Matisse PCIe Dummy Function\n\t148b  Starship/Matisse Non-Transparent Bridge\n\t148c  Starship USB 3.0 Host Controller\n\t148d  Starship/Matisse Switch Upstream (PCIE SW.US)\n\t148e  Starship/Matisse Switch Downstream (PCIE SW.DS)\n\t148f  Starship Reserved SSP\n\t1490  Starship Device 24; Function 0\n\t1491  Starship Device 24; Function 1\n\t1492  Starship Device 24; Function 2\n\t1493  Starship Device 24; Function 3\n\t1494  Starship Device 24; Function 4\n\t1495  Starship Device 24; Function 5\n\t1496  Starship Device 24; Function 6\n\t1497  Starship Device 24; Function 7\n\t1498  Starship/Matisse PTDMA\n\t1499  Starship/Matisse NVMe\n\t149a  Starship PCIe GPP Bridge [1:0]\n\t149b  Starship Reserved SSP\n\t149c  Matisse USB 3.0 Host Controller\n\t1510  Family 14h Processor Root Complex\n\t\t174b 1001  PURE Fusion Mini\n\t1512  Family 14h Processor Root Port\n\t1513  Family 14h Processor Root Port\n\t1514  Family 14h Processor Root Port\n\t1515  Family 14h Processor Root Port\n\t1516  Family 14h Processor Root Port\n\t1530  Family 16h Processor Function 0\n\t1531  Family 16h Processor Function 1\n\t1532  Family 16h Processor Function 2\n\t1533  Family 16h Processor Function 3\n\t1534  Family 16h Processor Function 4\n\t1535  Family 16h Processor Function 5\n\t1536  Family 16h Processor Root Complex\n\t1537  Kabini/Mullins PSP-Platform Security Processor\n\t1538  Family 16h Processor Function 0\n\t1539  Kabini P2P Bridge for PCIe Ports[4:0]\n\t1540  Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky HT Configuration\n\t1541  Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky Address Maps\n\t1542  Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky DRAM Configuration\n\t1543  Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky Miscellaneous Configuration\n\t1544  Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky PM Configuration\n\t1545  Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky NB Performance Monitor\n\t1546  Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky Root Complex\n\t1547  Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky IOMMU\n\t1548  Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky UMI PCIe Dummy Host Bridge\n\t1549  Kryptos/Cato/Garfield/Garfield+ P2P Bridge for PCIe Port [3:0]\n\t154a  Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky Audio Processor\n\t154b  Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky Security Processor\n\t154d  Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky/Anubis HDMI Controller\n\t154f  Anubis Audio Processor\n\t1550  Garfield+/Arlene/Pooky/Anubis SPLL Configuration\n\t1553  Arlene/Pooky P2P Bridge for PCIE (3:0)\n\t155b  Anubis Root Complex\n\t155c  Anubis IOMMU\n\t155d  Anubis UMI PCIe Dummy Bridge\n\t155e  Anubis P2P Bridge for PCIe Ports [4:0]\n\t1560  Anubis Security Processor\n\t1566  Family 16h (Models 30h-3fh) Processor Root Complex\n\t1567  Mullins IOMMU\n\t156b  Family 16h (Models 30h-3fh) Host Bridge\n\t1570  Family 15h (Models 60h-6fh) Processor Function 0\n\t1571  Family 15h (Models 60h-6fh) Processor Function 1\n\t1572  Family 15h (Models 60h-6fh) Processor Function 2\n\t1573  Family 15h (Models 60h-6fh) Processor Function 3\n\t1574  Family 15h (Models 60h-6fh) Processor Function 4\n\t1575  Family 15h (Models 60h-6fh) Processor Function 5\n\t1576  Family 15h (Models 60h-6fh) Processor Root Complex\n\t1577  Family 15h (Models 60h-6fh) I/O Memory Management Unit\n\t1578  Carrizo Platform Security Processor\n\t1579  Carrizo Audio Processor\n\t157a  Family 15h (Models 60h-6fh) Audio Controller\n\t157b  Family 15h (Models 60h-6fh) Host Bridge\n\t157c  Family 15h (Models 60h-6fh) Processor Root Port\n\t157d  Carrizo Audio Dummy Host Bridge\n\t157e  Carrizo Audio Controller\n\t1580  Family 16h (Models 30h-3fh) Processor Function 0\n\t1581  Family 16h (Models 30h-3fh) Processor Function 1\n\t1582  Family 16h (Models 30h-3fh) Processor Function 2\n\t1583  Family 16h (Models 30h-3fh) Processor Function 3\n\t1584  Family 16h (Models 30h-3fh) Processor Function 4\n\t1585  Family 16h (Models 30h-3fh) Processor Function 5\n\t1590  Amur/Nolan HT Configuration\n\t1591  Amur/Nolan Address Maps\n\t1592  Amur/Nolan DRAM Configuration\n\t1593  Amur/Nolan Miscellaneous Configuration\n\t1594  Amur/Nolan PM Configuration\n\t1595  Amur/Nolan NB Performance Monitor\n\t1596  Amur/Nolan Root Complex\n\t1597  Amur/Nolan IOMMU\n\t1598  Amur/Nolan Platform Security Processor\n\t1599  Amur/Nolan PCIe Dummy Host Bridge\n\t159d  Amur Function 6: Gasket\n\t15b0  Stoney HT Configuration\n\t15b1  Stoney Address Maps\n\t15b2  Stoney DRAM Configuration\n\t15b3  Stoney Miscellaneous Configuration\n\t15b4  Stoney PM Configuration\n\t15b5  Stoney NB Performance Monitor\n\t15bc  Stoney PCIe [GFX,GPP] Bridge [4:0]\n\t15be  Stoney Audio Processor\n\t15d0  Raven/Raven2 Root Complex\n\t\t103c 8615  Pavilion Laptop 15-cw1xxx\n\t15d1  Raven/Raven2 IOMMU\n\t\t103c 8615  Pavilion Laptop 15-cw1xxx\n\t15d2  Raven/Raven2 PCIe Dummy Host Bridge\n\t15d3  Raven/Raven2 PCIe GPP Bridge [6:0]\n\t15d4  FireFlight USB 3.1\n\t15d5  FireFlight USB 3.1\n\t15da  Raven/Raven2 PCIe Dummy Host Bridge\n\t15db  Raven/Raven2 Internal PCIe GPP Bridge 0 to Bus A\n\t15dc  Raven/Raven2 Internal PCIe GPP Bridge 0 to Bus B\n\t15de  Raven/Raven2/FireFlight HD Audio Controller\n\t15df  Family 17h (Models 10h-1fh) Platform Security Processor\n\t15e0  Raven USB 3.1\n\t\t103c 8615  Pavilion Laptop 15-cw1xxx\n\t15e1  Raven USB 3.1\n\t\t103c 8615  Pavilion Laptop 15-cw1xxx\n\t15e2  Raven/Raven2/FireFlight/Renoir Audio Processor\n\t15e3  Family 17h (Models 10h-1fh) HD Audio Controller\n\t\t103c 8615  Pavilion Laptop 15-cw1xxx\n\t15e4  Raven/Raven2/Renoir Sensor Fusion Hub\n\t15e5  Raven2 USB 3.1\n\t15e6  Raven/Raven2/Renoir Non-Sensor Fusion Hub KMDF driver\n\t\t1022 15e4  Raven/Raven2/Renoir Sensor Fusion Hub\n\t15e8  Raven/Raven2 Device 24: Function 0\n\t15e9  Raven/Raven2 Device 24: Function 1\n\t15ea  Raven/Raven2 Device 24: Function 2\n\t15eb  Raven/Raven2 Device 24: Function 3\n\t15ec  Raven/Raven2 Device 24: Function 4\n\t15ed  Raven/Raven2 Device 24: Function 5\n\t15ee  Raven/Raven2 Device 24: Function 6\n\t15ef  Raven/Raven2 Device 24: Function 7\n\t15f0  FireFlight Device 24: Function 0\n\t15f1  FireFlight Device 24: Function 1\n\t15f2  FireFlight Device 24: Function 2\n\t15f3  FireFlight Device 24: Function 3\n\t15f4  FireFlight Device 24: Function 4\n\t15f5  FireFlight Device 24: Function 5\n\t15f6  FireFlight Device 24: Function 6\n\t15f7  FireFlight Device 24: Function 7\n\t15f8  FireFlight Root Complex\n\t15f9  FireFlight IOMMU\n\t15fa  FireFlight PCIe Dummy Host Bridge\n\t15fb  FireFlight PCIe GPP Bride 3:0\n\t15fc  FireFlight PCIe Dummy Host Bridge\n\t15fd  FireFlight Internal PCIe GPP Bridge 0 to Bus A\n\t15fe  FireFlight Internal PCIe GPP Bridge 0 to Bus B\n\t15ff  FireFlight Bus A; Device 0: Function 0: Internal GPU\n\t1600  Family 15h Processor Function 0\n\t1601  Family 15h Processor Function 1\n\t1602  Family 15h Processor Function 2\n\t1603  Family 15h Processor Function 3\n\t1604  Family 15h Processor Function 4\n\t1605  Family 15h Processor Function 5\n\t1606  Arden Security Processor\n\t1608  Arden Device 18h: Function 0\n\t1609  Arden Device 18h: Function 1\n\t160a  Arden Device 18h: Function 2\n\t160b  Arden Device 18h: Function 3\n\t160c  Arden Device 18h: Function 4\n\t160d  Arden Device 18h: Function 5\n\t160e  Arden Device 18h: Function 6\n\t160f  Arden Device 18h: Function 7\n\t1620  Anubis HT Configuration\n\t1621  Anubis Address Maps\n\t1622  Anubis DRAM Configuration\n\t1623  Anubis Miscellaneous Configuration\n\t1624  Anubis PM Configuration\n\t1625  Anubis NB Performance Monitor\n\t1626  Arden Root Complex\n\t1627  Arden IOMMU\n\t1628  Arden PCIe Dummy Host Bridge\n\t1629  Arden PCIe GPP Bridge\n\t162a  Arden Internal PCIe GPP Bridge 0 to bus X\n\t162b  Arden PCIe Non-Transparent Bridge\n\t1630  Renoir Root Complex\n\t1631  Renoir IOMMU\n\t1632  Renoir PCIe Dummy Host Bridge\n\t1633  Renoir PCIe GPP Bridge\n\t1634  Renoir PCIe GPP Bridge\n\t1635  Renoir Internal PCIe GPP Bridge to Bus\n\t1637  Renoir HD Audio Controller\n\t1639  Renoir USB 3.1\n\t1641  Renoir 10GbE Controller Port 0 (XGBE0/1)\n\t1642  Renoir WLAN\n\t1643  Renoir BT\n\t1644  Renoir I2S\n\t1700  Family 12h/14h Processor Function 0\n\t1701  Family 12h/14h Processor Function 1\n\t1702  Family 12h/14h Processor Function 2\n\t1703  Family 12h/14h Processor Function 3\n\t1704  Family 12h/14h Processor Function 4\n\t1705  Family 12h Processor Root Complex\n\t1706  Llano P2P Bridge to external GPU\n\t1707  Family 12h Processor Root Port\n\t1708  Family 12h Processor Root Port\n\t1709  Family 12h Processor Root Port\n\t170a  Family 12h Processor Root Port\n\t170b  Family 12h Processor Root Port\n\t170c  Family 12h Processor Root Port\n\t170d  Family 12h Processor Root Port\n\t1716  Family 12h/14h Processor Function 5\n\t1718  Family 12h/14h Processor Function 6\n\t1719  Family 12h/14h Processor Function 7\n\t2000  79c970 [PCnet32 LANCE]\n\t\t1014 2000  NetFinity 10/100 Fast Ethernet\n\t\t1022 2000  PCnet - Fast 79C971\n\t\t103c 104c  Ethernet with LAN remote power Adapter\n\t\t103c 1064  Ethernet with LAN remote power Adapter\n\t\t103c 1065  Ethernet with LAN remote power Adapter\n\t\t103c 106c  Ethernet with LAN remote power Adapter\n\t\t103c 106e  Ethernet with LAN remote power Adapter\n\t\t103c 10ea  Ethernet with LAN remote power Adapter\n\t\t1113 1220  EN1220 10/100 Fast Ethernet\n\t\t1259 2450  AT-2450 10/100 Fast Ethernet\n\t\t1259 2454  AT-2450v4 10Mb Ethernet Adapter\n\t\t1259 2700  AT-2700TX 10/100 Fast Ethernet\n\t\t1259 2701  AT-2700FX 100Mb Ethernet\n\t\t1259 2702  AT-2700FTX 10/100 Mb Fiber/Copper Fast Ethernet\n\t\t1259 2703  AT-2701FX\n\t\t1259 2704  AT-2701FTX 10/100 Mb Fiber/Copper Fast Ethernet\n\t\t4c53 1000  CC7/CR7/CP7/VC7/VP7/VR7 mainboard\n\t\t4c53 1010  CP5/CR6 mainboard\n\t\t4c53 1020  VR6 mainboard\n\t\t4c53 1030  PC5 mainboard\n\t\t4c53 1040  CL7 mainboard\n\t\t4c53 1060  PC7 mainboard\n\t2001  79c978 [HomePNA]\n\t\t1092 0a78  Multimedia Home Network Adapter\n\t\t1668 0299  ActionLink Home Network Adapter\n\t2003  Am 1771 MBW [Alchemy]\n\t2020  53c974 [PCscsi]\n\t\t1af4 1100  QEMU Virtual Machine\n\t2040  79c974\n\t2080  CS5536 [Geode companion] Host Bridge\n\t2081  Geode LX Video\n\t2082  Geode LX AES Security Block\n\t208f  CS5536 GeodeLink PCI South Bridge\n\t2090  CS5536 [Geode companion] ISA\n\t2091  CS5536 [Geode companion] FLASH\n\t2093  CS5536 [Geode companion] Audio\n\t2094  CS5536 [Geode companion] OHC\n\t2095  CS5536 [Geode companion] EHC\n\t2096  CS5536 [Geode companion] UDC\n\t2097  CS5536 [Geode companion] UOC\n\t209a  CS5536 [Geode companion] IDE\n\t3000  ELanSC520 Microcontroller\n\t43a0  Hudson PCI to PCI bridge (PCIE port 0)\n\t43a1  Hudson PCI to PCI bridge (PCIE port 1)\n\t43a2  Hudson PCI to PCI bridge (PCIE port 2)\n\t43a3  Hudson PCI to PCI bridge (PCIE port 3)\n\t43b0  X370 Series Chipset PCIe Upstream Port\n\t\t1849 43c6  Fatal1ty X370 Professional Gaming\n\t43b1  X399 Series Chipset PCIe Bridge\n\t43b4  300 Series Chipset PCIe Port\n\t43b5  X370 Series Chipset SATA Controller\n\t\t1849 43c8  Fatal1ty X370 Professional Gaming\n\t43b6  X399 Series Chipset SATA Controller\n\t43b7  300 Series Chipset SATA Controller\n\t43b9  X370 Series Chipset USB 3.1 xHCI Controller\n\t\t1849 43d0  Fatal1ty X370 Professional Gaming\n\t43ba  X399 Series Chipset USB 3.1 xHCI Controller\n\t43bb  300 Series Chipset USB 3.1 xHCI Controller\n\t43c6  400 Series Chipset PCIe Bridge\n\t43c7  400 Series Chipset PCIe Port\n\t43c8  400 Series Chipset SATA Controller\n\t43d5  400 Series Chipset USB 3.1 XHCI Controller\n\t7006  AMD-751 [Irongate] System Controller\n\t7007  AMD-751 [Irongate] AGP Bridge\n\t700a  AMD-IGR4 AGP Host to PCI Bridge\n\t700b  AMD-IGR4 PCI to PCI Bridge\n\t700c  AMD-760 MP [IGD4-2P] System Controller\n\t700d  AMD-760 MP [IGD4-2P] AGP Bridge\n\t700e  AMD-760 [IGD4-1P] System Controller\n\t700f  AMD-760 [IGD4-1P] AGP Bridge\n\t7400  AMD-755 [Cobra] ISA\n\t7401  AMD-755 [Cobra] IDE\n\t7403  AMD-755 [Cobra] ACPI\n\t7404  AMD-755 [Cobra] USB\n\t7408  AMD-756 [Viper] ISA\n\t7409  AMD-756 [Viper] IDE\n\t740b  AMD-756 [Viper] ACPI\n\t740c  AMD-756 [Viper] USB\n\t7410  AMD-766 [ViperPlus] ISA\n\t7411  AMD-766 [ViperPlus] IDE\n\t7413  AMD-766 [ViperPlus] ACPI\n\t7414  AMD-766 [ViperPlus] USB\n\t7440  AMD-768 [Opus] ISA\n\t\t1043 8044  A7M-D Mainboard\n\t7441  AMD-768 [Opus] IDE\n\t7443  AMD-768 [Opus] ACPI\n\t\t1043 8044  A7M-D Mainboard\n\t7445  AMD-768 [Opus] Audio\n\t7446  AMD-768 [Opus] MC97 Modem\n\t7448  AMD-768 [Opus] PCI\n\t7449  AMD-768 [Opus] USB\n\t7450  AMD-8131 PCI-X Bridge\n\t7451  AMD-8131 PCI-X IOAPIC\n\t7454  AMD-8151 System Controller\n\t7455  AMD-8151 AGP Bridge\n\t7458  AMD-8132 PCI-X Bridge\n\t7459  AMD-8132 PCI-X IOAPIC\n\t7460  AMD-8111 PCI\n\t\t161f 3017  HDAMB\n\t7461  AMD-8111 USB\n\t7462  AMD-8111 Ethernet\n\t7463  AMD-8111 USB EHCI\n\t7464  AMD-8111 USB OHCI\n\t\t161f 3017  HDAMB\n\t7468  AMD-8111 LPC\n\t\t161f 3017  HDAMB\n\t7469  AMD-8111 IDE\n\t\t1022 2b80  AMD-8111 IDE [Quartet]\n\t\t161f 3017  HDAMB\n\t746a  AMD-8111 SMBus 2.0\n\t746b  AMD-8111 ACPI\n\t\t161f 3017  HDAMB\n\t746d  AMD-8111 AC97 Audio\n\t\t161f 3017  HDAMB\n\t746e  AMD-8111 MC97 Modem\n\t756b  AMD-8111 ACPI\n\t7800  FCH SATA Controller [IDE mode]\n\t7801  FCH SATA Controller [AHCI mode]\n\t\t103c 168b  ProBook 4535s Notebook\n\t\t103c 194e  ProBook 455 G1 Notebook\n\t7802  FCH SATA Controller [RAID mode]\n\t7803  FCH SATA Controller [RAID mode]\n\t7804  FCH SATA Controller [AHCI mode]\n\t\t103c 1985  Pavilion 17-e163sg Notebook PC\n\t7805  FCH SATA Controller [RAID mode]\n\t7806  FCH SD Flash Controller\n\t7807  FCH USB OHCI Controller\n\t\t103c 194e  ProBook 455 G1 Notebook\n\t\t103c 1985  Pavilion 17-e163sg Notebook PC\n\t7808  FCH USB EHCI Controller\n\t\t103c 194e  ProBook 455 G1 Notebook\n\t\t103c 1985  Pavilion 17-e163sg Notebook PC\n\t7809  FCH USB OHCI Controller\n\t\t103c 194e  ProBook 455 G1 Notebook\n\t780a  Kabini/Mullins SATA Raid/AHCI Mode (DotHill driver)\n\t780b  FCH SMBus Controller\n\t\t103c 194e  ProBook 455 G1 Notebook\n\t\t103c 1985  Pavilion 17-e163sg Notebook PC\n\t780c  FCH IDE Controller\n\t780d  FCH Azalia Controller\n\t\t103c 194e  ProBook 455 G1 Notebook\n\t\t103c 1985  Pavilion 17-e163sg Notebook PC\n\t\t1043 8444  F2A85-M Series\n\t780e  FCH LPC Bridge\n\t\t103c 194e  ProBook 455 G1 Notebook\n\t\t103c 1985  Pavilion 17-e163sg Notebook PC\n\t780f  FCH PCI Bridge\n\t7812  FCH USB XHCI Controller\n\t7813  FCH SD Flash Controller\n\t7814  FCH USB XHCI Controller\n\t\t103c 194e  ProBook 455 G1 Notebook\n\t\t103c 1985  Pavilion 17-e163sg Notebook PC\n\t7900  FCH SATA Controller [IDE mode]\n\t7901  FCH SATA Controller [AHCI mode]\n\t\t103c 8615  Pavilion Laptop 15-cw1xxx\n\t7902  FCH SATA Controller [RAID mode]\n\t7903  FCH SATA Controller [RAID mode]\n\t7904  FCH SATA Controller [AHCI mode]\n\t7906  FCH SD Flash Controller\n\t7908  FCH USB EHCI Controller\n\t790b  FCH SMBus Controller\n\t\t103c 8615  Pavilion Laptop 15-cw1xxx\n\t790e  FCH LPC Bridge\n\t\t103c 8615  Pavilion Laptop 15-cw1xxx\n\t790f  FCH PCI Bridge\n\t7914  FCH USB XHCI Controller\n\t9600  RS780 Host Bridge\n\t\t1043 82ee  M378A-CM Motherboard\n\t\t1043 82f1  M3A78-EH Motherboard\n\t9601  RS880 Host Bridge\n\t\t1019 2120  A785GM-M\n\t\t1043 83a2  M4A785-M Mainboard\n\t\t1043 843e  M5A88-V EVO\n\t9602  RS780/RS880 PCI to PCI bridge (int gfx)\n\t9603  RS780 PCI to PCI bridge (ext gfx port 0)\n\t9604  RS780/RS880 PCI to PCI bridge (PCIE port 0)\n\t9605  RS780/RS880 PCI to PCI bridge (PCIE port 1)\n\t9606  RS780 PCI to PCI bridge (PCIE port 2)\n\t9607  RS780/RS880 PCI to PCI bridge (PCIE port 3)\n\t9608  RS780/RS880 PCI to PCI bridge (PCIE port 4)\n\t9609  RS780/RS880 PCI to PCI bridge (PCIE port 5)\n\t960a  RS780 PCI to PCI bridge (NB-SB link)\n\t960b  RS780 PCI to PCI bridge (ext gfx port 1)\n1023  Trident Microsystems\n\t0194  82C194\n\t2000  4DWave DX\n\t2001  4DWave NX\n\t\t122d 1400  Trident PCI288-Q3DII (NX)\n\t2100  CyberBlade XP4m32\n\t2200  XGI Volari XP5\n\t8400  CyberBlade/i7\n\t\t1023 8400  CyberBlade i7 AGP\n\t8420  CyberBlade/i7d\n\t\t0e11 b15a  CyberBlade i7 AGP\n\t8500  CyberBlade/i1\n\t8520  CyberBlade i1\n\t\t0e11 b16e  CyberBlade i1 AGP\n\t\t1023 8520  CyberBlade i1 AGP\n\t8620  CyberBlade/i1\n\t\t1014 0502  ThinkPad R30/T30\n\t\t1014 1025  Travelmate 352TE\n\t8820  CyberBlade XPAi1\n\t9320  TGUI 9320\n\t9350  GUI Accelerator\n\t9360  Flat panel GUI Accelerator\n\t9382  Cyber 9382 [Reference design]\n\t9383  Cyber 9383 [Reference design]\n\t9385  Cyber 9385 [Reference design]\n\t9386  Cyber 9386\n\t9388  Cyber 9388\n\t9397  Cyber 9397\n\t939a  Cyber 9397DVD\n\t9420  TGUI 9420\n\t9430  TGUI 9430\n\t9440  TGUI 9440\n\t9460  TGUI 9460\n\t9470  TGUI 9470\n\t9520  Cyber 9520\n\t9525  Cyber 9525\n\t9540  Cyber 9540\n\t9660  TGUI 9660/938x/968x\n\t9680  TGUI 9680\n\t9682  TGUI 9682\n\t9683  TGUI 9683\n\t9685  ProVIDIA 9685\n\t9750  3DImage 9750\n\t\t1014 9750  3DImage 9750\n\t\t1023 9750  3DImage 9750\n\t9753  TGUI 9753\n\t9754  TGUI 9754\n\t9759  TGUI 975\n\t9783  TGUI 9783\n\t9785  TGUI 9785\n\t9850  3DImage 9850\n\t9880  Blade 3D PCI/AGP\n\t\t1023 9880  Blade 3D\n\t9910  CyberBlade/XP\n\t9930  CyberBlade/XPm\n\t9960  CyberBlade XP2\n1024  Zenith Data Systems\n1025  Acer Incorporated [ALI]\n\t1435  M1435\n\t1445  M1445\n\t1449  M1449\n\t1451  M1451\n\t1461  M1461\n\t1489  M1489\n\t1511  M1511\n\t1512  ALI M1512 Aladdin\n\t1513  M1513\n\t1521  ALI M1521 Aladdin III CPU Bridge\n\t\t10b9 1521  ALI M1521 Aladdin III CPU Bridge\n\t1523  ALI M1523 ISA Bridge\n\t\t10b9 1523  ALI M1523 ISA Bridge\n\t1531  M1531 Northbridge [Aladdin IV/IV+]\n\t1533  M1533 PCI-to-ISA Bridge\n\t\t10b9 1533  ALI M1533 Aladdin IV/V ISA South Bridge\n\t1535  M1535 PCI Bridge + Super I/O + FIR\n\t1541  M1541 Northbridge [Aladdin V]\n\t\t10b9 1541  ALI M1541 Aladdin V/V+ AGP+PCI North Bridge\n\t1542  M1542 Northbridge [Aladdin V]\n\t1543  M1543 PCI-to-ISA Bridge + Super I/O + FIR\n\t1561  M1561 Northbridge [Aladdin 7]\n\t1621  M1621 Northbridge [Aladdin-Pro II]\n\t1631  M1631 Northbridge+3D Graphics [Aladdin TNT2]\n\t1641  M1641 Northbridge [Aladdin-Pro IV]\n\t1647  M1647 [MaGiK1] PCI North Bridge\n\t1671  M1671 Northbridge [ALADDiN-P4]\n\t1672  Northbridge [CyberALADDiN-P4]\n\t3141  M3141\n\t3143  M3143\n\t3145  M3145\n\t3147  M3147\n\t3149  M3149\n\t3151  M3151\n\t3307  M3307 MPEG-I Video Controller\n\t3309  M3309 MPEG-II Video w/ Software Audio Decoder\n\t3321  M3321 MPEG-II Audio/Video Decoder\n\t5212  M4803\n\t5215  ALI PCI EIDE Controller\n\t5217  M5217H\n\t5219  M5219\n\t5225  M5225\n\t5229  M5229\n\t5235  M5235\n\t5237  M5237 PCI USB Host Controller\n\t5240  EIDE Controller\n\t5241  PCMCIA Bridge\n\t5242  General Purpose Controller\n\t5243  PCI to PCI Bridge Controller\n\t5244  Floppy Disk Controller\n\t5247  M1541 PCI to PCI Bridge\n\t5251  M5251 P1394 Controller\n\t5427  PCI to AGP Bridge\n\t5451  M5451 PCI AC-Link Controller Audio Device\n\t5453  M5453 PCI AC-Link Controller Modem Device\n\t7101  M7101 PCI PMU Power Management Controller\n\t\t10b9 7101  M7101 PCI PMU Power Management Controller\n# should be 1022:9602\n\t9602  AMD RS780/RS880 PCI to PCI bridge (int gfx)\n1028  Dell\n\t0001  PowerEdge Expandable RAID Controller 2/Si\n\t\t1028 0001  PowerEdge 2400\n\t0002  PowerEdge Expandable RAID Controller 3/Di\n\t\t1028 0002  PowerEdge 4400\n\t\t1028 00d1  PERC 3/DiV [Viper]\n\t\t1028 00d9  PERC 3/DiL [Lexus]\n\t0003  PowerEdge Expandable RAID Controller 3/Si\n\t\t1028 0003  PowerEdge 2450\n# PowerEdge Codename Iguana\n\t0004  PowerEdge Expandable RAID Controller 3/Di [Iguana]\n\t\t1028 0004  PERC 3/DiF [Iguana]\n\t0006  PowerEdge Expandable RAID Controller 3/Di\n\t0007  Remote Access Card III\n\t0008  Remote Access Card III\n\t0009  Remote Access Card III: BMC/SMIC device not present\n\t000a  PowerEdge Expandable RAID Controller 3/Di\n\t\t1028 0106  PERC 3/DiJ [Jaguar]\n\t\t1028 011b  PERC 3/DiD [Dagger]\n\t\t1028 0121  PERC 3/DiB [Boxster]\n\t000c  Embedded Remote Access or ERA/O\n\t000d  Embedded Remote Access: BMC/SMIC device\n\t000e  PowerEdge Expandable RAID controller 4/Di\n\t000f  PowerEdge Expandable RAID controller 4/Di\n\t\t1028 014a  PowerEdge 1750\n\t0010  Remote Access Card 4\n\t0011  Remote Access Card 4 Daughter Card\n\t0012  Remote Access Card 4 Daughter Card Virtual UART\n\t0013  PowerEdge Expandable RAID controller 4\n\t\t1028 016c  PowerEdge Expandable RAID Controller 4e/Si\n\t\t1028 016d  PowerEdge Expandable RAID Controller 4e/Di\n\t\t1028 016e  PowerEdge Expandable RAID Controller 4e/Di\n\t\t1028 016f  PowerEdge Expandable RAID Controller 4e/Di\n\t\t1028 0170  PowerEdge Expandable RAID Controller 4e/Di\n\t0014  Remote Access Card 4 Daughter Card SMIC interface\n\t0015  PowerEdge Expandable RAID controller 5\n\t\t1028 1f01  PERC 5/E Adapter RAID Controller\n\t\t1028 1f02  PERC 5/i Adapter RAID Controller\n\t\t1028 1f03  PERC 5/i Integrated RAID Controller\n\t0016  PowerEdge Expandable RAID controller S300\n\t\t1028 1f24  PERC S300 Controller\n# NV-RAM Adapter used in Dell DR appliances\n\t0073  NV-RAM Adapter\n1029  Siemens Nixdorf IS\n102a  LSI Logic\n\t0000  HYDRA\n\t0010  ASPEN\n\t001f  AHA-2940U2/U2W /7890/7891 SCSI Controllers\n\t\t9005 000f  2940U2W SCSI Controller\n\t\t9005 0106  2940U2W SCSI Controller\n\t\t9005 a180  2940U2W SCSI Controller\n\t00c5  AIC-7899 U160/m SCSI Controller\n\t\t1028 00c5  PowerEdge 2550/2650/4600\n\t00cf  AIC-7899P U160/m\n\t\t1028 0106  PowerEdge 4600\n\t\t1028 0121  PowerEdge 2650\n102b  Matrox Electronics Systems Ltd.\n# DJ: I've a suspicion that 0010 is a duplicate of 0d10.\n\t0010  MGA-I [Impression?]\n\t0100  MGA 1064SG [Mystique]\n\t0518  MGA-II [Athena]\n\t0519  MGA 2064W [Millennium]\n\t051a  MGA 1064SG [Mystique]\n\t\t102b 0100  MGA-1064SG Mystique\n\t\t102b 1100  MGA-1084SG Mystique\n\t\t102b 1200  MGA-1084SG Mystique\n\t\t1100 102b  MGA-1084SG Mystique\n\t\t110a 0018  Scenic Pro C5 (D1025)\n\t051b  MGA 2164W [Millennium II]\n\t\t102b 051b  MGA-2164W Millennium II\n\t\t102b 1100  MGA-2164W Millennium II\n\t\t102b 1200  MGA-2164W Millennium II\n\t\t102b 2100  MGA-2164W Millennium II\n\t051e  MGA 1064SG [Mystique] AGP\n\t051f  MGA 2164W [Millennium II] AGP\n\t\t102b 2100  MGA-2164WA [Millennium II A]\n\t0520  MGA G200\n\t\t102b dbc2  G200 Multi-Monitor\n\t\t102b dbc8  G200 Multi-Monitor\n\t\t102b dbe2  G200 Multi-Monitor\n\t\t102b dbe8  G200 Multi-Monitor\n\t\t102b ff03  Millennium G200 SD\n\t\t102b ff04  Marvel G200\n\t0521  MGA G200 AGP\n\t\t1014 ff03  Millennium G200 AGP\n\t\t102b 48e9  Mystique G200 AGP\n\t\t102b 48f8  Millennium G200 SD AGP\n\t\t102b 4a60  Millennium G200 LE AGP\n\t\t102b 4a64  Millennium G200 AGP\n\t\t102b c93c  Millennium G200 AGP\n\t\t102b c9b0  Millennium G200 AGP\n\t\t102b c9bc  Millennium G200 AGP\n\t\t102b ca60  Millennium G250 LE AGP\n\t\t102b ca6c  Millennium G250 AGP\n\t\t102b dbbc  Millennium G200 AGP\n\t\t102b dbc2  Millennium G200 MMS (Dual G200)\n\t\t102b dbc3  G200 Multi-Monitor\n\t\t102b dbc8  Millennium G200 MMS (Dual G200)\n\t\t102b dbd2  G200 Multi-Monitor\n\t\t102b dbd3  G200 Multi-Monitor\n\t\t102b dbd4  G200 Multi-Monitor\n\t\t102b dbd5  G200 Multi-Monitor\n\t\t102b dbd8  G200 Multi-Monitor\n\t\t102b dbd9  G200 Multi-Monitor\n\t\t102b dbe2  Millennium G200 MMS (Quad G200)\n\t\t102b dbe3  G200 Multi-Monitor\n\t\t102b dbe8  Millennium G200 MMS (Quad G200)\n\t\t102b dbf2  G200 Multi-Monitor\n\t\t102b dbf3  G200 Multi-Monitor\n\t\t102b dbf4  G200 Multi-Monitor\n\t\t102b dbf5  G200 Multi-Monitor\n\t\t102b dbf8  G200 Multi-Monitor\n\t\t102b dbf9  G200 Multi-Monitor\n\t\t102b f806  Mystique G200 Video AGP\n\t\t102b ff00  MGA-G200 AGP\n\t\t102b ff02  Mystique G200 AGP\n\t\t102b ff03  Millennium G200A AGP\n\t\t102b ff04  Marvel G200 AGP\n\t\t110a 0032  MGA-G200 AGP\n\t0522  MGA G200e [Pilot] ServerEngines (SEP1)\n\t\t103c 31fa  ProLiant DL140 G3\n\t0525  MGA G400/G450\n\t\t0e11 b16f  MGA-G400 AGP\n\t\t102b 0328  Millennium G400 16Mb SDRAM\n\t\t102b 0338  Millennium G400 16Mb SDRAM\n\t\t102b 0378  Millennium G400 32Mb SDRAM\n\t\t102b 0541  Millennium G450 Dual Head\n\t\t102b 0542  Millennium G450 Dual Head LX\n\t\t102b 0543  Millennium G450 Single Head LX\n\t\t102b 0641  Millennium G450 32Mb SDRAM Dual Head\n\t\t102b 0642  Millennium G450 32Mb SDRAM Dual Head LX\n\t\t102b 0643  Millennium G450 32Mb SDRAM Single Head LX\n\t\t102b 07c0  Millennium G450 Dual Head LE\n\t\t102b 07c1  Millennium G450 SDR Dual Head LE\n\t\t102b 0d41  Millennium G450 Dual Head PCI\n\t\t102b 0d42  Millennium G450 Dual Head LX PCI\n\t\t102b 0d43  Millennium G450 32Mb Dual Head PCI\n\t\t102b 0e00  Marvel G450 eTV\n\t\t102b 0e01  Marvel G450 eTV\n\t\t102b 0e02  Marvel G450 eTV\n\t\t102b 0e03  Marvel G450 eTV\n\t\t102b 0f80  Millennium G450 Low Profile\n\t\t102b 0f81  Millennium G450 Low Profile\n\t\t102b 0f82  Millennium G450 Low Profile DVI\n\t\t102b 0f83  Millennium G450 Low Profile DVI\n\t\t102b 19d8  Millennium G400 16Mb SGRAM\n\t\t102b 19f8  Millennium G400 32Mb SGRAM\n\t\t102b 2159  Millennium G400 Dual Head 16Mb\n\t\t102b 2179  Millennium G400 MAX/Dual Head 32Mb\n\t\t102b 217d  Millennium G400 Dual Head Max\n\t\t102b 23c0  Millennium G450\n\t\t102b 23c1  Millennium G450\n\t\t102b 23c2  Millennium G450 DVI\n\t\t102b 23c3  Millennium G450 DVI\n\t\t102b 2f58  Millennium G400\n\t\t102b 2f78  Millennium G400\n\t\t102b 3693  Marvel G400 AGP\n\t\t102b 5dd0  4Sight II\n\t\t102b 5f50  4Sight II\n\t\t102b 5f51  4Sight II\n\t\t102b 5f52  4Sight II\n\t\t102b 9010  Millennium G400 Dual Head\n\t\t1458 0400  GA-G400\n\t\t1705 0001  Millennium G450 32MB SGRAM\n\t\t1705 0002  Millennium G450 16MB SGRAM\n\t\t1705 0003  Millennium G450 32MB\n\t\t1705 0004  Millennium G450 16MB\n\t0527  Parhelia\n\t\t102b 0840  Parhelia 128Mb\n\t\t102b 0850  Parhelia 256MB\n\t\t102b 0870  MED2mp-DVI\n\t\t102b 0880  P-256 Edge Overlap Controller\n\t0528  Parhelia\n\t\t102b 1020  Parhelia 128MB\n\t\t102b 1030  Parhelia 256 MB Dual DVI\n\t\t102b 1040  MED2mp-DVI\n\t\t102b 1050  Sono S20\n\t\t102b 1060  PJ-30L\n\t\t102b 1070  PJ-40L\n\t\t102b 1421  MED5mp\n\t\t102b 1431  MED3mp-DVI\n\t\t102b 1451  MED5mp-DVI\n\t\t102b 1491  MED2mp-DVI\n\t\t102b 14b1  MED3mp-DVI\n\t\t102b 14c1  MED5mp-DVI\n\t\t102b 14e1  Parhelia PCI 256MB\n\t\t102b 14f1  Parhelia Precision SGT\n\t\t102b 1501  ATC-4MP\n\t\t102b 1511  ATC-4MP\n\t\t102b 1521  TheatreVUE T30\n\t\t102b 1531  TheatreVUE T20\n\t\t102b 1541  MED2mp-DVI\n\t\t102b 1551  MED3mp-DVI\n\t\t102b 1561  MED5mp-DVI\n\t\t102b 1571  Parhelia DL256 PCI\n\t\t102b 1591  Parhelia Precision SDT\n\t\t102b 15a1  MED4mp-DVI\n\t\t102b 2011  Parhelia HR256\n\t\t102b 2021  QID Pro\n\t\t102b 2061  PJ-40LP\n\t\t102b 2081  EWS Quad\n\t\t102b 2411  PPX-OUT8\n\t\t102b 2421  VPX-OUT8\n\t\t102b 2441  PPX-OUT4\n\t\t102b 2451  VPX-OUT4\n\t\t102b 2491  LPX-OUT4\n\t0530  MGA G200EV\n\t0532  MGA G200eW WPCM450\n\t\t1028 0235  PowerEdge R710 MGA G200eW WPCM450\n\t\t1028 0236  PowerEdge R610 MGA G200eW WPCM450\n\t\t1028 0237  PowerEdge T610 MGA G200eW WPCM450\n\t\t1028 0287  PowerEdge M610 MGA G200eW WPCM450\n\t\t1028 028c  PowerEdge R410 MGA G200eW WPCM450\n\t\t1028 028d  PowerEdge T410 MGA G200eW WPCM450\n\t\t1028 029c  PowerEdge M710 MGA G200eW WPCM450\n\t\t1028 02a4  PowerEdge T310 MGA G200eW WPCM450\n\t\t15d9 0605  X8SIL\n\t\t15d9 0624  X9SCM-F Motherboard\n\t\t15d9 066b  X9SRL-F\n\t\t15d9 a811  H8DGU\n\t0533  MGA G200EH\n\t\t103c 3381  iLO4\n\t0534  G200eR2\n\t\t1028 04f7  PowerEdge R320 server\n\t0536  Integrated Matrox G200eW3 Graphics Controller\n\t0538  MGA G200eH3\n\t\t1590 00e4  iLO5 VGA\n\t0540  M91XX\n\t\t102b 2080  M9140 LP PCIe x16\n\t\t102b 20c0  Xenia\n\t\t102b 20c1  Xenia Pro\n\t\t102b 2100  M9120 PCIe x16\n\t\t102b 2140  M9125 PCIe x16\n\t\t102b 2180  M9120 Plus LP PCIe x16\n\t\t102b 21c0  M9120 Plus LP PCIe x1\n\t\t102b 2200  VDA1164 Output Board\n\t\t102b 2240  M9148 LP PCIe x16\n\t\t102b 2241  M9138 LP PCIe x16\n\t\t102b 2280  M9188 ATX PCIe x16\n\t\t102b 22c0  M9128 LP PCIe x16\n\t0550  SV2\n\t\t102b 00c0  MURA-IPX-I4EF\n\t\t102b 00c1  MURA-IPX-I4DF\n\t\t102b 00c3  MURA-IPX-I4DHF\n\t\t102b 00c5  MURA-IPX-I4EHF\n\t0d10  MGA Ultima/Impression\n\t1000  MGA G100 [Productiva]\n\t\t102b ff01  Productiva G100\n\t\t102b ff05  Productiva G100 Multi-Monitor\n\t1001  MGA G100 [Productiva] AGP\n\t\t102b 1001  MGA-G100 AGP\n\t\t102b ff00  MGA-G100 AGP\n\t\t102b ff01  MGA-G100 Productiva AGP\n\t\t102b ff03  Millennium G100 AGP\n\t\t102b ff04  MGA-G100 AGP\n\t\t102b ff05  MGA-G100 Productiva AGP Multi-Monitor\n\t\t110a 001e  MGA-G100 AGP\n\t2007  MGA Mistral\n\t2527  Millennium G550\n# PCI\\VEN_102B&DEV_2527&SUBSYS_0F42102B&REV_01\n\t\t102b 0f42  Matrox G550 Low Profile PCI\n\t\t102b 0f83  Millennium G550\n\t\t102b 0f84  Millennium G550 Dual Head DDR 32Mb\n\t\t102b 1e41  Millennium G550\n\t\t102b 22c0  G550 PCIe\n\t\t102b 2300  Millennium G550 LP PCIE\n\t2537  Millennium P650/P750\n\t\t102b 1820  Millennium P750 64MB\n\t\t102b 1830  Millennium P650 64MB\n\t\t102b 1850  RAD2mp\n\t\t102b 1860  RAD3mp\n\t\t102b 1880  Sono S10\n\t\t102b 1c10  QID 128MB\n\t\t102b 2811  Millennium P650 Low-profile PCI 64MB\n\t\t102b 2821  Millennium P650 Low-profile PCI\n\t\t102b 2841  RAD PCI\n\t\t102b 2851  Spectrum PCI\n\t\t102b 2871  EpicA TC2\n\t\t102b 2c11  QID Low-profile PCI\n\t\t102b 2c21  QID LP PCI LW\n\t\t102b 2c31  QID LP PCI\n\t\t102b 2c41  EpicA TC4\n\t\t102b 3001  Extio F1400\n\t\t102b 3011  Extio F1220\n\t\t102b 3041  RG-200DL\n\t\t102b 3051  RG-400SL\n\t\t102b 3061  Extio F1420\n\t\t102b 3081  Extio F1240\n\t2538  Millennium P650 PCIe\n\t\t102b 0847  RAD PCIe\n\t\t102b 08c7  Millennium P650 PCIe 128MB\n\t\t102b 0907  Millennium P650 PCIe 64MB\n\t\t102b 0947  Parhelia APVe\n\t\t102b 0987  ATC PCIe 4MP\n\t\t102b 1047  Millennium P650 LP PCIe 128MB\n\t\t102b 1087  Millennium P650 LP PCIe 64MB\n\t\t102b 1801  Millennium P650 PCIe x1\n\t\t102b 2538  Parhelia APVe\n\t\t102b 3007  QID Low-profile PCIe\n\t\t102b 3087  Aurora VX3mp\n\t\t102b 30c7  QID LP PCIe\n\t2539  Millennium P690\n\t\t102b 0040  Millennium P690 PCIe x16\n\t\t102b 0042  ONYX\n\t\t102b 0043  SPECTRA\n\t\t102b 0080  Millennium P690 Plus LP PCIe x16\n\t\t102b 0081  Millennium P690 LP PCIe x16\n\t\t102b 0082  RAD LPX PCIe x16\n\t\t102b 00c0  Millennium P690 Plus LP PCI\n\t\t102b 00c2  Millennium P690 LP PCI\n\t\t102b 00c3  RAD LPX PCI\n\t\t102b 0101  Millennium P690 PCI\n\t\t102b 0140  Millennium P690 LP PCIe x1\n\t\t102b 0180  Display Wall IP Decode 128 MB\n\t4164  Morphis QxT frame grabber\n\t43b4  Morphis Qxt encoding engine\n\t4510  Morphis COM port\n\t4536  VIA Framegrabber\n\t4686  Concord GX (customized Intel 82541)\n\t475b  Solios eCL/XCL-B frame grabber\n\t475d  Vio frame grabber family\n\t\t102b 4b90  Vio Duo frame grabber (single channel)\n\t\t102b 4b91  Vio Duo frame grabber\n\t\t102b 4b92  Vio Analog frame grabber\n\t\t102b 4b93  Vio SDI Frame Grabber\n\t\t102b 4b94  Vio DVI-A frame grabber\n\t475f  Solios (single-Full) CL frame grabber\n\t\t102b 475f  Solios eCL/XCL-F frame grabber\n\t\t102b 4d5f  Solios eV-CL (single-Full) frame grabber\n\t\t102b 4e5f  Solios eM-CL (single-Full) frame grabber\n\t47a1  Solios eA/XA frame grabber\n\t\t102b 4be0  Solios eA/XA (single) frame grabber\n\t\t102b 4be1  Solios eA/XA (dual) frame grabber\n\t\t102b 4be2  Solios eA/XA (quad) frame grabber\n\t47a2  Solios COM port\n\t47c1  Solios (dual-Base/single-Medium) CL frame grabber\n\t\t102b 0000  Solios frame grabber\n\t\t102b 4b80  Solios eCL/XCL (single-Medium) frame grabber\n\t\t102b 4b81  Solios eCL/XCL (dual-Base) frame grabber\n\t\t102b 4d80  Solios eV-CL (single-Medium) frame grabber\n\t\t102b 4d81  Solios eV-CL (dual-Base) frame grabber\n\t\t102b 4e80  Solios eM-CL (single-Medium) frame grabber\n\t\t102b 4e81  Solios eM-CL (dual-Base) frame grabber\n\t47c2  Solios COM port\n\t4949  Radient frame grabber family\n\t\t102b 0010  Radient eCL (Single-full) frame grabber\n\t\t102b 0011  Radient eCLV (Single-full) frame grabber\n\t\t102b 0020  Radient eCL (Dual-base) frame grabber\n\t\t102b 0030  Radient eCL (Dual-full) frame grabber\n\t\t102b 0040  Radient eCL (Quad-base) frame grabber\n\t\t102b 0050  Radient eCL (Golden) frame grabber\n\t\t102b 1010  Radient eV-CXP (quad CXP-6) frame grabber\n\t\t102b 1015  Radient eV-CXP (dual CXP-6) frame grabber\n\t\t102b 1020  Radient eV-CXP (quad CXP-3) frame grabber\n\t\t102b 1050  Radient eV-CXP (Golden) frame grabber\n\t4cdc  Morphis JPEG2000 accelerator\n\t4f54  Morphis (e)Quad frame grabber\n\t4fc5  Morphis (e)Dual frame grabber\n\t5e10  Morphis aux I/O\n\t6573  Shark 10/100 Multiport SwitchNIC\n102c  Chips and Technologies\n\t00b8  F64310\n\t00c0  F69000 HiQVideo\n\t\t102c 00c0  F69000 HiQVideo\n\t\t4c53 1000  CC7/CR7/CP7/VC7/VP7/VR7 mainboard\n\t\t4c53 1010  CP5/CR6 mainboard\n\t\t4c53 1020  VR6 mainboard\n\t\t4c53 1030  PC5 mainboard\n\t\t4c53 1050  CT7 mainboard\n\t\t4c53 1051  CE7 mainboard\n\t00d0  F65545\n\t00d8  F65545\n\t00dc  F65548\n\t00e0  F65550\n\t00e4  F65554\n\t00e5  F65555 HiQVPro\n\t\t0e11 b049  Armada 1700 Laptop Display Controller\n\t\t1179 0001  Satellite Pro/Satellite\n\t00f0  F68554\n\t00f4  F68554 HiQVision\n\t00f5  F68555\n\t0c30  F69030\n\t\t4c53 1000  CC7/CR7/CP7/VC7/VP7/VR7 mainboard\n\t\t4c53 1050  CT7 mainboard\n\t\t4c53 1051  CE7 mainboard\n\t\t4c53 1080  CT8 mainboard\n102d  Wyse Technology Inc.\n\t50dc  3328 Audio\n102e  Olivetti Advanced Technology\n102f  Toshiba America\n\t0009  r4x00\n\t000a  TX3927 MIPS RISC PCI Controller\n\t0020  ATM Meteor 155\n\t\t102f 00f8  ATM Meteor 155\n\t0030  TC35815CF PCI 10/100 Mbit Ethernet Controller\n\t0031  TC35815CF PCI 10/100 Mbit Ethernet Controller with WOL\n\t0032  TC35815CF PCI 10/100 Mbit Ethernet Controller on TX4939\n\t0105  TC86C001 [goku-s] IDE\n\t0106  TC86C001 [goku-s] USB 1.1 Host\n\t0107  TC86C001 [goku-s] USB Device Controller\n\t0108  TC86C001 [goku-s] I2C/SIO/GPIO Controller\n\t0180  TX4927/38 MIPS RISC PCI Controller\n\t0181  TX4925 MIPS RISC PCI Controller\n\t0182  TX4937 MIPS RISC PCI Controller\n\t01b4  Celleb platform IDE interface\n\t01b5  SCC USB 2.0 EHCI controller\n\t01b6  SCC USB 1.1 OHCI controller\n1030  TMC Research\n1031  Miro Computer Products AG\n\t5601  DC20 ASIC\n\t5607  Video I/O & motion JPEG compressor\n\t5631  Media 3D\n\t6057  MiroVideo DC10/DC30+\n1032  Compaq\n1033  NEC Corporation\n\t0000  Vr4181A USB Host or Function Control Unit\n\t0001  PCI to 486-like bus Bridge\n\t0002  PCI to VL98 Bridge\n\t0003  ATM Controller\n\t0004  R4000 PCI Bridge\n\t0005  PCI to 486-like bus Bridge\n\t0006  PC-9800 Graphic Accelerator\n\t0007  PCI to UX-Bus Bridge\n\t0008  PC-9800 Graphic Accelerator\n\t0009  PCI to PC9800 Core-Graph Bridge\n\t0016  PCI to VL Bridge\n\t001a  [Nile II]\n\t0021  Vrc4373 [Nile I]\n\t0029  PowerVR PCX1\n\t002a  PowerVR 3D\n\t002c  Star Alpha 2\n\t002d  PCI to C-bus Bridge\n\t0035  OHCI USB Controller\n\t\t1033 0035  USB Controller\n\t\t103c 1293  USB add-in card\n\t\t103c 1294  USB 2.0 add-in card\n\t\t1179 0001  USB\n\t\t1186 0035  DUB-C2 USB 2.0 2-port 32-bit cardbus controller\n\t\t12ee 7000  Root Hub\n\t\t14c2 0105  PTI-205N USB 2.0 Host Controller\n\t\t1799 0001  Root Hub\n\t\t1931 000a  GlobeTrotter Fusion Quad Lite (PPP data)\n\t\t1931 000b  GlobeTrotter Fusion Quad Lite (GSM data)\n\t\t807d 0035  PCI-USB2 (OHCI subsystem)\n\t003b  PCI to C-bus Bridge\n\t003e  NAPCCARD Cardbus Controller\n\t0046  PowerVR PCX2 [midas]\n\t005a  Vrc5074 [Nile 4]\n\t0063  uPD72862 [Firewarden] IEEE1394 OHCI 1.0 Link Controller\n\t0067  PowerVR Neon 250 Chipset\n\t\t1010 0020  PowerVR Neon 250 AGP 32Mb\n\t\t1010 0080  PowerVR Neon 250 AGP 16Mb\n\t\t1010 0088  PowerVR Neon 250 16Mb\n\t\t1010 0090  PowerVR Neon 250 AGP 16Mb\n\t\t1010 0098  PowerVR Neon 250 16Mb\n\t\t1010 00a0  PowerVR Neon 250 AGP 32Mb\n\t\t1010 00a8  PowerVR Neon 250 32Mb\n\t\t1010 0120  PowerVR Neon 250 AGP 32Mb\n\t0072  uPD72874 IEEE1394 OHCI 1.1 3-port PHY-Link Ctrlr\n\t0074  56k Voice Modem\n\t\t1033 8014  RCV56ACF 56k Voice Modem\n\t009b  Vrc5476\n\t00a5  VRC4173\n\t00a6  VRC5477 AC97\n\t00cd  uPD72870 [Firewarden] IEEE1394a OHCI 1.0 Link/3-port PHY Controller\n\t\t12ee 8011  Root hub\n\t00ce  uPD72871 [Firewarden] IEEE1394a OHCI 1.0 Link/1-port PHY Controller\n\t00df  Vr4131\n\t00e0  uPD72010x USB 2.0 Controller\n\t\t1186 f100  DUB-C2 USB 2.0 2-port 32-bit cardbus controller\n\t\t12ee 7001  Root hub\n\t\t14c2 0205  PTI-205N USB 2.0 Host Controller\n\t\t1799 0002  Root Hub\n\t\t807d 1043  PCI-USB2 (EHCI subsystem)\n\t00e7  uPD72873 [Firewarden] IEEE1394a OHCI 1.1 Link/2-port PHY Controller\n\t00f2  uPD72874 [Firewarden] IEEE1394a OHCI 1.1 Link/3-port PHY Controller\n\t00f3  uPD6113x Multimedia Decoder/Processor [EMMA2]\n\t010c  VR7701\n\t0125  uPD720400 PCI Express - PCI/PCI-X Bridge\n\t013a  Dual Tuner/MPEG Encoder\n\t0194  uPD720200 USB 3.0 Host Controller\n\t\t1028 04a3  Precision M4600\n\t\t1028 04b2  Vostro 3350\n\t\t1028 04da  Vostro 3750\n\t\t1043 8413  P8P67 Deluxe Motherboard\n\t\t104d 907a  Vaio VPCF1\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t1b96 0001  USB 3.0 PCIe Card\n\t01e7  uPD72873 [Firewarden] IEEE1394a OHCI 1.1 Link/2-port PHY Controller\n\t01f2  uPD72874 [Firewarden] IEEE1394a OHCI 1.1 Link/3-port PHY Controller\n1034  Framatome Connectors USA Inc.\n1035  Comp. & Comm. Research Lab\n1036  Future Domain Corp.\n\t0000  TMC-18C30 [36C70]\n1037  Hitachi Micro Systems\n1038  AMP, Inc\n1039  Silicon Integrated Systems [SiS]\n\t0001  AGP Port (virtual PCI-to-PCI bridge)\n\t0002  AGP Port (virtual PCI-to-PCI bridge)\n\t0003  AGP Port (virtual PCI-to-PCI bridge)\n\t0004  PCI-to-PCI bridge\n\t\t1039 0000  PCIe x16 port\n\t0006  85C501/2/3\n\t0008  SiS85C503/5513 (LPC Bridge)\n\t0009  5595 Power Management Controller\n\t000a  PCI-to-PCI bridge\n\t\t1039 0000  PCIe x1 port\n\t0016  SiS961/2/3 SMBus controller\n\t0018  SiS85C503/5513 (LPC Bridge)\n\t0163  163 802.11b/g Wireless LAN Adapter\n\t0180  RAID bus controller 180 SATA/PATA  [SiS]\n\t0181  SATA\n\t0182  182 SATA/RAID Controller\n\t\t1734 1095  D2030-A1\n\t0186  AHCI Controller (0106)\n\t0190  190 Ethernet Adapter\n\t0191  191 Gigabit Ethernet Adapter\n\t\t1043 8139  P5SD2-FM/S mainboard\n\t0200  5597/5598/6326 VGA\n\t\t1039 0000  SiS5597 SVGA (Shared RAM)\n\t0204  82C204\n\t0205  SG86C205\n\t0300  300/305 PCI/AGP VGA Display Adapter\n\t\t107d 2720  Leadtek WinFast VR300\n\t0310  315H PCI/AGP VGA Display Adapter\n\t0315  315 PCI/AGP VGA Display Adapter\n\t0325  315PRO PCI/AGP VGA Display Adapter\n\t0330  330 [Xabre] PCI/AGP VGA Display Adapter\n\t0406  85C501/2\n\t0496  85C496\n\t0530  530 Host\n\t0540  540 Host\n\t0550  550 Host\n\t0597  5513C\n\t0601  85C601\n\t0620  620 Host\n\t0630  630 Host\n\t0633  633 Host\n\t0635  635 Host\n\t0645  SiS645 Host & Memory & AGP Controller\n\t0646  SiS645DX Host & Memory & AGP Controller\n\t0648  645xx\n\t0649  SiS649 Host\n\t0650  650/M650 Host\n\t0651  651 Host\n\t0655  655 Host\n\t0660  660 Host\n\t0661  661FX/M661FX/M661MX Host\n\t0662  662 Host\n\t0671  671MX\n\t0730  730 Host\n\t0733  733 Host\n\t0735  735 Host\n\t0740  740 Host\n\t0741  741/741GX/M741 Host\n\t\t1849 0741  K7S41/K7S41GX motherboard\n\t0745  745 Host\n\t0746  746 Host\n\t0755  755 Host\n\t0760  760/M760 Host\n\t0761  761/M761 Host\n\t\t1734 1099  D2030-A1 Motherboard\n\t0900  SiS900 PCI Fast Ethernet\n\t\t1019 0a14  K7S5A motherboard\n\t\t1039 0900  SiS900 10/100 Ethernet Adapter onboard\n\t\t1043 8035  CUSI-FX motherboard\n\t\t1043 80a7  Motherboard P4S800D-X\n\t\t1462 0900  MS-6701 motherboard\n\t0961  SiS961 [MuTIOL Media IO]\n\t0962  SiS962 [MuTIOL Media IO] LPC Controller\n\t0963  SiS963 [MuTIOL Media IO] LPC Controller\n\t0964  SiS964 [MuTIOL Media IO] LPC Controller\n\t0965  SiS965 [MuTIOL Media IO]\n\t0966  SiS966 [MuTIOL Media IO]\n\t0968  SiS968 [MuTIOL Media IO]\n\t1180  SATA Controller / IDE mode\n\t1182  SATA Controller / RAID mode\n\t\t1039 0180  SiS 966 4-port SATA controller\n\t1183  SATA Controller / IDE mode\n\t\t1039 0180  SiS 966 4-port SATA controller\n\t1184  AHCI Controller / RAID mode\n\t1185  AHCI IDE Controller (0106)\n\t3602  83C602\n\t5107  5107\n\t5300  SiS540 PCI Display Adapter\n\t5315  550 PCI/AGP VGA Display Adapter\n\t5401  486 PCI Chipset\n\t5511  5511/5512\n\t5513  5513 IDE Controller\n\t\t1019 0970  P6STP-FL motherboard\n\t\t1039 5513  SiS5513 EIDE Controller (A,B step)\n\t\t1043 8035  CUSI-FX motherboard\n\t\t1462 7010  MS-6701 motherboard\n\t\t1631 5513  GA-8SIML Rev1.0 Motherboard\n\t\t1734 1095  D2030-A1 Motherboard\n\t5517  5517\n\t5571  5571\n\t5581  5581 Pentium Chipset\n\t5582  5582\n\t5591  5591/5592 Host\n\t5596  5596 Pentium Chipset\n\t5597  5597 [SiS5582]\n\t5600  5600 Host\n\t6204  Video decoder & MPEG interface\n\t6205  VGA Controller\n\t6236  6236 3D-AGP\n\t6300  630/730 PCI/AGP VGA Display Adapter\n\t\t1019 0970  P6STP-FL motherboard\n\t\t1043 8035  CUSI-FX motherboard\n\t\t104d 80e2  VAIO PCV-J200\n\t6306  530/620 PCI/AGP VGA Display Adapter\n\t6325  65x/M650/740 PCI/AGP VGA Display Adapter\n\t\t1039 6325  SiS 651 onboard [Asus P4SC-EA]\n\t\t1631 1004  SiS 651C onboard [Gigabyte GA-8SIML Rev1.0]\n\t6326  86C326 5598/6326\n\t\t1039 6326  SiS6326 GUI Accelerator\n\t\t1092 0a50  SpeedStar A50\n\t\t1092 0a70  SpeedStar A70\n\t\t1092 4910  SpeedStar A70\n\t\t1092 4920  SpeedStar A70\n\t\t10b0 6326  S6110-B (AGP)\n\t\t1569 6326  SiS6326 GUI Accelerator\n\t6330  661/741/760 PCI/AGP or 662/761Gx PCIE VGA Display Adapter\n\t\t1039 6330  [M]661xX/[M]741[GX]/[M]760 PCI/AGP VGA Adapter\n\t\t1043 8113  SiS Real 256E (ASUS P5S800-VM motherboard)\n\t\t1458 d000  SiS661FX GUI 2D/3D Accelerator\n\t\t1734 1099  D2030-A1\n\t6350  770/670 PCIE VGA Display Adapter\n\t6351  771/671 PCIE VGA Display Adapter\n\t7001  USB 1.1 Controller\n\t\t1019 0a14  K7S5A motherboard\n\t\t1039 7000  Onboard USB Controller\n\t\t1462 5470  ECS K7SOM+ motherboard\n\t\t1462 7010  MS-6701 motherboard\n\t\t1734 1095  D2030-A1 Motherboard\n\t7002  USB 2.0 Controller\n\t\t1462 5470  K7SOM+ 5.2C Motherboard\n\t\t1462 7010  MS-6701 motherboard\n\t\t1509 7002  Onboard USB Controller\n\t\t1734 1095  D2030-A1\n\t7007  FireWire Controller\n\t\t1462 701d  MS-6701\n\t7012  SiS7012 AC'97 Sound Controller\n\t\t1019 0f05  A928 (i-Buddie)\n\t\t1039 7012  SiS 7012 onboard [Asus P4SC-EA] AC'97 Sound Controller\n\t\t1043 818f  A8S-X Motherboard\n\t\t13f6 0300  CMI9739(A) on ECS K7S series motherboard\n\t\t1462 5850  MSI 648 Max (MS-6585)\n\t\t1462 7010  MS-6701 motherboard\n\t\t15bd 1001  DFI 661FX motherboard\n\t\t1734 109f  D2030-A1 Motherboard\n\t\t1849 7012  K7S41GX motherboard\n# There are may be different modem codecs here (Intel537 compatible and incompatible)\n\t7013  AC'97 Modem Controller\n\t7016  SiS7016 PCI Fast Ethernet Adapter\n\t\t1039 7016  SiS7016 10/100 Ethernet Adapter\n\t7018  SiS PCI Audio Accelerator\n\t\t1014 01b6  SiS PCI Audio Accelerator\n\t\t1014 01b7  SiS PCI Audio Accelerator\n\t\t1019 7018  SiS PCI Audio Accelerator\n\t\t1025 000e  SiS PCI Audio Accelerator\n\t\t1025 0018  SiS PCI Audio Accelerator\n\t\t1039 7018  SiS PCI Audio Accelerator\n\t\t1043 1453  SiS PCI Audio Accelerator\n\t\t1043 800b  SiS PCI Audio Accelerator\n\t\t104d 80e2  VAIO PCV-J200\n\t\t1054 7018  SiS PCI Audio Accelerator\n\t\t107d 5330  SiS PCI Audio Accelerator\n\t\t107d 5350  SiS PCI Audio Accelerator\n\t\t1170 3209  SiS PCI Audio Accelerator\n\t\t1462 400a  SiS PCI Audio Accelerator\n\t\t14a4 2089  SiS PCI Audio Accelerator\n\t\t14cd 2194  SiS PCI Audio Accelerator\n\t\t14ff 1100  SiS PCI Audio Accelerator\n\t\t152d 8808  SiS PCI Audio Accelerator\n\t\t1558 1103  SiS PCI Audio Accelerator\n\t\t1558 2200  SiS PCI Audio Accelerator\n\t\t1563 7018  SiS PCI Audio Accelerator\n\t\t15c5 0111  SiS PCI Audio Accelerator\n\t\t270f a171  SiS PCI Audio Accelerator\n\t\ta0a0 0022  SiS PCI Audio Accelerator\n\t7019  SiS7019 Audio Accelerator\n\t7502  Azalia Audio Controller\n\t\t1043 81a1  P5SD2-FM/S mainboard\n103a  Seiko Epson Corporation\n103b  Tatung Corp. Of America\n103c  Hewlett-Packard Company\n\t1005  A4977A Visualize EG\n\t1008  Visualize FX\n\t1028  Tach TL Fibre Channel Host Adapter\n\t1029  Tach XL2 Fibre Channel Host Adapter\n\t\t107e 000f  Interphase 5560 Fibre Channel Adapter\n\t\t9004 9210  1Gb/2Gb Family Fibre Channel Controller\n\t\t9004 9211  1Gb/2Gb Family Fibre Channel Controller\n\t102a  Tach TS Fibre Channel Host Adapter\n\t\t107e 000e  Interphase 5540/5541 Fibre Channel Adapter\n\t\t9004 9110  1Gb/2Gb Family Fibre Channel Controller\n\t\t9004 9111  1Gb/2Gb Family Fibre Channel Controller\n\t1030  J2585A DeskDirect 10/100VG NIC\n\t1031  J2585B HP 10/100VG PCI LAN Adapter\n\t\t103c 1040  J2973A DeskDirect 10BaseT NIC\n\t\t103c 1041  J2585B DeskDirect 10/100VG NIC\n\t\t103c 1042  J2970A DeskDirect 10BaseT/2 NIC\n\t1040  J2973A DeskDirect 10BaseT NIC\n\t1041  J2585B DeskDirect 10/100 NIC\n\t1042  J2970A DeskDirect 10BaseT/2 NIC\n\t1048  Diva Serial [GSP] Multiport UART\n\t\t103c 1049  Tosca Console\n\t\t103c 104a  Tosca Secondary\n\t\t103c 104b  Maestro SP2\n\t\t103c 1223  Superdome Console\n\t\t103c 1226  Keystone SP2\n\t\t103c 1227  Powerbar SP2\n\t\t103c 1282  Everest SP2\n\t\t103c 1301  Diva RMP3\n\t1054  PCI Local Bus Adapter\n\t1064  79C970 PCnet Ethernet Controller\n\t108b  Visualize FXe\n\t10c1  NetServer Smart IRQ Router\n\t10ed  TopTools Remote Control\n\t10f0  rio System Bus Adapter\n\t10f1  rio I/O Controller\n\t1219  NetServer PCI Hot-Plug Controller\n\t121a  NetServer SMIC Controller\n\t121b  NetServer Legacy COM Port Decoder\n\t121c  NetServer PCI COM Port Decoder\n\t1229  zx1 System Bus Adapter\n\t122a  zx1 I/O Controller\n\t122e  PCI-X Local Bus Adapter\n\t127b  sx1000 System Bus Adapter\n\t127c  sx1000 I/O Controller\n\t128d  Diva [GSP] Management Board\n\t1290  Auxiliary Diva Serial Port\n\t\t103c 1291  Diva SP2\n\t1291  Auxiliary Diva Serial Port\n\t12b4  zx1 QuickSilver AGP8x Local Bus Adapter\n\t12eb  sx2000 System Bus Adapter\n\t12ec  sx2000 I/O Controller\n\t12ee  PCI-X 2.0 Local Bus Adapter\n\t1302  RMP-3 Shared Memory Driver\n\t1303  RMP-3 (Remote Management Processor)\n\t22f6  iLO5 Virtual USB Controller\n\t\t1590 00e4  iLO5 Standard Virtual USB Controller\n\t2910  E2910A PCIBus Exerciser\n\t2925  E2925A 32 Bit, 33 MHzPCI Exerciser & Analyzer\n\t3206  Adaptec Embedded Serial ATA HostRAID\n\t3220  Smart Array P600\n\t\t103c 3225  3 Gb/s SAS RAID\n\t3230  Smart Array Controller\n\t\t103c 3223  Smart Array P800\n\t\t103c 3234  P400 SAS Controller\n\t\t103c 3235  P400i SAS Controller\n\t\t103c 3237  E500 SAS Controller\n\t\t103c 323d  P700m SAS Controller\n\t3238  Smart Array E200i (SAS Controller)\n\t\t103c 3211  Smart Array E200i\n\t\t103c 3212  Smart Array E200\n\t3239  Smart Array Gen9 Controllers\n\t\t103c 21bd  P244br\n\t\t103c 21be  P741m\n\t\t103c 21bf  H240ar\n\t\t103c 21c0  P440ar\n\t\t103c 21c1  P840ar\n\t\t103c 21c2  P440\n\t\t103c 21c3  P441\n\t\t103c 21c4  Smart Array\n\t\t103c 21c5  P841\n\t\t103c 21c6  H244br\n\t\t103c 21c7  H240\n\t\t103c 21c8  H241\n\t\t103c 21c9  Smart Array\n\t\t103c 21ca  P246br\n\t\t103c 21cb  P840\n\t\t103c 21cc  Smart Array\n\t\t103c 21cd  P240nr\n\t\t103c 21ce  H240nr\n\t323a  Smart Array G6 controllers\n\t\t103c 3241  Smart Array P212\n\t\t103c 3243  Smart Array P410\n\t\t103c 3245  Smart Array P410i\n\t\t103c 3247  Smart Array P411\n\t\t103c 3249  Smart Array P812\n\t\t103c 324a  Smart Array 712m (Mezzanine RAID controller)\n\t\t103c 324b  Smart Array P711m (Mezzanine RAID controller)\n\t323b  Smart Array Gen8 Controllers\n\t\t103c 3350  P222\n\t\t103c 3351  P420\n\t\t103c 3352  P421\n\t\t103c 3354  P420i\n\t\t103c 3355  P220i\n\t323c  Smart Array Gen8+ Controllers\n\t\t103c 1920  P430i\n\t\t103c 1921  P830i\n\t\t103c 1922  P430\n\t\t103c 1923  P431\n\t\t103c 1924  P830\n\t\t103c 1925  Smart Array\n\t\t103c 1926  P731m\n\t\t103c 1928  P230i\n\t3300  Integrated Lights-Out Standard Virtual USB Controller\n\t\t103c 3304  iLO2\n\t\t103c 3305  iLO2\n\t\t103c 3309  iLO2 GXL/iLO3 GXE\n\t\t103c 330e  iLO3\n\t\t103c 3381  iLO4\n\t3301  Integrated Lights-Out Standard Serial Port\n\t\t103c 3304  iLO2\n\t\t103c 3305  iLO2\n\t\t103c 330e  iLO3\n\t\t103c 3381  iLO4\n# Virtual serial port which is presented on a Java applet\n\t3302  Integrated Lights-Out Standard KCS Interface\n\t\t103c 3304  iLO2\n\t\t103c 3305  iLO2\n\t\t103c 330e  iLO3\n\t\t103c 3381  iLO4\n\t3305  Integrated Lights-Out (iLO2) Controller\n\t3306  Integrated Lights-Out Standard Slave Instrumentation & System Support\n\t\t103c 330e  iLO3\n\t\t103c 3381  iLO4\n\t\t1590 00e4  iLO5\n\t3307  Integrated Lights-Out Standard Management Processor Support and Messaging\n# HP DL380 G6\n\t\t103c 3309  iLO 2\n\t\t103c 330e  iLO3\n\t\t103c 3381  iLO4\n\t3308  Integrated Lights-Out Standard MS Watchdog Timer\n\t\t103c 330e  iLO3\n\t\t103c 3381  iLO4\n\t4030  zx2 System Bus Adapter\n\t4031  zx2 I/O Controller\n\t4037  PCIe Local Bus Adapter\n\t9602  AMD RS780/RS880 PCI to PCI bridge (int gfx)\n103e  Solliday Engineering\n103f  Synopsys/Logic Modeling Group\n1040  Accelgraphics Inc.\n1041  Computrend\n1042  Micron\n\t1000  PC Tech RZ1000\n\t1001  PC Tech RZ1001\n\t3000  Samurai_0\n\t3010  Samurai_1\n\t3020  Samurai_IDE\n1043  ASUSTeK Computer Inc.\n\t0464  Radeon R9 270x GPU\n\t0521  RX580 [RX 580 Dual O8G]\n\t0675  ISDNLink P-IN100-ST-D\n\t\t0675 1704  ISDN Adapter (PCI Bus, D, C)\n\t\t0675 1707  ISDN Adapter (PCI Bus, DV, W)\n\t\t10cf 105e  ISDN Adapter (PCI Bus, DV, W)\n# Should be 1022:9602\n\t9602  AMD RS780/RS880 PCI to PCI bridge (int gfx)\n\t\t1043 83a2  M4A785TD Motherboard\n1044  Adaptec (formerly DPT)\n\t1012  Domino RAID Engine\n\ta400  SmartCache/Raid I-IV Controller\n\ta500  PCI Bridge\n\ta501  SmartRAID V Controller\n\t\t1044 c001  PM1554U2 Ultra2 Single Channel\n\t\t1044 c002  PM1654U2 Ultra2 Single Channel\n\t\t1044 c003  PM1564U3 Ultra3 Single Channel\n\t\t1044 c004  PM1564U3 Ultra3 Dual Channel\n\t\t1044 c005  PM1554U2 Ultra2 Single Channel (NON ACPI)\n\t\t1044 c00a  PM2554U2 Ultra2 Single Channel\n\t\t1044 c00b  PM2654U2 Ultra2 Single Channel\n\t\t1044 c00c  PM2664U3 Ultra3 Single Channel\n\t\t1044 c00d  PM2664U3 Ultra3 Dual Channel\n\t\t1044 c00e  PM2554U2 Ultra2 Single Channel (NON ACPI)\n\t\t1044 c00f  PM2654U2 Ultra2 Single Channel (NON ACPI)\n\t\t1044 c014  PM3754U2 Ultra2 Single Channel (NON ACPI)\n\t\t1044 c015  PM3755U2B Ultra2 Single Channel (NON ACPI)\n\t\t1044 c016  PM3755F Fibre Channel (NON ACPI)\n\t\t1044 c01e  PM3757U2 Ultra2 Single Channel\n\t\t1044 c01f  PM3757U2 Ultra2 Dual Channel\n\t\t1044 c020  PM3767U3 Ultra3 Dual Channel\n\t\t1044 c021  PM3767U3 Ultra3 Quad Channel\n\t\t1044 c028  PM2865U3 Ultra3 Single Channel\n\t\t1044 c029  PM2865U3 Ultra3 Dual Channel\n\t\t1044 c02a  PM2865F Fibre Channel\n\t\t1044 c03c  2000S Ultra3 Single Channel\n\t\t1044 c03d  2000S Ultra3 Dual Channel\n\t\t1044 c03e  2000F Fibre Channel\n\t\t1044 c046  3000S Ultra3 Single Channel\n\t\t1044 c047  3000S Ultra3 Dual Channel\n\t\t1044 c048  3000F Fibre Channel\n\t\t1044 c050  5000S Ultra3 Single Channel\n\t\t1044 c051  5000S Ultra3 Dual Channel\n\t\t1044 c052  5000F Fibre Channel\n\t\t1044 c05a  2400A UDMA Four Channel\n\t\t1044 c05b  2400A UDMA Four Channel DAC\n\t\t1044 c064  3010S Ultra3 Dual Channel\n\t\t1044 c065  3410S Ultra160 Four Channel\n\t\t1044 c066  3010S Fibre Channel\n\ta511  SmartRAID V Controller\n\t\t1044 c032  ASR-2005S I2O Zero Channel\n\t\t1044 c035  ASR-2010S I2O Zero Channel\n\tc066  3010S Ultra3 Dual Channel\n1045  OPTi Inc.\n\ta0f8  82C750 [Vendetta] USB Controller\n\tc101  92C264\n\tc178  92C178\n\tc556  82X556 [Viper]\n\tc557  82C557 [Viper-M]\n\tc558  82C558 [Viper-M ISA+IDE]\n\tc567  82C750 [Vendetta], device 0\n\tc568  82C750 [Vendetta], device 1\n\tc569  82C579 [Viper XPress+ Chipset]\n\tc621  82C621 [Viper-M/N+]\n\tc700  82C700 [FireStar]\n\tc701  82C701 [FireStar Plus]\n\tc814  82C814 [Firebridge 1]\n\tc822  82C822\n\tc824  82C824\n\tc825  82C825 [Firebridge 2]\n\tc832  82C832\n\tc861  82C861 OHCI USB Host\n\tc881  82C881 [FireLink] 1394 OHCI Link Controller\n\tc895  82C895\n\tc935  EV1935 ECTIVA MachOne PCIAudio\n\td568  82C825 [Firebridge 2]\n\td721  IDE [FireStar]\n1046  IPC Corporation, Ltd.\n1047  Genoa Systems Corp\n1048  Elsa AG\n\t0c60  Gladiac MX\n\t0d22  Quadro4 900XGL [ELSA GLoria4 900XGL]\n\t1000  QuickStep 1000\n\t3000  QuickStep 3000\n\t8901  Gloria XL\n\t\t1048 0935  GLoria XL (Virge)\n1049  Fountain Technologies, Inc.\n# nee SGS Thomson Microelectronics\n104a  STMicroelectronics\n\t0000  STLS2F Host Bridge\n\t0008  STG 2000X\n\t0009  STG 1764X\n\t0010  STG4000 [3D Prophet Kyro Series]\n\t\t104a 4018  ST PowerVR Kyro (64MB AGP TVO)\n# 64MB AGP\n\t\t1681 0010  PowerVR Kyro II [3D Prophet 4500]\n\t\t1681 0028  3D Prophet 4000XT\n\t\t1681 c010  3D Prophet 4500 TV-Out\n\t\t1681 c069  3D Prophet 4000XT\n\t0201  STPC Vega Northbridge\n\t0209  STPC Consumer/Industrial North- and Southbridge\n\t020a  STPC Atlas/ConsumerS/Consumer IIA Northbridge\n\t020b  STPC Consumer II ISA Bridge\n\t0210  STPC Atlas ISA Bridge\n\t021a  STPC Consumer S Southbridge\n\t021b  STPC Consumer IIA Southbridge\n\t0220  STPC Industrial PCI to PCCard bridge\n\t0228  STPC Atlas IDE\n\t0229  STPC Vega IDE\n\t0230  STPC Atlas/Vega OHCI USB Controller\n\t0238  STPC Vega LAN\n\t0500  ST70137 [Unicorn] ADSL DMT Transceiver\n\t\t104a 0500  BeWAN ADSL PCI st\n\t0564  STPC Client Northbridge\n\t0981  21x4x DEC-Tulip compatible 10/100 Ethernet\n\t1746  STG 1764X\n\t2774  21x4x DEC-Tulip compatible 10/100 Ethernet\n\t3520  MPEG-II decoder card\n\t55cc  STPC Client Southbridge\n104b  BusLogic\n\t0140  BT-946C (old) [multimaster  01]\n\t1040  BT-946C (BA80C30) [MultiMaster 10]\n\t8130  Flashpoint LT\n104c  Texas Instruments\n\t0500  100 MBit LAN Controller\n\t0508  TMS380C2X Compressor Interface\n\t1000  Eagle i/f AS\n\t104c  PCI1510 PC card Cardbus Controller\n\t3d04  TVP4010 [Permedia]\n\t3d07  TVP4020 [Permedia 2]\n\t\t1011 4d10  Comet\n\t\t1040 000f  AccelStar II\n\t\t1040 0011  AccelStar II\n\t\t1048 0a31  WINNER 2000\n\t\t1048 0a32  GLoria Synergy\n\t\t1048 0a34  GLoria Synergy\n\t\t1048 0a35  GLoria Synergy\n\t\t1048 0a36  GLoria Synergy\n\t\t1048 0a43  GLoria Synergy\n\t\t1048 0a44  GLoria Synergy\n\t\t107d 2633  WinFast 3D L2300\n\t\t1092 0126  FIRE GL 1000 PRO\n\t\t1092 0127  FIRE GL 1000 PRO\n\t\t1092 0136  FIRE GL 1000 PRO\n\t\t1092 0141  FIRE GL 1000 PRO\n\t\t1092 0146  FIRE GL 1000 PRO\n\t\t1092 0148  FIRE GL 1000 PRO\n\t\t1092 0149  FIRE GL 1000 PRO\n\t\t1092 0152  FIRE GL 1000 PRO\n\t\t1092 0154  FIRE GL 1000 PRO\n\t\t1092 0155  FIRE GL 1000 PRO\n\t\t1092 0156  FIRE GL 1000 PRO\n\t\t1092 0157  FIRE GL 1000 PRO\n\t\t1097 3d01  Jeronimo Pro\n\t\t1102 100f  Graphics Blaster Extreme\n\t\t3d3d 0100  Reference Permedia 2 3D\n\t8000  PCILynx/PCILynx2 IEEE 1394 Link Layer Controller\n\t\t105e 8003  FireBoard200\n\t\t1443 8003  FireBoard200\n\t\t1443 8005  FireBoard400\n\t\t1443 8006  FireBoard400\n\t\te4bf 1010  CF1-1-SNARE\n\t\te4bf 1020  CF1-2-SNARE\n\t\te4bf 1040  FireCompact400\n\t8009  TSB12LV22 IEEE-1394 Controller\n\t\t104d 8032  8032 OHCI i.LINK (IEEE 1394) Controller\n\t\t1443 8010  FireBoard400-OHCI\n\t8017  PCI4410 FireWire Controller\n\t8019  TSB12LV23 IEEE-1394 Controller\n\t\t11bd 000a  Studio DV500-1394\n\t\t11bd 000e  Studio DV\n\t\t1443 8010  FireBoard400-OHCI\n\t\te4bf 1010  CF2-1-CYMBAL\n\t8020  TSB12LV26 IEEE-1394 Controller (Link)\n\t\t1028 00d8  Precision 530\n\t\t104d 80e2  VAIO PCV-J200\n\t\t11bd 000f  Studio DV500-1394\n\t\t11bd 001c  Excalibur 4.1\n\t\t1443 8010  FireBoard400-OHCI\n\t8021  TSB43AA22 IEEE-1394 Controller (PHY/Link Integrated)\n\t\t104d 80df  Vaio PCG-FX403\n\t\t104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP\n\t8022  TSB43AB22 IEEE-1394a-2000 Controller (PHY/Link) [iOHCI-Lynx]\n\t\t104c 8023  TSB43AB22/A IEEE-1394a-2000 Controller (PHY/Link)\n\t8023  TSB43AB22A IEEE-1394a-2000 Controller (PHY/Link) [iOHCI-Lynx]\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t\t103c 088c  NC8000 laptop\n\t\t1043 808b  K8N4/A8N Series Mainboard\n\t\t1043 815b  P5W DH Deluxe Motherboard\n\t\t1443 8023  FireCard400\n\t\t8086 5044  Desktop Board DP35DP\n\t8024  TSB43AB23 IEEE-1394a-2000 Controller (PHY/Link)\n\t\t107d 6620  Winfast DV2000 FireWire Controller\n\t\t1443 8024  FireBoard Blue\n\t\t1458 1000  Motherboard\n\t8025  TSB82AA2 IEEE-1394b Link Layer Controller\n\t\t1043 813c  P5P series mainboard\n\t\t1443 8025  FireBoard800\n\t\t1458 1000  GA-K8N Ultra-9 Mainboard\n\t\t1546 8025  FWB-PCI01\n\t\t17fc 8025  GIC3800\n\t8026  TSB43AB21 IEEE-1394a-2000 Controller (PHY/Link)\n\t\t1025 0035  TravelMate 660\n\t\t1025 003c  Aspire 2001WLCi (Compaq CL50 motherboard)\n\t\t103c 0025  XE4500 Notebook\n\t\t103c 006a  NX9500\n\t\t1043 808d  A7V333 mainboard.\n\t8027  PCI4451 IEEE-1394 Controller\n\t\t1028 00e5  Latitude C810\n\t\t1028 00e6  PCI4451 IEEE-1394 Controller (Dell Inspiron 8100)\n\t8029  PCI4510 IEEE-1394 Controller\n\t\t1028 0163  Latitude D505\n\t\t1028 0196  Inspiron 5160\n\t\t1071 8160  MIM2900\n\t802b  PCI7410,7510,7610 OHCI-Lynx Controller\n\t\t1028 0139  Latitude D400\n\t\t1028 014e  PCI7410,7510,7610 OHCI-Lynx Controller (Latitude D800)\n\t802e  PCI7x20 1394a-2000 OHCI Two-Port PHY/Link-Layer Controller\n\t\t1028 018d  Inspiron 700m/710m\n\t8031  PCIxx21/PCIxx11/PCIx515 PC Card Controller\n\t\t1025 0064  Extensa 3000 series laptop\n\t\t1025 0080  Aspire 5024WLMi\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t103c 099c  NX6110/NC6120\n\t\t103c 308b  MX6125\n\t8032  OHCI Compliant IEEE 1394 Host Controller\n\t\t1025 0064  Extensa 3000 series laptop\n\t\t1025 0080  Aspire 5024WLMi\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 099c  NX6110/NC6120\n\t\t103c 308b  MX6125\n\t8033  PCIxx21/PCIxx11 Flash Media Controller\n\t\t1025 0064  Extensa 3000 series laptop\n\t\t1025 0080  Aspire 5024WLMi\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t103c 099c  NX6110/NC6120\n\t\t103c 308b  MX6125\n\t8034  PCIxx21/PCIxx11 SD Host Controller\n\t\t1025 0080  Aspire 5024WLMi\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t103c 099c  NX6110/NC6120\n\t\t103c 308b  MX6125\n\t8035  PCIxx21/PCIxx11 Smart Card Controller\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t103c 099c  NX6110/NC6120\n\t8036  PCI6515 Cardbus Controller\n\t8038  PCI6515 SmartCard Controller\n\t8039  PCIxx12 Cardbus Controller\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a1  NC2400\n\t\t103c 30a3  Compaq nw8440\n\t\t104d 902d  VAIO VGN-NR120E\n\t803a  PCIxx12 OHCI Compliant IEEE 1394 Host Controller\n\t\t103c 309f  nx9420\n\t\t103c 30a1  NC2400\n\t\t103c 30a3  Compaq nw8440\n\t\t104d 902d  VAIO VGN-NR120E\n\t803b  PCIxx12 Flash Media Controller\n\t\t103c 309f  nx9420\n\t\t103c 30a3  Compaq nw8440\n\t\t104d 8212  VAIO VGN-N21E\n\t\t104d 902d  VAIO VGN-NR120E\n\t803c  PCIxx12 SDA Standard Compliant SD Host Controller\n\t\t103c 309f  nx9420\n\t\t103c 30a3  Compaq nw8440\n\t803d  PCIxx12 GemCore based SmartCard controller\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a1  NC2400\n\t\t103c 30a3  nc8430\n\t\t103c 30aa  nc6310\n\t8101  TSB43DB42 IEEE-1394a-2000 Controller (PHY/Link)\n\t8201  PCI1620 Firmware Loading Function\n\t8204  PCI7410/7510/7610 PCI Firmware Loading Function\n\t\t1028 0139  Latitude D400\n\t\t1028 014e  Latitude D800\n\t8231  XIO2000(A)/XIO2200A PCI Express-to-PCI Bridge\n\t\t5678 1234  DC-1394 PCIe\n\t8232  XIO3130 PCI Express Switch (Upstream)\n\t8233  XIO3130 PCI Express Switch (Downstream)\n\t8235  XIO2200A IEEE-1394a-2000 Controller (PHY/Link)\n\t\t5678 1234  DC-1394 PCIe\n\t823e  XIO2213A/B/XIO2221 PCI Express to PCI Bridge [Cheetah Express]\n\t823f  XIO2213A/B/XIO2221 IEEE-1394b OHCI Controller [Cheetah Express]\n\t\t1546 803c  FWB-PCIE1X11B\n\t8240  XIO2001 PCI Express-to-PCI Bridge\n\t8241  TUSB73x0 SuperSpeed USB 3.0 xHCI Host Controller\n\t\t1014 04b2  S824 (8286-42A)\n\t8400  ACX 100 22Mbps Wireless Interface\n\t\t1186 3b00  DWL-650+ PC Card cardbus 22Mbs Wireless Adapter [AirPlus]\n\t\t1186 3b01  DWL-520+ 22Mbps PCI Wireless Adapter\n\t\t1395 2201  WL22-PC\n\t\t16ab 8501  WL-8305 IEEE802.11b+ Wireless LAN PCI Adapter\n\t8401  ACX 100 22Mbps Wireless Interface\n\t8888  Multicore DSP+ARM KeyStone II SOC\n\t9000  Wireless Interface (of unknown type)\n\t9065  TMS320DM642\n\t9066  ACX 111 54Mbps Wireless Interface\n\t\t0308 3404  G-102 v1 802.11g Wireless Cardbus Adapter\n\t\t0308 3406  G-162 v2 802.11g Wireless Cardbus Adapter\n\t\t104c 9066  WL212 Sitecom Wireless Network PCI-Card 100M (Version 1)\n# Found in Philips ADSL ANNEX A WLAN Router SNA6500/18 sold by Belgacom\n\t\t104c 9067  TNETW1130GVF\n\t\t104c 9096  Trendnet TEW-412PC Wireless PCI Adapter (Version A)\n\t\t1186 3b04  DWL-G520+ Wireless PCI Adapter\n\t\t1186 3b05  DWL-G650+ AirPlusG+ CardBus Wireless LAN\n\t\t1186 3b08  AirPlus G DWL-G630 Wireless Cardbus Adapter (rev.B1)\n\t\t1385 4c00  WG311v2 802.11g Wireless PCI Adapter\n\t\t13d1 aba0  SWLMP-54108 108Mbps Wireless mini PCI card 802.11g+\n\t\t14ea ab07  GW-NS54GM Wireless Cardbus Adapter\n\t\t16ec 010d  USR5416 802.11g Wireless Turbo PCI Adapter\n\t\t16ec 010e  USR5410 802.11g Wireless Cardbus Adapter\n\t\t1737 0033  WPC54G v2 802.11g Wireless-G Notebook Adapter\n\t\t17cf 0032  G-162 v1 802.11g Wireless Cardbus Adapter\n\t\t17cf 0033  Z-Com XG650 Wireless miniPCI 802.11b/g\n\t\t187e 340b  G-302 v2 802.11g Wireless PCI Adapter\n\t\t187e 340c  G-360 v2 802.11g Wireless PCI Adapter\n\ta001  TDC1570\n\ta100  TDC1561\n\ta102  TNETA1575 HyperSAR Plus w/PCI Host i/f & UTOPIA i/f\n\ta106  TMS320C6414 TMS320C6415 TMS320C6416\n\t\t175c 5000  ASI50xx Audio Adapter\n\t\t175c 6400  ASI6400 Cobranet series\n\t\t175c 8700  ASI87xx Radio Tuner card\n\tac10  PCI1050\n\tac11  PCI1053\n\tac12  PCI1130\n\tac13  PCI1031\n\tac15  PCI1131\n\tac16  PCI1250\n\t\t1014 0092  ThinkPad 600\n\tac17  PCI1220\n\tac18  PCI1260\n\tac19  PCI1221\n\tac1a  PCI1210\n\tac1b  PCI1450\n\t\t0e11 b113  Armada M700\n\t\t1014 0130  ThinkPad 600X/A21m/T20/T22\n\tac1c  PCI1225\n\t\t0e11 b121  Armada E500\n\t\t1028 0088  Latitude CPi A400XT\n\tac1d  PCI1251A\n\tac1e  PCI1211\n\tac1f  PCI1251B\n\tac20  TI 2030\n\tac21  PCI2031\n\tac22  PCI2032 PCI Docking Bridge\n\tac23  PCI2250 PCI-to-PCI Bridge\n\tac28  PCI2050 PCI-to-PCI Bridge\n\tac2c  PCI2060 PCI-to-PCI Bridge\n\tac30  PCI1260 PC card Cardbus Controller\n\tac40  PCI4450 PC card Cardbus Controller\n\tac41  PCI4410 PC card Cardbus Controller\n\tac42  PCI4451 PC card Cardbus Controller\n\t\t1028 00e6  PCI4451 PC card CardBus Controller (Inspiron 8100)\n\tac44  PCI4510 PC card Cardbus Controller\n\t\t1028 0149  Inspiron 5100\n\t\t1028 0163  Latitude D505\n\t\t1028 0196  Inspiron 5160\n\t\t1071 8160  MIM2000\n\tac46  PCI4520 PC card Cardbus Controller\n\t\t1014 0552  ThinkPad\n\tac47  PCI7510 PC card Cardbus Controller\n\t\t1028 0139  Latitude D400\n\t\t1028 013f  Precision M60\n\t\t1028 014e  Latitude D800\n\tac48  PCI7610 PC Card Cardbus Controller\n\tac49  PCI7410 PC Card Cardbus Controller\n\tac4a  PCI7510/7610 CardBus Bridge\n\t\t1028 0139  Latitude D400\n\t\t1028 014e  Latitude D800\n\tac4b  PCI7610 SD/MMC controller\n\tac4c  PCI7610 Memory Stick controller\n\tac50  PCI1410 PC card Cardbus Controller\n\tac51  PCI1420 PC card Cardbus Controller\n\t\t0e11 004e  Evo N600c\n\t\t1014 0148  ThinkPad A20m\n\t\t1014 023b  ThinkPad T23\n\t\t1028 00b1  Latitude C600\n\t\t1028 012a  Latitude C640\n\t\t1033 80cd  Versa Note VXi\n\t\t10cf 1095  Lifebook S-4510/C6155\n\t\te4bf 1000  CP2-2-HIPHOP\n\tac52  PCI1451 PC card Cardbus Controller\n\tac53  PCI1421 PC card Cardbus Controller\n\tac54  PCI1620 PC Card Controller\n\t\t103c 08b0  tc1100 tablet\n\tac55  PCI1520 PC card Cardbus Controller\n\t\t1014 0512  ThinkPad T30/T40\n\t\t103c 0025  XE4500 Notebook\n\tac56  PCI1510 PC card Cardbus Controller\n\t\t1014 0512  ThinkPad R50e\n\t\t1014 0528  ThinkPad R40e\n\t\t17aa 2012  ThinkPad T60/R60 series\n\tac60  PCI2040 PCI to DSP Bridge Controller\n\t\t175c 5100  ASI51xx Audio Adapter\n\t\t175c 6100  ASI61xx Audio Adapter\n\t\t175c 6200  ASI62xx Audio Adapter\n\t\t175c 8800  ASI88xx Audio Adapter\n\t\t186f 3001  WR-G303 PCI radio receiver\n\t\t186f 3005  WR-G305 PCI radio receiver\n\t\t186f 3101  WR-G313 PCI radio receiver\n\t\t186f 3105  WR-G315 PCI radio receiver\n\tac8d  PCI 7620\n\tac8e  PCI7420 CardBus Controller\n\t\t1028 018d  Inspiron 700m/710m\n\tac8f  PCI7420/7620 SD/MS-Pro Controller\n\t\t1028 018d  Inspiron 700m/710m\n\tb001  TMS320C6424\n\tfe00  FireWire Host Controller\n\tfe03  12C01A FireWire Host Controller\n104d  Sony Corporation\n\t8004  DTL-H2500 [Playstation development board]\n\t8009  CXD1947Q i.LINK Controller\n\t800c  DTL-H800 [PS1 sound development board]\n\t8039  CXD3222 i.LINK Controller\n\t8047  PS2 TOOL MRP\n\t8056  Rockwell HCF 56K modem\n\t808a  Memory Stick Controller\n\t80ff  PS2 Performance Analyzer\n\t814a  PS2 Performance Analyzer\n\t8183  ATHENS [PS3 prototype developer interface card]\n\t81b0  BM-1 [PSP TOOL Board Management Device]\n\t81c3  VO-4 [PSP TOOL Video Output Device]\n\t81ce  SxS Pro memory card\n\t81ff  PS3 TOOL MRP\n\t8200  PS3 TOOL RSX Tracing FPGA\n\t820e  CXD9208GP [PS3 PS2 emulation subsystem adapter]\n# 2nd ID\n\t905c  SxS Pro memory card\n# 2nd ID\n\t907f  SxS Pro+ memory card\n\t908f  Aeolia ACPI\n\t909e  Aeolia Ethernet Controller (Marvell Yukon 2 Family)\n\t909f  Aeolia SATA AHCI Controller\n\t90a0  Aeolia SD/MMC Host Controller\n\t90a1  Aeolia PCI Express Glue and Miscellaneous Devices\n\t90a2  Aeolia DMA Controller\n\t90a3  Aeolia Memory (DDR3/SPM)\n\t90a4  Aeolia USB 3.0 xHCI Host Controller\n\t90bc  SxS Pro+ memory card\n\t90c8  Belize ACPI\n\t90c9  Belize Ethernet Controller\n\t90ca  Belize SATA AHCI Controller\n\t90cb  Belize SD/MMC Host Controller\n\t90cc  Belize PCI Express Glue and Miscellaneous Devices\n\t90cd  Belize DMA Controller\n\t90ce  Belize Memory (DDR3/SPM)\n\t90cf  Belize USB 3.0 xHCI Host Controller\n\t90d7  Baikal ACPI\n\t90d8  Baikal Ethernet Controller\n\t90d9  Baikal SATA AHCI Controller\n\t90da  Baikal SD/MMC Host Controller\n\t90db  Baikal PCI Express Glue and Miscellaneous Devices\n\t90dc  Baikal DMA Controller\n\t90dd  Baikal Memory (DDR3/SPM)\n\t90de  Baikal USB 3.0 xHCI Host Controller\n104e  Oak Technology, Inc\n\t0017  OTI-64017\n\t0107  OTI-107 [Spitfire]\n\t0109  Video Adapter\n\t0111  OTI-64111 [Spitfire]\n\t0217  OTI-64217\n\t0317  OTI-64317\n104f  Co-time Computer Ltd\n1050  Winbond Electronics Corp\n\t0000  NE2000\n\t0001  W83769F\n\t0033  W89C33D 802.11 a/b/g BB/MAC\n\t0105  W82C105\n\t0840  W89C840\n\t\t1050 0001  W89C840 Ethernet Adapter\n\t\t1050 0840  W89C840 Ethernet Adapter\n\t0940  W89C940\n\t5a5a  W89C940F\n\t6692  W6692\n\t\t1043 1702  ISDN Adapter (PCI Bus, D, W)\n\t\t1043 1703  ISDN Adapter (PCI Bus, DV, W)\n\t\t1043 1707  ISDN Adapter (PCI Bus, DV, W)\n\t\t144f 1702  ISDN Adapter (PCI Bus, D, W)\n\t\t144f 1703  ISDN Adapter (PCI Bus, DV, W)\n\t\t144f 1707  ISDN Adapter (PCI Bus, DV, W)\n\t9921  W99200F MPEG-1 Video Encoder\n\t9922  W99200F/W9922PF MPEG-1/2 Video Encoder\n\t9970  W9970CF\n1051  Anigma, Inc.\n1052  ?Young Micro Systems\n1053  Young Micro Systems\n1054  Hitachi, Ltd\n\t3009  2Gbps Fibre Channel to PCI HBA 3009\n\t300a  4Gbps Fibre Channel to PCI-X HBA 300a\n\t300b  4Gbps Fibre Channel to PCI-X HBA 300b\n\t300f  ColdFusion 3 Chipset Processor to I/O Controller\n\t3010  ColdFusion 3 Chipset Memory Controller Hub\n\t3011  ColdFusion 3e Chipset Processor to I/O Controller\n\t3012  ColdFusion 3e Chipset Memory Controller Hub\n\t3017  Unassigned Hitachi Shared FC Device 3017\n\t301b  Virtual VGA Device\n\t301d  PCIe-to-PCIe Bridge with Virtualization IO Assist Feature\n\t3020  FIVE-EX based Fibre Channel to PCIe HBA\n\t302c  M001 PCI Express Switch Upstream Port\n\t302d  M001 PCI Express Switch Downstream Port\n\t3070  Hitachi FIVE-FX Fibre Channel to PCIe HBA\n\t3505  SH7751 PCI Controller (PCIC)\n\t350e  SH7751R PCI Controller (PCIC)\n1055  Microchip Technology / SMSC\n\t9130  SLC90E66 [Victory66] IDE\n\t9460  SLC90E66 [Victory66] ISA\n\t9462  SLC90E66 [Victory66] USB\n\t9463  SLC90E66 [Victory66] ACPI\n\te420  LAN9420/LAN9420i\n1056  ICL\n# Motorola made a mistake and used 1507 instead of 1057 in some chips. Please look at the 1507 entry as well when updating this.\n1057  Motorola\n\t0001  MPC105 [Eagle]\n\t0002  MPC106 [Grackle]\n\t0003  MPC8240 [Kahlua]\n\t0004  MPC107\n\t0006  MPC8245 [Unity]\n\t0008  MPC8540\n\t0009  MPC8560\n\t0012  MPC8548 [PowerQUICC III]\n\t0100  MC145575 [HFC-PCI]\n\t0431  KTI829c 100VG\n\t1073  Nokia N770\n\t1219  Nokia N800\n\t1801  DSP56301 Digital Signal Processor\n\t\t14fb 0101  Transas Radar Imitator Board [RIM]\n\t\t14fb 0102  Transas Radar Imitator Board [RIM-2]\n\t\t14fb 0202  Transas Radar Integrator Board [RIB-2]\n\t\t14fb 0611  1 channel CAN bus Controller [CanPci-1]\n\t\t14fb 0612  2 channels CAN bus Controller [CanPci-2]\n\t\t14fb 0613  3 channels CAN bus Controller [CanPci-3]\n\t\t14fb 0614  4 channels CAN bus Controller [CanPci-4]\n\t\t14fb 0621  1 channel CAN bus Controller [CanPci2-1]\n\t\t14fb 0622  2 channels CAN bus Controller [CanPci2-2]\n\t\t14fb 0810  Transas VTS Radar Integrator Board [RIB-4]\n\t\t175c 4200  ASI4215 Audio Adapter\n\t\t175c 4300  ASI43xx Audio Adapter\n\t\t175c 4400  ASI4401 Audio Adapter\n\t\tecc0 0010  Darla\n\t\tecc0 0020  Gina\n\t\tecc0 0030  Layla rev.0\n\t\tecc0 0031  Layla rev.1\n\t\tecc0 0040  Darla24 rev.0\n\t\tecc0 0041  Darla24 rev.1\n\t\tecc0 0050  Gina24 rev.0\n\t\tecc0 0051  Gina24 rev.1\n\t\tecc0 0070  Mona rev.0\n\t\tecc0 0071  Mona rev.1\n\t\tecc0 0072  Mona rev.2\n\t18c0  MPC8265A/8266/8272\n\t18c1  MPC8271/MPC8272\n\t3052  SM56 Data Fax Modem\n\t3410  DSP56361 Digital Signal Processor\n\t\tecc0 0050  Gina24 rev.0\n\t\tecc0 0051  Gina24 rev.1\n\t\tecc0 0060  Layla24\n\t\tecc0 0070  Mona rev.0\n\t\tecc0 0071  Mona rev.1\n\t\tecc0 0072  Mona rev.2\n\t\tecc0 0080  Mia rev.0\n\t\tecc0 0081  Mia rev.1\n\t\tecc0 0090  Indigo\n\t\tecc0 00a0  Indigo IO\n\t\tecc0 00b0  Indigo DJ\n\t\tecc0 0100  3G\n\t4801  Raven\n\t4802  Falcon\n\t4803  Hawk\n\t4806  CPX8216\n\t4d68  20268\n\t5600  SM56 PCI Modem\n\t\t1057 0300  SM56 PCI Speakerphone Modem\n\t\t1057 0301  SM56 PCI Voice Modem\n\t\t1057 0302  SM56 PCI Fax Modem\n\t\t1057 5600  SM56 PCI Voice modem\n\t\t13d2 0300  SM56 PCI Speakerphone Modem\n\t\t13d2 0301  SM56 PCI Voice modem\n\t\t13d2 0302  SM56 PCI Fax Modem\n\t\t1436 0300  SM56 PCI Speakerphone Modem\n\t\t1436 0301  SM56 PCI Voice modem\n\t\t1436 0302  SM56 PCI Fax Modem\n\t\t144f 100c  SM56 PCI Fax Modem\n\t\t1494 0300  SM56 PCI Speakerphone Modem\n\t\t1494 0301  SM56 PCI Voice modem\n\t\t14c8 0300  SM56 PCI Speakerphone Modem\n\t\t14c8 0302  SM56 PCI Fax Modem\n\t\t1668 0300  SM56 PCI Speakerphone Modem\n\t\t1668 0302  SM56 PCI Fax Modem\n\t5608  Wildcard X100P\n\t5803  MPC5200\n\t5806  MCF54 Coldfire\n\t5808  MPC8220\n\t5809  MPC5200B\n\t6400  MPC190 Security Processor (S1 family, encryption)\n\t6405  MPC184 Security Processor (S1 family)\n1058  Electronics & Telecommunications RSH\n1059  Kontron\n105a  Promise Technology, Inc.\n\t0d30  PDC20265 (FastTrak100 Lite/Ultra100)\n\t\t1043 8042  AV7266-E South Bridge Promise RAID\n\t\t105a 4d33  Ultra100\n\t0d38  20263\n\t\t105a 4d39  Fasttrak66\n\t1275  20275\n\t3318  PDC20318 (SATA150 TX4)\n\t3319  PDC20319 (FastTrak S150 TX4)\n\t\t105a 3319  FastTrak S150 TX4 4 port SATA PCI board\n\t\t8086 3427  S875WP1-E mainboard\n\t3371  PDC20371 (FastTrak S150 TX2plus)\n\t3373  PDC20378 (FastTrak 378/SATA 378)\n\t\t1043 80f5  K8V Deluxe/PC-DL Deluxe motherboard\n\t\t1462 590d  KT6 Delta-FIS2R (MS-6590)\n\t\t1462 702e  K8T NEO FIS2R motherboard\n\t3375  PDC20375 (SATA150 TX2plus)\n\t3376  PDC20376 (FastTrak 376)\n\t\t1043 809e  A7V8X motherboard\n\t3515  PDC40719 [FastTrak TX4300/TX4310]\n\t3519  PDC40519 (FastTrak TX4200)\n\t3570  PDC20771 [FastTrak TX2300]\n\t3571  PDC20571 (FastTrak TX2200)\n\t3574  PDC20579 SATAII 150 IDE Controller\n\t3577  PDC40779 (SATA 300 779)\n\t3d17  PDC40718 (SATA 300 TX4)\n\t3d18  PDC20518/PDC40518 (SATAII 150 TX4)\n\t3d73  PDC40775 (SATA 300 TX2plus)\n\t3d75  PDC20575 (SATAII150 TX2plus)\n\t3f20  PDC42819 [FastTrak TX2650/TX4650]\n\t4302  80333 [SuperTrak EX4350]\n\t4d30  PDC20267 (FastTrak100/Ultra100)\n\t\t105a 4d33  Ultra100\n\t\t105a 4d39  FastTrak100\n\t\t8086 5744  S845WD1-E mainboard\n\t4d33  20246\n\t\t105a 4d33  20246 IDE Controller\n\t4d38  PDC20262 (FastTrak66/Ultra66)\n\t\t105a 4d30  Ultra Device on SuperTrak\n\t\t105a 4d33  Ultra66\n\t\t105a 4d39  FastTrak66\n\t4d68  PDC20268 [Ultra100 TX2]\n\t\t105a 4d68  Ultra100 TX2\n\t4d69  20269\n\t\t105a 4d68  Ultra133TX2\n\t5275  PDC20276 (MBFastTrak133 Lite)\n\t\t1043 807e  A7V333 motherboard.\n\t\t105a 0275  SuperTrak SX6000 IDE\n\t\t105a 1275  MBFastTrak133 Lite (tm) Controller (RAID mode)\n\t\t1458 b001  MBUltra 133\n\t5300  DC5300\n\t6268  PDC20270 (FastTrak100 LP/TX2/TX4)\n\t\t105a 4d68  FastTrak100 TX2\n\t6269  PDC20271 (FastTrak TX2000)\n\t\t105a 6269  FastTrak TX2/TX2000\n\t6300  PDC81731 [FastTrak SX8300]\n\t6621  PDC20621 (FastTrak S150 SX4/FastTrak SX4000 lite)\n\t6622  PDC20621 [SATA150 SX4] 4 Channel IDE RAID Controller\n\t6624  PDC20621 [FastTrak SX4100]\n\t6626  PDC20618 (Ultra 618)\n\t6629  PDC20619 (FastTrak TX4000)\n\t7275  PDC20277 (SBFastTrak133 Lite)\n\t8002  SATAII150 SX8\n\t8350  80333 [SuperTrak EX8350/EX16350], 80331 [SuperTrak EX8300/EX16300]\n\t8650  81384 [SuperTrak EX SAS and SATA RAID Controller]\n\t\t105a 4600  SuperTrak EX4650A\n\t\t105a 4601  SuperTrak EX4650\n\t\t105a 4610  SuperTrak EX4650EL\n\t\t105a 8600  SuperTrak EX8650EL\n\t\t105a 8601  SuperTrak EX8650A\n\t\t105a 8602  SuperTrak EX8654\n\t\t105a 8603  SuperTrak EX8658\n\t\t105a 8604  SuperTrak EX8650\n\t\t105a 8610  SuperTrak EX8650M\n\t\t105a a600  SuperTrak EX12650\n\t\t105a b600  SuperTrak EX16650\n\t\t105a b601  SuperTrak EX16654\n\t\t105a b602  SuperTrak EX16658\n\t8760  PM8010 [SuperTrak EX SAS and SATA 6G RAID Controller]\n\tc350  80333 [SuperTrak EX12350]\n\te350  80333 [SuperTrak EX24350]\n105b  Foxconn International, Inc.\n105c  Wipro Infotech Limited\n105d  Number 9 Computer Company\n\t2309  Imagine 128\n\t2339  Imagine 128-II\n\t\t105d 0000  Imagine 128 series 2 4Mb VRAM\n\t\t105d 0001  Imagine 128 series 2 4Mb VRAM\n\t\t105d 0002  Imagine 128 series 2 4Mb VRAM\n\t\t105d 0003  Imagine 128 series 2 4Mb VRAM\n\t\t105d 0004  Imagine 128 series 2 4Mb VRAM\n\t\t105d 0005  Imagine 128 series 2 4Mb VRAM\n\t\t105d 0006  Imagine 128 series 2 4Mb VRAM\n\t\t105d 0007  Imagine 128 series 2 4Mb VRAM\n\t\t105d 0008  Imagine 128 series 2e 4Mb DRAM\n\t\t105d 0009  Imagine 128 series 2e 4Mb DRAM\n\t\t105d 000a  Imagine 128 series 2 8Mb VRAM\n\t\t105d 000b  Imagine 128 series 2 8Mb H-VRAM\n\t\t11a4 000a  Barco Metheus 5 Megapixel\n\t\t13cc 0000  Barco Metheus 5 Megapixel\n\t\t13cc 0004  Barco Metheus 5 Megapixel\n\t\t13cc 0005  Barco Metheus 5 Megapixel\n\t\t13cc 0006  Barco Metheus 5 Megapixel\n\t\t13cc 0008  Barco Metheus 5 Megapixel\n\t\t13cc 0009  Barco Metheus 5 Megapixel\n\t\t13cc 000a  Barco Metheus 5 Megapixel\n\t\t13cc 000c  Barco Metheus 5 Megapixel\n\t493d  Imagine 128 T2R [Ticket to Ride]\n\t\t11a4 000a  Barco Metheus 5 Megapixel, Dual Head\n\t\t11a4 000b  Barco Metheus 5 Megapixel, Dual Head\n\t\t13cc 0002  Barco Metheus 4 Megapixel, Dual Head\n\t\t13cc 0003  Barco Metheus 5 Megapixel, Dual Head\n\t\t13cc 0007  Barco Metheus 5 Megapixel, Dual Head\n\t\t13cc 0008  Barco Metheus 5 Megapixel, Dual Head\n\t\t13cc 0009  Barco Metheus 5 Megapixel, Dual Head\n\t\t13cc 000a  Barco Metheus 5 Megapixel, Dual Head\n\t5348  Revolution 4\n\t\t105d 0037  Revolution IV-FP AGP (For SGI 1600SW)\n\t\t11a4 0028  PVS5600M\n\t\t11a4 0038  PVS5600D\n105e  Vtech Computers Ltd\n105f  Infotronic America Inc\n1060  United Microelectronics [UMC]\n\t0001  UM82C881\n\t0002  UM82C886\n\t0101  UM8673F\n\t0881  UM8881\n\t0886  UM8886F\n\t0891  UM8891A\n\t1001  UM886A\n\t673a  UM8886BF\n\t673b  EIDE Master/DMA\n\t8710  UM8710\n\t886a  UM8886A\n\t8881  UM8881F\n\t8886  UM8886F\n\t888a  UM8886A\n\t8891  UM8891A\n\t9017  UM9017F\n\t9018  UM9018\n\t9026  UM9026\n\te881  UM8881N\n\te886  UM8886N\n\te88a  UM8886N\n\te891  UM8891N\n1061  I.I.T.\n\t0001  AGX016\n\t0002  IIT3204/3501\n1062  Maspar Computer Corp\n1063  Ocean Office Automation\n1064  Alcatel\n\t1102  Dynamite 2840 (ADSL PCI modem)\n1065  Texas Microsystems\n1066  PicoPower Technology\n\t0000  PT80C826\n\t0001  PT86C521 [Vesuvius v1] Host Bridge\n\t0002  PT86C523 [Vesuvius v3] PCI-ISA Bridge Master\n\t0003  PT86C524 [Nile] PCI-to-PCI Bridge\n\t0004  PT86C525 [Nile-II] PCI-to-PCI Bridge\n\t0005  National PC87550 System Controller\n\t8002  PT86C523 [Vesuvius v3] PCI-ISA Bridge Slave\n1067  Mitsubishi Electric\n\t0301  AccelGraphics AccelECLIPSE\n\t0304  AccelGALAXY A2100 [OEM Evans & Sutherland]\n\t0308  Tornado 3000 [OEM Evans & Sutherland]\n\t1002  VG500 [VolumePro Volume Rendering Accelerator]\n1068  Diversified Technology\n1069  Mylex Corporation\n\t0001  DAC960P\n\t0002  DAC960PD\n\t0010  DAC960PG\n\t0020  DAC960LA\n\t0050  AcceleRAID 352/170/160 support Device\n\t\t1069 0050  AcceleRAID 352 support Device\n\t\t1069 0052  AcceleRAID 170 support Device\n\t\t1069 0054  AcceleRAID 160 support Device\n\tb166  AcceleRAID 600/500/400/Sapphire support Device\n\t\t1014 0242  iSeries 2872 DASD IOA\n\t\t1014 0266  Dual Channel PCI-X U320 SCSI Adapter\n\t\t1014 0278  Dual Channel PCI-X U320 SCSI RAID Adapter\n\t\t1014 02d3  Dual Channel PCI-X U320 SCSI Adapter\n\t\t1014 02d4  Dual Channel PCI-X U320 SCSI RAID Adapter\n\t\t1069 0200  AcceleRAID 400, Single Channel, PCI-X, U320, SCSI RAID\n\t\t1069 0202  AcceleRAID Sapphire, Dual Channel, PCI-X, U320, SCSI RAID\n\t\t1069 0204  AcceleRAID 500, Dual Channel, Low-Profile, PCI-X, U320, SCSI RAID\n\t\t1069 0206  AcceleRAID 600, Dual Channel, PCI-X, U320, SCSI RAID\n\tba55  eXtremeRAID 1100 support Device\n\tba56  eXtremeRAID 2000/3000 support Device\n\t\t1069 0030  eXtremeRAID 3000 support Device\n\t\t1069 0040  eXtremeRAID 2000 support Device\n\tba57  eXtremeRAID 4000/5000 support Device\n\t\t1069 0072  eXtremeRAID 5000 support Device\n106a  Aten Research Inc\n106b  Apple Inc.\n\t0001  Bandit PowerPC host bridge\n\t0002  Grand Central I/O\n\t0003  Control Video\n\t0004  PlanB Video-In\n\t0007  O'Hare I/O\n\t000c  DOS on Mac\n\t000e  Hydra Mac I/O\n\t0010  Heathrow Mac I/O\n\t0017  Paddington Mac I/O\n\t0018  UniNorth FireWire\n\t0019  KeyLargo USB\n\t001e  UniNorth Internal PCI\n\t001f  UniNorth PCI\n\t0020  UniNorth AGP\n\t0021  UniNorth GMAC (Sun GEM)\n\t0022  KeyLargo Mac I/O\n\t0024  UniNorth/Pangea GMAC (Sun GEM)\n\t0025  KeyLargo/Pangea Mac I/O\n\t0026  KeyLargo/Pangea USB\n\t0027  UniNorth/Pangea AGP\n\t0028  UniNorth/Pangea PCI\n\t0029  UniNorth/Pangea Internal PCI\n\t002d  UniNorth 1.5 AGP\n\t002e  UniNorth 1.5 PCI\n\t002f  UniNorth 1.5 Internal PCI\n\t0030  UniNorth/Pangea FireWire\n\t0031  UniNorth 2 FireWire\n\t\t106b 5811  iBook G4 2004\n\t0032  UniNorth 2 GMAC (Sun GEM)\n\t0033  UniNorth 2 ATA/100\n\t0034  UniNorth 2 AGP\n\t0035  UniNorth 2 PCI\n\t0036  UniNorth 2 Internal PCI\n\t003b  UniNorth/Intrepid ATA/100\n\t003e  KeyLargo/Intrepid Mac I/O\n\t003f  KeyLargo/Intrepid USB\n\t\t1af4 1100  QEMU Virtual Machine\n\t0040  K2 KeyLargo USB\n\t0041  K2 KeyLargo Mac/IO\n\t0042  K2 FireWire\n\t0043  K2 ATA/100\n\t0045  K2 HT-PCI Bridge\n\t0046  K2 HT-PCI Bridge\n\t0047  K2 HT-PCI Bridge\n\t0048  K2 HT-PCI Bridge\n\t0049  K2 HT-PCI Bridge\n\t004a  CPC945 HT Bridge\n\t004b  U3 AGP\n\t004c  K2 GMAC (Sun GEM)\n\t004f  Shasta Mac I/O\n\t0050  Shasta IDE\n\t0051  Shasta (Sun GEM)\n\t0052  Shasta Firewire\n\t0053  Shasta PCI Bridge\n\t0054  Shasta PCI Bridge\n\t0055  Shasta PCI Bridge\n\t0056  U4 PCIe\n\t0057  U3 HT Bridge\n\t0058  U3L AGP Bridge\n\t0059  U3H AGP Bridge\n\t005b  CPC945 PCIe Bridge\n\t0066  Intrepid2 AGP Bridge\n\t0067  Intrepid2 PCI Bridge\n\t0068  Intrepid2 PCI Bridge\n\t0069  Intrepid2 ATA/100\n\t006a  Intrepid2 Firewire\n\t006b  Intrepid2 GMAC (Sun GEM)\n\t0074  U4 HT Bridge\n# should be 14e4:1645\n\t1645  Broadcom NetXtreme BCM5701 Gigabit Ethernet\n\t1801  T2 Bridge Controller\n\t1802  T2 Secure Enclave Processor\n\t1803  Apple Audio Device\n\t2001  S1X NVMe Controller\n\t2002  S3ELab NVMe Controller\n\t2003  S3X NVMe Controller\n\t2005  ANS2 NVMe Controller\n106c  Hynix Semiconductor\n\t8139  8139c 100BaseTX Ethernet Controller\n\t8801  Dual Pentium ISA/PCI Motherboard\n\t8802  PowerPC ISA/PCI Motherboard\n\t8803  Dual Window Graphics Accelerator\n\t8804  LAN Controller\n\t8805  100-BaseT LAN\n106d  Sequent Computer Systems\n106e  DFI, Inc\n106f  City Gate Development Ltd\n1070  Daewoo Telecom Ltd\n1071  Mitac\n\t8160  Mitac 8060B Mobile Platform\n1072  GIT Co Ltd\n1073  Yamaha Corporation\n\t0001  3D GUI Accelerator\n\t0002  YGV615 [RPA3 3D-Graphics Controller]\n\t0003  YMF-740\n\t0004  YMF-724\n\t\t1073 0004  YMF724-Based PCI Audio Adapter\n\t0005  DS1 Audio\n\t\t1073 0005  DS-XG PCI Audio CODEC\n\t0006  DS1 Audio\n\t0008  DS1 Audio\n\t\t1073 0008  DS-XG PCI Audio CODEC\n\t000a  DS1L Audio\n\t\t1073 0004  DS-XG PCI Audio CODEC\n\t\t1073 000a  DS-XG PCI Audio CODEC\n\t\t8086 4d55  DS-XG PCI Audio CODEC [Intel MU440EX]\n\t000c  YMF-740C [DS-1L Audio Controller]\n\t\t107a 000c  DS-XG PCI Audio CODEC\n\t000d  YMF-724F [DS-1 Audio Controller]\n\t\t1073 000d  DS-XG PCI Audio CODEC\n\t0010  YMF-744B [DS-1S Audio Controller]\n\t\t1073 0006  DS-XG PCI Audio CODEC\n\t\t1073 0010  DS-XG PCI Audio CODEC\n\t0012  YMF-754 [DS-1E Audio Controller]\n\t\t1073 0012  DS-XG PCI Audio Codec\n\t0020  DS-1 Audio\n\t1000  SW1000XG [XG Factory]\n\t2000  DS2416 Digital Mixing Card\n\t\t1073 2000  DS2416 Digital Mixing Card\n1074  NexGen Microsystems\n\t4e78  82c500/1\n1075  Advanced Integrations Research\n1076  Chaintech Computer Co. Ltd\n1077  QLogic Corp.\n\t1016  ISP10160 Single Channel Ultra3 SCSI Processor\n\t1020  ISP1020 Fast-wide SCSI\n\t1022  ISP1022 Fast-wide SCSI\n\t1080  ISP1080 SCSI Host Adapter\n\t1216  ISP12160 Dual Channel Ultra3 SCSI Processor\n\t\t101e 8471  QLA12160 on AMI MegaRAID\n\t\t101e 8493  QLA12160 on AMI MegaRAID\n\t1240  ISP1240 SCSI Host Adapter\n\t1280  ISP1280 SCSI Host Adapter\n\t1634  FastLinQ QL45000 Series 40GbE Controller\n\t\t1077 e4f1  FastLinQ QL45212H 40GbE Adapter\n\t\t1077 e4f2  FastLinQ QL45211H 40GbE Adapter\n\t\t1077 e4f3  FastLinQ QL45412H 40GbE Adapter\n\t\t1077 e4f4  FastLinQ QL45411H 40GbE Adapter\n\t1644  FastLinQ QL45000 Series 100GbE Controller\n\t\t1077 e4f8  FastLinQ QL45611H 100GbE Adapter\n\t1654  FastLinQ QL45000 Series 50GbE Controller\n\t\t1077 0032  QL45212 Flex 50Gb 2-port Ethernet Adapter\n\t\t1590 0223  Synergy 6810C 25/50Gb Ethernet Adapter\n\t\t1590 0287  Synergy 6820C 25/50Gb CNA\n\t1656  FastLinQ QL45000 Series 25GbE Controller\n\t\t1077 0033  QL45214 Flex 25Gb 4-port Ethernet Adapter\n\t\t1077 02a7  QL45212-DE 25GbE Adapter\n\t\t1077 e4f6  FastLinQ QL45211H 25GbE Adapter\n\t\t1077 e4f7  FastLinQ QL45212H 25GbE Adapter\n\t\t1590 0245  10/20/25GbE 2P 4820c CNA\n\t165c  FastLinQ QL45000 Series 10/25/40/50GbE Controller (FCoE)\n\t\t1077 0034  QL45262 Flex 50Gb 2-port Ethernet Adapter w/ iSCSI/FCoE\n\t\t1077 e4f1  FastLinQ QL45462H 40GbE FCoE Adapter\n\t\t1077 e4f2  FastLinQ QL45461H 40GbE FCoE Adapter\n\t\t1590 0245  10/20/25GbE 2P 4820c CNA FCoE\n\t165e  FastLinQ QL45000 Series 10/25/40/50GbE Controller (iSCSI)\n\t\t1077 0034  QL45262 Flex 50Gb 2-port Ethernet Adapter w/ iSCSI/FCoE\n\t\t1077 e4f1  FastLinQ QL45462H 40GbE iSCSI Adapter\n\t\t1077 e4f2  FastLinQ QL45461H 40GbE iSCSI Adapter\n\t\t1590 0245  10/20/25GbE 2P 4820c CNA iSCSI\n\t1664  FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF)\n\t\t1077 e4f1  FastLinQ QL45462H 40GbE Adapter (SR-IOV VF)\n\t\t1077 e4f2  FastLinQ QL45461H 40GbE Adapter (SR-IOV VF)\n\t\t1077 e4f3  FastLinQ QL45412H 40GbE Adapter (SR-IOV VF)\n\t\t1077 e4f4  FastLinQ QL45411H 40GbE Adapter (SR-IOV VF)\n\t\t1077 e4f6  FastLinQ QL45211H 25GbE Adapter (SR-IOV VF)\n\t\t1077 e4f7  FastLinQ QL45212H 25GbE Adapter (SR-IOV VF)\n\t\t1077 e4f8  FastLinQ QL45611H 100GbE Adapter (SR-IOV VF)\n\t\t1590 0245  10/20/25GbE 2P 4820c CNA SRIOV\n\t2020  ISP2020A Fast!SCSI Basic Adapter\n\t2031  ISP8324-based 16Gb Fibre Channel to PCI Express Adapter\n\t\t103c 17e7  SN1000Q 16Gb Single Port Fibre Channel Adapter\n\t\t103c 17e8  SN1000Q 16Gb Dual Port Fibre Channel Adapter\n\t\t103c 1939  QMH2672 16Gb Dual Port Fibre Channel Adapter\n\t\t103c 8002  3830C 16G Fibre Channel Host Bus Adapter\n\t2071  ISP2714-based 16/32Gb Fibre Channel to PCIe Adapter\n\t\t1077 0283  QLE2764 Quad Port 32Gb Fibre Channel to PCIe Adapter\n\t\t1077 029e  QLE2694 Quad Port 16Gb Fibre Channel to PCIe Adapter\n\t\t1077 02a2  QLE2694L Quad Port 16Gb Fibre Channel to PCIe Adapter\n\t\t1077 02ad  QLE2694U Quad Port 16/32Gb Fibre Channel to PCIe Adapter\n\t2081  ISP2814-based 64/32G Fibre Channel to PCIe Controller\n\t\t1077 02e1  QLE2874 Quad Port 64GFC PCIe Gen4 x16 Adapter\n\t\t1077 02e3  QLE2774 Quad Port 32GFC PCIe Gen4 x16 Adapter\n\t2100  QLA2100 64-bit Fibre Channel Adapter\n\t\t1077 0001  QLA2100 64-bit Fibre Channel Adapter\n\t2200  QLA2200 64-bit Fibre Channel Adapter\n\t\t1077 0002  QLA2200\n\t2261  ISP2722-based 16/32Gb Fibre Channel to PCIe Adapter\n\t\t1077 0299  QLE2740 Single Port 32Gb Fibre Channel to PCIe Adapter\n\t\t1077 029a  QLE2742 Dual Port 32Gb Fibre Channel to PCIe Adapter\n\t\t1077 029b  QLE2690 Single Port 16Gb Fibre Channel to PCIe Adapter\n\t\t1077 029c  QLE2692 Dual Port 16Gb Fibre Channel to PCIe Adapter\n\t\t1077 02a7  QLE2690 Single Port 16Gb FC to PCIe Gen3 x8 Adapter\n\t\t1077 02a8  QLE2692 Dual Port 16Gb FC to PCIe Gen3 x8 Adapter\n\t\t1077 02ab  QLE2740 Single Port 32Gb FC to PCIe Gen3 x8 Adapter\n\t\t1077 02ac  QLE2742 Dual Port 32Gb FC to PCIe Gen3 x8 Adapter\n\t\t1077 02b8  2x16Gb QME2692 FC HBA\n\t\t1077 02b9  2x32Gb QME2742 FC HBA\n\t\t1590 00f9  StoreFabric SN1100Q 16Gb Single Port Fibre Channel Host Bus Adapter\n\t\t1590 00fa  StoreFabric SN1100Q 16Gb Dual Port Fibre Channel Host Bus Adapter\n\t\t1590 0203  StoreFabric SN1600Q 32Gb Single Port Fibre Channel Host Bus Adapter\n\t\t1590 0204  StoreFabric SN1600Q 32Gb Dual Port Fibre Channel Host Bus Adapter\n\t\t1590 022d  5830C 32Gb Dual Port Fibre Channel Adapter\n\t2281  ISP2812-based 64/32G Fibre Channel to PCIe Controller\n\t\t1077 02e2  QLE2872 Dual Port 64GFC PCIe Gen4 x8 Adapter\n\t\t1077 02e4  QLE2772 Dual Port 32GFC PCIe Gen4 x8 Adapter\n\t\t1077 02ee  QLE2870 Single Port 64GFC PCIe Gen4 x8 Adapter\n\t\t1077 02f0  QLE2770 Single Port 32GFC PCIe Gen4 x8 Adapter\n\t\t1590 02d3  SN1610Q - 1P Enhanced 32GFC Single Port Fibre Channel Host Bus Adapter\n\t\t1590 02d4  SN1610Q – 2P Enhanced 32GFC Dual Port Fibre Channel Host Bus Adapter\n\t2300  QLA2300 64-bit Fibre Channel Adapter\n\t2312  ISP2312-based 2Gb Fibre Channel to PCI-X HBA\n\t\t103c 0131  2Gb Fibre Channel - Single port [A7538A]\n\t\t103c 12ba  2Gb Fibre Channel - Dual port [A6826A]\n\t2322  ISP2322-based 2Gb Fibre Channel to PCI-X HBA\n\t2422  ISP2422-based 4Gb Fibre Channel to PCI-X HBA\n\t\t103c 12d7  4Gb Fibre Channel [AB379A]\n\t\t103c 12dd  4Gb Fibre Channel [AB429A]\n\t2432  ISP2432-based 4Gb Fibre Channel to PCI Express HBA\n\t\t103c 7040  FC1142SR 4Gb 1-port PCIe Fibre Channel Host Bus Adapter [HPAE311A]\n\t\t1077 0137  QLE2460 4 GB PCI-X Host-Bus-Adapter\n\t2532  ISP2532-based 8Gb Fibre Channel to PCI Express HBA\n\t\t1014 041e  FC EN0Y/EN12 PCIe2 LP 8 Gb 4-port Fibre Channel Adapter for POWER\n\t\t103c 3262  StorageWorks 81Q\n\t\t103c 3263  StorageWorks 82Q\n\t\t1077 015c  QLE2560 PCI Express to 8Gb FC Single Channel\n\t\t1077 015d  QLE2562 PCI Express to 8Gb FC Dual Channel\n\t\t1077 015e  QLE2564 PCI Express to 8Gb FC Quad Channel\n\t\t1077 0167  QME2572 Dual Port FC8 HBA Mezzanine\n\t\t1590 00fc  StoreFabric 84Q 8Gb Quad Port Fibre Channel Host Bus Adapter\n\t2971  ISP2684\n\t3022  ISP4022-based Ethernet NIC\n\t3032  ISP4032-based Ethernet IPv6 NIC\n\t4010  ISP4010-based iSCSI TOE HBA\n\t4022  ISP4022-based iSCSI TOE HBA\n\t4032  ISP4032-based iSCSI TOE IPv6 HBA\n\t5432  SP232-based 4Gb Fibre Channel to PCI Express HBA\n\t6312  SP202-based 2Gb Fibre Channel to PCI-X HBA\n\t6322  SP212-based 2Gb Fibre Channel to PCI-X HBA\n\t7220  IBA7220 InfiniBand HCA\n\t7322  IBA7322 QDR InfiniBand HCA\n\t8000  10GbE Converged Network Adapter (TCP/IP Networking)\n\t8001  10GbE Converged Network Adapter (FCoE)\n\t\t1014 03af  FC 5708/5270 10 Gb FCoE PCIe Dual Port Adapter for POWER\n\t8020  cLOM8214 1/10GbE Controller\n\t\t1028 1f64  QMD8262-k 10G DP bNDC KR\n\t\t103c 3346  CN1000Q Dual Port Converged Network Adapter\n\t\t103c 3733  NC523SFP 10Gb 2-port Server Adapter\n\t\t1077 0203  8200 Series Single Port 10GbE Converged Network Adapter (TCP/IP Networking)\n\t\t1077 0207  8200 Series Dual Port 10GbE Converged Network Adapter (TCP/IP Networking)\n\t\t1077 020b  3200 Series Dual Port 10Gb Intelligent Ethernet Adapter\n\t\t1077 020c  3200 Series Quad Port 1Gb Intelligent Ethernet Adapter\n\t\t1077 020f  3200 Series Single Port 10Gb Intelligent Ethernet Adapter\n\t\t1077 0210  QME8242-k 10GbE Dual Port Mezzanine Card\n\t\t1077 0233  QME8262-k 10GbE Dual Port Mezzanine Card\n\t8021  8200 Series 10GbE Converged Network Adapter (FCoE)\n\t\t103c 3348  CN1000Q Dual Port Converged Network Adapter\n\t\t1077 0211  QME8242-k 10GbE Dual Port Mezzanine Card, FCoE\n\t8022  8200 Series 10GbE Converged Network Adapter (iSCSI)\n\t\t103c 3347  CN1000Q Dual Port Converged Network Adapter\n\t\t1077 0212  QME8242-k 10GbE Dual Port Mezzanine Card, iSCSI\n\t8030  ISP8324 1/10GbE Converged Network Controller\n\t\t1077 0243  8300 Series Single Port 10GbE Converged Network Adapter (TCP/IP Networking)\n\t\t1077 0246  8300 Series Dual Port 10GbE Converged Network Adapter (TCP/IP Networking)\n\t8031  8300 Series 10GbE Converged Network Adapter (FCoE)\n\t8032  8300 Series 10GbE Converged Network Adapter (iSCSI)\n\t8070  FastLinQ QL41000 Series 10/25/40/50GbE Controller\n\t\t1077 0001  10GE 2P QL41162HxRJ-DE Adapter\n\t\t1077 0002  10GE 2P QL41112HxCU-DE Adapter\n\t\t1077 0004  4x10GE QL41164HFCU CNA\n\t\t1077 0005  QLogic 4x10GE QL41164HMRJ CNA\n\t\t1077 0006  QLogic 4x10GE QL41164HMCU CNA\n\t\t1077 0007  QLogic 2x1GE+2x10GE QL41264HMCU CNA\n\t\t1077 0009  QLogic 2x1GE+2x10GE QL41162HMRJ CNA\n\t\t1077 000b  25GE 2P QL41262HxCU-DE Adapter\n\t\t1077 000f  2x25GE QL41262HMKR CNA\n\t\t1077 0010  2x25GE QL41232HMKR NIC\n\t\t1077 0011  FastLinQ QL41212HLCU 25GbE Adapter\n\t\t1077 0012  FastLinQ QL41112H 10GbE Adapter\n\t\t1077 0019  QL41232HOCU - Dual Port 25/10GbE SFP28 OCP Adapter\n\t\t1077 0039  QLogic QL41262 PCIe 25Gb 2-Port SFP28 Ethernet Adapter\n\t\t1077 0053  QLogic 2x25GE QL41232HQCU NIC\n\t\t1077 0054  2x10GE QL41132HQRJ NIC\n\t\t1077 0055  QLogic 2x10GE QL41132HQCU NIC\n\t\t1077 0056  2x10GE QL41132HxRJ NIC\n\t\t1077 0057  2x25GE QL41232HxCU NIC\n\t\t1590 021a  10GbE 2P QL41162HLRJ-HP Adapter\n\t\t1590 021b  10GbE 2P QL41162HLRJ-HP Adapter\n\t\t1590 021d  10/25GbE 2P QL41222HLCU-HP Adapter\n\t\t1590 021e  10/25GbE 2P QL41162HMRJ-HP Adapter\n\t\t1590 021f  10/25GbE 2P QL41262HMCU-HP Adapter\n\t\t1590 0220  10/25GbE 2P QL41122HLRJ-HP Adapter\n\t\t1590 02bd  10Gb 2P 524SFP+ NIC\n\t8080  FastLinQ QL41000 Series 10/25/40/50GbE Controller (FCoE)\n\t\t1077 0001  10GE 2P QL41162HxRJ-DE Adapter\n\t\t1077 0002  10GE 2P QL41112HxCU-DE Adapter\n\t\t1077 0004  4x10GE QL41164HFCU CNA\n\t\t1077 0005  QLogic 4x10GE QL41164HMRJ CNA\n\t\t1077 0006  QLogic 4x10GE QL41164HMCU CNA\n\t\t1077 0007  QLogic 2x1GE+2x10GE QL41264HMCU CNA\n\t\t1077 0009  QLogic 2x1GE+2x10GE QL41162HMRJ CNA\n\t\t1077 000b  25GE 2P QL41262HxCU-DE Adapter\n\t\t1077 000c  QLogic 2x25GE QL41262HMCU CNA\n\t\t1077 000d  FastLinQ QL41262H 25GbE FCoE Adapter\n\t\t1077 000e  FastLinQ QL41162H 10GbE FCoE Adapter\n\t\t1077 000f  2x25GE QL41262HMKR CNA\n\t\t1590 021a  10GbE 2P QL41162HLRJ-HP Adapter\n\t\t1590 021b  10GbE 2P QL41162HLRJ-HP Adapter\n\t8084  FastLinQ QL41000 Series 10/25/40/50GbE Controller (iSCSI)\n\t\t1077 0001  10GE 2P QL41162HxRJ-DE Adapter\n\t\t1077 0002  10GE 2P QL41112HxCU-DE Adapter\n\t\t1077 0003  4x10GE QL41164HxRJ CNA\n\t\t1077 0004  4x10GE QL41164HFCU CNA\n\t\t1077 0005  QLogic 4x10GE QL41164HMRJ CNA\n\t\t1077 0006  QLogic 4x10GE QL41164HMCU CNA\n\t\t1077 0007  QLogic 2x25GE QL41262HMCU CNA\n\t\t1077 0009  QLogic 2x1GE+2x10GE QL41162HMRJ CNA\n\t\t1077 000b  25GE 2P QL41262HxCU-DE Adapter\n\t\t1077 000c  QLogic 2x25GE QL41262HMCU CNA\n\t\t1077 000d  FastLinQ QL41262H 25GbE iSCSI Adapter\n\t\t1077 000e  FastLinQ QL41162H 10GbE iSCSI Adapter\n\t\t1077 000f  2x25GE QL41262HMKR CNA\n\t\t1590 021a  10GbE 2P QL41162HLRJ-HP Adapter\n\t\t1590 021b  10GbE 2P QL41162HLRJ-HP Adapter\n\t8090  FastLinQ QL41000 Series Gigabit Ethernet Controller (SR-IOV VF)\n\t\t1077 0001  25GE 2P QL41262HxCU-DE Adapter\n\t\t1077 0002  10GE 2P QL41112HxCU-DE Adapter\n\t\t1077 0003  4x10GE QL41164HxRJ CNA\n\t\t1077 0004  4x10GE QL41164HFCU CNA\n\t\t1077 0005  QLogic 4x10GE QL41164HMRJ CNA\n\t\t1077 0006  QLogic 4x10GE QL41164HMCU CNA\n\t\t1077 0007  QLogic 2x1GE+2x10GE QL41264HMCU CNA\n\t\t1077 0009  QLogic 2x1GE+2x10GE QL41162HMRJ CNA\n\t\t1077 000b  25GE 2P QL41262HxCU-DE Adapter\n\t\t1077 000c  QLogic 2x25GE QL41262HMCU CNA\n\t\t1077 000d  FastLinQ QL41262H 25GbE FCoE Adapter (SR-IOV VF)\n\t\t1077 000e  FastLinQ QL41162H 10GbE iSCSI Adapter (SR-IOV VF)\n\t\t1077 000f  2x25GE QL41262HMKR CNA\n\t\t1077 0010  2x25GE QL41232HMKR NIC\n\t\t1077 0011  FastLinQ QL41212H 25GbE Adapter (SR-IOV VF)\n\t\t1077 0012  FastLinQ QL41112H 10GbE Adapter (SR-IOV VF)\n\t\t1077 0053  QLogic 2x25GE QL41232HQCU NIC\n\t\t1077 0054  QLogic 2x10GE QL41132HQRJ NIC\n\t\t1077 0055  QLogic 2x10GE QL41132HQCU NIC\n\t\t1077 0056  2x10GE QL41132HxRJ NIC\n\t\t1077 0057  2x25GE QL41232HxCU NIC\n\t\t1590 021a  10GbE 2P QL41162HLRJ-HP Adapter\n\t\t1590 021b  10GbE 2P QL41162HLRJ-HP Adapter\n\t\t1590 021e  10/25GbE 2P QL41162HMRJ-HP Adapter\n\t\t1590 021f  10/25GbE 2P QL41262HMCU-HP Adapter\n\t\t1590 02bd  10Gb 2P 524SFP+ NIC\n\t8430  ISP8324 1/10GbE Converged Network Controller (NIC VF)\n\t8431  8300 Series 10GbE Converged Network Adapter (FCoE VF)\n\t8432  ISP2432M-based 10GbE Converged Network Adapter (CNA)\n1078  Cyrix Corporation\n\t0000  5510 [Grappa]\n\t0001  PCI Master\n\t0002  5520 [Cognac]\n\t0100  5530 Legacy [Kahlua]\n\t0101  5530 SMI [Kahlua]\n\t0102  5530 IDE [Kahlua]\n\t0103  5530 Audio [Kahlua]\n\t0104  5530 Video [Kahlua]\n\t0400  ZFMicro PCI Bridge\n\t0401  ZFMicro Chipset SMI\n\t0402  ZFMicro Chipset IDE\n\t0403  ZFMicro Expansion Bus\n1079  I-Bus\n107a  NetWorth\n# formerly Gateway 2000 / acquired by Acer Inc.\n107b  Gateway, Inc.\n107c  LG Electronics [Lucky Goldstar Co. Ltd]\n107d  LeadTek Research Inc.\n\t0000  P86C850\n107e  Interphase Corporation\n\t0001  5515 ATM Adapter [Flipper]\n\t0002  100 VG AnyLan Controller\n\t0004  5526 Fibre Channel Host Adapter\n\t0005  x526 Fibre Channel Host Adapter\n\t0008  5525/5575 ATM Adapter (155 Mbit) [Atlantic]\n\t9003  5535-4P-BRI-ST\n\t9007  5535-4P-BRI-U\n\t9008  5535-1P-SR\n\t900c  5535-1P-SR-ST\n\t900e  5535-1P-SR-U\n\t9011  5535-1P-PRI\n\t9013  5535-2P-PRI\n\t9023  5536-4P-BRI-ST\n\t9027  5536-4P-BRI-U\n\t9031  5536-1P-PRI\n\t9033  5536-2P-PRI\n107f  Data Technology Corporation\n\t0802  SL82C105\n1080  Contaq Microsystems\n\t0600  82C599\n\tc691  Cypress CY82C691\n\tc693  82c693\n1081  Supermac Technology\n\t0d47  Radius PCI to NuBUS Bridge\n1082  EFA Corporation of America\n1083  Forex Computer Corporation\n\t0001  FR710\n1084  Parador\n1086  J. Bond Computer Systems\n1087  Cache Computer\n1088  Microcomputer Systems (M) Son\n1089  Data General Corporation\n# Formerly Bit3 Computer Corp.\n108a  SBS Technologies\n\t0001  VME Bridge Model 617\n\t0010  VME Bridge Model 618\n\t0040  dataBLIZZARD\n\t3000  VME Bridge Model 2706\n108c  Oakleigh Systems Inc.\n108d  Olicom\n\t0001  Token-Ring 16/4 PCI Adapter (3136/3137)\n\t0002  16/4 Token Ring\n\t0004  RapidFire OC-3139/3140 Token-Ring 16/4 PCI Adapter\n\t\t108d 0004  OC-3139/3140 RapidFire Token-Ring 16/4 Adapter\n\t0005  GoCard 3250 Token-Ring 16/4 CardBus PC Card\n\t0006  OC-3530 RapidFire Token-Ring 100\n\t0007  RapidFire 3141 Token-Ring 16/4 PCI Fiber Adapter\n\t\t108d 0007  OC-3141 RapidFire Token-Ring 16/4 Adapter\n\t0008  RapidFire 3540 HSTR 100/16/4 PCI Adapter\n\t\t108d 0008  OC-3540 RapidFire HSTR 100/16/4 Adapter\n\t0011  OC-2315\n\t0012  OC-2325\n\t0013  OC-2183/2185\n\t0014  OC-2326\n\t0019  OC-2327/2250 10/100 Ethernet Adapter\n\t\t108d 0016  OC-2327 Rapidfire 10/100 Ethernet Adapter\n\t\t108d 0017  OC-2250 GoCard 10/100 Ethernet Adapter\n\t0021  OC-6151/6152 [RapidFire ATM 155]\n\t0022  ATM Adapter\n108e  Oracle/SUN\n\t0001  EBUS\n\t1000  EBUS\n\t1001  Happy Meal 10/100 Ethernet [hme]\n\t1100  RIO EBUS\n\t\t108e 1100  RIO EBUS on Blade 100 motherboard\n\t1101  RIO 10/100 Ethernet [eri]\n\t\t108e 1101  RIO GEM on Blade 100 motherboard\n\t1102  RIO 1394\n\t\t108e 1102  RIO 1394 on Blade 100 motherboard\n\t1103  RIO USB\n\t\t108e 1103  RIO USB on Blade 100 motherboard\n\t1647  Broadcom 570x 10/100/1000 Ethernet [bge]\n\t1648  Broadcom 570x 10/100/1000 Ethernet [bge]\n\t16a7  Broadcom 570x 10/100/1000 Ethernet [bge]\n\t16a8  Broadcom 570x 10/100/1000 Ethernet [bge]\n\t2bad  GEM 10/100/1000 Ethernet [ge]\n\t5000  Simba Advanced PCI Bridge\n\t\t108e 5000  Netra AX1105-500\n\t5043  SunPCI Co-processor\n\t5ca0  Crypto Accelerator 6000 [mca]\n\t6300  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6301  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6302  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6303  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6310  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6311  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6312  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6313  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6320  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6323  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6330  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6331  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6332  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6333  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6340  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6343  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6350  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6353  Intel 21554 PCI-PCI bus bridge [db21554]\n\t6722  Intel 21554 PCI-PCI bus bridge [db21554]\n\t676e  SunPCiIII\n\t7063  SunPCiII / SunPCiIIpro\n\t8000  Psycho PCI Bus Module\n\t8001  Schizo PCI Bus Module\n\t8002  Schizo+ PCI Bus Module\n\t80f0  PCIe switch [px]\n\t80f8  PCIe switch [px]\n\t9010  PCIe/PCI bridge switch [pxb_plx]\n\t9020  PCIe/PCI bridge switch [pxb_plx]\n\t9102  Davicom Fast Ethernet driver for Davicom DM9102A [dmfe]\n\ta000  Psycho UPA-PCI Bus Module [pcipsy]\n\ta001  Psycho UPA-PCI Bus Module [pcipsy]\n\t\t108e a001  Ultra IIe on Blade 100 motherboard\n\ta801  Schizo Fireplane-PCI bus bridge module [pcisch]\n\taaaa  Multithreaded Shared 10GbE Ethernet Network Controller\n\tabba  Cassini 10/100/1000\n\tabcd  Multithreaded 10-Gigabit Ethernet Network Controller\n\tc416  Sun Fire System/System Controller Interface chip [sbbc]\n108f  Systemsoft\n1090  Compro Computer Services, Inc.\n\t4610  PCI RTOM\n\t4620  GPIO HSD\n1091  Intergraph Corporation\n\t0020  3D graphics processor\n\t0021  3D graphics processor w/Texturing\n\t0040  3D graphics frame buffer\n\t0041  3D graphics frame buffer\n\t0060  Proprietary bus bridge\n\t00e4  Powerstorm 4D50T\n\t0720  Motion JPEG codec\n\t0780  Intense3D Wildcat 3410 (MSMT496)\n\t07a0  Sun Expert3D-Lite Graphics Accelerator\n\t1091  Sun Expert3D Graphics Accelerator\n1092  Diamond Multimedia Systems\n\t0028  Viper V770\n\t\t1092 4a00  Viper V770 32MB\n\t00a0  Speedstar Pro SE\n\t00a8  Speedstar 64\n\t0550  Viper V550\n\t08d4  Supra 2260 Modem\n\t094c  SupraExpress 56i Pro\n\t1001  Video Crunch It 1001 capture card\n\t1092  Viper V330\n\t6120  Maximum DVD\n\t8810  Stealth SE\n\t8811  Stealth 64/SE\n\t8880  Stealth\n\t8881  Stealth\n\t88b0  Stealth 64\n\t88b1  Stealth 64\n\t88c0  Stealth 64\n\t88c1  Stealth 64\n\t88d0  Stealth 64\n\t88d1  Stealth 64\n\t88f0  Stealth 64\n\t88f1  Stealth 64\n\t9999  DMD-I0928-1 \"Monster sound\" sound chip\n1093  National Instruments\n\t0160  PCI-DIO-96\n\t0162  PCI-MIO-16XE-50\n\t0fe1  PXI-8320\n\t1150  PCI-6533 (PCI-DIO-32HS)\n\t1170  PCI-MIO-16XE-10\n\t1180  PCI-MIO-16E-1\n\t1190  PCI-MIO-16E-4\n\t11b0  PXI-6070E\n\t11c0  PXI-6040E\n\t11d0  PXI-6030E\n\t1270  PCI-6032E\n\t1290  PCI-6704\n\t12b0  PCI-6534\n\t1310  PCI-6602\n\t1320  PXI-6533\n\t1330  PCI-6031E\n\t1340  PCI-6033E\n\t1350  PCI-6071E\n\t1360  PXI-6602\n\t13c0  PXI-6508\n\t1490  PXI-6534\n\t14e0  PCI-6110\n\t14f0  PCI-6111\n\t1580  PXI-6031E\n\t15b0  PXI-6071E\n\t1710  PXI-6509\n\t17c0  PXI-5690\n\t17d0  PCI-6503\n\t1870  PCI-6713\n\t1880  PCI-6711\n\t18b0  PCI-6052E\n\t18c0  PXI-6052E\n\t1920  PXI-6704\n\t1930  PCI-6040E\n\t19c0  PCI-4472\n\t1aa0  PXI-4110\n\t1ad0  PCI-6133\n\t1ae0  PXI-6133\n\t1e30  PCI-6624\n\t1e40  PXI-6624\n\t1e50  PXI-5404\n\t2410  PCI-6733\n\t2420  PXI-6733\n\t2430  PCI-6731\n\t2470  PCI-4474\n\t24a0  PCI-4065\n\t24b0  PXI-4200\n\t24f0  PXI-4472\n\t2510  PCI-4472\n\t2520  PCI-4474\n\t27a0  PCI-6123\n\t27b0  PXI-6123\n\t2880  DAQCard-6601\n\t2890  PCI-6036E\n\t28a0  PXI-4461\n\t28b0  PCI-6013\n\t28c0  PCI-6014\n\t28d0  PCI-5122\n\t28e0  PXI-5122\n\t29f0  PXI-7334\n\t2a00  PXI-7344\n\t2a60  PCI-6023E\n\t2a70  PCI-6024E\n\t2a80  PCI-6025E\n\t2ab0  PXI-6025E\n\t2b10  PXI-6527\n\t2b20  PCI-6527\n\t2b80  PXI-6713\n\t2b90  PXI-6711\n\t2c60  PCI-6601\n\t2c70  PXI-6601\n\t2c80  PCI-6035E\n\t2c90  PCI-6703\n\t2ca0  PCI-6034E\n\t2cb0  PCI-7344\n\t2cc0  PXI-6608\n\t2d20  PXI-5600\n\t2db0  PCI-6608\n\t2dc0  PCI-4070\n\t2dd0  PXI-4070\n\t2eb0  PXI-4472\n\t2ec0  PXI-6115\n\t2ed0  PCI-6115\n\t2ee0  PXI-6120\n\t2ef0  PCI-6120\n\t2fd1  PCI-7334\n\t2fd2  PCI-7350\n\t2fd3  PCI-7342\n\t2fd5  PXI-7350\n\t2fd6  PXI-7342\n\t7003  PCI-6551\n\t7004  PXI-6551\n\t700b  PXI-5421\n\t700c  PCI-5421\n\t701a  VXIpc-87xB\n\t701b  VXIpc-770\n\t7023  PXI-2593\n\t7027  PCI-MXI-2 Universal\n\t702c  PXI-7831R\n\t702d  PCI-7831R\n\t702e  PXI-7811R\n\t702f  PCI-7811R\n\t7030  PCI-CAN (Series 2)\n\t7031  PCI-CAN/2 (Series 2)\n\t7032  PCI-CAN/LS (Series 2)\n\t7033  PCI-CAN/LS2 (Series 2)\n\t7034  PCI-CAN/DS (Series 2)\n\t7035  PXI-8460 (Series 2, 1 port)\n\t7036  PXI-8460 (Series 2, 2 ports)\n\t7037  PXI-8461 (Series 2, 1 port)\n\t7038  PXI-8461 (Series 2, 2 ports)\n\t7039  PXI-8462 (Series 2)\n\t703f  PXI-2566\n\t7040  PXI-2567\n\t7044  MXI-4 Connection Monitor\n\t7047  PXI-6653\n\t704c  PXI-2530\n\t704f  PXI-4220\n\t7050  PXI-4204\n\t7055  PXI-7830R\n\t7056  PCI-7830R\n\t705a  PCI-CAN/XS (Series 2)\n\t705b  PCI-CAN/XS2 (Series 2)\n\t705c  PXI-8464 (Series 2, 1 port)\n\t705d  PXI-8464 (Series 2, 2 ports)\n\t705e  cRIO-9102\n\t7060  PXI-5610\n\t7064  PXI-1045 Trigger Routing Module\n\t7065  PXI-6652\n\t7066  PXI-6651\n\t7067  PXI-2529\n\t7068  PCI-CAN/SW (Series 2)\n\t7069  PCI-CAN/SW2 (Series 2)\n\t706a  PXI-8463 (Series 2, 1 port)\n\t706b  PXI-8463 (Series 2, 2 ports)\n\t7073  PCI-6723\n\t7074  PXI-7833R\n\t7075  PXI-6552\n\t7076  PCI-6552\n\t707c  PXI-1428\n\t707e  PXI-4462\n\t7080  PXI-8430/2 (RS-232) Interface\n\t7081  PXI-8431/2 (RS-485) Interface\n\t7083  PCI-7833R\n\t7085  PCI-6509\n\t7086  PXI-6528\n\t7087  PCI-6515\n\t7088  PCI-6514\n\t708c  PXI-2568\n\t708d  PXI-2569\n\t70a9  PCI-6528\n\t70aa  PCI-6229\n\t70ab  PCI-6259\n\t70ac  PCI-6289\n\t70ad  PXI-6251\n\t70ae  PXI-6220\n\t70af  PCI-6221\n\t70b0  PCI-6220\n\t70b1  PXI-6229\n\t70b2  PXI-6259\n\t70b3  PXI-6289\n\t70b4  PCI-6250\n\t70b5  PXI-6221\n\t70b6  PCI-6280\n\t70b7  PCI-6254\n\t70b8  PCI-6251\n\t70b9  PXI-6250\n\t70ba  PXI-6254\n\t70bb  PXI-6280\n\t70bc  PCI-6284\n\t70bd  PCI-6281\n\t70be  PXI-6284\n\t70bf  PXI-6281\n\t70c0  PCI-6143\n\t70c3  PCI-6511\n\t70c4  PXI-7330\n\t70c5  PXI-7340\n\t70c6  PCI-7330\n\t70c7  PCI-7340\n\t70c8  PCI-6513\n\t70c9  PXI-6515\n\t70ca  PCI-1405\n\t70cc  PCI-6512\n\t70cd  PXI-6514\n\t70ce  PXI-1405\n\t70cf  PCIe-GPIB\n\t70d0  PXI-2570\n\t70d1  PXI-6513\n\t70d2  PXI-6512\n\t70d3  PXI-6511\n\t70d4  PCI-6722\n\t70d6  PXI-4072\n\t70d7  PXI-6541\n\t70d8  PXI-6542\n\t70d9  PCI-6541\n\t70da  PCI-6542\n\t70db  PCI-8430/2 (RS-232) Interface\n\t70dc  PCI-8431/2 (RS-485) Interface\n\t70dd  PXI-8430/4 (RS-232) Interface\n\t70de  PXI-8431/4 (RS-485) Interface\n\t70df  PCI-8430/4 (RS-232) Interface\n\t70e0  PCI-8431/4 (RS-485) Interface\n\t70e1  PXI-2532\n\t70e2  PXI-8430/8 (RS-232) Interface\n\t70e3  PXI-8431/8 (RS-485) Interface\n\t70e4  PCI-8430/8 (RS-232) Interface\n\t70e5  PCI-8431/8 (RS-485) Interface\n\t70e6  PXI-8430/16 (RS-232) Interface\n\t70e7  PCI-8430/16 (RS-232) Interface\n\t70e8  PXI-8432/2 (Isolated RS-232) Interface\n\t70e9  PXI-8433/2 (Isolated RS-485) Interface\n\t70ea  PCI-8432/2 (Isolated RS-232) Interface\n\t70eb  PCI-8433/2 (Isolated RS-485) Interface\n\t70ec  PXI-8432/4 (Isolated RS-232) Interface\n\t70ed  PXI-8433/4 (Isolated RS-485) Interface\n\t70ee  PCI-8432/4 (Isolated RS-232) Interface\n\t70ef  PCI-8433/4 (Isolated RS-485) Interface\n\t70f0  PXI-5922\n\t70f1  PCI-5922\n\t70f2  PCI-6224\n\t70f3  PXI-6224\n\t70f6  cRIO-9101\n\t70f7  cRIO-9103\n\t70f8  cRIO-9104\n\t70ff  PXI-6723\n\t7100  PXI-6722\n\t7104  PCIx-1429\n\t7105  PCIe-1429\n\t710a  PXI-4071\n\t710d  PXI-6143\n\t710e  PCIe-GPIB\n\t710f  PXI-5422\n\t7110  PCI-5422\n\t7111  PXI-5441\n\t7119  PXI-6561\n\t711a  PXI-6562\n\t711b  PCI-6561\n\t711c  PCI-6562\n\t7120  PCI-7390\n\t7121  PXI-5122EX\n\t7122  PCI-5122EX\n\t7123  PXIe-5653\n\t7124  PCI-6510\n\t7125  PCI-6516\n\t7126  PCI-6517\n\t7127  PCI-6518\n\t7128  PCI-6519\n\t7137  PXI-2575\n\t713c  PXI-2585\n\t713d  PXI-2586\n\t7142  PXI-4224\n\t7144  PXI-5124\n\t7145  PCI-5124\n\t7146  PCI-6132\n\t7147  PXI-6132\n\t7148  PCI-6122\n\t7149  PXI-6122\n\t714c  PXI-5114\n\t714d  PCI-5114\n\t7150  PXI-2564\n\t7152  PCI-5640R\n\t7156  PXI-1044 Trigger Routing Module\n\t715d  PCI-1426\n\t7167  PXI-5412\n\t7168  PCI-5412\n\t716b  PCI-6230\n\t716c  PCI-6225\n\t716d  PXI-6225\n\t716f  PCI-4461\n\t7170  PCI-4462\n\t7171  PCI-6010\n\t7174  PXI-8360\n\t7177  PXI-6230\n\t717d  PCIe-6251\n\t717f  PCIe-6259\n\t7187  PCI-1410\n\t718b  PCI-6521\n\t718c  PXI-6521\n\t7191  PCI-6154\n\t7193  PXI-7813R\n\t7194  PCI-7813R\n\t7195  PCI-8254R\n\t7197  PXI-5402\n\t7198  PCI-5402\n\t719f  PCIe-6535\n\t71a0  PCIe-6536\n\t71a3  PXI-5650\n\t71a4  PXI-5652\n\t71a5  PXI-2594\n\t71a7  PXI-2595\n\t71a9  PXI-2596\n\t71aa  PXI-2597\n\t71ab  PXI-2598\n\t71ac  PXI-2599\n\t71ad  PCI-GPIB+\n\t71ae  PCIe-1430\n\t71b7  PXI-1056 Trigger Routing Module\n\t71b8  PXI-1045 Trigger Routing Module\n\t71b9  PXI-1044 Trigger Routing Module\n\t71bb  PXI-2584\n\t71bc  PCI-6221 (37-pin)\n\t71bf  PCIe-1427\n\t71c5  PCI-6520\n\t71c6  PXI-2576\n\t71c7  cRIO-9072\n\t71dc  PCI-1588\n\t71e0  PCI-6255\n\t71e1  PXI-6255\n\t71e2  PXI-5406\n\t71e3  PCI-5406\n\t71fc  PXI-4022\n\t7209  PCI-6233\n\t720a  PXI-6233\n\t720b  PCI-6238\n\t720c  PXI-6238\n\t7260  PXI-5142\n\t7261  PCI-5142\n\t726d  PXI-5651\n\t7273  PXI-4461\n\t7274  PXI-4462\n\t7279  PCI-6232\n\t727a  PXI-6232\n\t727b  PCI-6239\n\t727c  PXI-6239\n\t727e  SMBus Controller\n\t\t1093 75ac  PXIe-8388\n\t\t1093 75ad  PXIe-8389\n\t\t1093 7650  PXIe-8381\n\t\t1093 8360  PXIe-8360\n\t\t1093 8370  PXIe-8370\n\t\t1093 8375  PXIe-8375\n\t7281  PCI-6236\n\t7282  PXI-6236\n\t7283  PXI-2554\n\t7288  PXIe-5611\n\t7293  PCIe-8255R\n\t729d  cRIO-9074\n\t72a4  PCIe-4065\n\t72a7  PCIe-6537\n\t72a8  PXI-5152\n\t72a9  PCI-5152\n\t72aa  PXI-5105\n\t72ab  PCI-5105\n\t72b8  PXI-6682\n\t72d0  PXI-2545\n\t72d1  PXI-2546\n\t72d2  PXI-2547\n\t72d3  PXI-2548\n\t72d4  PXI-2549\n\t72d5  PXI-2555\n\t72d6  PXI-2556\n\t72d7  PXI-2557\n\t72d8  PXI-2558\n\t72d9  PXI-2559\n\t72e8  PXIe-6251\n\t72e9  PXIe-6259\n\t72ef  PXI-4498\n\t72f0  PXI-4496\n\t72fb  PXIe-6672\n\t730e  PXI-4130\n\t730f  PXI-5922EX\n\t7310  PCI-5922EX\n\t731c  PXI-2535\n\t731d  PXI-2536\n\t7322  PXIe-6124\n\t7327  PXI-6529\n\t732c  VXI-8360T\n\t7331  PXIe-5602\n\t7332  PXIe-5601\n\t7333  PXI-5900\n\t7335  PXI-2533\n\t7336  PXI-2534\n\t7342  PXI-4461\n\t7349  PXI-5154\n\t734a  PCI-5154\n\t7357  PXI-4065\n\t7359  PXI-4495\n\t7370  PXI-4461\n\t7373  sbRIO-9601\n\t7374  IOtech-9601\n\t7375  sbRIO-9602\n\t7378  sbRIO-9641\n\t737d  PXI-5124EX\n\t7384  PXI-7851R\n\t7385  PXI-7852R\n\t7386  PCIe-7851R\n\t7387  PCIe-7852R\n\t7390  PXI-7841R\n\t7391  PXI-7842R\n\t7392  PXI-7853R\n\t7393  PCIe-7841R\n\t7394  PCIe-7842R\n\t7397  sbRIO-9611\n\t7398  sbRIO-9612\n\t7399  sbRIO-9631\n\t739a  sbRIO-9632\n\t739b  sbRIO-9642\n\t73a1  PXIe-4498\n\t73a2  PXIe-4496\n\t73a5  PXIe-5641R\n\t73a7  PXI-8250 Chassis Monitor Module\n\t73a8  PXI-8511 CAN/LS\n\t73a9  PXI-8511 CAN/LS\n\t73aa  PXI-8512 CAN/HS\n\t73ab  PXI-8512 CAN/HS\n\t73ac  PXI-8513 CAN/XS\n\t73ad  PXI-8513 CAN/XS\n\t73af  PXI-8516 LIN\n\t73b1  PXI-8517 FlexRay\n\t73b2  PXI-8531 CANopen\n\t73b3  PXI-8531 CANopen\n\t73b4  PXI-8532 DeviceNet\n\t73b5  PXI-8532 DeviceNet\n\t73b6  PCI-8511 CAN/LS\n\t73b7  PCI-8511 CAN/LS\n\t73b8  PCI-8512 CAN/HS\n\t73b9  PCI-8512 CAN/HS\n\t73ba  PCI-8513 CAN/XS\n\t73bb  PCI-8513 CAN/XS\n\t73bd  PCI-8516 LIN\n\t73bf  PCI-8517 FlexRay\n\t73c0  PCI-8531 CANopen\n\t73c1  PCI-8531 CANopen\n\t73c2  PCI-8532 DeviceNet\n\t73c3  PCI-8532 DeviceNet\n\t73c5  PXIe-2527\n\t73c6  PXIe-2529\n\t73c8  PXIe-2530\n\t73c9  PXIe-2532\n\t73ca  PXIe-2569\n\t73cb  PXIe-2575\n\t73cc  PXIe-2593\n\t73d5  PXI-7951R\n\t73d6  PXI-7952R\n\t73d7  PXI-7953R\n\t73e1  PXI-7854R\n\t73ec  PXI-7954R\n\t73ed  cRIO-9073\n\t73f0  PXI-5153\n\t73f1  PCI-5153\n\t73f4  PXI-2515\n\t73f6  cRIO-9111\n\t73f7  cRIO-9112\n\t73f8  cRIO-9113\n\t73f9  cRIO-9114\n\t73fa  cRIO-9116\n\t73fb  cRIO-9118\n\t7404  PXI-4132\n\t7405  PXIe-6674T\n\t7406  PXIe-6674\n\t740e  PCIe-8430/16 (RS-232) Interface\n\t740f  PCIe-8430/8 (RS-232) Interface\n\t7410  PCIe-8431/16 (RS-485) Interface\n\t7411  PCIe-8431/8 (RS-485) Interface\n\t7414  PCIe-GPIB+\n\t741c  PXI-5691\n\t741d  PXI-5695\n\t743c  CSC-3059\n\t7448  PXI-2510\n\t7454  PXI-2512\n\t7455  PXI-2514\n\t7456  PXIe-2512\n\t7457  PXIe-2514\n\t745a  PXI-6682H\n\t745e  PXI-5153EX\n\t745f  PCI-5153EX\n\t7460  PXI-5154EX\n\t7461  PCI-5154EX\n\t746d  PXIe-5650\n\t746e  PXIe-5651\n\t746f  PXIe-5652\n\t7472  PXI-2800\n\t7495  PXIe-5603\n\t7497  PXIe-5605\n\t74ae  PXIe-2515\n\t74b4  PXI-2531\n\t74b5  PXIe-2531\n\t74c1  PXIe-8430/16 (RS-232) Interface\n\t74c2  PXIe-8430/8 (RS-232) Interface\n\t74c3  PXIe-8431/16 (RS-485) Interface\n\t74c4  PXIe-8431/8 (RS-485) Interface\n\t74d5  PXIe-5630\n\t74d9  PCIe-8432/2 (Isolated RS-232) Interface\n\t74da  PCIe-8433/2 (Isolated RS-485) Interface\n\t74db  PCIe-8432/4 (Isolated RS-232) Interface\n\t74dc  PCIe-8433/4 (Isolated RS-485) Interface\n\t74e8  NI 9148\n\t7515  PCIe-8430/2 (RS-232) Interface\n\t7516  PCIe-8430/4 (RS-232) Interface\n\t7517  PCIe-8431/2 (RS-485) Interface\n\t7518  PCIe-8431/4 (RS-485) Interface\n\t751b  cRIO-9081\n\t751c  cRIO-9082\n\t7528  PXIe-4497\n\t7529  PXIe-4499\n\t752a  PXIe-4492\n\t7539  NI 9157\n\t753a  NI 9159\n\t7598  PXI-2571\n\t75a4  PXI-4131A\n\t75b1  PCIe-7854R\n\t75ba  PXI-2543\n\t75bb  PXIe-2543\n\t75e5  PXI-6683\n\t75e6  PXI-6683H\n\t75ef  PXIe-5632\n\t761c  VXI-8360LT\n\t761f  PXI-2540\n\t7620  PXIe-2540\n\t7621  PXI-2541\n\t7622  PXIe-2541\n\t7626  NI 9154\n\t7627  NI 9155\n\t7638  PXI-2720\n\t7639  PXI-2722\n\t763a  PXIe-2725\n\t763b  PXIe-2727\n\t763c  PXI-4465\n\t764b  PXIe-2790\n\t764c  PXI-2520\n\t764d  PXI-2521\n\t764e  PXI-2522\n\t764f  PXI-2523\n\t7654  PXI-2796\n\t7655  PXI-2797\n\t7656  PXI-2798\n\t7657  PXI-2799\n\t765d  PXI-2542\n\t765e  PXIe-2542\n\t765f  PXI-2544\n\t7660  PXIe-2544\n\t766d  PCIe-6535B\n\t766e  PCIe-6536B\n\t766f  PCIe-6537B\n\t76a3  PXIe-6535B\n\t76a4  PXIe-6536B\n\t76a5  PXIe-6537B\n\t783e  PXI-8368\n\t9020  PXI-2501\n\t9030  PXI-2503\n\t9040  PXI-2527\n\t9050  PXI-2565\n\t9060  PXI-2590\n\t9070  PXI-2591\n\t9080  PXI-2580\n\t9090  PCI-4021\n\t90a0  PXI-4021\n\ta001  PCI-MXI-2\n\tb001  PCI-1408\n\tb011  PXI-1408\n\tb021  PCI-1424\n\tb022  PXI-1424\n\tb031  PCI-1413\n\tb041  PCI-1407\n\tb051  PXI-1407\n\tb061  PCI-1411\n\tb071  PCI-1422\n\tb081  PXI-1422\n\tb091  PXI-1411\n\tb0b1  PCI-1409\n\tb0c1  PXI-1409\n\tb0e1  PCI-1428\n\tc4c4  PXIe/PCIe Device\n\t\t1093 728a  PXIe-5421\n\t\t1093 728b  PXIe-5442\n\t\t1093 728d  PXIe-5451\n\t\t1093 72a2  PXIe-5122\n\t\t1093 72da  PXIe-5422\n\t\t1093 72f7  PXIe-6535\n\t\t1093 72f8  PXIe-6536\n\t\t1093 72f9  PXIe-6537\n\t\t1093 7326  PCIe-6509\n\t\t1093 736c  PXIe-4140\n\t\t1093 738b  PXIe-5622\n\t\t1093 73c4  PXIe-5450\n\t\t1093 73c7  PXIe-6545\n\t\t1093 73d4  PXIe-6544\n\t\t1093 7425  PCIe-6320\n\t\t1093 7427  PCIe-6321\n\t\t1093 7428  PXIe-6323\n\t\t1093 7429  PCIe-6323\n\t\t1093 742a  PXIe-6341\n\t\t1093 742b  PCIe-6341\n\t\t1093 742c  PXIe-6343\n\t\t1093 742d  PCIe-6343\n\t\t1093 742f  PCIe-6351\n\t\t1093 7431  PCIe-6353\n\t\t1093 7432  PXIe-6361\n\t\t1093 7433  PCIe-6361\n\t\t1093 7434  PXIe-6363\n\t\t1093 7435  PCIe-6363\n\t\t1093 7436  PXIe-6356\n\t\t1093 7437  PXIe-6358\n\t\t1093 7438  PXIe-6366\n\t\t1093 7439  PXIe-6368\n\t\t1093 7468  PXIe-5185\n\t\t1093 7469  PXIe-5186\n\t\t1093 7492  PXIe-4300\n\t\t1093 7498  PXIe-6548\n\t\t1093 7499  PXIe-6547\n\t\t1093 74a8  PXIe-4330\n\t\t1093 74a9  PXIe-4331\n\t\t1093 74b1  PXIe-4154\n\t\t1093 74b2  PXIe-4353\n\t\t1093 74b6  PCIe-1433\n\t\t1093 74cd  PXIe-5643R\n\t\t1093 74d0  PXIe-7961R\n\t\t1093 74dd  PXIe-6376\n\t\t1093 74de  PXIe-6378\n\t\t1093 74e2  PXIe-7962R\n\t\t1093 74e3  PXIe-7965R\n\t\t1093 74e5  PXIe-4844\n\t\t1093 74f3  PCIe-5140\n\t\t1093 753c  PXIe-1435\n\t\t1093 7548  PXIe-5622 (25MHz DDC)\n\t\t1093 754d  PCIe-5155\n\t\t1093 7551  PXIe-6556\n\t\t1093 7553  PCIe-1473R\n\t\t1093 7570  PCIe-1474R\n\t\t1093 7571  PXIe-1475R\n\t\t1093 7572  PXIe-1476R\n\t\t1093 75a2  PXIe-5693\n\t\t1093 75a3  PXIe-5694\n\t\t1093 75a5  PXIe-4141\n\t\t1093 75ce  PXIe-7966R\n\t\t1093 75cf  PXIe-4357\n\t\t1093 75d2  PXIe-RevB-5643R\n\t\t1093 75d3  PXIe-5644R\n\t\t1093 75ee  PXIe-5645R\n\t\t1093 7613  PXIe-6555\n\t\t1093 7619  PXIe-5185\n\t\t1093 761a  PXIe-5186\n\t\t1093 7629  PXIe-4142\n\t\t1093 762a  PXIe-4143\n\t\t1093 762b  PXIe-4138\n\t\t1093 762c  PXIe-4144\n\t\t1093 762d  PXIe-4145\n\t\t1093 762e  PXIe-5606\n\t\t1093 7644  PXIe-4841\n\t\t1093 764a  PCIe-8237R-S\n\t\t1093 7658  PXIe-5162 (4CH)\n\t\t1093 76ab  PXIe-4322\n\t\t1093 76ad  PXIe-4112\n\t\t1093 76ae  PXIe-4113\n\t\t1093 76b5  PXIe-7971R\n\t\t1093 76b6  PXIe-7972R\n\t\t1093 76b7  PXIe-7975R\n\t\t1093 76b8  PXIe-5696\n\t\t1093 76b9  PXIe-5654\n\t\t1093 76c8  PXIe-6614\n\t\t1093 76c9  PXIe-6612\n\t\t1093 76cb  PXIe-5646R\n\t\t1093 76cc  PXIe-5162 (2CH)\n\t\t1093 76ce  CVS-1459\n\t\t1093 76d0  PXIe-5160 (2CH)\n\t\t1093 76d1  PXIe-5160 (4CH)\n\t\t1093 76dc  PXIe-4610\n\t\t1093 76ec  PXIe-2524\n\t\t1093 76ed  PXIe-2525\n\t\t1093 76ee  PXIe-2526\n\t\t1093 76ef  PXIe-2737\n\t\t1093 76f0  PXIe-2738\n\t\t1093 76f1  PXIe-2739\n\t\t1093 76fb  PCIe-1473R-LX110\n\t\t1093 76fc  PXIe-5105\n\t\t1093 76fd  PXIe-5114\n\t\t1093 76fe  PXIe-5644R\n\t\t1093 76ff  PXIe-5644R\n\t\t1093 7700  PXIe-5644R\n\t\t1093 7701  PXIe-5645R\n\t\t1093 7702  PXIe-5645R\n\t\t1093 7703  PXIe-5645R\n\t\t1093 770c  PXIe-4139\n\t\t1093 7711  PXIe-4464\n\t\t1093 7712  PXIe-4463\n\t\t1093 7716  PCIe-6612\n\t\t1093 771d  Unconfigured CA4 Switch\n\t\t1093 771e  PXIe-4339\n\t\t1093 7735  cRIO-9033\n\t\t1093 773e  PXIe-5624R\n\t\t1093 774b  cRIO-9031\n\t\t1093 774d  cRIO-9034\n\t\t1093 7755  cRIO-9030\n\t\t1093 7768  PXIe-2747\n\t\t1093 7769  PXIe-2748\n\t\t1093 776a  PXIe-2746\n\t\t1093 7777  PXIe-7976R\n\t\t1093 7782  PXIe-5646R\n\t\t1093 7783  PXIe-5646R\n\t\t1093 7784  PXIe-5646R\n\t\t1093 7790  PXIe-5170R (4CH)\n\t\t1093 7791  PXIe-5170R (8CH)\n\t\t1093 7793  PXIe-5171R (8CH)\n\t\t1093 77a5  PXIe-6345\n\t\t1093 77a6  PXIe-6355\n\t\t1093 77a7  PXIe-6365\n\t\t1093 77a8  PXIe-6375\n\t\t1093 77aa  CVS-1458\n\t\t1093 77ad  IC-3173\n\t\t1093 77b4  PXIe-7820R\n\t\t1093 77b5  PXIe-7821R\n\t\t1093 77b6  PXIe-7822R\n\t\t1093 77b9  cRIO-9038\n\t\t1093 77ba  PXIe-4136\n\t\t1093 77bb  PXIe-4137\n\t\t1093 77c0  PXIe-5624R\n\t\t1093 77c1  PXIe-5624R\n\t\t1093 77c2  PXIe-5624R\n\t\t1093 77ca  PXIe-6738\n\t\t1093 77cb  PXIe-6739\n\t\t1093 77db  cRIO-9035\n\t\t1093 77dc  cRIO-9036\n\t\t1093 77dd  cRIO-9039\n\t\t1093 7802  PXIe-4302\n\t\t1093 7803  PXIe-4303\n\t\t1093 7805  PXIe-4305\n\t\t1093 786f  PXIe-4163\n\t\t1093 788e  PXIe-4304\n\t\t1093 78f8  NI FlexRIO Module (KU035)\n\t\t1093 78f9  NI FlexRIO Module (KU040)\n\t\t1093 78fa  NI FlexRIO Module (KU060)\n\t\t1093 78ff  PXIe-4162\n\t\t1093 7995  PXIe-7911R\n\t\t1093 7996  PXIe-7912R\n\t\t1093 7997  PXIe-7915R\n\t\t1093 79d3  NI FlexRIO PCIe Module (KU035)\n\t\t1093 79d4  NI FlexRIO PCIe Module (KU040)\n\t\t1093 79d5  NI FlexRIO PCIe Module (KU060)\n\tc801  PCI-GPIB\n\tc811  PCI-GPIB+\n\tc821  PXI-GPIB\n\tc831  PMC-GPIB\n\tc840  PCI-GPIB\n\td130  PCI-232/2 Interface\n\td140  PCI-232/4 Interface\n\td150  PCI-232/8 Interface\n\td160  PCI-485/2 Interface\n\td170  PCI-485/4 Interface\n\td190  PXI-8422/2 (Isolated RS-232) Interface\n\td1a0  PXI-8422/4 (Isolated RS-232) Interface\n\td1b0  PXI-8423/2 (Isolated RS-485) Interface\n\td1c0  PXI-8423/4 (Isolated RS-485) Interface\n\td1d0  PXI-8420/2 (RS-232) Interface\n\td1e0  PXI-8420/4 (RS-232) Interface\n\td1f0  PXI-8420/8 (RS-232) Interface\n\td1f1  PXI-8420/16 (RS-232) Interface\n\td230  PXI-8421/2 (RS-485) Interface\n\td240  PXI-8421/4 (RS-485) Interface\n\td250  PCI-232/2 (Isolated) Interface\n\td260  PCI-485/2 (Isolated) Interface\n\td270  PCI-232/4 (Isolated) Interface\n\td280  PCI-485/4 (Isolated) Interface\n\td290  PCI-485/8 Interface\n\td2a0  PXI-8421/8 (RS-485) Interface\n\td2b0  PCI-232/16 Interface\n\te111  PCI-CAN\n\te131  PXI-8461 (1 port)\n\te141  PCI-CAN/LS\n\te151  PXI-8460 (1 port)\n\te211  PCI-CAN/2\n\te231  PXI-8461 (2 ports)\n\te241  PCI-CAN/LS2\n\te251  PXI-8460 (2 ports)\n\te261  PCI-CAN/DS\n\te271  PXI-8462\n\tf110  VMEpc-650\n\tf120  VXIpc-650\n\tfe00  VXIpc-87x\n\tfe41  VXIpc-860\n\tfe51  VXIpc-74x\n\tfe61  VXIpc-850\n\tfe70  VXIpc-880\n1094  First International Computers [FIC]\n# nee CMD Technology Inc\n1095  Silicon Image, Inc.\n\t0240  Adaptec AAR-1210SA SATA HostRAID Controller\n\t0640  PCI0640\n\t0643  PCI0643\n\t0646  PCI0646\n\t0647  PCI0647\n\t0648  PCI0648\n\t\t1043 8025  CUBX motherboard\n\t0649  SiI 0649 Ultra ATA/100 PCI to ATA Host Controller\n\t\t0e11 005d  Integrated Ultra ATA-100 Dual Channel Controller\n\t\t0e11 007e  Integrated Ultra ATA-100 IDE RAID Controller\n\t\t101e 0649  AMI MegaRAID IDE 100 Controller\n\t0650  PBC0650A\n\t0670  USB0670\n\t\t1095 0670  USB0670\n\t0673  USB0673\n\t0680  PCI0680 Ultra ATA-133 Host Controller\n\t\t1095 0680  SiI 0680 ATA/133 Controller\n\t\t1095 3680  Winic W-680 (Silicon Image 680 based)\n\t3112  SiI 3112 [SATALink/SATARaid] Serial ATA Controller\n\t\t1095 3112  SiI 3112 SATALink Controller\n\t\t1095 6112  SiI 3112 SATARaid Controller\n\t\t9005 0250  SATAConnect 1205SA Host Controller\n\t3114  SiI 3114 [SATALink/SATARaid] Serial ATA Controller\n\t\t1043 8167  A8N-SLI Deluxe/Premium Mainboard\n\t\t1095 3114  SiI 3114 SATALink Controller\n\t\t1095 6114  SiI 3114 SATARaid Controller\n\t3124  SiI 3124 PCI-X Serial ATA Controller\n\t\t1095 3124  SiI 3124 PCI-X Serial ATA Controller\n\t3132  SiI 3132 Serial ATA Raid II Controller\n\t3512  SiI 3512 [SATALink/SATARaid] Serial ATA Controller\n\t\t1095 3512  SiI 3512 SATALink Controller\n\t\t1095 6512  SiI 3512 SATARaid Controller\n\t3531  SiI 3531 [SATALink/SATARaid] Serial ATA Controller\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n1096  Alacron\n1097  Appian Technology\n1098  Quantum Designs (H.K.) Ltd\n\t0001  QD-8500\n\t0002  QD-8580\n1099  Samsung Electronics Co., Ltd\n109a  Packard Bell\n109b  Gemlight Computer Ltd.\n109c  Megachips Corporation\n109d  Zida Technologies Ltd.\n109e  Brooktree Corporation\n\t0310  Bt848 Video Capture\n\t032e  Bt878 Video Capture\n\t0350  Bt848 Video Capture\n\t0351  Bt849A Video capture\n\t0369  Bt878 Video Capture\n\t\t1002 0001  TV-Wonder\n\t\t1002 0003  TV-Wonder/VE\n\t036c  Bt879(??) Video Capture\n\t\t13e9 0070  Win/TV (Video Section)\n\t036e  Bt878 Video Capture\n\t\t0000 0001  Euresys Picolo PCIe\n\t\t0070 13eb  WinTV Series\n\t\t0070 ff01  Viewcast Osprey 200\n\t\t0071 0101  DigiTV PCI\n\t\t107d 6606  WinFast TV 2000\n\t\t11bd 0012  PCTV pro (TV + FM stereo receiver)\n\t\t11bd 001c  PCTV Sat (DBC receiver)\n\t\t127a 0001  Bt878 Mediastream Controller NTSC\n\t\t127a 0002  Bt878 Mediastream Controller PAL BG\n\t\t127a 0003  Bt878a Mediastream Controller PAL BG\n\t\t127a 0048  Bt878/832 Mediastream Controller\n\t\t144f 3000  MagicTView CPH060 - Video\n\t\t1461 0002  TV98 Series (TV/No FM/Remote)\n\t\t1461 0003  AverMedia UltraTV PCI 350\n\t\t1461 0004  AVerTV WDM Video Capture\n\t\t1461 0761  AverTV DVB-T\n\t\t1461 0771  AverMedia AVerTV DVB-T 771\n\t\t14f1 0001  Bt878 Mediastream Controller NTSC\n\t\t14f1 0002  Bt878 Mediastream Controller PAL BG\n\t\t14f1 0003  Bt878a Mediastream Controller PAL BG\n\t\t14f1 0048  Bt878/832 Mediastream Controller\n\t\t1822 0001  VisionPlus DVB card\n\t\t1851 1850  FlyVideo'98 - Video\n\t\t1851 1851  FlyVideo II\n\t\t1852 1852  FlyVideo'98 - Video (with FM Tuner)\n\t\t18ac d500  DViCO FusionHDTV5 Lite\n\t\t270f fc00  Digitop DTT-1000\n# Vendor/ID appear to be randomly chosen\n\t\taa00 1460  Spectra8 CardA Input0\n# Vendor/ID appear to be randomly chosen\n\t\taa01 1461  Spectra8 CardA Input1\n# Vendor/ID appear to be randomly chosen\n\t\taa02 1462  Spectra8 CardA Input2\n# Vendor/ID appear to be randomly chosen\n\t\taa03 1463  Spectra8 CardA Input3\n# Vendor/ID appear to be randomly chosen\n\t\taa04 1464  Spectra8 CardB Input0\n# Vendor/ID appear to be randomly chosen\n\t\taa05 1465  Spectra8 CardB Input1\n# Vendor/ID appear to be randomly chosen\n\t\taa06 1466  Spectra8 CardB Input2\n# Vendor/ID appear to be randomly chosen\n\t\taa07 1467  Spectra8 CardB Input3\n# Vendor/ID appear to be randomly chosen\n\t\taa08 1468  Spectra8 CardC Input0\n# Vendor/ID appear to be randomly chosen\n\t\taa09 1469  Spectra8 CardC Input1\n# Vendor/ID appear to be randomly chosen\n\t\taa0a 146a  Spectra8 CardC Input2\n# Vendor/ID appear to be randomly chosen\n\t\taa0b 146b  Spectra8 CardC Input3\n# Vendor/ID appear to be randomly chosen\n\t\taa0c 146c  Spectra8 CardD Input0\n# Vendor/ID appear to be randomly chosen\n\t\taa0d 146d  Spectra8 CardD Input1\n# Vendor/ID appear to be randomly chosen\n\t\taa0e 146e  Spectra8 CardD Input2\n# Vendor/ID appear to be randomly chosen\n\t\taa0f 146f  Spectra8 CardD Input3\n\t\tbd11 1200  PCTV pro (TV + FM stereo receiver)\n\t036f  Bt879 Video Capture\n\t\t127a 0044  Bt879 Video Capture NTSC\n\t\t127a 0122  Bt879 Video Capture PAL I\n\t\t127a 0144  Bt879 Video Capture NTSC\n\t\t127a 0222  Bt879 Video Capture PAL BG\n\t\t127a 0244  Bt879a Video Capture NTSC\n\t\t127a 0322  Bt879 Video Capture NTSC\n\t\t127a 0422  Bt879 Video Capture NTSC\n\t\t127a 1122  Bt879 Video Capture PAL I\n\t\t127a 1222  Bt879 Video Capture PAL BG\n\t\t127a 1322  Bt879 Video Capture NTSC\n\t\t127a 1522  Bt879a Video Capture PAL I\n\t\t127a 1622  Bt879a Video Capture PAL BG\n\t\t127a 1722  Bt879a Video Capture NTSC\n\t\t14f1 0044  Bt879 Video Capture NTSC\n\t\t14f1 0122  Bt879 Video Capture PAL I\n\t\t14f1 0144  Bt879 Video Capture NTSC\n\t\t14f1 0222  Bt879 Video Capture PAL BG\n\t\t14f1 0244  Bt879a Video Capture NTSC\n\t\t14f1 0322  Bt879 Video Capture NTSC\n\t\t14f1 0422  Bt879 Video Capture NTSC\n\t\t14f1 1122  Bt879 Video Capture PAL I\n\t\t14f1 1222  Bt879 Video Capture PAL BG\n\t\t14f1 1322  Bt879 Video Capture NTSC\n\t\t14f1 1522  Bt879a Video Capture PAL I\n\t\t14f1 1622  Bt879a Video Capture PAL BG\n\t\t14f1 1722  Bt879a Video Capture NTSC\n\t\t1851 1850  FlyVideo'98 - Video\n\t\t1851 1851  FlyVideo II\n\t\t1852 1852  FlyVideo'98 - Video (with FM Tuner)\n\t0370  Bt880 Video Capture\n\t\t1851 1850  FlyVideo'98\n\t\t1851 1851  FlyVideo'98 EZ - video\n\t\t1852 1852  FlyVideo'98 (with FM Tuner)\n\t0878  Bt878 Audio Capture\n\t\t0000 0001  Euresys Picolo PCIe\n\t\t0070 13eb  WinTV Series\n\t\t0070 ff01  Viewcast Osprey 200\n\t\t0071 0101  DigiTV PCI\n\t\t1002 0001  TV-Wonder\n\t\t1002 0003  TV-Wonder/VE\n\t\t11bd 0012  PCTV pro (TV + FM stereo receiver, audio section)\n\t\t11bd 001c  PCTV Sat (DBC receiver)\n\t\t127a 0001  Bt878 Video Capture (Audio Section)\n\t\t127a 0002  Bt878 Video Capture (Audio Section)\n\t\t127a 0003  Bt878 Video Capture (Audio Section)\n\t\t127a 0048  Bt878 Video Capture (Audio Section)\n\t\t13e9 0070  Win/TV (Audio Section)\n\t\t144f 3000  MagicTView CPH060 - Audio\n\t\t1461 0002  Avermedia PCTV98 Audio Capture\n\t\t1461 0003  UltraTV PCI 350\n\t\t1461 0004  AVerTV WDM Audio Capture\n\t\t1461 0761  AVerTV DVB-T\n\t\t1461 0771  AverMedia AVerTV DVB-T 771\n\t\t14f1 0001  Bt878 Video Capture (Audio Section)\n\t\t14f1 0002  Bt878 Video Capture (Audio Section)\n\t\t14f1 0003  Bt878 Video Capture (Audio Section)\n\t\t14f1 0048  Bt878 Video Capture (Audio Section)\n\t\t1822 0001  VisionPlus DVB Card\n\t\t18ac d500  DViCO FusionHDTV5 Lite\n\t\t270f fc00  Digitop DTT-1000\n\t\tbd11 1200  PCTV pro (TV + FM stereo receiver, audio section)\n\t0879  Bt879 Audio Capture\n\t\t127a 0044  Bt879 Video Capture (Audio Section)\n\t\t127a 0122  Bt879 Video Capture (Audio Section)\n\t\t127a 0144  Bt879 Video Capture (Audio Section)\n\t\t127a 0222  Bt879 Video Capture (Audio Section)\n\t\t127a 0244  Bt879 Video Capture (Audio Section)\n\t\t127a 0322  Bt879 Video Capture (Audio Section)\n\t\t127a 0422  Bt879 Video Capture (Audio Section)\n\t\t127a 1122  Bt879 Video Capture (Audio Section)\n\t\t127a 1222  Bt879 Video Capture (Audio Section)\n\t\t127a 1322  Bt879 Video Capture (Audio Section)\n\t\t127a 1522  Bt879 Video Capture (Audio Section)\n\t\t127a 1622  Bt879 Video Capture (Audio Section)\n\t\t127a 1722  Bt879 Video Capture (Audio Section)\n\t\t14f1 0044  Bt879 Video Capture (Audio Section)\n\t\t14f1 0122  Bt879 Video Capture (Audio Section)\n\t\t14f1 0144  Bt879 Video Capture (Audio Section)\n\t\t14f1 0222  Bt879 Video Capture (Audio Section)\n\t\t14f1 0244  Bt879 Video Capture (Audio Section)\n\t\t14f1 0322  Bt879 Video Capture (Audio Section)\n\t\t14f1 0422  Bt879 Video Capture (Audio Section)\n\t\t14f1 1122  Bt879 Video Capture (Audio Section)\n\t\t14f1 1222  Bt879 Video Capture (Audio Section)\n\t\t14f1 1322  Bt879 Video Capture (Audio Section)\n\t\t14f1 1522  Bt879 Video Capture (Audio Section)\n\t\t14f1 1622  Bt879 Video Capture (Audio Section)\n\t\t14f1 1722  Bt879 Video Capture (Audio Section)\n\t0880  Bt880 Audio Capture\n\t2115  BtV 2115 Mediastream controller\n\t2125  BtV 2125 Mediastream controller\n\t2164  BtV 2164\n\t2165  BtV 2165\n\t8230  Bt8230 ATM Segment/Reassembly Ctrlr (SRC)\n\t8472  Bt8472\n\t8474  Bt8474\n109f  Trigem Computer Inc.\n10a0  Meidensha Corporation\n10a1  Juko Electronics Ind. Co. Ltd\n10a2  Quantum Corporation\n10a3  Everex Systems Inc\n10a4  Globe Manufacturing Sales\n10a5  Smart Link Ltd.\n\t3052  SmartPCI562 56K Modem\n\t5449  SmartPCI561 modem\n10a6  Informtech Industrial Ltd.\n10a7  Benchmarq Microelectronics\n10a8  Sierra Semiconductor\n\t0000  STB Horizon 64\n10a9  Silicon Graphics Intl. Corp.\n\t0001  Crosstalk to PCI Bridge\n\t0002  Linc I/O controller\n\t0003  IOC3 I/O controller\n\t0004  O2 MACE\n\t0005  RAD Audio\n\t0006  HPCEX\n\t0007  RPCEX\n\t0008  DiVO VIP\n\t0009  AceNIC Gigabit Ethernet\n\t\t10a9 8002  AceNIC Gigabit Ethernet\n\t0010  AMP Video I/O\n\t0011  GRIP\n\t0012  SGH PSHAC GSN\n\t0208  SSIM1 SAS Adapter\n\t1001  Magic Carpet\n\t1002  Lithium\n\t1003  Dual JPEG 1\n\t1004  Dual JPEG 2\n\t1005  Dual JPEG 3\n\t1006  Dual JPEG 4\n\t1007  Dual JPEG 5\n\t1008  Cesium\n\t100a  IOC4 I/O controller\n\t1504  SSIM1 Fibre Channel Adapter\n\t2001  Fibre Channel\n\t2002  ASDE\n\t4001  TIO-CE PCI Express Bridge\n\t4002  TIO-CE PCI Express Port\n\t8001  O2 1394\n\t8002  G-net NT\n# PCIe x1 Low Profile\n\t802b  REACT external interrupt controller\n10aa  ACC Microelectronics\n\t0000  ACCM 2188\n\t2051  2051 CPU bridge\n\t5842  2051 ISA bridge\n10ab  Digicom\n10ac  Honeywell IAC\n10ad  Symphony Labs\n\t0001  W83769F\n\t0003  SL82C103\n\t0005  SL82C105\n\t0103  SL82c103\n\t0105  SL82c105\n\t0565  W83C553F/W83C554F\n10ae  Cornerstone Technology\n10af  Micro Computer Systems Inc\n10b0  CardExpert Technology\n10b1  Cabletron Systems Inc\n10b2  Raytheon Company\n10b3  Databook Inc\n\t3106  DB87144\n\tb106  DB87144\n10b4  STB Systems Inc\n\t1b1d  Velocity 128 3D\n\t\t10b4 237e  Velocity 4400\n10b5  PLX Technology, Inc.\n\t0001  i960 PCI bus interface\n\t0557  PCI9030 32-bit 33MHz PCI <-> IOBus Bridge\n\t\t10b5 9030  Digium Tormenta 2 T400P-SS7 or E400P-SS7 Quad T1 or E1 PCI card\n\t1000  PCI9030 32-bit 33MHz PCI <-> IOBus Bridge\n\t\t10b5 9030  ATCOM AT400P Quad T1 PCI card\n\t1024  Acromag, Inc. IndustryPack Carrier Card\n\t1042  Brandywine / jxi2, Inc. - PMC-SyncClock32, IRIG A & B, Nasa 36\n\t106a  Dual OX16C952 4 port serial adapter [Megawolf Romulus/4]\n\t1076  VScom 800 8 port serial adaptor\n\t1077  VScom 400 4 port serial adaptor\n\t1078  VScom 210 2 port serial and 1 port parallel adaptor\n\t1103  VScom 200 2 port serial adaptor\n\t1146  VScom 010 1 port parallel adaptor\n\t1147  VScom 020 2 port parallel adaptor\n\t2000  PCI9030 32-bit 33MHz PCI <-> IOBus Bridge\n\t\t10b5 9030  ATCOM AE400P Quad E1 PCI card\n\t2540  IXXAT CAN-Interface PC-I 04/PCI\n\t2724  Thales PCSM Security Card\n\t3376  Cosateq 4 Port CAN Card\n\t4000  PCI9030 32-bit 33MHz PCI <-> IOBus Bridge\n\t\t10b5 9030  Tormenta 3 Varion V400P/ATCOM TE400P Quad E1/T1/J1 PCI card\n\t4001  PCI9030 32-bit 33MHz PCI <-> IOBus Bridge\n\t\t10b5 9030  ATCOM A400PE Quad E1 PCI card\n\t4002  PCI9030 32-bit 33MHz PCI <-> IOBus Bridge\n\t\t10b5 9030  ATCOM A400PT Quad T1 PCI card\n\t6140  PCI6140 32-bit 33MHz PCI-to-PCI Bridge\n\t6150  PCI6150 32-bit 33MHz PCI-to-PCI Bridge\n\t6152  PCI6152 32-bit 66MHz PCI-to-PCI Bridge\n\t6154  PCI6154 64-bit 66MHz PCI-to-PCI Bridge\n\t6254  PCI6254 64-bit 66MHz PCI-to-PCI Bridge\n\t6466  PCI6466 64-bit 66MHz PCI-to-PCI Bridge\n\t6520  PCI6520 64-bit 133MHz PCI-X-to-PCI-X Bridge\n\t6540  PCI6540 64-bit 133MHz PCI-X-to-PCI-X Bridge\n\t\t1775 1100  CR11 Single Board Computer\n\t\t4c53 10e0  PSL09 PrPMC\n\t6541  PCI6540/6466 PCI-PCI bridge (non-transparent mode, primary side)\n\t\t1775 1100  CR11 Single Board Computer\n\t\t4c53 10e0  PSL09 PrPMC\n\t6542  PCI6540/6466 PCI-PCI bridge (non-transparent mode, secondary side)\n\t\t1775 1100  CR11 Single Board Computer\n\t\t4c53 10e0  PSL09 PrPMC\n\t8111  PEX 8111 PCI Express-to-PCI Bridge\n\t8112  PEX8112 x1 Lane PCI Express-to-PCI Bridge\n\t8114  PEX 8114 PCI Express-to-PCI/PCI-X Bridge\n\t8311  PEX8311 x1 Lane PCI Express-to-Generic Local Bus Bridge\n\t8505  PEX 8505 5-lane, 5-port PCI Express Switch\n\t8508  PEX 8508 8-lane, 5-port PCI Express Switch\n\t8509  PEX 8509 8-lane, 8-port PCI Express Switch\n\t8512  PEX 8512 12-lane, 5-port PCI Express Switch\n\t8516  PEX 8516  Versatile PCI Express Switch\n\t8517  PEX 8517 16-lane, 5-port PCI Express Switch\n\t8518  PEX 8518 16-lane, 5-port PCI Express Switch\n\t8524  PEX 8524 24-lane, 6-port PCI Express Switch\n\t8525  PEX 8525 24-lane, 5-port PCI Express Switch\n\t8532  PEX 8532  Versatile PCI Express Switch\n\t8533  PEX 8533 32-lane, 6-port PCI Express Switch\n\t8547  PEX 8547 48-lane, 3-port PCI Express Switch\n\t8548  PEX 8548 48-lane, 9-port PCI Express Switch\n\t8603  PEX 8603 3-lane, 3-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8604  PEX 8604 4-lane, 4-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8605  PEX 8605 PCI Express 4-port Gen2 Switch\n\t8606  PEX 8606 6 Lane, 6 Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8608  PEX 8608 8-lane, 8-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8609  PEX 8609 8-lane, 8-Port PCI Express Gen 2 (5.0 GT/s) Switch with DMA\n\t8612  PEX 8612 12-lane, 4-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8613  PEX 8613 12-lane, 3-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8614  PEX 8614 12-lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8615  PEX 8615 12-lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch with DMA\n\t8616  PEX 8616 16-lane, 4-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8617  PEX 8617 16-lane, 4-Port PCI Express Gen 2 (5.0 GT/s) Switch with P2P\n\t8618  PEX 8618 16-lane, 16-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8619  PEX 8619 16-lane, 16-Port PCI Express Gen 2 (5.0 GT/s) Switch with DMA\n\t8624  PEX 8624 24-lane, 6-Port PCI Express Gen 2 (5.0 GT/s) Switch [ExpressLane]\n\t\t13a3 1845  DX1845 Acceleration Card\n\t8625  PEX 8625 24-lane, 24-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8632  PEX 8632 32-lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8636  PEX 8636 36-lane, 24-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8647  PEX 8647 48-Lane, 3-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8648  PEX 8648 48-lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8649  PEX 8649 48-lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8664  PEX 8664 64-lane, 16-Port PCI Express Gen 2 (5.0 GT/s) Switch\n\t8680  PEX 8680 80-lane, 20-Port PCI Express Gen 2 (5.0 GT/s) Multi-Root Switch\n\t8696  PEX 8696 96-lane, 24-Port PCI Express Gen 2 (5.0 GT/s) Multi-Root Switch\n\t8717  PEX 8717 16-lane, 8-Port PCI Express Gen 3 (8.0 GT/s) Switch with DMA\n\t8718  PEX 8718 16-Lane, 5-Port PCI Express Gen 3 (8.0 GT/s) Switch\n\t8724  PEX 8724 24-Lane, 6-Port PCI Express Gen 3 (8 GT/s) Switch, 19 x 19mm FCBGA\n\t8732  PEX 8732 32-lane, 8-Port PCI Express Gen 3 (8.0 GT/s) Switch\n\t8734  PEX 8734 32-lane, 8-Port PCI Express Gen 3 (8.0GT/s) Switch\n\t8747  PEX 8747 48-Lane, 5-Port PCI Express Gen 3 (8.0 GT/s) Switch\n\t8748  PEX 8748 48-Lane, 12-Port PCI Express Gen 3 (8 GT/s) Switch, 27 x 27mm FCBGA\n# This is the Non-Transparent-Bridge Virtualized Port as presented by the PLX PEX 8732 chip, the physical bridges show up at 10b5:8732\n\t87b0  PEX 8732 32-lane, 8-Port PCI Express Gen 3 (8.0 GT/s) Switch\n\t\t1093 7761  PXIe-8830mc\n\t9016  PLX 9016 8-port serial controller\n\t9030  PCI9030 32-bit 33MHz PCI <-> IOBus Bridge\n\t\t10b5 2695  Hilscher CIF50-PB/DPS Profibus\n\t\t10b5 2862  Alpermann+Velte PCL PCI LV (3V/5V): Timecode Reader Board\n\t\t10b5 2906  Alpermann+Velte PCI TS (3V/5V): Time Synchronisation Board\n\t\t10b5 2940  Alpermann+Velte PCL PCI D (3V/5V): Timecode Reader Board\n\t\t10b5 2977  IXXAT iPC-I XC16/PCI CAN Board\n\t\t10b5 2978  SH ARC-PCIu/SH ARC-PCI104/SH ARC-PCIe SOHARD ARCNET card\n\t\t10b5 3025  Alpermann+Velte PCL PCI L (3V/5V): Timecode Reader Board\n\t\t10b5 3068  Alpermann+Velte PCL PCI HD (3V/5V): Timecode Reader Board\n\t\t10b5 3463  Alpermann+Velte PCL PCI D (v2) (3V/5V): Timecode Reader Board\n\t\t10b5 3591  PLURA PCL PCI L (v2) (3.3V/5V): Time Code Reader Board\n\t\t12fe 0111  CPCI-ASIO4 (ESD 4-port Serial Interface Board)\n\t\t1369 9c01  VX222v2\n\t\t1369 9d01  VX222-Mic\n\t\t1369 9d02  VX222-Mic\n\t\t1369 9e01  PCX924v2\n\t\t1369 9f01  PCX924-Mic\n\t\t1369 9f02  PCX924-Mic\n\t\t1369 a001  PCX22v2\n\t\t1369 a701  LCM220v2\n\t\t1369 a801  LCM200\n\t\t1397 3136  4xS0-ISDN PCI Adapter\n\t\t1397 3137  S2M-E1-ISDN PCI Adapter\n\t\t1518 0200  ThinkIO-C\n\t\t15ed 1002  MCCS 8-port Serial Hot Swap\n\t\t15ed 1003  MCCS 16-port Serial Hot Swap\n# MIL-STD-1553B Board\n\t\te1c5 0001  TE1-PCI\n\t\te1c5 0005  TA1-PCI\n\t\te1c5 0006  TA1-PCI4\n\t9036  9036\n\t9050  PCI <-> IOBus Bridge\n\t\t10b5 1067  IXXAT CAN i165\n\t\t10b5 114e  Wasco WITIO PCI168extended\n\t\t10b5 1169  Wasco OPTOIO32standard 32 digital in, 32 digital out\n\t\t10b5 1172  IK220 (Heidenhain)\n\t\t10b5 2036  SatPak GPS\n\t\t10b5 2221  Alpermann+Velte PCL PCI LV: Timecode Reader Board\n\t\t10b5 2273  SH ARC-PCI SOHARD ARCNET card\n\t\t10b5 2431  Alpermann+Velte PCL PCI D: Timecode Reader Board\n\t\t10b5 2905  Alpermann+Velte PCI TS: Time Synchronisation Board\n\t\t10b5 3196  Goramo PLX200SYN sync serial card\n\t\t10b5 9050  PCI-I04 PCI Passive PC/CAN Interface\n\t\t1369 8901  PCX11+ PCI\n\t\t1369 8f01  VX222\n\t\t1369 9401  PCX924\n\t\t1369 9501  PCX22\n\t\t1498 0362  TPMC866 8 Channel Serial Card\n\t\t1522 0001  RockForce 4 Port V.90 Data/Fax/Voice Modem\n\t\t1522 0002  RockForce 2 Port V.90 Data/Fax/Voice Modem\n\t\t1522 0003  RockForce 6 Port V.90 Data/Fax/Voice Modem\n\t\t1522 0004  RockForce 8 Port V.90 Data/Fax/Voice Modem\n\t\t1522 0010  RockForce2000 4 Port V.90 Data/Fax/Voice Modem\n\t\t1522 0020  RockForce2000 2 Port V.90 Data/Fax/Voice Modem\n\t\t15ed 1000  Macrolink MCCS 8-port Serial\n\t\t15ed 1001  Macrolink MCCS 16-port Serial\n\t\t15ed 1002  Macrolink MCCS 8-port Serial Hot Swap\n\t\t15ed 1003  Macrolink MCCS 16-port Serial Hot Swap\n\t\t5654 2036  OpenSwitch 6 Telephony card\n\t\t5654 3132  OpenSwitch 12 Telephony card\n\t\t5654 5634  OpenLine4 Telephony Card\n\t\td531 c002  PCIntelliCAN 2xSJA1000 CAN bus\n\t\td84d 4006  EX-4006 1P\n\t\td84d 4008  EX-4008 1P EPP/ECP\n\t\td84d 4014  EX-4014 2P\n\t\td84d 4018  EX-4018 3P EPP/ECP\n\t\td84d 4025  EX-4025 1S(16C550) RS-232\n\t\td84d 4027  EX-4027 1S(16C650) RS-232\n\t\td84d 4028  EX-4028 1S(16C850) RS-232\n\t\td84d 4036  EX-4036 2S(16C650) RS-232\n\t\td84d 4037  EX-4037 2S(16C650) RS-232\n\t\td84d 4038  EX-4038 2S(16C850) RS-232\n\t\td84d 4052  EX-4052 1S(16C550) RS-422/485\n\t\td84d 4053  EX-4053 2S(16C550) RS-422/485\n\t\td84d 4055  EX-4055 4S(16C550) RS-232\n\t\td84d 4058  EX-4055 4S(16C650) RS-232\n\t\td84d 4065  EX-4065 8S(16C550) RS-232\n\t\td84d 4068  EX-4068 8S(16C650) RS-232\n\t\td84d 4078  EX-4078 2S(16C552) RS-232+1P\n\t9052  PCI9052 PCI <-> IOBus Bridge\n\t9054  PCI9054 32-bit 33MHz PCI <-> IOBus Bridge\n\t\t10b5 2455  Wessex Techology PHIL-PCI\n\t\t10b5 2696  Innes Corp AM Radcap card\n\t\t10b5 2717  Innes Corp Auricon card\n\t\t10b5 2844  Innes Corp TVS Encoder card\n\t\t12c7 4001  Intel Dialogic DM/V960-4T1 PCI\n\t\t12d9 0002  PCI Prosody Card rev 1.5\n\t\t14b4 d100  Dektec DTA-100\n\t\t14b4 d114  Dektec DTA-120\n\t\t16df 0011  PIKA PrimeNet MM PCI\n\t\t16df 0012  PIKA PrimeNet MM cPCI 8\n\t\t16df 0013  PIKA PrimeNet MM cPCI 8 (without CAS Signaling)\n\t\t16df 0014  PIKA PrimeNet MM cPCI 4\n\t\t16df 0015  PIKA Daytona MM\n\t\t16df 0016  PIKA InLine MM\n\t9056  PCI9056 32-bit 66MHz PCI <-> IOBus Bridge\n\t\t10b5 2979  CellinkBlade 11 - CPCI board VoATM AAL1\n\t\t10b5 3268  IXXAT iPC-I XC16/PCIe CAN Board\n\t\t10b5 3334  Cambridge Pixel HPx Radar Input Card\n\t\t10b5 3352  Alpermann+Velte PCL PCIe HD: Timecode Reader Board\n\t\t10b5 3353  Alpermann+Velte PCL PCIe D: Timecode Reader Board\n\t\t10b5 3354  Alpermann+Velte PCL PCIe LV: Timecode Reader Board\n\t\t10b5 3355  Alpermann+Velte PCL PCIe L: Timecode Reader Board\n\t\t10b5 3415  Alpermann+Velte PCIe TS: Time Synchronisation Board\n\t\t10b5 3493  Alpermann+Velte PCL PCIe 3G: Timecode Reader Board\n\t\t10b5 3565  Cambridge Pixel HPx Radar Output Card\n\t\t1369 c001  LX6464ES\n\t\t1369 c201  LX1616ES\n\t\t14b4 d10a  DekTec DTA-110T\n\t\t14b4 d128  Dektec DTA-140\n\t\t14b4 d140  Dektec DTA-140\n\t\t1a0e 006f  Dektec DTA-111\n\t9060  PCI9060 32-bit 33MHz PCI <-> IOBus Bridge\n\t906d  9060SD\n\t\t125c 0640  Aries 16000P\n\t906e  9060ES\n\t9080  PCI9080 32-bit; 33MHz PCI <-> IOBus Bridge\n\t\t103c 10eb  (Agilent) E2777B 83K Series Optical Communication Interface\n\t\t103c 10ec  (Agilent) E6978-66442 PCI CIC\n\t\t10b5 1123  Sectra KK631 encryption board\n\t\t10b5 9080  9080 [real subsystem ID not set]\n\t\t12d9 0002  PCI Prosody Card\n\t\t12df 4422  4422PCI [\"Do-All\" Telemetry Data Acquisition System]\n\t\t1369 9601  PCX822np\n\t\t1369 a102  PCX822v2\n\t\t1369 a201  PCX442\n\t\t1369 a301  LCM440v2\n\t\t1369 a401  VX822\n\t\t1369 a402  VX822v2\n\t\t1369 a901  LCM420\n\t\t1369 aa01  VX820v2\n\t\t1517 000b  ECSG-1R3ADC-PMC Clock synthesizer\n\t9656  PCI9656 PCI <-> IOBus Bridge\n\t\t1517 000f  ECDR-GC314-PMC Receiver\n\t\t1885 0700  Tsunami FPGA PMC with Altera Stratix S40\n\t\t1885 0701  Tsunami FPGA PMC with Altera Stratix S30\n\t9733  PEX 9733 33-lane, 9-port PCI Express Gen 3 (8.0 GT/s) Switch\n\t\t1d49 0001  ThinkSystem 1610-4P NVMe Switch Adapter\n\t\t1d49 0002  ThinkSystem 810-4P NVMe Switch Adapter\n\t9749  PEX 9749 49-lane, 13-port PCI Express Gen 3 (8.0 GT/s) Switch\n\t\t1d49 0004  ThinkSystem 1610-8P NVMe Switch Adapter\n\ta100  Blackmagic Design DeckLink\n\tbb04  B&B 3PCIOSD1A Isolated PCI Serial\n\tc001  CronyxOmega-PCI (8-port RS232)\n\td00d  PCI9030 32-bit 33MHz PCI <-> IOBus Bridge\n\t\t10b5 9030  Digium Tormenta 2 T400P or E400P Quad T1 or E1 PCI card\n\td33d  PCI9030 32-bit 33MHz PCI <-> IOBus Bridge\n\t\t10b5 9030  Tormenta 3 Varion V401PT Quad T1/J1 PCI card\n\td44d  PCI9030 32-bit 33MHz PCI <-> IOBus Bridge\n\t\t10b5 17f6  Allo CP100P/E 1-port E1/T1/J1 PCI/PCIe card\n\t\t10b5 17f7  Allo CP400P/E 4-port E1/T1/J1 PCI/PCIe card\n\t\t10b5 17f8  Allo CP200P/E 2-port E1/T1/J1 PCI/PCIe card\n\t\t10b5 9030  Tormenta 3 Varion V401PE Quad E1 PCI card\n10b6  Madge Networks\n\t0001  Smart 16/4 PCI Ringnode\n\t0002  Smart 16/4 PCI Ringnode Mk2\n\t\t10b6 0002  Smart 16/4 PCI Ringnode Mk2\n\t\t10b6 0006  16/4 CardBus Adapter\n\t0003  Smart 16/4 PCI Ringnode Mk3\n\t\t0e11 b0fd  Compaq NC4621 PCI, 4/16, WOL\n\t\t10b6 0003  Smart 16/4 PCI Ringnode Mk3\n\t\t10b6 0007  Presto PCI Plus Adapter\n\t0004  Smart 16/4 PCI Ringnode Mk1\n\t0006  16/4 Cardbus Adapter\n\t\t10b6 0006  16/4 CardBus Adapter\n\t0007  Presto PCI Adapter\n\t\t10b6 0007  Presto PCI\n\t0009  Smart 100/16/4 PCI-HS Ringnode\n\t\t10b6 0009  Smart 100/16/4 PCI-HS Ringnode\n\t000a  Token Ring 100/16/4 Ringnode/Ringrunner\n\t\t10b6 000a  Token Ring 100/16/4 Ringnode/Ringrunner\n\t000b  16/4 CardBus Adapter Mk2\n\t\t10b6 0008  16/4 CardBus Adapter Mk2\n\t\t10b6 000b  16/4 Cardbus Adapter Mk2\n\t000c  RapidFire 3140V2 16/4 TR Adapter\n\t\t10b6 000c  RapidFire 3140V2 16/4 TR Adapter\n\t1000  Collage 25/155 ATM Client Adapter\n\t1001  Collage 155 ATM Server Adapter\n10b7  3Com Corporation\n\t0001  3c985 1000BaseSX (SX/TX)\n# wrong ID?\n\t\t9850 0001  3c985B-SX\n\t0013  AR5212 802.11abg NIC (3CRDAG675)\n\t\t10b7 2031  3CRDAG675 11a/b/g Wireless PCI Adapter\n\t0910  3C910-A01\n\t1006  MINI PCI type 3B Data Fax Modem\n\t1007  Mini PCI 56k Winmodem\n\t\t10b7 615b  Mini PCI 56K Modem\n\t\t10b7 615c  Mini PCI 56K Modem\n\t1201  3c982-TXM 10/100baseTX Dual Port A [Hydra]\n\t1202  3c982-TXM 10/100baseTX Dual Port B [Hydra]\n\t1700  3c940 10/100/1000Base-T [Marvell]\n\t\t1043 80eb  A7V600/P4P800/K8V motherboard\n\t\t10b7 0010  3C940 Gigabit LOM Ethernet Adapter\n\t\t10b7 0020  3C941 Gigabit LOM Ethernet Adapter\n\t\t147b 1407  KV8-MAX3 motherboard\n\t3390  3c339 TokenLink Velocity\n\t3590  3c359 TokenLink Velocity XL\n\t\t10b7 3590  TokenLink Velocity XL Adapter (3C359/359B)\n\t4500  3c450 HomePNA [Tornado]\n\t5055  3c555 Laptop Hurricane\n\t5057  3c575 Megahertz 10/100 LAN CardBus [Boomerang]\n\t\t10b7 5a57  3C575 Megahertz 10/100 LAN Cardbus PC Card\n\t5157  3cCFE575BT Megahertz 10/100 LAN CardBus [Cyclone]\n\t\t10b7 5b57  3C575 Megahertz 10/100 LAN Cardbus PC Card\n\t5257  3cCFE575CT CardBus [Cyclone]\n\t\t10b7 5c57  FE575C-3Com 10/100 LAN CardBus-Fast Ethernet\n\t5900  3c590 10BaseT [Vortex]\n\t5920  3c592 EISA 10mbps Demon/Vortex\n\t5950  3c595 100BaseTX [Vortex]\n\t5951  3c595 100BaseT4 [Vortex]\n\t5952  3c595 100Base-MII [Vortex]\n\t5970  3c597 EISA Fast Demon/Vortex\n\t5b57  3c595 Megahertz 10/100 LAN CardBus [Boomerang]\n\t\t10b7 5b57  3C575 Megahertz 10/100 LAN Cardbus PC Card\n\t6000  3CRSHPW796 [OfficeConnect Wireless CardBus]\n\t6001  3com 3CRWE154G72 [Office Connect Wireless LAN Adapter]\n\t6055  3c556 Hurricane CardBus [Cyclone]\n\t6056  3c556B CardBus [Tornado]\n\t\t10b7 6556  10/100 Mini PCI Ethernet Adapter\n\t6560  3cCFE656 CardBus [Cyclone]\n\t\t10b7 656a  3CCFEM656 10/100 LAN+56K Modem CardBus\n\t6561  3cCFEM656 10/100 LAN+56K Modem CardBus\n\t\t10b7 656b  3CCFEM656 10/100 LAN+56K Modem CardBus\n\t6562  3cCFEM656B 10/100 LAN+Winmodem CardBus [Cyclone]\n\t\t10b7 656b  3CCFEM656B 10/100 LAN+56K Modem CardBus\n\t6563  3cCFEM656B 10/100 LAN+56K Modem CardBus\n\t\t10b7 656b  3CCFEM656 10/100 LAN+56K Modem CardBus\n\t6564  3cXFEM656C 10/100 LAN+Winmodem CardBus [Tornado]\n\t7646  3cSOHO100-TX Hurricane\n\t7770  3CRWE777 PCI Wireless Adapter [Airconnect]\n\t7940  3c803 FDDILink UTP Controller\n\t7980  3c804 FDDILink SAS Controller\n\t7990  3c805 FDDILink DAS Controller\n\t80eb  3c940B 10/100/1000Base-T\n\t8811  Token ring\n\t9000  3c900 10BaseT [Boomerang]\n\t9001  3c900 10Mbps Combo [Boomerang]\n\t9004  3c900B-TPO Etherlink XL [Cyclone]\n\t\t10b7 9004  3C900B-TPO Etherlink XL TPO 10Mb\n\t9005  3c900B-Combo Etherlink XL [Cyclone]\n\t\t10b7 9005  3C900B-Combo Etherlink XL Combo\n\t9006  3c900B-TPC Etherlink XL [Cyclone]\n\t900a  3c900B-FL 10base-FL [Cyclone]\n\t9050  3c905 100BaseTX [Boomerang]\n\t9051  3c905 100BaseT4 [Boomerang]\n\t9054  3C905B-TX Fast Etherlink XL PCI\n\t\t10b7 9054  3C905B-TX Fast Etherlink XL PCI\n\t9055  3c905B 100BaseTX [Cyclone]\n\t\t1028 0080  3C905B Fast Etherlink XL 10/100\n\t\t1028 0081  3C905B Fast Etherlink XL 10/100\n\t\t1028 0082  3C905B Fast Etherlink XL 10/100\n\t\t1028 0083  3C905B Fast Etherlink XL 10/100\n\t\t1028 0084  3C905B Fast Etherlink XL 10/100\n\t\t1028 0085  3C905B Fast Etherlink XL 10/100\n\t\t1028 0086  3C905B Fast Etherlink XL 10/100\n\t\t1028 0087  3C905B Fast Etherlink XL 10/100\n\t\t1028 0088  3C905B Fast Etherlink XL 10/100\n\t\t1028 0089  3C905B Fast Etherlink XL 10/100\n\t\t1028 0090  3C905B Fast Etherlink XL 10/100\n\t\t1028 0091  3C905B Fast Etherlink XL 10/100\n\t\t1028 0092  3C905B Fast Etherlink XL 10/100\n\t\t1028 0093  3C905B Fast Etherlink XL 10/100\n\t\t1028 0094  3C905B Fast Etherlink XL 10/100\n\t\t1028 0095  3C905B Fast Etherlink XL 10/100\n\t\t1028 0096  3C905B Fast Etherlink XL 10/100\n\t\t1028 0097  3C905B Fast Etherlink XL 10/100\n\t\t1028 0098  3C905B Fast Etherlink XL 10/100\n\t\t1028 0099  3C905B Fast Etherlink XL 10/100\n\t\t10b7 9055  3C905B Fast Etherlink XL 10/100\n\t9056  3c905B-T4 Fast EtherLink XL [Cyclone]\n\t9058  3c905B Deluxe Etherlink 10/100/BNC [Cyclone]\n\t905a  3c905B-FX Fast Etherlink XL FX 100baseFx [Cyclone]\n\t9200  3c905C-TX/TX-M [Tornado]\n\t\t1028 0095  3C920 Integrated Fast Ethernet Controller\n\t\t1028 0097  3C920 Integrated Fast Ethernet Controller\n\t\t1028 00b4  OptiPlex GX110\n\t\t1028 00d8  Precision 530\n\t\t1028 00fe  Optiplex GX240\n\t\t1028 012a  3C920 Integrated Fast Ethernet Controller [Latitude C640]\n\t\t10b7 1000  3C905CX-TX/TX-M Fast Etherlink for PC Management NIC\n\t\t10b7 7000  10/100 Mini PCI Ethernet Adapter\n\t\t10f1 2466  Tiger MPX S2466 (3C920 Integrated Fast Ethernet Controller)\n\t\t144d c005  X10 Laptop\n\t9201  3C920B-EMB Integrated Fast Ethernet Controller [Tornado]\n\t\t1043 80ab  A7N8X Deluxe onboard 3C920B-EMB Integrated Fast Ethernet Controller\n\t9202  3Com 3C920B-EMB-WNM Integrated Fast Ethernet Controller\n\t9210  3C920B-EMB-WNM Integrated Fast Ethernet Controller\n\t9300  3CSOHO100B-TX 910-A01 [tulip]\n\t9800  3c980-TX Fast Etherlink XL Server Adapter [Cyclone]\n\t\t10b7 9800  3c980-TX Fast Etherlink XL Server Adapter\n\t9805  3c980-C 10/100baseTX NIC [Python-T]\n\t\t10b7 1201  EtherLink Server 10/100 Dual Port A\n\t\t10b7 1202  EtherLink Server 10/100 Dual Port B\n\t\t10b7 9805  3c980 10/100baseTX NIC [Python-T]\n\t\t10f1 2462  Thunder K7 S2462\n\t9900  3C990-TX [Typhoon]\n\t9902  3CR990-TX-95 [Typhoon 56-bit]\n\t9903  3CR990-TX-97 [Typhoon 168-bit]\n\t9904  3C990B-TX-M/3C990BSVR [Typhoon2]\n\t\t10b7 1000  3CR990B-TX-M [Typhoon2]\n\t\t10b7 2000  3CR990BSVR [Typhoon2 Server]\n\t9905  3CR990-FX-95/97/95 [Typhon Fiber]\n\t\t10b7 1101  3CR990-FX-95 [Typhoon Fiber 56-bit]\n\t\t10b7 1102  3CR990-FX-97 [Typhoon Fiber 168-bit]\n\t\t10b7 2101  3CR990-FX-95 Server [Typhoon Fiber 56-bit]\n\t\t10b7 2102  3CR990-FX-97 Server [Typhoon Fiber 168-bit]\n\t9908  3CR990SVR95 [Typhoon Server 56-bit]\n\t9909  3CR990SVR97 [Typhoon Server 168-bit]\n\t990a  3C990SVR [Typhoon Server]\n\t990b  3C990SVR [Typhoon Server]\n10b8  Standard Microsystems Corp [SMC]\n\t0005  83c170 EPIC/100 Fast Ethernet Adapter\n\t\t1055 e000  LANEPIC 10/100 [EVB171Q-PCI]\n\t\t1055 e002  LANEPIC 10/100 [EVB171G-PCI]\n\t\t10b8 a011  EtherPower II 10/100\n\t\t10b8 a014  EtherPower II 10/100\n\t\t10b8 a015  EtherPower II 10/100\n\t\t10b8 a016  EtherPower II 10/100\n\t\t10b8 a017  EtherPower II 10/100\n\t0006  83c175 EPIC/100 Fast Ethernet Adapter\n\t\t1055 e100  LANEPIC Cardbus Fast Ethernet Adapter\n\t\t1055 e102  LANEPIC Cardbus Fast Ethernet Adapter\n\t\t1055 e300  LANEPIC Cardbus Fast Ethernet Adapter\n\t\t1055 e302  LANEPIC Cardbus Fast Ethernet Adapter\n\t\t10b8 a012  LANEPIC Cardbus Fast Ethernet Adapter\n\t\t13a2 8002  LANEPIC Cardbus Fast Ethernet Adapter\n\t\t13a2 8006  LANEPIC Cardbus Fast Ethernet Adapter\n\t1000  FDC 37c665\n\t1001  FDC 37C922\n\ta011  83C170QF\n\tb106  SMC34C90\n# Split off ALi Corporation in 2003\n10b9  ULi Electronics Inc.\n\t0101  CMI8338/C3DX PCI Audio Device\n\t0111  C-Media CMI8738/C3DX Audio Device (OEM)\n\t\t10b9 0111  C-Media CMI8738/C3DX Audio Device (OEM)\n\t0780  Multi-IO Card\n\t0782  Multi-IO Card\n\t1435  M1435\n\t1445  M1445\n\t1449  M1449\n\t1451  M1451\n\t1461  M1461\n\t1489  M1489\n\t1511  M1511 [Aladdin]\n\t1512  M1512 [Aladdin]\n\t1513  M1513 [Aladdin]\n\t1521  M1521 [Aladdin III]\n\t\t10b9 1521  ALI M1521 Aladdin III CPU Bridge\n\t1523  M1523\n\t\t10b9 1523  ALI M1523 ISA Bridge\n\t1531  M1531 [Aladdin IV]\n\t1533  M1533/M1535/M1543 PCI to ISA Bridge [Aladdin IV/V/V+]\n\t\t1014 053b  ThinkPad R40e\n\t\t10b9 1533  ALi M1533 Aladdin IV/V ISA Bridge\n\t1541  M1541\n\t\t10b9 1541  ALI M1541 Aladdin V/V+ AGP System Controller\n\t1543  M1543\n\t1563  M1563 HyperTransport South Bridge\n\t\t10b9 1563  ASRock 939Dual-SATA2 Motherboard\n\t\t1849 1563  ASRock 939Dual-SATA2 Motherboard\n\t1573  PCI to LPC Controller\n\t1575  M1575 South Bridge\n\t1621  M1621\n\t1631  ALI M1631 PCI North Bridge Aladdin Pro III\n\t1632  M1632M Northbridge+Trident\n\t1641  ALI M1641 PCI North Bridge Aladdin Pro IV\n\t1644  M1644/M1644T Northbridge+Trident\n\t1646  M1646 Northbridge+Trident\n\t1647  M1647 Northbridge [MAGiK 1 / MobileMAGiK 1]\n\t1651  M1651/M1651T Northbridge [Aladdin-Pro 5/5M,Aladdin-Pro 5T/5TM]\n\t1671  M1671 Super P4 Northbridge [AGP4X,PCI and SDR/DDR]\n\t1672  M1672 Northbridge [CyberALADDiN-P4]\n\t1681  M1681 P4 Northbridge [AGP8X,HyperTransport and SDR/DDR]\n\t1687  M1687 K8 Northbridge [AGP8X and HyperTransport]\n\t1689  M1689 K8 Northbridge [Super K8 Single Chip]\n\t1695  M1695 Host Bridge\n\t1697  M1697 HTT Host Bridge\n\t3141  M3141\n\t3143  M3143\n\t3145  M3145\n\t3147  M3147\n\t3149  M3149\n\t3151  M3151\n\t3307  M3307\n\t3309  M3309\n\t3323  M3325 Video/Audio Decoder\n\t5212  M4803\n\t5215  MS4803\n\t5217  M5217H\n\t5219  M5219\n\t5225  M5225\n\t5228  M5228 ALi ATA/RAID Controller\n\t5229  M5229 IDE\n\t\t1014 050f  ThinkPad R30\n\t\t1014 053d  ThinkPad R40e\n\t\t103c 0024  Pavilion ze4400 builtin IDE\n\t\t103c 0025  XE4500 Notebook\n\t\t1043 8053  A7A266 Motherboard IDE\n\t\t1849 5229  ASRock 939Dual-SATA2 Motherboard IDE (PATA)\n\t5235  M5225\n\t5237  USB 1.1 Controller\n\t\t1014 0540  ThinkPad R40e\n\t\t103c 0024  Pavilion ze4400 builtin USB\n\t\t103c 0025  XE4500 Notebook\n\t\t104d 810f  VAIO PCG-U1 USB/OHCI Revision 1.0\n\t\t10b9 5237  ASRock 939Dual-SATA2 Motherboard\n\t\t1849 5237  ASRock 939Dual-SATA2 Motherboard\n\t5239  USB 2.0 Controller\n\t\t10b9 5239  ASRock 939Dual-SATA2 Motherboard\n\t\t1849 5239  ASRock 939Dual-SATA2 Motherboard\n\t5243  M1541 PCI to AGP Controller\n\t5246  AGP8X Controller\n\t5247  PCI to AGP Controller\n\t5249  M5249 HTT to PCI Bridge\n\t524b  PCI Express Root Port\n\t524c  PCI Express Root Port\n\t524d  PCI Express Root Port\n\t524e  PCI Express Root Port\n\t5251  M5251 P1394 OHCI 1.0 Controller\n\t5253  M5253 P1394 OHCI 1.1 Controller\n\t5261  M5261 Ethernet Controller\n\t5263  ULi 1689,1573 integrated ethernet.\n\t5281  ALi M5281 Serial ATA / RAID Host Controller\n\t5287  ULi 5287 SATA\n\t5288  ULi M5288 SATA\n\t\t1043 8056  A8R-MVP Mainboard\n\t5289  ULi 5289 SATA\n\t5450  Lucent Technologies Soft Modem AMR\n\t5451  M5451 PCI AC-Link Controller Audio Device\n\t\t1014 0506  ThinkPad R30\n\t\t1014 053e  ThinkPad R40e\n\t\t103c 0024  Pavilion ze4400 builtin Audio\n\t\t103c 0025  XE4500 Notebook\n\t5453  M5453 PCI AC-Link Controller Modem Device\n\t5455  M5455 PCI AC-Link Controller Audio Device\n\t\t10b9 5455  ASRock 939Dual-SATA2 Motherboard\n\t\t1849 0850  ASRock 939Dual-SATA2 Motherboard\n\t5457  M5457 AC'97 Modem Controller\n\t\t1014 0535  ThinkPad R40e\n\t\t103c 0024  Pavilion ze4400 builtin Modem Device\n\t\t103c 0025  XE4500 Notebook\n\t5459  SmartLink SmartPCI561 56K Modem\n\t545a  SmartLink SmartPCI563 56K Modem\n\t5461  HD Audio Controller\n\t5471  M5471 Memory Stick Controller\n\t5473  M5473 SD-MMC Controller\n\t7101  M7101 Power Management Controller [PMU]\n\t\t1014 0510  ThinkPad R30\n\t\t1014 053c  ThinkPad R40e\n\t\t103c 0024  Pavilion ze4400\n\t\t103c 0025  XE4500 Notebook\n\t\t1849 7101  ASRock 939Dual-SATA2 Motherboard\n10ba  Mitsubishi Electric Corp.\n\t0301  AccelGraphics AccelECLIPSE\n\t0304  AccelGALAXY A2100 [OEM Evans & Sutherland]\n\t0308  Tornado 3000 [OEM Evans & Sutherland]\n\t\t10dd 0024  Tornado 3000\n\t1002  VG500 [VolumePro Volume Rendering Accelerator]\n10bb  Dapha Electronics Corporation\n10bc  Advanced Logic Research\n10bd  Surecom Technology\n\t0e34  NE-34\n10be  Tseng Labs International Co.\n10bf  Most Inc\n10c0  Boca Research Inc.\n10c1  ICM Co., Ltd.\n10c2  Auspex Systems Inc.\n10c3  Samsung Semiconductors, Inc.\n10c4  Award Software International Inc.\n10c5  Xerox Corporation\n10c6  Rambus Inc.\n10c7  Media Vision\n10c8  Neomagic Corporation\n\t0001  NM2070 [MagicGraph 128]\n\t0002  NM2090 [MagicGraph 128V]\n\t0003  NM2093 [MagicGraph 128ZV]\n\t0004  NM2160 [MagicGraph 128XD]\n\t\t1014 00ba  MagicGraph 128XD\n\t\t1025 1007  MagicGraph 128XD\n\t\t1028 0074  MagicGraph 128XD\n\t\t1028 0075  MagicGraph 128XD\n\t\t1028 007d  MagicGraph 128XD\n\t\t1028 007e  MagicGraph 128XD\n\t\t1033 802f  MagicGraph 128XD\n\t\t104d 801b  MagicGraph 128XD\n\t\t104d 802f  MagicGraph 128XD\n\t\t104d 830b  MagicGraph 128XD\n\t\t10ba 0e00  MagicGraph 128XD\n\t\t10c8 0004  MagicGraph 128XD\n\t\t10cf 1029  MagicGraph 128XD\n\t\t10f7 8308  MagicGraph 128XD\n\t\t10f7 8309  MagicGraph 128XD\n\t\t10f7 830b  MagicGraph 128XD\n\t\t10f7 830d  MagicGraph 128XD\n\t\t10f7 8312  MagicGraph 128XD\n\t0005  NM2200 [MagicGraph 256AV]\n\t\t1014 00dd  ThinkPad 570\n\t\t1028 0088  Latitude CPi A\n\t0006  NM2360 [MagicMedia 256ZX]\n\t\t1014 0152  ThinkPad 600X\n\t0016  NM2380 [MagicMedia 256XL+]\n\t\t10c8 0016  MagicMedia 256XL+\n\t0025  NM2230 [MagicGraph 256AV+]\n\t0083  NM2093 [MagicGraph 128ZV+]\n\t8005  NM2200 [MagicMedia 256AV Audio]\n\t\t0e11 b0d1  MagicMedia 256AV Audio Device on Discovery\n\t\t0e11 b126  MagicMedia 256AV Audio Device on Durango\n\t\t1014 00dd  ThinkPad 390/i1720/i1721\n\t\t1025 1003  MagicMedia 256AV Audio Device on TravelMate 720\n\t\t1028 0088  Latitude CPi A\n\t\t1028 008f  MagicMedia 256AV Audio Device on Colorado Inspiron\n\t\t103c 0007  MagicMedia 256AV Audio Device on Voyager II\n\t\t103c 0008  MagicMedia 256AV Audio Device on Voyager III\n\t\t103c 000d  MagicMedia 256AV Audio Device on Omnibook 900\n\t\t10c8 8005  MagicMedia 256AV Audio Device on FireAnt\n\t\t110a 8005  MagicMedia 256AV Audio Device\n\t\t14c0 0004  MagicMedia 256AV Audio Device\n\t8006  NM2360 [MagicMedia 256ZX Audio]\n\t8016  NM2380 [MagicMedia 256XL+ Audio]\n10c9  Dataexpert Corporation\n10ca  Fujitsu Microelectr., Inc.\n10cb  Omron Corporation\n# nee Mentor ARC Inc\n10cc  Mai Logic Incorporated\n\t0660  Articia S Host Bridge\n\t0661  Articia S PCI Bridge\n10cd  Advanced System Products, Inc\n\t1100  ASC1100\n\t1200  ASC1200 [(abp940) Fast SCSI-II]\n\t1300  ASC1300 / ASC3030 [ABP940-U / ABP960-U / ABP3925]\n\t\t10cd 1310  ASC1300/3030 SCSI adapter\n\t\t1195 1320  Ultra-SCSI CardBus PC Card REX CB31\n\t2300  ABP940-UW\n\t2500  ABP940-U2W\n\t2700  ABP3950-U3W\n10ce  Radius\n# nee Citicorp TTI\n10cf  Fujitsu Limited.\n\t01ef  PCEA4 PCI-Express Dual Port ESCON Adapter\n\t1414  On-board USB 1.1 companion controller\n\t1415  On-board USB 2.0 EHCI controller\n\t1422  E8410 nVidia graphics adapter\n\t142d  HD audio (Realtek ALC262)\n\t1430  82566MM Intel 1Gb copper LAN interface\n\t1623  PCEA4 PCI-Express Dual Port ESCON Adapter\n\t2001  mb86605\n\t200c  MB86613L IEEE1394 OHCI 1.0 Controller\n\t2010  MB86613S IEEE1394 OHCI 1.1 Controller\n\t2019  MB86295S [CORAL P]\n\t201e  MB86296S [CORAL PA]\n\t202b  MB86297A [Carmine Graphics Controller]\n10d1  FuturePlus Systems Corp.\n10d2  Molex Incorporated\n10d3  Jabil Circuit Inc\n10d4  Hualon Microelectronics\n10d5  Autologic Inc.\n10d6  Cetia\n10d7  BCM Advanced Research\n10d8  Advanced Peripherals Labs\n10d9  Macronix, Inc. [MXIC]\n\t0431  MX98715\n\t0512  MX98713\n\t0531  MX987x5\n\t\t1186 1200  DFE-540TX ProFAST 10/100 Adapter\n\t8625  MX86250\n\t8626  Macronix MX86251 + 3Dfx Voodoo Rush\n\t8888  MX86200\n10da  Compaq IPG-Austin\n\t0508  TC4048 Token Ring 4/16\n\t3390  Tl3c3x9\n10db  Rohm LSI Systems, Inc.\n10dc  CERN/ECP/EDU\n\t0001  STAR/RD24 SCI-PCI (PMC)\n\t0002  TAR/RD24 SCI-PCI (PMC)\n\t0021  HIPPI destination\n\t0022  HIPPI source\n\t10dc  ATT2C15-3 FPGA\n10dd  Evans & Sutherland\n\t0100  Lightning 1200\n\t\t10dd 0023  Lightning 1200 15+16M\n10de  NVIDIA Corporation\n\t0008  NV1 [STG2000X-B Series]\n\t0009  NV1 [NV1 Series]\n\t0018  NV3 [Riva 128]\n\t0019  NV3 [Riva 128ZX]\n\t0020  NV4 [Riva TNT]\n\t\t1043 0200  V3400 TNT\n\t\t1048 0c18  Erazor II SGRAM\n\t\t1048 0c19  Erazor II\n\t\t1048 0c1b  Erazor II\n\t\t1048 0c1c  Erazor II\n\t\t1092 0550  Viper V550\n\t\t1092 0552  Viper V550\n\t\t1092 4804  Viper V550\n\t\t1092 4808  Viper V550\n\t\t1092 4810  Viper V550\n\t\t1092 4812  Viper V550\n\t\t1092 4815  Viper V550\n\t\t1092 4820  Viper V550 with TV out\n\t\t1092 4822  Viper V550\n\t\t1092 4904  Viper V550\n\t\t1092 4914  Viper V550\n\t\t1092 8225  Viper V550\n\t\t10b4 273d  Velocity 4400\n\t\t10b4 273e  Velocity 4400\n\t\t10b4 2740  Velocity 4400\n\t\t10de 0020  Riva TNT\n\t\t1102 1015  Graphics Blaster CT6710\n\t\t1102 1016  Graphics Blaster RIVA TNT\n\t0028  NV5 [Riva TNT2 / TNT2 Pro]\n\t\t1043 0200  AGP-V3800 SGRAM\n\t\t1043 0201  AGP-V3800 SDRAM\n\t\t1043 0205  PCI-V3800\n\t\t1043 4000  AGP-V3800PRO\n\t\t1048 0c21  Synergy II\n\t\t1048 0c28  Erazor III\n\t\t1048 0c29  Erazor III\n\t\t1048 0c2a  Erazor III\n\t\t1048 0c2b  Erazor III\n\t\t1048 0c31  Erazor III Pro\n\t\t1048 0c32  Erazor III Pro\n\t\t1048 0c33  Erazor III Pro\n\t\t1048 0c34  Erazor III Pro\n\t\t107d 2134  WinFast 3D S320 II + TV-Out\n\t\t1092 4804  Viper V770\n\t\t1092 4a00  Viper V770\n\t\t1092 4a02  Viper V770 Ultra\n\t\t1092 5a00  RIVA TNT2/TNT2 Pro\n\t\t1092 5a40  Viper V770D AGP\n\t\t1092 6a02  Viper V770 Ultra\n\t\t1092 7a02  Viper V770 Ultra\n\t\t10de 0005  RIVA TNT2 Pro\n\t\t10de 000f  Compaq NVIDIA TNT2 Pro\n\t\t1102 1020  3D Blaster RIVA TNT2\n\t\t1102 1026  3D Blaster RIVA TNT2 Digital\n\t\t1462 8806  MS-8806 AGPhantom Graphics Card\n\t\t14af 5810  Maxi Gamer Xentor\n\t0029  NV5 [Riva TNT2 Ultra]\n\t\t1043 0200  AGP-V3800 Deluxe\n\t\t1043 0201  AGP-V3800 Ultra SDRAM\n\t\t1043 0205  PCI-V3800 Ultra\n\t\t1048 0c2e  Erazor III Ultra\n\t\t1048 0c2f  Erazor III Ultra\n\t\t1048 0c30  Erazor III Ultra\n\t\t1102 1021  3D Blaster RIVA TNT2 Ultra\n\t\t1102 1029  3D Blaster RIVA TNT2 Ultra\n\t\t1102 102f  3D Blaster RIVA TNT2 Ultra\n\t\t14af 5820  Maxi Gamer Xentor 32\n\t\t4843 4f34  Dynamite\n\t002a  NV5 [Riva TNT2]\n\t002b  NV5 [Riva TNT2]\n\t002c  NV5 [Vanta / Vanta LT]\n\t\t1043 0200  AGP-V3800 Combat SDRAM\n\t\t1043 0201  AGP-V3800 Combat\n\t\t1048 0c20  TNT2 Vanta\n\t\t1048 0c21  TNT2 Vanta\n\t\t1048 0c25  TNT2 Vanta 16MB\n\t\t1092 6820  Viper V730\n\t\t1102 1031  CT6938 VANTA 8MB\n\t\t1102 1034  CT6894 VANTA 16MB\n\t\t14af 5008  Maxi Gamer Phoenix 2\n\t002d  NV5 [Riva TNT2 Model 64 / Model 64 Pro]\n\t\t1043 0200  AGP-V3800M\n\t\t1043 0201  AGP-V3800M\n\t\t1048 0c3a  Erazor III LT\n\t\t1048 0c3b  Erazor III LT\n\t\t107d 2137  WinFast 3D S325\n\t\t10de 0006  RIVA TNT2 Model 64/Model 64 Pro\n\t\t10de 001e  M64 AGP4x\n\t\t1102 1023  CT6892 RIVA TNT2 Value\n\t\t1102 1024  CT6932 RIVA TNT2 Value 32Mb\n\t\t1102 102c  CT6931 RIVA TNT2 Value [Jumper]\n\t\t1102 1030  CT6931 RIVA TNT2 Value\n# S26361-D1243-V116\n\t\t110a 006f  GM1000-16\n# S26361-D1243-V216\n\t\t110a 0081  GM1000-16\n\t\t1462 8808  MSI-8808\n\t\t14af 5620  Gamer Cougar Video Edition\n\t\t1554 1041  Pixelview RIVA TNT2 M64\n\t\t1569 002d  Palit Microsystems Daytona TNT2 M64\n\t0034  MCP04 SMBus\n\t0035  MCP04 IDE\n\t0036  MCP04 Serial ATA Controller\n\t0037  MCP04 Ethernet Controller\n\t0038  MCP04 Ethernet Controller\n\t003a  MCP04 AC'97 Audio Controller\n\t003b  MCP04 USB Controller\n\t003c  MCP04 USB Controller\n\t003d  MCP04 PCI Bridge\n\t003e  MCP04 Serial ATA Controller\n\t0040  NV40 [GeForce 6800 Ultra]\n\t0041  NV40 [GeForce 6800]\n\t\t1043 817b  V9999 Gamer Edition\n\t\t107d 2992  WinFast A400\n\t\t1458 310f  Geforce 6800 GV-N6812\n\t0042  NV40 [GeForce 6800 LE]\n\t\t107d 299b  WinFast A400 LE\n\t0043  NV40 [GeForce 6800 XE]\n\t0044  NV40 [GeForce 6800 XT]\n\t0045  NV40 [GeForce 6800 GT]\n\t\t1043 817d  V9999GT\n\t\t1458 3140  GV-N68T256D\n\t0047  NV40 [GeForce 6800 GS]\n\t\t1682 2109  GeForce 6800 GS\n\t0048  NV40 [GeForce 6800 XT]\n\t004e  NV40GL [Quadro FX 4000]\n\t0050  CK804 ISA Bridge\n\t\t1043 815a  K8N4/A8N Series Mainboard\n\t\t10f1 2865  Tomcat K8E (S2865)\n\t\t1458 0c11  GA-K8N Ultra-9 Mainboard\n\t\t1462 7100  MSI K8N Diamond\n\t\t1462 7125  K8N Neo4-F mainboard\n\t\t147b 1c1a  KN8-Ultra Mainboard\n\t\t1565 3402  NF4 AM2L Mainboard\n\t0051  CK804 ISA Bridge\n\t\t1028 0225  PowerEdge T105 ISA Bridge\n\t0052  CK804 SMBus\n\t\t1028 0225  PowerEdge T105 SMBus\n\t\t1043 815a  K8N4/A8N Series Mainboard\n\t\t10f1 2865  Tomcat K8E (S2865)\n\t\t1458 0c11  GA-K8N Ultra-9 Mainboard\n\t\t1462 7100  MSI K8N Diamond\n\t\t1462 7125  K8N Neo4-F mainboard\n\t\t147b 1c1a  KN8-Ultra Mainboard\n\t\t1565 3402  NF4 AM2L Mainboard\n\t0053  CK804 IDE\n\t\t1043 815a  K8N4/A8N Series Mainboard\n\t\t10f1 2865  Tomcat K8E (S2865)\n\t\t1458 5002  GA-K8N Ultra-9 Mainboard\n\t\t1462 7100  MSI K8N Diamond\n\t\t1462 7125  K8N Neo4-F mainboard\n\t\t147b 1c1a  KN8-Ultra Mainboard\n\t\t1565 3402  NF4 AM2L Mainboard\n\t0054  CK804 Serial ATA Controller\n\t\t1028 0225  PowerEdge T105 Serial ATA\n\t\t1043 815a  A8N Series Mainboard\n\t\t10f1 2865  Tomcat K8E (S2865)\n\t\t1458 b003  GA-K8N Ultra-9 Mainboard\n\t\t1462 7100  MSI K8N Diamond\n\t\t1462 7125  K8N Neo4-F mainboard\n\t\t147b 1c1a  KN8-Ultra Mainboard\n\t\t1565 5401  NF4 AM2L Mainboard\n\t0055  CK804 Serial ATA Controller\n\t\t1028 0225  PowerEdge T105 Serial ATA\n\t\t1043 815a  K8N4/A8N Series Mainboard\n\t\t10f1 2865  Tomcat K8E (S2865)\n\t\t1458 b003  GA-K8N Ultra-9 Mainboard\n\t\t1462 7125  K8N Neo4-F mainboard\n\t\t147b 1c1a  KN8-Ultra Mainboard\n\t\t1565 5401  NF4 AM2L Mainboard\n\t0056  CK804 Ethernet Controller\n\t0057  CK804 Ethernet Controller\n\t\t1043 8141  K8N4/A8N Series Mainboard\n\t\t10de cb84  NF4 Lanparty\n\t\t10f1 2865  Tomcat K8E (S2865)\n\t\t1458 e000  GA-K8N Ultra-9 Mainboard\n\t\t1462 7100  MSI K8N Diamond\n\t\t1462 7125  K8N Neo4-F mainboard\n\t\t147b 1c1a  KN8-Ultra Mainboard\n\t\t1565 2501  NF4 AM2L Mainboard\n\t0058  CK804 AC'97 Modem\n\t0059  CK804 AC'97 Audio Controller\n\t\t1043 812a  K8N4/A8N Series Mainboard\n\t\t10f1 2865  Tomcat K8E (S2865)\n\t\t1462 7585  K8N Neo4-F mainboard\n\t\t147b 1c1a  KN8-Ultra Mainboard\n\t\t1565 8211  NF4 AM2L Mainboard\n\t005a  CK804 USB Controller\n\t\t1028 0225  PowerEdge T105 onboard USB\n\t\t1043 815a  K8N4/A8N Series Mainboard\n\t\t10f1 2865  Tomcat K8E (S2865)\n\t\t1458 5004  GA-K8N Ultra-9 Mainboard\n\t\t1462 7100  MSI K8N Diamond\n\t\t1462 7125  K8N Neo4-F mainboard\n\t\t147b 1c1a  KN8-Ultra Mainboard\n\t\t1565 3402  NF4 AM2L Mainboard\n\t005b  CK804 USB Controller\n\t\t1028 0225  PowerEdge T105 onboard USB\n\t\t1043 815a  K8N4/A8N Series Mainboard\n\t\t10f1 2865  Tomcat K8E (S2865)\n\t\t1458 5004  GA-K8N Ultra-9 Mainboard\n\t\t1462 7100  MSI K8N Diamond\n\t\t1462 7125  K8N Neo4-F mainboard\n\t\t147b 1c1a  KN8-Ultra Mainboard\n\t\t1565 3402  NF4 AM2L Mainboard\n\t005c  CK804 PCI Bridge\n\t005d  CK804 PCIE Bridge\n\t005e  CK804 Memory Controller\n\t\t1028 0225  PowerEdge T105 Memory Controller\n\t\t1043 815a  A8N Series Mainboard\n\t\t10de 005e  ECS Elitegroup NFORCE3-A939 motherboard.\n\t\t10f1 2865  Tomcat K8E (S2865)\n\t\t10f1 2891  Thunder K8SRE Mainboard\n\t\t1458 5000  GA-K8N Ultra-9 Mainboard\n\t\t1462 7100  K8N Diamond Mainboard\n\t\t1462 7125  K8N Neo4-F Mainboard\n\t\t147b 1c1a  KN8-Ultra Mainboard\n\t\t1565 3402  NF4 AM2L Mainboard\n\t005f  CK804 Memory Controller\n\t0060  nForce2 ISA Bridge\n\t\t1043 80ad  A7N8X Mainboard\n\t\t147b 1c02  NF7-S/NF7 (nVidia-nForce2) 2.X\n\t\ta0a0 03ba  UK79G-1394 motherboard\n\t0064  nForce2 SMBus (MCP)\n\t\t147b 1c02  NF7-S/NF7 (nVidia-nForce2) 2.X\n\t\ta0a0 03bb  UK79G-1394 motherboard\n\t0065  nForce2 IDE\n\t\t10de 0c11  nForce 2 EIDE Controller\n\t\ta0a0 03b2  UK79G-1394 motherboard\n\t0066  nForce2 Ethernet Controller\n\t\t1043 80a7  A7N8X Mainboard onboard nForce2 Ethernet\n\t\t10de 0c11  nForce MCP-T Networking Adapter\n\t\ta0a0 03b3  UK79G-1394 motherboard\n\t0067  nForce2 USB Controller\n\t\t1043 0c11  A7N8X Mainboard\n\t\ta0a0 03b4  UK79G-1394 motherboard\n\t0068  nForce2 USB Controller\n\t\t1043 0c11  A7N8X Mainboard\n\t\ta0a0 03b4  UK79G-1394 motherboard\n\t006a  nForce2 AC97 Audio Controler (MCP)\n\t\t1043 8095  nForce2 AC97 Audio Controller (MCP)\n\t\ta0a0 0304  UK79G-1394 motherboard\n\t006b  nForce Audio Processing Unit\n\t\t10de 006b  nForce2 MCP Audio Processing Unit\n\t\ta0a0 0304  UK79G-1394 motherboard\n\t006c  nForce2 External PCI Bridge\n\t006d  nForce2 PCI Bridge\n\t006e  nForce2 FireWire (IEEE 1394) Controller\n\t\ta0a0 0306  UK79G-1394 motherboard\n\t0080  MCP2A ISA bridge\n\t\t147b 1c09  NV7 Motherboard\n\t0084  MCP2A SMBus\n\t\t147b 1c09  NV7 Motherboard\n\t0085  MCP2A IDE\n\t\t147b 1c09  NV7 Motherboard\n\t0086  MCP2A Ethernet Controller\n\t0087  MCP2A USB Controller\n\t\t147b 1c09  NV7 Motherboard\n\t0088  MCP2A USB Controller\n\t\t147b 1c09  NV7 Motherboard\n\t008a  MCP2S AC'97 Audio Controller\n\t\t147b 1c09  NV7 Motherboard\n\t008b  MCP2A PCI Bridge\n\t008c  MCP2A Ethernet Controller\n\t008e  nForce2 Serial ATA Controller\n\t0090  G70 [GeForce 7800 GTX]\n\t0091  G70 [GeForce 7800 GTX]\n\t0092  G70 [GeForce 7800 GT]\n\t0093  G70 [GeForce 7800 GS]\n\t0095  G70 [GeForce 7800 SLI]\n\t0097  G70 [GeForce GTS 250]\n\t0098  G70M [GeForce Go 7800]\n\t0099  G70M [GeForce Go 7800 GTX]\n\t009d  G70GL [Quadro FX 4500]\n\t00a0  NV0A [Aladdin TNT2 IGP]\n\t\t14af 5810  Maxi Gamer Xentor\n\t00c0  NV41 [GeForce 6800 GS]\n\t00c1  NV41 [GeForce 6800]\n\t00c2  NV41 [GeForce 6800 LE]\n\t00c3  NV41 [GeForce 6800 XT]\n\t00c5  NV41\n\t00c6  NV41\n\t00c7  NV41\n\t00c8  NV41M [GeForce Go 6800]\n\t00c9  NV41M [GeForce Go 6800 Ultra]\n\t00cc  NV41GLM [Quadro FX Go1400]\n\t00cd  NV42GL [Quadro FX 3450/4000 SDI]\n\t\t10de 029b  Quadro FX 3450\n\t00ce  NV41GL [Quadro FX 1400]\n\t00cf  NV41\n\t00d0  nForce3 LPC Bridge\n\t00d1  nForce3 Host Bridge\n\t00d2  nForce3 AGP Bridge\n\t00d3  CK804 Memory Controller\n\t00d4  nForce3 SMBus\n\t00d5  nForce3 IDE\n\t00d6  nForce3 Ethernet\n\t00d7  nForce3 USB 1.1\n\t00d8  nForce3 USB 2.0\n\t00d9  nForce3 Audio\n\t00da  nForce3 Audio\n\t00dd  nForce3 PCI Bridge\n\t00df  CK8S Ethernet Controller\n\t\t1043 80a7  K8N-E\n\t\t105b 0c43  Winfast NF3250K8AA\n\t\t147b 1c0b  NF8 Mainboard\n\t00e0  nForce3 250Gb LPC Bridge\n\t\t1043 813f  K8N-E\n\t\t10de 0c11  Winfast NF3250K8AA\n\t\t1462 7030  K8N Neo-FSR v2.0\n\t\t147b 1c0b  NF8 Mainboard\n\t\t1849 00e0  Motherboard (one of many)\n\t00e1  nForce3 250Gb Host Bridge\n\t\t1043 813f  K8N-E\n\t\t1462 7030  K8N Neo-FSR v2.0\n\t\t147b 1c0b  NF8 Mainboard\n\t\t1849 00e1  Motherboard (one of many)\n\t00e2  nForce3 250Gb AGP Host to PCI Bridge\n\t00e3  nForce3 Serial ATA Controller\n\t\t1043 813f  K8N-E\n\t\t105b 0c43  Winfast NF3250K8AA\n\t\t147b 1c0b  NF8 Mainboard\n\t\t1849 00e3  Motherboard (one of many)\n\t00e4  nForce 250Gb PCI System Management\n\t\t1043 813f  K8N-E\n\t\t105b 0c43  Winfast NF3250K8AA\n\t\t1462 7030  K8N Neo-FSR v2.0\n\t\t147b 1c0b  NF8 Mainboard\n\t\t1849 00e4  Motherboard (one of many)\n\t00e5  CK8S Parallel ATA Controller (v2.5)\n\t\t1043 813f  K8N-E\n\t\t105b 0c43  Winfast NF3250K8AA\n\t\t1462 7030  K8N Neo-FSR v2.0\n\t\t147b 1c0b  NF8 Mainboard\n\t\t1849 00e5  Motherboard (one of many)\n\t\tf849 00e5  Motherboard (one of many)\n\t00e6  CK8S Ethernet Controller\n\t00e7  CK8S USB Controller\n\t\t1043 813f  K8N-E\n\t\t105b 0c43  Winfast NF3250K8AA\n\t\t1462 7030  K8N Neo-FSR v2.0\n\t\t147b 1c0b  NF8 Mainboard\n\t\t1849 00e7  Motherboard (one of many)\n\t00e8  nForce3 EHCI USB 2.0 Controller\n\t\t1043 813f  K8N-E\n\t\t105b 0c43  Winfast NF3250K8AA\n\t\t1462 7030  K8N Neo-FSR v2.0\n\t\t147b 1c0b  NF8 Mainboard\n\t\t1849 00e8  Motherboard (one of many)\n\t00ea  nForce3 250Gb AC'97 Audio Controller\n\t\t1043 819d  K8N-E\n\t\t105b 0c43  Winfast NF3250K8AA\n\t\t1462 b010  K8N Neo-FSR v2.0\n\t\t147b 1c0b  NF8 Mainboard\n\t00ed  nForce3 250Gb PCI-to-PCI Bridge\n\t00ee  nForce3 Serial ATA Controller 2\n\t00f1  NV43 [GeForce 6600 GT]\n\t\t1043 81a6  N6600GT TD 128M AGP\n\t\t1043 81c6  N6600GT TD 128M AGP\n\t\t1458 3150  GV-N66T128VP\n\t\t1554 1191  PixelView PV-N43UA (128KD)\n\t\t1682 2119  GeForce 6600 GT AGP\n\t00f2  NV43 [GeForce 6600]\n\t\t1554 1194  PixelView PV-N43AT (256KD)\n\t\t1682 211c  GeForce 6600 256MB DDR DUAL DVI TV\n\t00f3  NV43 [GeForce 6200]\n\t00f4  NV43 [GeForce 6600 LE]\n\t00f5  G71 [GeForce 7800 GS]\n\t00f6  NV43 [GeForce 6800 GS/XT]\n\t\t1682 217e  XFX GeForce 6800 XTreme 256MB DDR3 AGP\n\t00f8  NV45GL [Quadro FX 3400/4400]\n\t00f9  NV40 [GeForce 6800 GT/GTO/Ultra]\n\t\t10de 00f9  NV40 [GeForce 6800 GT]\n\t\t1682 2120  GEFORCE 6800 GT PCI-E\n\t00fa  NV39 [GeForce PCX 5750]\n\t00fb  NV35 [GeForce PCX 5900]\n\t00fc  NV37GL [Quadro FX 330/GeForce PCX 5300]\n\t00fd  NV37GL [Quadro PCI-E Series]\n\t00fe  NV38GL [Quadro FX 1300]\n\t00ff  NV19 [GeForce PCX 4300]\n\t0100  NV10 [GeForce 256 SDR]\n\t\t1043 0200  AGP-V6600 SGRAM\n\t\t1043 0201  AGP-V6600 SDRAM\n\t\t1043 4008  AGP-V6600 SGRAM\n\t\t1043 4009  AGP-V6600 SDRAM\n\t\t1048 0c41  Erazor X\n\t\t1048 0c43  ERAZOR X PCI\n\t\t1048 0c48  Synergy Force\n\t\t1102 102d  CT6941 GeForce 256\n\t\t14af 5022  3D Prophet SE\n\t0101  NV10 [GeForce 256 DDR]\n\t\t1043 0202  AGP-V6800 DDR\n\t\t1043 400a  AGP-V6800 DDR SGRAM\n\t\t1043 400b  AGP-V6800 DDR SDRAM\n\t\t1048 0c42  Erazor X\n\t\t107d 2822  WinFast GeForce 256\n\t\t1102 102e  CT6970/CT6971\n\t\t14af 5021  3D Prophet DDR-DVI\n\t0103  NV10GL [Quadro]\n\t\t1048 0c40  GLoria II-64\n\t\t1048 0c44  GLoria II\n\t\t1048 0c45  GLoria II\n\t\t1048 0c4a  GLoria II-64 Pro\n\t\t1048 0c4b  GLoria II-64 Pro DVII\n\t\t10a9 9002  VPro VR3\n\t0110  NV11 [GeForce2 MX/MX 400]\n\t\t1043 4015  AGP-V7100 Pro\n\t\t1043 4021  V7100 Deluxe Combo\n\t\t1043 4031  V7100 Pro with TV output\n\t\t1048 0c60  Gladiac MX\n\t\t1048 0c61  Gladiac 511PCI\n\t\t1048 0c63  Gladiac 511TV-OUT 32MB\n\t\t1048 0c64  Gladiac 511TV-OUT 64MB\n\t\t1048 0c65  Gladiac 511TWIN\n\t\t1048 0c66  Gladiac 311\n\t\t10b0 0001  GeForce2 MX Jumbo TV\n\t\t10de 0091  Dell OEM GeForce 2 MX 400\n\t\t10de 00a1  Apple OEM GeForce2 MX\n\t\t1462 8523  MS-8852\n\t\t1462 8817  MSI GeForce2 MX400 Pro32S [MS-8817]\n\t\t14af 7102  3D Prophet II MX\n\t\t14af 7103  3D Prophet II MX Dual-Display\n\t\t1545 0023  Xtasy Rev. B2\n\t\t1554 1081  MVGA-NVG11AM(400)\n\t0111  NV11 [GeForce2 MX200]\n\t0112  NV11M [GeForce2 Go]\n\t0113  NV11GL [Quadro2 MXR/EX/Go]\n\t\t1028 00e5  Quadro2 Go\n\t0140  NV43 [GeForce 6600 GT]\n\t\t1458 3125  GV-NX66T128D\n\t\t1458 3126  GV-NX66T256DE\n\t\t1462 8939  MS-8983\n\t0141  NV43 [GeForce 6600]\n\t\t1043 81b0  EN6600 Silencer\n\t\t107d 593a  LR2A22 128MB TV OUT\n\t\t107d 597b  WINFAST PX6600\n\t\t1458 3124  GV-NX66128DP Turbo Force Edition\n\t0142  NV43 [GeForce 6600 LE]\n\t0143  NV43 [GeForce 6600 VE]\n\t0144  NV43M [GeForce Go 6600]\n\t0145  NV43 [GeForce 6610 XL]\n\t0146  NV43M [GeForce Go6200 TE / 6600 TE]\n\t0147  NV43 [GeForce 6700 XL]\n\t0148  NV43M [GeForce Go 6600]\n\t0149  NV43M [GeForce Go 6600 GT]\n\t014a  NV43 [Quadro NVS 440]\n\t014b  NV43\n\t014d  NV43GL [Quadro FX 550]\n\t014e  NV43GL [Quadro FX 540]\n\t014f  NV43 [GeForce 6200]\n\t0150  NV15 [GeForce2 GTS/Pro]\n\t\t1043 4016  V7700 AGP Video Card\n\t\t1043 402a  AGP-V7700\n\t\t1048 0c50  Gladiac\n\t\t1048 0c52  Gladiac-64\n\t\t107d 2840  WinFast GeForce2 GTS with TV output\n\t\t107d 2842  WinFast GeForce 2 Pro\n\t\t10de 002e  GeForce2 GTS\n\t\t1462 815a  MS-8815\n\t\t1462 8831  Creative GeForce2 Pro\n\t0151  NV15 [GeForce2 Ti]\n\t\t1043 405f  V7700Ti\n\t\t1462 5506  Creative 3D Blaster GeForce2 Titanium\n\t\t1462 8364  MS-8836\n\t0152  NV15 [GeForce2 Ultra]\n\t\t1048 0c56  GLADIAC Ultra\n\t0153  NV15GL [Quadro2 Pro]\n\t0160  NV44 [GeForce 6500]\n\t0161  NV44 [GeForce 6200 TurboCache]\n\t0162  NV44 [GeForce 6200 SE TurboCache]\n\t0163  NV44 [GeForce 6200 LE]\n\t0164  NV44M [GeForce Go 6200]\n\t0165  NV44 [Quadro NVS 285]\n\t0166  NV44M [GeForce Go 6400]\n\t0167  NV44M [GeForce Go 6200]\n\t0168  NV44M [GeForce Go 6400]\n\t0169  NV44 [GeForce 6250]\n\t016a  NV44 [GeForce 7100 GS]\n\t016d  NV44\n\t016e  NV44\n\t016f  NV44\n\t0170  NV17 [GeForce4 MX 460]\n\t\t1462 8630  MS-8863\n\t0171  NV17 [GeForce4 MX 440]\n\t\t10b0 0002  Gainward Pro/600 TV\n\t\t10de 0008  Apple OEM GeForce4 MX 440\n\t\t1462 8661  G4MX440-VTP\n\t\t1462 8730  MX440SES-T (MS-8873)\n\t\t1462 8743  MS-8874\n\t\t1462 8852  GeForce4 MX440 PCI\n\t\t147b 8f00  Abit Siluro GeForce4MX440\n\t0172  NV17 [GeForce4 MX 420]\n\t\t1462 8730  MS-8873\n\t\t1462 8784  MS-8878\n\t0173  NV17 [GeForce4 MX 440-SE]\n\t0174  NV17M [GeForce4 440 Go]\n\t0175  NV17M [GeForce4 420 Go]\n\t0176  NV17M [GeForce4 420 Go 32M]\n\t\t103c 08b0  tc1100 tablet\n\t\t144d c005  X10 Laptop\n\t\t4c53 1090  Cx9 / Vx9 mainboard\n\t0177  NV17M [GeForce4 460 Go]\n\t0178  NV17GL [Quadro4 550 XGL]\n\t0179  NV17M [GeForce4 440 Go 64M]\n\t\t10de 0179  GeForce4 MX (Mac)\n\t017a  NV17GL [Quadro NVS]\n\t017b  NV17GL [Quadro4 550 XGL]\n\t017c  NV17GL [Quadro4 500 GoGL]\n\t017f  NV17\n\t0181  NV18 [GeForce4 MX 440 AGP 8x]\n\t\t1043 8063  GeForce4 MX 440 AGP 8X\n\t\t1043 806f  V9180 Magic\n\t\t1462 8880  MS-StarForce GeForce4 MX 440 with AGP8X\n\t\t1462 8900  MS-8890 GeForce 4 MX440 AGP8X\n\t\t1462 9350  MSI GeForce4 MX T8X with AGP8X\n\t\t147b 8f0d  Siluro GF4 MX-8X\n\t\t1554 1111  PixelView MVGA-NVG18A\n\t0182  NV18 [GeForce4 MX 440SE AGP 8x]\n\t0183  NV18 [GeForce4 MX 420 AGP 8x]\n\t0184  NV18 [GeForce4 MX]\n\t0185  NV18 [GeForce4 MX 4000]\n\t0186  NV18M [GeForce4 448 Go]\n\t0187  NV18M [GeForce4 488 Go]\n\t0188  NV18GL [Quadro4 580 XGL]\n\t0189  NV18 [GeForce4 MX with AGP8X (Mac)]\n\t018a  NV18GL [Quadro NVS 280 SD]\n\t018b  NV18GL [Quadro4 380 XGL]\n\t018c  NV18GL [Quadro NVS 50 PCI]\n\t018d  NV18M [GeForce4 448 Go]\n\t0190  G80 [GeForce 8800 GTS / 8800 GTX]\n\t0191  G80 [GeForce 8800 GTX]\n\t0192  G80 [GeForce 8800 GTS]\n\t0193  G80 [GeForce 8800 GTS]\n\t\t107d 20bd  WinFast PX 8800 GTS TDH\n\t0194  G80 [GeForce 8800 Ultra]\n\t0197  G80GL [Tesla C870]\n\t019d  G80GL [Quadro FX 5600]\n\t019e  G80GL [Quadro FX 4600]\n\t01a0  nForce 220/420 NV1A [GeForce2 MX]\n\t01a4  nForce CPU bridge\n\t01ab  nForce 420 Memory Controller (DDR)\n\t01ac  nForce 220/420 Memory Controller\n\t01ad  nForce 220/420 Memory Controller\n\t01b0  nForce Audio Processing Unit\n\t01b1  nForce AC'97 Audio Controller\n\t01b2  nForce ISA Bridge\n\t01b4  nForce PCI System Management\n\t01b7  nForce AGP to PCI Bridge\n\t01b8  nForce PCI-to-PCI bridge\n\t01bc  nForce IDE\n\t01c1  nForce AC'97 Modem Controller\n\t01c2  nForce USB Controller\n\t01c3  nForce Ethernet Controller\n\t01d0  G72 [GeForce 7350 LE]\n\t01d1  G72 [GeForce 7300 LE]\n\t\t107d 5efa  WinFast PX7300LE-TD128\n\t\t107d 5efb  WinFast PX7300LE-TD256\n\t\t1462 0345  7300LE PCI Express Graphics Adapter\n\t01d2  G72 [GeForce 7550 LE]\n\t01d3  G72 [GeForce 7200 GS / 7300 SE]\n\t\t1043 8203  EN7300SE\n\t\t1043 8250  EN7200GS\n\t01d5  G72\n\t01d6  G72M [GeForce Go 7200]\n\t01d7  G72M [Quadro NVS 110M/GeForce Go 7300]\n\t01d8  G72M [GeForce Go 7400]\n\t\t1028 01d7  XPS M1210\n\t01d9  G72M [GeForce Go 7450]\n\t01da  G72M [Quadro NVS 110M]\n\t01db  G72M [Quadro NVS 120M]\n\t01dc  G72GLM [Quadro FX 350M]\n\t01dd  G72 [GeForce 7500 LE]\n\t01de  G72GL [Quadro FX 350]\n\t\t10de 01dc  Quadro  FX Go350M\n\t01df  G72 [GeForce 7300 GS]\n\t01e0  nForce2 IGP2\n\t\t147b 1c09  NV7 Motherboard\n\t01e8  nForce2 AGP\n\t01ea  nForce2 Memory Controller 0\n\t\ta0a0 03b9  UK79G-1394 motherboard\n\t01eb  nForce2 Memory Controller 1\n\t\ta0a0 03b9  UK79G-1394 motherboard\n\t01ec  nForce2 Memory Controller 2\n\t\ta0a0 03b9  UK79G-1394 motherboard\n\t01ed  nForce2 Memory Controller 3\n\t\ta0a0 03b9  UK79G-1394 motherboard\n\t01ee  nForce2 Memory Controller 4\n\t\t10de 01ee  MSI Delta-L nForce2 memory controller\n\t\ta0a0 03b9  UK79G-1394 motherboard\n\t01ef  nForce2 Memory Controller 5\n\t\ta0a0 03b9  UK79G-1394 motherboard\n\t01f0  NV1F C17 [GeForce4 MX IGP]\n\t\ta0a0 03b5  UK79G-1394 motherboard\n\t0200  NV20 [GeForce3]\n\t\t1043 402f  AGP-V8200 DDR\n\t\t1048 0c70  GLADIAC 920\n\t0201  NV20 [GeForce3 Ti 200]\n\t0202  NV20 [GeForce3 Ti 500]\n\t\t1043 405b  V8200 T5\n\t\t1545 002f  Xtasy 6964\n\t0203  NV20GL [Quadro DCC]\n\t0211  NV48 [GeForce 6800]\n\t0212  NV48 [GeForce 6800 LE]\n\t0215  NV48 [GeForce 6800 GT]\n\t0218  NV48 [GeForce 6800 XT]\n\t0221  NV44A [GeForce 6200]\n\t\t1043 81e1  N6200/TD/256M/A\n\t\t3842 a341  256A8N341DX\n\t0222  NV44 [GeForce 6200 A-LE]\n\t0224  NV44\n\t0240  C51PV [GeForce 6150]\n\t\t1043 81cd  A8N-VM CSM\n\t\t1462 7207  K8NGM2 series\n\t0241  C51 [GeForce 6150 LE]\n\t0242  C51G [GeForce 6100]\n\t\t105b 0cad  Winfast 6100K8MB\n\t0243  C51 PCI Express Bridge\n\t0244  C51 [GeForce Go 6150]\n\t\t103c 30b5  Presario V3242AU\n\t\t103c 30b7  Presario V6133CL\n\t\t10de 0244  GeForce Go 6150\n\t0245  C51 [Quadro NVS 210S/GeForce 6150LE]\n\t0246  C51 PCI Express Bridge\n\t0247  C51 [GeForce Go 6100]\n\t\t1043 1382  MCP51 PCI-X GeForce Go 6100\n\t0248  C51 PCI Express Bridge\n\t0249  C51 PCI Express Bridge\n\t024a  C51 PCI Express Bridge\n\t024b  C51 PCI Express Bridge\n\t024c  C51 PCI Express Bridge\n\t024d  C51 PCI Express Bridge\n\t024e  C51 PCI Express Bridge\n\t024f  C51 PCI Express Bridge\n\t0250  NV25 [GeForce4 Ti 4600]\n\t0251  NV25 [GeForce4 Ti 4400]\n\t\t1043 8023  v8440 GeForce 4 Ti4400\n\t\t10de 0251  PNY GeForce4 Ti 4400\n\t\t1462 8710  PNY GeForce4 Ti 4400\n\t0252  NV25 [GeForce4 Ti]\n\t0253  NV25 [GeForce4 Ti 4200]\n\t\t107d 2896  WinFast A250 LE TD (Dual VGA/TV-out/DVI)\n\t\t147b 8f09  Siluro (Dual VGA/TV-out/DVI)\n\t0258  NV25GL [Quadro4 900 XGL]\n\t0259  NV25GL [Quadro4 750 XGL]\n\t025b  NV25GL [Quadro4 700 XGL]\n\t0260  MCP51 LPC Bridge\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81bc  A8N-VM CSM Mainboard\n\t\t1458 5001  GA-M55plus-S3G\n\t\t1462 7207  K8NGM2 series\n\t0261  MCP51 LPC Bridge\n\t\t105b 0cad  Winfast 6100K8MB\n\t0262  MCP51 LPC Bridge\n\t0263  MCP51 LPC Bridge\n\t0264  MCP51 SMBus\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81bc  A8N-VM CSM Mainboard\n\t\t105b 0cad  Winfast 6100K8MB\n\t\t1462 7207  K8NGM2 series\n\t0265  MCP51 IDE\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81bc  A8N-VM CSM Mainboard\n\t\t1462 7207  K8NGM2 series\n# Foxconn has used a wrong vendor ID for this one\n\t\tf05b 0cad  Winfast 6100K8MB\n\t0266  MCP51 Serial ATA Controller\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81bc  A8N-VM CSM Mainboard\n\t\t1462 7207  K8NGM2 series\n\t0267  MCP51 Serial ATA Controller\n\t\t103c 2a34  Pavilion a1677c\n\t\t1043 81bc  A8N-VM CSM Mainboard\n\t\t1462 7207  K8NGM2 series\n\t0268  MCP51 Ethernet Controller\n\t0269  MCP51 Ethernet Controller\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 8141  A8N-VM CSM Mainboard\n\t\t1462 7207  K8NGM2 series\n\t026a  MCP51 MCI\n\t026b  MCP51 AC97 Audio Controller\n\t\t105b 0cad  Winfast 6100K8MB\n\t026c  MCP51 High Definition Audio\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b5  Presario V3242AU\n\t\t103c 30b7  Presario V6133CL\n\t\t10de cb84  ASUSTeK Computer Inc. A8N-VM CSM Mainboard\n\t\t1462 7207  K8NGM2 series\n\t026d  MCP51 USB Controller\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81bc  A8N-VM CSM Mainboard\n\t\t105b 0cad  Winfast 6100K8MB\n\t\t1462 7207  K8NGM2 series\n\t026e  MCP51 USB Controller\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81bc  A8N-VM CSM Mainboard\n\t\t105b 0cad  Winfast 6100K8MB\n\t\t1462 7207  K8NGM2 series\n\t026f  MCP51 PCI Bridge\n\t\t103c 30b7  Presario V6133CL\n\t0270  MCP51 Host Bridge\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81bc  A8N-VM CSM Mainboard\n\t\t105b 0cad  Winfast 6100K8MB\n\t\t1458 5001  GA-M55plus-S3G\n\t\t1462 7207  K8NGM2 series\n\t0271  MCP51 PMU\n\t\t103c 30b5  Presario V3242AU\n\t\t103c 30b7  Presario V6133CL\n\t0272  MCP51 Memory Controller 0\n\t\t103c 2a34  Pavilion a1677c\n\t\t105b 0cad  Winfast 6100K8MB\n\t027e  C51 Memory Controller 2\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81cd  A8N-VM CSM Mainboard\n\t\t1458 5000  GA-M55plus-S3G\n\t\t1462 7207  K8NGM2 series\n\t027f  C51 Memory Controller 3\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81cd  A8N-VM CSM Mainboard\n\t\t1458 5000  GA-M55plus-S3G\n\t\t1462 7207  K8NGM2 series\n\t0280  NV28 [GeForce4 Ti 4800]\n\t0281  NV28 [GeForce4 Ti 4200 AGP 8x]\n\t0282  NV28 [GeForce4 Ti 4800 SE]\n\t0286  NV28M [GeForce4 Ti 4200 Go AGP 8x]\n\t0288  NV28GL [Quadro4 980 XGL]\n\t0289  NV28GL [Quadro4 780 XGL]\n\t028c  NV28GLM [Quadro4 Go700]\n\t0290  G71 [GeForce 7900 GTX]\n\t0291  G71 [GeForce 7900 GT/GTO]\n\t\t10de 042b  NX7900GTO-T2D512E [7900 GTO]\n\t0292  G71 [GeForce 7900 GS]\n\t0293  G71 [GeForce 7900 GX2]\n\t0294  G71 [GeForce 7950 GX2]\n\t0295  G71 [GeForce 7950 GT]\n\t\t1043 8225  GeForce 7950 GT\n\t\t107d 2a68  WinFast PX7950GT TDH\n\t\t1462 0663  NX7950GT-VT2D512EZ-HD\n\t0297  G71M [GeForce Go 7950 GTX]\n\t0298  G71M [GeForce Go 7900 GS]\n\t0299  G71M [GeForce Go 7900 GTX]\n\t029a  G71GLM [Quadro FX 2500M]\n\t029b  G71GLM [Quadro FX 1500M]\n\t029c  G71GL [Quadro FX 5500]\n\t029d  G71GL [Quadro FX 3500]\n\t\t1028 019b  G71GLM [Quadro FX 3500M]\n\t029e  G71GL [Quadro FX 1500]\n\t029f  G71GL [Quadro FX 4500 X2]\n# Xbox Graphics Processing Unit (Integrated). GeForce3 derivative (NV20 < NV2A < NV25).\n\t02a0  NV2A [XGPU]\n\t02a5  MCPX CPU Bridge\n\t02a6  MCPX Memory Controller\n\t02e0  G73 [GeForce 7600 GT]\n\t\t02e0 2249  GF 7600GT 560M 256MB DDR3 DUAL DVI TV\n\t02e1  G73 [GeForce 7600 GS]\n\t\t1682 222b  PV-T73K-UAL3 (256MB)\n\t\t1682 2247  GF 7600GS 512MB DDR2\n\t02e2  G73 [GeForce 7300 GT]\n\t02e3  G71 [GeForce 7900 GS]\n\t02e4  G71 [GeForce 7950 GT]\n\t\t1682 2271  PV-T71A-YDF7 (512MB)\n\t02f0  C51 Host Bridge\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81cd  A8N-VM CSM Mainboard\n\t\t1462 7207  K8NGM2 series\n\t02f1  C51 Host Bridge\n\t\t1458 5000  GA-M55plus-S3G\n\t02f2  C51 Host Bridge\n\t02f3  C51 Host Bridge\n\t02f4  C51 Host Bridge\n\t02f5  C51 Host Bridge\n\t02f6  C51 Host Bridge\n\t02f7  C51 Host Bridge\n\t02f8  C51 Memory Controller 5\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81cd  A8N-VM CSM Mainboard\n\t\t1458 5000  GA-M55plus-S3G\n\t\t1462 7207  K8NGM2 series\n\t02f9  C51 Memory Controller 4\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81cd  A8N-VM CSM Mainboard\n\t\t1458 5000  GA-M55plus-S3G\n\t\t1462 7207  K8NGM2 series\n\t02fa  C51 Memory Controller 0\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81cd  A8N-VM CSM Mainboard\n\t\t1458 5000  GA-M55plus-S3G\n\t\t1462 7207  K8NGM2 series\n\t02fb  C51 PCI Express Bridge\n\t02fc  C51 PCI Express Bridge\n\t\t103c 30b7  Presario V6133CL\n\t02fd  C51 PCI Express Bridge\n\t\t103c 30b7  Presario V6133CL\n\t02fe  C51 Memory Controller 1\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81cd  A8N-VM CSM Mainboard\n\t\t1458 5000  GA-M55plus-S3G\n\t\t1462 7207  K8NGM2 series\n\t02ff  C51 Host Bridge\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 30b7  Presario V6133CL\n\t\t1043 81cd  A8N-VM CSM Mainboard\n\t\t1458 5000  GA-M55plus-S3G\n\t\t1462 7207  K8NGM2 series\n\t0300  NV30 [GeForce FX]\n\t0301  NV30 [GeForce FX 5800 Ultra]\n\t0302  NV30 [GeForce FX 5800]\n\t0308  NV30GL [Quadro FX 2000]\n\t0309  NV30GL [Quadro FX 1000]\n\t0311  NV31 [GeForce FX 5600 Ultra]\n\t0312  NV31 [GeForce FX 5600]\n\t0314  NV31 [GeForce FX 5600XT]\n\t\t1043 814a  V9560XT/TD\n\t0316  NV31M\n\t0318  NV31GL\n\t031a  NV31M [GeForce FX Go5600]\n\t031b  NV31M [GeForce FX Go5650]\n\t031c  NV31GLM [Quadro FX Go700]\n\t0320  NV34 [GeForce FX 5200]\n\t0321  NV34 [GeForce FX 5200 Ultra]\n\t0322  NV34 [GeForce FX 5200]\n\t\t1043 02fb  V9250 Magic\n\t\t1043 8180  V9520-X/TD/128M\n\t\t107d 2967  WinFast A340T 128MB\n\t\t1462 9110  MS-8911 (FX5200-TD128)\n\t\t1462 9171  MS-8917 (FX5200-T128)\n\t\t1462 9360  MS-8936 (FX5200-T128)\n\t\t1682 1351  GeForce FX 5200\n\t0323  NV34 [GeForce FX 5200LE]\n\t0324  NV34M [GeForce FX Go5200 64M]\n\t\t1028 0196  Inspiron 5160\n\t\t103c 006a  Pavilion ZD7000 laptop\n\t\t1071 8160  MIM2000\n\t0325  NV34M [GeForce FX Go5250]\n\t0326  NV34 [GeForce FX 5500]\n\t\t1458 310d  GeForce FX 5500 128 MB\n\t\t1682 2034  GeForce 5500 256 MB\n\t0327  NV34 [GeForce FX 5100]\n\t0328  NV34M [GeForce FX Go5200 32M/64M]\n\t0329  NV34M [GeForce FX Go5200]\n\t\t10de 0010  Powerbook G4\n\t032a  NV34GL [Quadro NVS 280 PCI]\n\t032b  NV34GL [Quadro FX 500/600 PCI]\n\t032c  NV34M [GeForce FX Go5300 / Go5350]\n\t032d  NV34M [GeForce FX Go5100]\n\t032e  NV34\n\t032f  NV34 [GeForce FX 5200]\n\t0330  NV35 [GeForce FX 5900 Ultra]\n\t\t1043 8137  V9950 Ultra / 256 MB\n\t0331  NV35 [GeForce FX 5900]\n\t\t1043 8145  V9950GE\n\t0332  NV35 [GeForce FX 5900XT]\n\t0333  NV38 [GeForce FX 5950 Ultra]\n\t0334  NV35 [GeForce FX 5900ZT]\n\t\t1462 9373  FX5900ZT-VTD128 (MS-8937)\n\t0338  NV35GL [Quadro FX 3000]\n\t033f  NV35GL [Quadro FX 700]\n\t0341  NV36 [GeForce FX 5700 Ultra]\n\t\t1462 9380  MS-8938 (FX5700U-TD128)\n\t0342  NV36 [GeForce FX 5700]\n\t0343  NV36 [GeForce FX 5700LE]\n\t0344  NV36 [GeForce FX 5700VE]\n\t0347  NV36M [GeForce FX Go5700]\n\t\t103c 006a  NX9500\n\t0348  NV36M [GeForce FX Go5700]\n\t034c  NV36 [Quadro FX Go1000]\n\t034d  NV36\n\t034e  NV36GL [Quadro FX 1100]\n\t0360  MCP55 LPC Bridge\n\t0361  MCP55 LPC Bridge\n\t\t1028 0221  PowerEdge R805 MCP55 LPC Bridge\n\t0362  MCP55 LPC Bridge\n\t\t147b 1c24  KN9 series mainboard\n\t0363  MCP55 LPC Bridge\n\t0364  MCP55 LPC Bridge\n\t\t1028 0221  PowerEdge R805 MCP55 LPC Bridge\n\t0365  MCP55 LPC Bridge\n\t0366  MCP55 LPC Bridge\n\t0367  MCP55 LPC Bridge\n\t0368  MCP55 SMBus Controller\n\t\t1028 020c  PowerEdge M605 MCP55 SMBus\n\t\t1028 0221  PowerEdge R805 MCP55 SMBus\n\t\t147b 1c24  KN9 series mainboard\n\t0369  MCP55 Memory Controller\n\t\t147b 1c24  KN9 series mainboard\n\t036a  MCP55 Memory Controller\n\t036b  MCP55 SMU\n\t036c  MCP55 USB Controller\n\t\t1028 020c  PowerEdge M605 MCP55 USB Controller\n\t\t1028 0221  PowerEdge R805 MCP55 USB Controller\n\t\t147b 1c24  KN9 series mainboard\n\t036d  MCP55 USB Controller\n\t\t1028 020c  PowerEdge M605 MCP55 USB Controller\n\t\t1028 0221  PowerEdge R805 MCP55 USB Controller\n\t\t147b 1c24  KN9 series mainboard\n\t036e  MCP55 IDE\n\t\t147b 1c24  KN9 series mainboard\n\t0370  MCP55 PCI bridge\n\t0371  MCP55 High Definition Audio\n\t\t147b 1c24  KN9 series mainboard\n\t0372  MCP55 Ethernet\n\t0373  MCP55 Ethernet\n\t\t147b 1c24  KN9 series mainboard\n\t0374  MCP55 PCI Express bridge\n\t0375  MCP55 PCI Express bridge\n\t0376  MCP55 PCI Express bridge\n\t0377  MCP55 PCI Express bridge\n\t0378  MCP55 PCI Express bridge\n\t037a  MCP55 Memory Controller\n\t037e  MCP55 SATA Controller\n\t037f  MCP55 SATA Controller\n\t\t1028 0221  PowerEdge R805 MCP55 SATA Controller\n\t\t147b 1c24  KN9 series mainboard\n\t038b  G73 [GeForce 7650 GS]\n\t0390  G73 [GeForce 7650 GS]\n\t0391  G73 [GeForce 7600 GT]\n\t\t1458 3427  GV-NX76T128D-RH\n\t\t1462 0452  NX7600GT-VT2D256E\n\t0392  G73 [GeForce 7600 GS]\n\t\t1462 0622  NX7600GS-T2D256EH\n\t0393  G73 [GeForce 7300 GT]\n\t\t10de 0412  NX7300GT-TD256EH\n\t\t1462 0412  NX7300GT-TD256EH\n\t0394  G73 [GeForce 7600 LE]\n\t0395  G73 [GeForce 7300 GT]\n\t0396  G73\n\t0397  G73M [GeForce Go 7700]\n\t0398  G73M [GeForce Go 7600]\n\t\t1025 006c  Aspire 9814WKMi\n\t0399  G73M [GeForce Go 7600 GT]\n\t039a  G73M [Quadro NVS 300M]\n\t039b  G73M [GeForce Go 7900 SE]\n\t039c  G73GLM [Quadro FX 550M]\n\t\t10de 039c  Quadro FX 560M\n\t039d  G73\n\t039e  G73GL [Quadro FX 560]\n\t039f  G73\n\t03a0  C55 Host Bridge\n\t03a1  C55 Host Bridge\n\t03a2  C55 Host Bridge\n\t03a3  C55 Host Bridge\n\t03a4  C55 Host Bridge\n\t03a5  C55 Host Bridge\n\t03a6  C55 Host Bridge\n\t03a7  C55 Host Bridge\n\t03a8  C55 Memory Controller\n\t03a9  C55 Memory Controller\n\t03aa  C55 Memory Controller\n\t03ab  C55 Memory Controller\n\t03ac  C55 Memory Controller\n\t03ad  C55 Memory Controller\n\t03ae  C55 Memory Controller\n\t03af  C55 Memory Controller\n\t03b0  C55 Memory Controller\n\t03b1  C55 Memory Controller\n\t03b2  C55 Memory Controller\n\t03b3  C55 Memory Controller\n\t03b4  C55 Memory Controller\n\t03b5  C55 Memory Controller\n\t03b6  C55 Memory Controller\n\t03b7  C55 PCI Express bridge\n\t03b8  C55 PCI Express bridge\n\t03b9  C55 PCI Express bridge\n\t03ba  C55 Memory Controller\n\t03bb  C55 PCI Express bridge\n\t03bc  C55 Memory Controller\n\t03d0  C61 [GeForce 6150SE nForce 430]\n\t\t1028 020e  Inspiron 531\n\t03d1  C61 [GeForce 6100 nForce 405]\n\t03d2  C61 [GeForce 6100 nForce 400]\n\t03d5  C61 [GeForce 6100 nForce 420]\n\t03d6  C61 [GeForce 7025 / nForce 630a]\n\t03e0  MCP61 LPC Bridge\n\t\t1028 020e  Inspiron 531\n\t\t1849 03e0  939NF6G-VSTA Board\n\t03e1  MCP61 LPC Bridge\n\t\t1043 83a4  M4N68T series motherboard\n\t03e2  MCP61 Host Bridge\n\t\t1043 83a4  M4N68T series motherboard\n\t03e3  MCP61 LPC Bridge\n\t03e4  MCP61 High Definition Audio\n\t03e5  MCP61 Ethernet\n\t03e6  MCP61 Ethernet\n\t03e7  MCP61 SATA Controller\n\t03e8  MCP61 PCI Express bridge\n\t\t1028 020e  Inspiron 531\n\t\t1849 03e8  939NF6G-VSTA Board\n\t03e9  MCP61 PCI Express bridge\n\t\t1028 020e  Inspiron 531\n\t\t1849 03e9  939NF6G-VSTA Board\n\t03ea  MCP61 Memory Controller\n\t\t1028 020e  Inspiron 531\n\t\t1849 03ea  939NF6G-VSTA Board\n\t03eb  MCP61 SMBus\n\t\t1028 020e  Inspiron 531\n\t\t1043 83a4  M4N68T series motherboard\n\t\t1849 03eb  939NF6G-VSTA Board\n\t03ec  MCP61 IDE\n\t\t1025 0392  ET1350\n\t\t1028 020e  Inspiron 531\n\t\t1043 83a4  M4N68T series motherboard\n\t\t1849 03ec  939NF6G-VSTA Board\n\t03ee  MCP61 Ethernet\n\t03ef  MCP61 Ethernet\n\t\t1025 8000  ET1350\n\t\t1028 020e  Inspiron 531\n\t\t1043 83a4  M4N68T series motherboard\n\t\t1849 03ef  939NF6G-VSTA Board\n\t03f0  MCP61 High Definition Audio\n\t\t1028 020e  Inspiron 531\n\t\t1043 8415  M4N68T series motherboard\n\t\t1849 0888  939NF6G-VSTA Board\n\t03f1  MCP61 USB 1.1 Controller\n\t\t1028 020e  Inspiron 531\n\t\t1043 83a4  M4N68T series motherboard\n\t\t1849 03f1  939NF6G-VSTA Board\n\t03f2  MCP61 USB 2.0 Controller\n\t\t1028 020e  Inspiron 531\n\t\t1043 83a4  M4N68T series motherboard\n\t\t1849 03f2  939NF6G-VSTA Board\n\t03f3  MCP61 PCI bridge\n\t\t1028 020e  Inspiron 531\n\t\t1849 03f3  939NF6G-VSTA Board\n\t03f4  MCP61 SMU\n\t03f5  MCP61 Memory Controller\n\t\t1028 020e  Inspiron 531\n\t\t1043 83a4  M4N68T series motherboard\n\t\t1849 03eb  939NF6G-VSTA Board\n\t03f6  MCP61 SATA Controller\n\t\t1028 020e  Inspiron 531\n\t\t1043 83a4  M4N68T series motherboard\n\t\t1849 03f6  939NF6G-VSTA Board\n\t03f7  MCP61 SATA Controller\n\t0400  G84 [GeForce 8600 GTS]\n\t\t1043 8241  EN8600GTS\n\t0401  G84 [GeForce 8600 GT]\n\t0402  G84 [GeForce 8600 GT]\n\t\t1458 3455  GV-NX86T512H\n\t\t1462 0910  NX8600GT-T2D256EZ\n\t0403  G84 [GeForce 8600 GS]\n\t0404  G84 [GeForce 8400 GS]\n\t\t1462 1230  NX8400GS-TD256E\n\t0405  G84M [GeForce 9500M GS]\n\t0406  G84 [GeForce 8300 GS]\n\t0407  G84M [GeForce 8600M GT]\n\t0408  G84M [GeForce 9650M GS]\n\t0409  G84M [GeForce 8700M GT]\n\t040a  G84GL [Quadro FX 370]\n\t040b  G84GLM [Quadro NVS 320M]\n\t040c  G84GLM [Quadro FX 570M]\n\t\t17aa 20d9  ThinkPad T61p\n\t040d  G84GLM [Quadro FX 1600M]\n\t040e  G84GL [Quadro FX 570]\n\t040f  G84GL [Quadro FX 1700]\n\t0410  G92 [GeForce GT 330]\n\t0414  G92 [GeForce 9800 GT]\n\t0418  G92 [GeForce GT 330 OEM]\n\t0420  G86 [GeForce 8400 SE]\n\t0421  G86 [GeForce 8500 GT]\n\t\t1462 0960  NX8500GT-TD512EH/M2\n\t0422  G86 [GeForce 8400 GS]\n\t0423  G86 [GeForce 8300 GS]\n\t0424  G86 [GeForce 8400 GS]\n\t0425  G86M [GeForce 8600M GS]\n\t\t1025 0121  Aspire 5920G\n\t\t1043 1514  F3SV\n\t0426  G86M [GeForce 8400M GT]\n\t0427  G86M [GeForce 8400M GS]\n\t\t103c 30cc  Pavilion dv6700\n\t\t103c 30cf  Pavilion dv9668eg Laptop\n\t0428  G86M [GeForce 8400M G]\n\t0429  G86M [Quadro NVS 140M]\n\t\t17aa 20d8  ThinkPad T61\n\t042a  G86M [Quadro NVS 130M]\n\t042b  G86M [Quadro NVS 135M]\n\t042c  G86 [GeForce 9400 GT]\n\t042d  G86GLM [Quadro FX 360M]\n\t042e  G86M [GeForce 9300M G]\n\t042f  G86 [Quadro NVS 290]\n\t0440  MCP65 LPC Bridge\n\t0441  MCP65 LPC Bridge\n\t0442  MCP65 LPC Bridge\n\t\t103c 30cf  Pavilion dv9668eg Laptop\n\t0443  MCP65 LPC Bridge\n\t0444  MCP65 Memory Controller\n\t\t103c 30cf  Pavilion dv9668eg Laptop\n\t0445  MCP65 Memory Controller\n\t0446  MCP65 SMBus\n\t\t103c 30cf  Pavilion dv9668eg Laptop\n\t0447  MCP65 SMU\n\t\t103c 30cf  Pavilion dv9500/9600/9700 series\n\t0448  MCP65 IDE\n\t\t103c 30cf  Pavilion dv9668eg Laptop\n\t0449  MCP65 PCI bridge\n\t\t10de cb84  HP Pavilion dv9668eg Laptop\n\t044a  MCP65 High Definition Audio\n\t\t103c 30cf  Pavilion dv9668eg Laptop\n\t044b  MCP65 High Definition Audio\n\t044c  MCP65 AHCI Controller\n\t044d  MCP65 AHCI Controller\n\t044e  MCP65 AHCI Controller\n\t044f  MCP65 AHCI Controller\n\t0450  MCP65 Ethernet\n\t\t103c 30cf  Pavilion dv9668eg Laptop\n\t0451  MCP65 Ethernet\n\t0452  MCP65 Ethernet\n\t0453  MCP65 Ethernet\n\t0454  MCP65 USB 1.1 OHCI Controller\n\t\t103c 30cf  Pavilion dv9668eg Laptop\n\t0455  MCP65 USB 2.0 EHCI Controller\n\t\t103c 30cf  Pavilion dv9668eg Laptop\n\t0456  MCP65 USB Controller\n\t0457  MCP65 USB Controller\n\t0458  MCP65 PCI Express bridge\n\t\t10de 0000  MCP65 PCI Express bridge\n\t0459  MCP65 PCI Express bridge\n\t\t10de 0000  MCP65 PCI Express bridge\n\t045a  MCP65 PCI Express bridge\n\t\t10de 0000  MCP65 PCI Express bridge\n\t045b  MCP65 PCI Express bridge\n\t\t10de 0000  MCP65 PCI Express bridge\n\t045c  MCP65 SATA Controller\n\t045d  MCP65 SATA Controller\n\t\t103c 30cf  Pavilion dv9668eg Laptop\n\t045e  MCP65 SATA Controller\n\t045f  MCP65 SATA Controller\n\t0531  C67 [GeForce 7150M / nForce 630M]\n\t0533  C67 [GeForce 7000M / nForce 610M]\n\t053a  C68 [GeForce 7050 PV / nForce 630a]\n\t053b  C68 [GeForce 7050 PV / nForce 630a]\n\t\t1043 8308  M2N68-AM Motherboard\n\t053e  C68 [GeForce 7025 / nForce 630a]\n\t0541  MCP67 Memory Controller\n\t0542  MCP67 SMBus\n\t\t1043 8308  M2N68-AM Motherboard\n\t0543  MCP67 Co-processor\n\t0547  MCP67 Memory Controller\n\t\t1043 8308  M2N68-AM Motherboard\n\t\t1849 0547  ALiveNF7G-HDready\n\t0548  MCP67 ISA Bridge\n\t\t1043 8308  M2N68-AM Motherboard\n\t054c  MCP67 Ethernet\n\t\t1043 8308  M2N68-AM Motherboard\n\t\t1849 054c  ALiveNF7G-HDready, MCP67 Gigabit Ethernet\n\t054d  MCP67 Ethernet\n\t054e  MCP67 Ethernet\n\t054f  MCP67 Ethernet\n\t0550  MCP67 AHCI Controller\n\t\t1043 8308  M2N68-AM Motherboard\n\t0554  MCP67 AHCI Controller\n\t\t1043 8308  M2N68-AM Motherboard\n\t0555  MCP67 SATA Controller\n\t\t1043 8308  M2N68-AM Motherboard\n\t055c  MCP67 High Definition Audio\n\t\t1043 8290  M2N68-AM Motherboard\n\t055d  MCP67 High Definition Audio\n\t055e  MCP67 OHCI USB 1.1 Controller\n\t\t1043 8308  M2N68-AM Motherboard\n\t055f  MCP67 EHCI USB 2.0 Controller\n\t\t1043 8308  M2N68-AM Motherboard\n\t0560  MCP67 IDE Controller\n\t\tf043 8308  M2N68-AM Motherboard\n\t0561  MCP67 PCI Bridge\n\t0562  MCP67 PCI Express Bridge\n\t\t1849 0562  ALiveNF7G-HDready\n\t0563  MCP67 PCI Express Bridge\n\t0568  MCP78S [GeForce 8200] Memory Controller\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 0568  K10N78FullHD-hSLI R3.0 Memory Controller\n\t0569  MCP78S [GeForce 8200] PCI Express Bridge\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 0569  K10N78FullHD-hSLI R3.0 PCI Express Bridge\n\t056a  MCP73 [nForce 630i] USB 2.0 Controller (EHCI)\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t056c  MCP73 IDE Controller\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t056d  MCP73 PCI Express bridge\n\t\t1019 297a  MCP73PVT-SM\n\t\t10de cb73  MCP73 PCI Bridge\n\t056e  MCP73 PCI Express bridge\n\t\t1019 297a  MCP73PVT-SM\n\t\t10de 0000  MCP73 PCIe x16 port\n\t056f  MCP73 PCI Express bridge\n\t\t1019 297a  MCP73PVT-SM\n\t\t10de 0000  MCP73 PCIe x1 port\n\t05b1  NF200 PCIe 2.0 switch\n\t05b8  NF200 PCIe 2.0 switch for GTX 295\n\t05be  NF200 PCIe 2.0 switch for Quadro Plex S4 / Tesla S870 / Tesla S1070 / Tesla S2050\n\t05e0  GT200b [GeForce GTX 295]\n\t05e1  GT200 [GeForce GTX 280]\n\t05e2  GT200 [GeForce GTX 260]\n\t05e3  GT200b [GeForce GTX 285]\n\t\t1682 2490  GX-285N-ZDF\n\t05e6  GT200b [GeForce GTX 275]\n\t05e7  GT200GL [Tesla C1060 / M1060]\n\t\t10de 0595  Tesla T10 Processor\n\t\t10de 068f  Tesla T10 Processor\n\t\t10de 0697  Tesla M1060\n\t\t10de 0714  Tesla M1060\n\t\t10de 0743  Tesla M1060\n\t05ea  GT200 [GeForce GTX 260]\n\t05eb  GT200 [GeForce GTX 295]\n\t05ed  GT200GL [Quadro Plex 2200 D2]\n\t05f1  GT200 [GeForce GTX 280]\n\t05f2  GT200 [GeForce GTX 260]\n\t05f8  GT200GL [Quadro Plex 2200 S4]\n\t05f9  GT200GL [Quadro CX]\n\t05fd  GT200GL [Quadro FX 5800]\n\t05fe  GT200GL [Quadro FX 4800]\n\t05ff  GT200GL [Quadro FX 3800]\n\t0600  G92 [GeForce 8800 GTS 512]\n\t0601  G92 [GeForce 9800 GT]\n\t0602  G92 [GeForce 8800 GT]\n\t0603  G92 [GeForce GT 230 OEM]\n\t0604  G92 [GeForce 9800 GX2]\n\t0605  G92 [GeForce 9800 GT]\n\t0606  G92 [GeForce 8800 GS]\n\t0607  G92 [GeForce GTS 240]\n\t0608  G92M [GeForce 9800M GTX]\n\t0609  G92M [GeForce 8800M GTS]\n\t\t106b 00a7  GeForce 8800 GS\n\t060a  G92M [GeForce GTX 280M]\n\t060b  G92M [GeForce 9800M GT]\n\t060c  G92M [GeForce 8800M GTX]\n\t060d  G92 [GeForce 8800 GS]\n\t060f  G92M [GeForce GTX 285M]\n\t0610  G92 [GeForce 9600 GSO]\n\t\t1682 2385  GeForce 9600 GSO 768mb\n\t0611  G92 [GeForce 8800 GT]\n\t\t107d 2ab0  Winfast PX8800 GT PCI-E\n\t\t1462 1170  NX8800GT series model V117 2xDVI+TV\n\t\t19da 1040  ZT-88TES2P-FSP\n\t0612  G92 [GeForce 9800 GTX / 9800 GTX+]\n\t0613  G92 [GeForce 9800 GTX+]\n\t0614  G92 [GeForce 9800 GT]\n\t\t107d 2ab3  WinFast PX9800 GT (S-Fanpipe)\n\t0615  G92 [GeForce GTS 250]\n\t\t3842 1150  GeForce GTS 250 P/N 512-P3-1150-TR\n# Overclocked\n\t\t3842 1151  GeForce GTS 250 P/N 512-P3-1151-TR\n\t\t3842 1155  GeForce GTS 250 P/N 01G-P3-1155-TR\n# Overclocked\n\t\t3842 1156  GeForce GTS 250 P/N 01G-P3-1156-TR\n\t0617  G92M [GeForce 9800M GTX]\n\t0618  G92M [GeForce GTX 260M]\n\t0619  G92GL [Quadro FX 4700 X2]\n\t061a  G92GL [Quadro FX 3700]\n\t061b  G92GL [Quadro VX 200]\n\t061c  G92GLM [Quadro FX 3600M]\n\t061d  G92GLM [Quadro FX 2800M]\n\t061e  G92GLM [Quadro FX 3700M]\n\t061f  G92GLM [Quadro FX 3800M]\n\t0620  G94 [GeForce 9800 GT]\n\t0621  G94 [GeForce GT 230]\n\t0622  G94 [GeForce 9600 GT]\n\t\t107d 2ac1  WinFast PX9600GT 1024MB\n\t\t1458 3481  GV-NX96T512HP\n\t0623  G94 [GeForce 9600 GS]\n\t0624  G94 [GeForce 9600 GT Green Edition]\n\t0625  G94 [GeForce 9600 GSO 512]\n\t0626  G94 [GeForce GT 130]\n\t0627  G94 [GeForce GT 140]\n\t0628  G94M [GeForce 9800M GTS]\n\t062a  G94M [GeForce 9700M GTS]\n\t062b  G94M [GeForce 9800M GS]\n\t062c  G94M [GeForce 9800M GTS]\n\t062d  G94 [GeForce 9600 GT]\n\t062e  G94 [GeForce 9600 GT]\n\t\t106b 0605  GeForce GT 130\n\t062f  G94 [GeForce 9800 S]\n\t0630  G94 [GeForce 9600 GT]\n\t0631  G94M [GeForce GTS 160M]\n\t0632  G94M [GeForce GTS 150M]\n\t0633  G94 [GeForce GT 220]\n\t0635  G94 [GeForce 9600 GSO]\n\t0637  G94 [GeForce 9600 GT]\n\t0638  G94GL [Quadro FX 1800]\n\t063a  G94GLM [Quadro FX 2700M]\n\t063f  G94 [GeForce 9600 GE]\n\t0640  G96C [GeForce 9500 GT]\n\t0641  G96C [GeForce 9400 GT]\n\t\t1682 4009  PV-T94G-ZAFG\n\t0642  G96 [D9M-10]\n\t0643  G96 [GeForce 9500 GT]\n\t0644  G96 [GeForce 9500 GS]\n\t\t174b 9600  Geforce 9500GS 512M DDR2 V/D/HDMI\n\t0645  G96C [GeForce 9500 GS]\n\t0646  G96C [GeForce GT 120]\n\t0647  G96CM [GeForce 9600M GT]\n\t0648  G96CM [GeForce 9600M GS]\n\t0649  G96CM [GeForce 9600M GT]\n\t\t1043 202d  GeForce GT 220M\n\t064a  G96M [GeForce 9700M GT]\n\t064b  G96M [GeForce 9500M G]\n\t064c  G96CM [GeForce 9650M GT]\n\t064e  G96C [GeForce 9600 GSO / 9800 GT]\n\t0651  G96CM [GeForce G 110M]\n\t0652  G96CM [GeForce GT 130M]\n\t\t152d 0850  GeForce GT 240M LE\n\t0653  G96CM [GeForce GT 120M]\n\t0654  G96CM [GeForce GT 220M]\n\t\t1043 14a2  GeForce GT 320M\n\t\t1043 14d2  GeForce GT 320M\n\t0655  G96 [GeForce GT 120 Mac Edition]\n\t0656  G96 [GeForce GT 120 Mac Edition]\n\t0658  G96GL [Quadro FX 380]\n\t0659  G96CGL [Quadro FX 580]\n\t065a  G96GLM [Quadro FX 1700M]\n\t065b  G96C [GeForce 9400 GT]\n\t065c  G96GLM [Quadro FX 770M]\n\t065d  G96 [GeForce 9500 GA / 9600 GT / GTS 250]\n\t065f  G96C [GeForce G210]\n\t06c0  GF100 [GeForce GTX 480]\n\t06c4  GF100 [GeForce GTX 465]\n\t06ca  GF100M [GeForce GTX 480M]\n\t06cb  GF100 [GeForce GTX 480]\n\t06cd  GF100 [GeForce GTX 470]\n\t06d0  GF100GL\n\t06d1  GF100GL [Tesla C2050 / C2070]\n\t\t10de 0771  Tesla C2050\n\t\t10de 0772  Tesla C2070\n\t06d2  GF100GL [Tesla M2070]\n\t\t10de 0774  Tesla M2070\n\t\t10de 0830  Tesla M2070\n\t\t10de 0842  Tesla M2070\n\t\t10de 088f  Tesla X2070\n\t\t10de 0908  Tesla M2070\n\t06d8  GF100GL [Quadro 6000]\n\t06d9  GF100GL [Quadro 5000]\n\t06da  GF100GLM [Quadro 5000M]\n\t06dc  GF100GL [Quadro 6000]\n\t06dd  GF100GL [Quadro 4000]\n\t06de  GF100GL [Tesla T20 Processor]\n\t\t10de 0773  Tesla S2050\n\t\t10de 082f  Tesla M2050\n\t\t10de 0840  Tesla X2070\n\t\t10de 0842  Tesla M2050\n\t\t10de 0846  Tesla M2050\n\t\t10de 0866  Tesla M2050\n\t\t10de 0907  Tesla M2050\n\t\t10de 091e  Tesla M2050\n\t06df  GF100GL [Tesla M2070-Q]\n\t\t10de 084d  Tesla M2070-Q\n\t\t10de 087f  Tesla M2070-Q\n\t06e0  G98 [GeForce 9300 GE]\n\t\t107d 5a96  Geforce 9300GE\n\t06e1  G98 [GeForce 9300 GS]\n\t06e2  G98 [GeForce 8400]\n\t06e3  G98 [GeForce 8300 GS]\n\t06e4  G98 [GeForce 8400 GS Rev. 2]\n\t\t1458 3475  GV-NX84S256HE [GeForce 8400 GS]\n\t06e5  G98M [GeForce 9300M GS]\n\t06e6  G98 [GeForce G 100]\n\t06e7  G98 [GeForce 9300 SE]\n\t06e8  G98M [GeForce 9200M GS]\n\t\t103c 360b  GeForce 9200M GE\n\t06e9  G98M [GeForce 9300M GS]\n\t\t1043 19b2  U6V laptop\n\t06ea  G98M [Quadro NVS 150M]\n\t06eb  G98M [Quadro NVS 160M]\n\t06ec  G98M [GeForce G 105M]\n\t06ed  G98 [GeForce 9600 GT / 9800 GT]\n\t06ee  G98 [GeForce 9600 GT / 9800 GT]\n\t06ef  G98M [GeForce G 103M]\n\t06f1  G98M [GeForce G 105M]\n\t06f8  G98 [Quadro NVS 420]\n\t06f9  G98GL [Quadro FX 370 LP]\n\t06fa  G98 [Quadro NVS 450]\n\t06fb  G98GLM [Quadro FX 370M]\n\t06fd  G98 [Quadro NVS 295]\n\t06ff  G98 [HICx16 + Graphics]\n\t\t10de 0711  HICx8 + Graphics\n\t0751  MCP78S [GeForce 8200] Memory Controller\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 0751  K10N78FullHD-hSLI R3.0 Memory Controller\n\t0752  MCP78S [GeForce 8200] SMBus\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 0752  K10N78FullHD-hSLI R3.0 SMBus\n\t0753  MCP78S [GeForce 8200] Co-Processor\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 0753  K10N78FullHD-hSLI R3.0 Co-Processor\n\t0754  MCP78S [GeForce 8200] Memory Controller\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 0754  K10N78FullHD-hSLI R3.0 Memory Controller\n\t0759  MCP78S [GeForce 8200] IDE\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 0759  K10N78FullHD-hSLI R3.0 IDE\n\t075a  MCP78S [GeForce 8200] PCI Bridge\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1849 075a  K10N78FullHD-hSLI R3.0 PCI Bridge\n\t075b  MCP78S [GeForce 8200] PCI Express Bridge\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 075b  K10N78FullHD-hSLI R3.0 PCI Express Bridge\n\t075c  MCP78S [GeForce 8200] LPC Bridge\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 075c  K10N78FullHD-hSLI R3.0 LPC Bridge\n\t075d  MCP78S [GeForce 8200] LPC Bridge\n\t\t1043 82e8  M3N72-D\n\t0760  MCP77 Ethernet\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 0760  K10N78FullHD-hSLI R3.0 Ethernet\n\t0761  MCP77 Ethernet\n\t0762  MCP77 Ethernet\n\t0763  MCP77 Ethernet\n\t0774  MCP72XE/MCP72P/MCP78U/MCP78S High Definition Audio\n\t\t103c 2a9e  Pavilion p6310f\n# has a Realtek ALC1200 HDAudio Codec\n\t\t1043 82fe  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 3662  K10N78FullHD-hSLI R3.0 High Definition Audio\n\t0778  MCP78S [GeForce 8200] PCI Express Bridge\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 0778  K10N78FullHD-hSLI R3.0 PCI Express Bridge\n\t077a  MCP78S [GeForce 8200] PCI Bridge\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 077a  K10N78FullHD-hSLI R3.0 PCI Bridge\n\t077b  MCP78S [GeForce 8200] OHCI USB 1.1 Controller\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 077b  K10N78FullHD-hSLI R3.0 OHCI USB 1.1 Controller\n\t077c  MCP78S [GeForce 8200] EHCI USB 2.0 Controller\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 077c  K10N78FullHD-hSLI R3.0 EHCI USB 2.0 Controller\n\t077d  MCP78S [GeForce 8200] OHCI USB 1.1 Controller\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 077d  K10N78FullHD-hSLI R3.0 OHCI USB 1.1 Controller\n\t077e  MCP78S [GeForce 8200] EHCI USB 2.0 Controller\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 077e  K10N78FullHD-hSLI R3.0 EHCI USB 2.0 Controller\n\t07c0  MCP73 Host Bridge\n\t\t1afa 7150  JW-IN7150-HD\n\t07c1  MCP73 Host Bridge\n\t\t1019 297a  MCP73PVT-SM\n\t07c2  MCP73 Host Bridge\n\t07c3  MCP73 Host Bridge\n\t\t147b 1c3e  I-N73V motherboard\n\t07c5  MCP73 Host Bridge\n\t07c8  MCP73 Memory Controller\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t07cb  nForce 610i/630i memory controller\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t07cd  nForce 610i/630i memory controller\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t07ce  nForce 610i/630i memory controller\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t07cf  nForce 610i/630i memory controller\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t07d0  nForce 610i/630i memory controller\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t07d1  nForce 610i/630i memory controller\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t07d2  nForce 610i/630i memory controller\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t07d3  nForce 610i/630i memory controller\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t07d6  nForce 610i/630i memory controller\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t07d7  MCP73 LPC Bridge\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t07d8  MCP73 SMBus\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t07d9  MCP73 Memory Controller\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t07da  MCP73 Co-processor\n\t\t1afa 7150  JW-IN7150-HD\n\t07dc  MCP73 Ethernet\n\t\t147b 1c3e  I-N73V motherboard\n\t07dd  MCP73 Ethernet\n\t07de  MCP73 Ethernet\n\t07df  MCP73 Ethernet\n\t07e0  C73 [GeForce 7150 / nForce 630i]\n\t\t1afa 7150  JW-IN7150-HD\n\t07e1  C73 [GeForce 7100 / nForce 630i]\n\t\t1019 297a  MCP73PVT-SM\n\t07e2  C73 [GeForce 7050 / nForce 630i]\n\t07e3  C73 [GeForce 7050 / nForce 610i]\n\t\t147b 1c3e  I-N73V motherboard\n\t07e5  C73 [GeForce 7100 / nForce 620i]\n\t07f0  MCP73 SATA Controller (IDE mode)\n\t\t147b 1c3e  I-N73V motherboard\n\t07f4  GeForce 7100/nForce 630i SATA\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t07f8  MCP73 SATA RAID Controller\n\t\t147b 1c3e  I-N73V motherboard\n\t07fc  MCP73 High Definition Audio\n\t\t1019 297a  MCP73PVT-SM\n\t\t10de 07fc  MCP73 High Definition Audio\n\t\t147b 1c3e  I-N73V motherboard\n\t07fe  MCP73 OHCI USB 1.1 Controller\n\t\t1019 297a  MCP73PVT-SM\n\t\t147b 1c3e  I-N73V motherboard\n\t\t1afa 7150  JW-IN7150-HD\n\t0840  C77 [GeForce 8200M]\n\t0844  C77 [GeForce 9100M G]\n\t0845  C77 [GeForce 8200M G]\n\t0846  C77 [GeForce 9200]\n\t0847  C78 [GeForce 9100]\n\t\t103c 2a9e  Pavilion p6310f\n\t0848  C77 [GeForce 8300]\n\t0849  C77 [GeForce 8200]\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 0849  K10N78FullHD-hSLI R3.0 GeForce 8200\n\t084a  C77 [nForce 730a]\n\t084b  C77 [GeForce 8200]\n\t084c  C77 [nForce 780a/980a SLI]\n\t084d  C77 [nForce 750a SLI]\n\t\t1043 82e8  M3N72-D mGPU\n\t084f  C77 [GeForce 8100 / nForce 720a]\n\t0860  C79 [GeForce 9300]\n\t0861  C79 [GeForce 9400]\n\t0862  C79 [GeForce 9400M G]\n\t0863  C79 [GeForce 9400M]\n\t\t106b 00aa  MacBook5,1\n\t0864  C79 [GeForce 9300]\n\t0865  C79 [GeForce 9300 / ION]\n\t0866  C79 [GeForce 9400M G]\n\t\t106b 00b1  GeForce 9400M\n\t0867  C79 [GeForce 9400]\n\t\t106b 00ad  iMac 9,1\n\t0868  C79 [nForce 760i SLI]\n\t0869  MCP7A [GeForce 9400]\n\t086a  C79 [GeForce 9400]\n\t086c  C79 [GeForce 9300 / nForce 730i]\n\t086d  C79 [GeForce 9200]\n\t086e  C79 [GeForce 9100M G]\n\t086f  MCP79 [GeForce 8200M G]\n\t0870  C79 [GeForce 9400M]\n\t0871  C79 [GeForce 9200]\n\t0872  C79 [GeForce G102M]\n\t\t1043 19b4  GeForce G102M\n\t\t1043 1aa2  GeForce G102M\n\t\t1043 1c02  GeForce G102M\n\t\t1043 1c42  GeForce G205M\n\t0873  C79 [GeForce G102M]\n\t\t1043 19b4  GeForce G102M\n\t\t1043 1c12  GeForce G102M\n\t\t1043 1c52  GeForce G205M\n\t0874  C79 [ION]\n\t0876  C79 [GeForce 9400M / ION]\n\t087a  C79 [GeForce 9400]\n\t087d  C79 [ION]\n\t\t19da a123  IONITX-F-E\n\t087e  C79 [ION LE]\n\t087f  C79 [ION LE]\n\t08a0  MCP89 [GeForce 320M]\n\t08a2  MCP89 [GeForce 320M]\n\t08a3  MCP89 [GeForce 320M]\n\t08a4  MCP89 [GeForce 320M]\n\t08a5  MCP89 [GeForce 320M]\n\t0a20  GT216 [GeForce GT 220]\n\t\t1043 8311  ENGT220/DI/1GD3(LP)/V2\n\t0a21  GT216M [GeForce GT 330M]\n\t0a22  GT216 [GeForce 315]\n\t0a23  GT216 [GeForce 210]\n\t0a26  GT216 [GeForce 405]\n\t0a27  GT216 [GeForce 405]\n\t0a28  GT216M [GeForce GT 230M]\n\t0a29  GT216M [GeForce GT 330M]\n\t0a2a  GT216M [GeForce GT 230M]\n\t0a2b  GT216M [GeForce GT 330M]\n\t0a2c  GT216M [NVS 5100M]\n\t0a2d  GT216M [GeForce GT 320M]\n\t0a30  GT216 [GeForce 505]\n\t0a32  GT216 [GeForce GT 415]\n\t0a34  GT216M [GeForce GT 240M]\n\t0a35  GT216M [GeForce GT 325M]\n\t0a38  GT216GL [Quadro 400]\n\t0a3c  GT216GLM [Quadro FX 880M]\n\t0a60  GT218 [GeForce G210]\n\t0a62  GT218 [GeForce 205]\n\t0a63  GT218 [GeForce 310]\n\t0a64  GT218 [ION]\n\t0a65  GT218 [GeForce 210]\n\t\t1043 8334  EN210 SILENT\n\t\t1458 36a9  GV-N210D3-1GI (rev. 6.0/6.1)\n\t\t1462 8094  N210 [Geforce 210] PCIe graphics adapter\n\t0a66  GT218 [GeForce 310]\n\t0a67  GT218 [GeForce 315]\n\t0a68  GT218M [GeForce G 105M]\n\t0a69  GT218M [GeForce G 105M]\n\t0a6a  GT218M [NVS 2100M]\n\t0a6c  GT218M [NVS 3100M]\n\t\t1028 040b  Latitude E6510\n\t\t17aa 2142  ThinkPad T410\n\t0a6e  GT218M [GeForce 305M]\n\t0a6f  GT218M [ION]\n\t0a70  GT218M [GeForce 310M]\n\t0a71  GT218M [GeForce 305M]\n\t0a72  GT218M [GeForce 310M]\n\t0a73  GT218M [GeForce 305M]\n\t0a74  GT218M [GeForce G210M]\n\t\t1b0a 903a  GeForce G210\n\t0a75  GT218M [GeForce 310M]\n\t0a76  GT218M [ION 2]\n\t0a78  GT218GL [Quadro FX 380 LP]\n\t0a7a  GT218M [GeForce 315M]\n\t\t104d 907e  GeForce 315M\n\t\t1179 fc50  GeForce 315M\n\t\t1179 fc61  GeForce 315M\n\t\t1179 fc71  GeForce 315M\n\t\t1179 fc90  GeForce 315M\n\t\t1179 fcc0  GeForce 315M\n\t\t1179 fcd0  GeForce 315M\n\t\t1179 fce2  GeForce 315M\n\t\t1179 fcf2  GeForce 315M\n\t\t1179 fd16  GeForce 315M\n\t\t1179 fd40  GeForce 315M\n\t\t1179 fd50  GeForce 315M\n\t\t1179 fd52  GeForce 315M\n\t\t1179 fd61  GeForce 315M\n\t\t1179 fd71  GeForce 315M\n\t\t1179 fd92  GeForce 315M\n\t\t1179 fd96  GeForce 315M\n\t\t1179 fdd0  GeForce 315M\n\t\t1179 fdd2  GeForce 315M\n\t\t1179 fdfe  GeForce 315M\n\t\t144d c0a2  GeForce 315M\n\t\t144d c0b2  GeForce 315M\n\t\t144d c581  GeForce 315M\n\t\t144d c587  GeForce 315M\n\t\t144d c588  GeForce 315M\n\t\t144d c597  GeForce 315M\n\t\t144d c606  GeForce 315M\n\t\t1462 aa51  GeForce 405\n\t\t1462 aa58  GeForce 405\n\t\t1462 ac71  GeForce 405\n\t\t1462 ac81  GeForce 315M\n\t\t1462 ac82  GeForce 405\n\t\t1462 ae33  GeForce 405\n\t\t1642 3980  GeForce 405\n\t\t17aa 3950  GeForce 405M\n\t\t17aa 397d  GeForce 405M\n\t\t1b0a 2091  GeForce 315M\n\t\t1b0a 90b4  GeForce 405\n\t\t1bfd 0003  GeForce 405\n\t\t1bfd 8006  GeForce 405\n\t\t1bfd 8007  GeForce 315M\n\t0a7b  GT218 [GeForce 505]\n\t0a7c  GT218GLM [Quadro FX 380M]\n\t0a80  MCP79 Host Bridge\n\t0a81  MCP79 Host Bridge\n\t0a82  MCP79 Host Bridge\n\t0a83  MCP79 Host Bridge\n\t0a84  MCP79 Host Bridge\n\t0a85  MCP79 Host Bridge\n\t0a86  MCP79 Host Bridge\n\t0a87  MCP79 Host Bridge\n\t0a88  MCP79 Memory Controller\n\t0a89  MCP79 Memory Controller\n\t0a98  MCP79 Memory Controller\n\t\t10de cb79  iMac 9,1\n\t0aa0  MCP79 PCI Express Bridge\n\t\t10de cb79  Apple iMac 9,1\n\t0aa2  MCP79 SMBus\n\t\t10de cb79  Apple iMac 9,1\n\t\t19da a123  IONITX-F-E\n\t0aa3  MCP79 Co-processor\n\t\t10de cb79  Apple iMac 9,1\n\t\t19da a123  IONITX-F-E\n\t0aa4  MCP79 Memory Controller\n\t\t19da a123  IONITX-F-E\n\t0aa5  MCP79 OHCI USB 1.1 Controller\n\t\t10de cb79  Apple iMac 9,1\n\t\t19da a123  IONITX-F-E\n\t0aa6  MCP79 EHCI USB 2.0 Controller\n\t\t10de cb79  Apple iMac 9,1\n\t\t19da a123  IONITX-F-E\n\t0aa7  MCP79 OHCI USB 1.1 Controller\n\t\t10de cb79  Apple iMac 9,1\n\t\t19da a123  IONITX-F-E\n\t0aa8  MCP79 OHCI USB 1.1 Controller\n\t0aa9  MCP79 EHCI USB 2.0 Controller\n\t\t10de cb79  Apple iMac 9,1\n\t\t19da a123  IONITX-F-E\n\t0aaa  MCP79 EHCI USB 2.0 Controller\n\t0aab  MCP79 PCI Bridge\n\t\t10de cb79  Apple iMac 9,1\n\t0aac  MCP79 LPC Bridge\n\t0aad  MCP79 LPC Bridge\n\t\t19da a123  IONITX-F-E\n\t0aae  MCP79 LPC Bridge\n\t\t10de cb79  Apple iMac 9,1\n\t0aaf  MCP79 LPC Bridge\n\t0ab0  MCP79 Ethernet\n\t\t10de cb79  Apple iMac 9,1\n\t\t19da a123  IONITX-F-E\n\t0ab1  MCP79 Ethernet\n\t0ab2  MCP79 Ethernet\n\t0ab3  MCP79 Ethernet\n\t0ab4  MCP79 SATA Controller\n\t\t19da a123  IONITX-F-E\n\t0ab5  MCP79 SATA Controller\n\t0ab6  MCP79 SATA Controller\n\t0ab7  MCP79 SATA Controller\n\t0ab8  MCP79 AHCI Controller\n\t0ab9  MCP79 AHCI Controller\n\t\t10de cb79  Apple iMac 9,1\n\t0aba  MCP79 AHCI Controller\n\t0abb  MCP79 AHCI Controller\n\t0abc  MCP79 RAID Controller\n\t0abd  MCP79 RAID Controller\n\t0abe  MCP79 RAID Controller\n\t0abf  MCP79 RAID Controller\n\t0ac0  MCP79 High Definition Audio\n\t\t10de cb79  Apple iMac 9,1\n\t0ac1  MCP79 High Definition Audio\n\t0ac2  MCP79 High Definition Audio\n\t0ac3  MCP79 High Definition Audio\n\t0ac4  MCP79 PCI Express Bridge\n\t\t10de cb79  Apple iMac 9,1\n\t0ac5  MCP79 PCI Express Bridge\n\t0ac6  MCP79 PCI Express Bridge\n\t\t10de cb79  Apple iMac 9,1\n\t0ac7  MCP79 PCI Express Bridge\n\t\t10de cb79  Apple iMac 9,1\n\t0ac8  MCP79 PCI Express Bridge\n\t0ad0  MCP78S [GeForce 8200] SATA Controller (non-AHCI mode)\n\t\t1462 7508  K9N2GM-FIH\n\t\t1849 0ad0  K10N78FullHD-hSLI R3.0 IDE\n\t0ad4  MCP78S [GeForce 8200] AHCI Controller\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 82e8  M3N72-D\n\t\t1849 0ad4  K10N78FullHD-hSLI R3.0 AHCI Controller\n\t0ad8  MCP78S [GeForce 8200] SATA Controller (RAID mode)\n\t0be2  GT216 HDMI Audio Controller\n\t\t1043 8311  ENGT220/DI/1GD3(LP)/V2\n\t0be3  High Definition Audio Controller\n\t\t1028 040b  Latitude E6510\n\t\t10de 066d  G98 [GeForce 8400GS]\n\t\t1462 8094  N210 [Geforce 210] PCIe graphics adapter\n\t0be4  High Definition Audio Controller\n\t0be5  GF100 High Definition Audio Controller\n\t0be9  GF106 High Definition Audio Controller\n\t\t1558 8687  CLEVO/KAPOK W860CU\n\t\t3842 1452  GeForce GTS 450\n\t0bea  GF108 High Definition Audio Controller\n\t\t3842 1430  GeForce GT 430\n\t0beb  GF104 High Definition Audio Controller\n\t\t1462 2322  N460GTX Cyclone 1GD5/OC\n\t0bee  GF116 High Definition Audio Controller\n\t0bf0  Tegra2 PCIe x4 Bridge\n\t0bf1  Tegra2 PCIe x2 Bridge\n\t0ca0  GT215 [GeForce GT 330]\n\t0ca2  GT215 [GeForce GT 320]\n\t0ca3  GT215 [GeForce GT 240]\n\t0ca4  GT215 [GeForce GT 340]\n\t0ca5  GT215 [GeForce GT 220]\n\t0ca7  GT215 [GeForce GT 330]\n\t0ca8  GT215M [GeForce GTS 260M]\n\t0ca9  GT215M [GeForce GTS 250M]\n\t0cac  GT215 [GeForce GT 220/315]\n\t0caf  GT215M [GeForce GT 335M]\n\t0cb0  GT215M [GeForce GTS 350M]\n\t0cb1  GT215M [GeForce GTS 360M]\n\t0cbc  GT215GLM [Quadro FX 1800M]\n\t0d60  MCP89 HOST Bridge\n\t0d68  MCP89 Memory Controller\n\t0d69  MCP89 Memory Controller\n\t0d76  MCP89 PCI Express Bridge\n\t0d79  MCP89 SMBus\n\t0d7a  MCP89 Co-Processor\n\t0d7b  MCP89 Memory Controller\n\t0d7d  MCP89 Ethernet\n\t0d80  MCP89 LPC Bridge\n\t0d85  MCP89 SATA Controller\n\t0d88  MCP89 SATA Controller (AHCI mode)\n\t0d89  MCP89 SATA Controller (AHCI mode)\n\t0d8d  MCP89 SATA Controller (RAID mode)\n\t0d94  MCP89 High Definition Audio\n\t0d9c  MCP89 OHCI USB 1.1 Controller\n\t0d9d  MCP89 EHCI USB 2.0 Controller\n\t0dc0  GF106 [GeForce GT 440]\n\t0dc4  GF106 [GeForce GTS 450]\n\t0dc5  GF106 [GeForce GTS 450 OEM]\n\t0dc6  GF106 [GeForce GTS 450 OEM]\n\t0dcd  GF106M [GeForce GT 555M]\n\t0dce  GF106M [GeForce GT 555M]\n\t0dd1  GF106M [GeForce GTX 460M]\n\t\t1558 8687  CLEVO/KAPOK W860CU\n\t0dd2  GF106M [GeForce GT 445M]\n\t0dd3  GF106M [GeForce GT 435M]\n\t0dd6  GF106M [GeForce GT 550M]\n\t0dd8  GF106GL [Quadro 2000]\n\t\t10de 0914  Quadro 2000D\n\t0dda  GF106GLM [Quadro 2000M]\n\t0de0  GF108 [GeForce GT 440]\n\t0de1  GF108 [GeForce GT 430]\n\t\t3842 1430  GeForce GT 430\n\t0de2  GF108 [GeForce GT 420]\n\t0de3  GF108M [GeForce GT 635M]\n\t0de4  GF108 [GeForce GT 520]\n\t0de5  GF108 [GeForce GT 530]\n\t0de7  GF108 [GeForce GT 610]\n\t0de8  GF108M [GeForce GT 620M]\n\t0de9  GF108M [GeForce GT 620M/630M/635M/640M LE]\n\t\t1025 0692  GeForce GT 620M\n\t\t1025 0725  GeForce GT 620M\n\t\t1025 0728  GeForce GT 620M\n\t\t1025 072b  GeForce GT 620M\n\t\t1025 072e  GeForce GT 620M\n\t\t1025 0753  GeForce GT 620M\n\t\t1025 0754  GeForce GT 620M\n\t\t17aa 3977  GeForce GT 640M LE\n\t\t1b0a 2210  GeForce GT 635M\n\t0dea  GF108M [GeForce 610M]\n\t\t17aa 365a  GeForce 615\n\t\t17aa 365b  GeForce 615\n\t\t17aa 365e  GeForce 615\n\t\t17aa 3660  GeForce 615\n\t\t17aa 366c  GeForce 615\n\t0deb  GF108M [GeForce GT 555M]\n\t0dec  GF108M [GeForce GT 525M]\n\t0ded  GF108M [GeForce GT 520M]\n\t0dee  GF108M [GeForce GT 415M]\n\t0def  GF108M [NVS 5400M]\n\t0df0  GF108M [GeForce GT 425M]\n\t0df1  GF108M [GeForce GT 420M]\n\t0df2  GF108M [GeForce GT 435M]\n\t0df3  GF108M [GeForce GT 420M]\n\t0df4  GF108M [GeForce GT 540M]\n\t\t152d 0952  GeForce GT 630M\n\t\t152d 0953  GeForce GT 630M\n\t0df5  GF108M [GeForce GT 525M]\n\t0df6  GF108M [GeForce GT 550M]\n\t0df7  GF108M [GeForce GT 520M]\n\t0df8  GF108GL [Quadro 600]\n\t0df9  GF108GLM [Quadro 500M]\n\t0dfa  GF108GLM [Quadro 1000M]\n\t0dfc  GF108GLM [NVS 5200M]\n\t0e08  GF119 HDMI Audio Controller\n\t\t1043 83a0  ENGT520 SILENT\n# 1024MB with passive cooling (heatsink)\n\t\t10b0 104a  Gainward GeForce GT 610\n\t0e09  GF110 High Definition Audio Controller\n\t0e0a  GK104 HDMI Audio Controller\n\t0e0b  GK106 HDMI Audio Controller\n\t0e0c  GF114 HDMI Audio Controller\n\t0e0f  GK208 HDMI/DP Audio Controller\n\t0e12  TegraK1 PCIe x4 Bridge\n\t0e13  TegraK1 PCIe x1 Bridge\n\t0e1a  GK110 High Definition Audio Controller\n\t0e1b  GK107 HDMI Audio Controller\n\t\t103c 197b  ZBook 15\n\t\t1043 8428  GTX650-DC-1GD5\n\t0e1c  Tegra3+ PCIe x4 Bridge\n\t0e1d  Tegra3+ PCIe x2 Bridge\n\t0e22  GF104 [GeForce GTX 460]\n\t\t1462 2322  N460GTX Cyclone 1GD5/OC\n\t0e23  GF104 [GeForce GTX 460 SE]\n\t0e24  GF104 [GeForce GTX 460 OEM]\n\t0e30  GF104M [GeForce GTX 470M]\n\t0e31  GF104M [GeForce GTX 485M]\n\t0e3a  GF104GLM [Quadro 3000M]\n\t0e3b  GF104GLM [Quadro 4000M]\n\t0f00  GF108 [GeForce GT 630]\n\t0f01  GF108 [GeForce GT 620]\n\t0f02  GF108 [GeForce GT 730]\n\t0f03  GF108 [GeForce GT 610]\n\t0f06  GF108 [GeForce GT 730]\n\t0fb0  GM200 High Definition Audio\n\t0fb8  GP108 High Definition Audio Controller\n\t0fb9  GP107GL High Definition Audio Controller\n\t0fba  GM206 High Definition Audio Controller\n\t0fbb  GM204 High Definition Audio Controller\n\t0fc0  GK107 [GeForce GT 640 OEM]\n\t0fc1  GK107 [GeForce GT 640]\n\t0fc2  GK107 [GeForce GT 630 OEM]\n\t0fc5  GK107 [GeForce GT 1030]\n\t0fc6  GK107 [GeForce GTX 650]\n\t\t1043 8428  GTX650-DC-1GD5\n\t0fc8  GK107 [GeForce GT 740]\n\t0fc9  GK107 [GeForce GT 730]\n\t0fcd  GK107M [GeForce GT 755M]\n\t0fce  GK107M [GeForce GT 640M LE]\n\t0fd1  GK107M [GeForce GT 650M]\n\t\t1043 1597  GeForce GT 650M\n\t\t1043 15a7  GeForce GT 650M\n\t\t1043 2103  N56VZ\n\t\t1043 2105  GeForce GT 650M\n\t\t1043 2141  GeForce GT 650M\n\t0fd2  GK107M [GeForce GT 640M]\n\t\t1028 054f  GeForce GT 640M\n\t\t1028 055f  GeForce GT 640M\n\t\t1028 0595  GeForce GT 640M LE\n\t\t1028 05b2  GeForce GT 640M LE\n\t0fd3  GK107M [GeForce GT 640M LE]\n\t0fd4  GK107M [GeForce GTX 660M]\n\t0fd5  GK107M [GeForce GT 650M Mac Edition]\n\t0fd8  GK107M [GeForce GT 640M Mac Edition]\n\t0fd9  GK107M [GeForce GT 645M]\n\t0fdb  GK107M\n\t0fdf  GK107M [GeForce GT 740M]\n\t0fe0  GK107M [GeForce GTX 660M Mac Edition]\n\t0fe1  GK107M [GeForce GT 730M]\n\t0fe2  GK107M [GeForce GT 745M]\n\t0fe3  GK107M [GeForce GT 745M]\n\t\t103c 2b16  GeForce GT 745A\n\t\t17aa 3675  GeForce GT 745A\n\t0fe4  GK107M [GeForce GT 750M]\n\t0fe5  GK107 [GeForce K340 USM]\n\t0fe6  GK107 [GRID K1 NVS USM]\n# GRID K1 USM\n\t0fe7  GK107GL [GRID K100 vGPU]\n\t\t10de 101e  GRID K100\n\t0fe9  GK107M [GeForce GT 750M Mac Edition]\n\t0fea  GK107M [GeForce GT 755M Mac Edition]\n\t0fec  GK107M [GeForce 710A]\n\t0fed  GK107M [GeForce 820M]\n\t0fee  GK107M [GeForce 810M]\n\t0fef  GK107GL [GRID K340]\n\t0ff1  GK107 [NVS 1000]\n\t0ff2  GK107GL [GRID K1]\n\t0ff3  GK107GL [Quadro K420]\n\t0ff5  GK107GL [GRID K1 Tesla USM]\n\t0ff6  GK107GLM [Quadro K1100M]\n\t\t103c 197b  ZBook 15\n# GRID K1 Quadro USM\n\t0ff7  GK107GL [GRID K140Q vGPU]\n\t\t10de 1037  GRID K140Q\n\t0ff8  GK107GLM [Quadro K500M]\n\t0ff9  GK107GL [Quadro K2000D]\n\t0ffa  GK107GL [Quadro K600]\n\t0ffb  GK107GLM [Quadro K2000M]\n\t0ffc  GK107GLM [Quadro K1000M]\n\t0ffd  GK107 [NVS 510]\n\t0ffe  GK107GL [Quadro K2000]\n\t0fff  GK107GL [Quadro 410]\n\t1001  GK110B [GeForce GTX TITAN Z]\n\t1003  GK110 [GeForce GTX Titan LE]\n\t1004  GK110 [GeForce GTX 780]\n\t\t3842 0784  GK110B [GeForce GTX 780 SC w/ ACX Cooler]\n\t\t3842 1784  GK110B [GeForce GTX 780 Dual FTW w/ ACX Cooler]\n\t\t3842 1788  GK110B [GeForce GTX 780 Dual Classified w/ ACX Cooler]\n\t1005  GK110 [GeForce GTX TITAN]\n\t\t1043 8451  GTXTITAN-6GD5\n# Reference Model\n\t\t10de 1035  GeForce GTX Titan\n# 06G-P4-2790-KR\n\t\t3842 2790  GeForce GTX Titan\n# 06G-P4-2791-KR\n\t\t3842 2791  GeForce GTX Titan SC\n# 06G-P4-2793-KR\n\t\t3842 2793  GeForce GTX Titan SC Signature\n# 06G-P4-2794-KR\n\t\t3842 2794  GeForce GTX Titan SC Hydro Copper\n# 06G-P4-2795-KR\n\t\t3842 2795  GeForce GTX Titan SC Hydro Copper Signature\n\t1007  GK110 [GeForce GTX 780 Rev. 2]\n\t1008  GK110 [GeForce GTX 780 Ti 6GB]\n\t100a  GK110B [GeForce GTX 780 Ti]\n\t100c  GK110B [GeForce GTX TITAN Black]\n\t101e  GK110GL [Tesla K20X]\n\t101f  GK110GL [Tesla K20]\n\t1020  GK110GL [Tesla K20X]\n\t1021  GK110GL [Tesla K20Xm]\n\t1022  GK110GL [Tesla K20c]\n\t1023  GK110BGL [Tesla K40m]\n\t\t10de 097e  12GB Computational Accelerator\n\t1024  GK180GL [Tesla K40c]\n\t1026  GK110GL [Tesla K20s]\n\t1027  GK110BGL [Tesla K40st]\n\t1028  GK110GL [Tesla K20m]\n\t1029  GK110BGL [Tesla K40s]\n\t102a  GK110BGL [Tesla K40t]\n\t102d  GK210GL [Tesla K80]\n\t102e  GK110BGL [Tesla K40d]\n\t102f  GK110BGL [Tesla Stella Solo]\n\t103a  GK110GL [Quadro K6000]\n\t103c  GK110GL [Quadro K5200]\n\t103f  GK110BGL [Tesla Stella SXM]\n\t1040  GF119 [GeForce GT 520]\n\t\t1043 83a0  ENGT520 SILENT\n\t1042  GF119 [GeForce 510]\n\t1045  GF119\n\t1048  GF119 [GeForce 605]\n\t1049  GF119 [GeForce GT 620 OEM]\n\t104a  GF119 [GeForce GT 610]\n# 1024MB with passive cooling (heatsink)\n\t\t10b0 104a  Gainward GeForce GT 610\n\t104b  GF119 [GeForce GT 625 OEM]\n\t104c  GF119 [GeForce GT 705]\n\t104d  GF119 [GeForce GT 710]\n\t1050  GF119M [GeForce GT 520M]\n\t1051  GF119M [GeForce GT 520MX]\n\t1052  GF119M [GeForce GT 520M]\n\t1054  GF119M [GeForce 410M]\n\t1055  GF119M [GeForce 410M]\n\t1056  GF119M [NVS 4200M]\n\t1057  GF119M [Quadro NVS 4200M]\n\t1058  GF119M [GeForce 610M]\n\t\t103c 2aed  GeForce 610\n\t\t103c 2af1  GeForce 610\n\t\t1043 10ac  GeForce GT 610M\n\t\t1043 10bc  GeForce GT 610M\n\t\t1043 1652  GeForce GT 610M\n\t\t17aa 367a  GeForce 610M\n\t\t17aa 3682  GeForce 800A\n\t\t17aa 3687  GeForce 800A\n\t\t17aa 3692  GeForce 705A\n\t\t17aa 3695  GeForce 800A\n\t\t17aa a117  GeForce 610M\n\t1059  GF119M [GeForce 610M]\n\t105a  GF119M [GeForce 610M]\n\t\t1043 2111  GeForce GT 610M\n\t\t1043 2112  GeForce GT 610M\n\t105b  GF119M [GeForce 705M]\n\t\t103c 2afb  GeForce 705A\n\t\t17aa 309d  GeForce 705A\n\t\t17aa 30b1  GeForce 800A\n\t\t17aa 30f3  GeForce 705A\n\t\t17aa 36a1  GeForce 800A\n\t107c  GF119 [NVS 315]\n\t107d  GF119 [NVS 310]\n\t1080  GF110 [GeForce GTX 580]\n\t1081  GF110 [GeForce GTX 570]\n\t\t10de 087e  Leadtek WinFast GTX 570\n\t1082  GF110 [GeForce GTX 560 Ti OEM]\n\t1084  GF110 [GeForce GTX 560 OEM]\n\t1086  GF110 [GeForce GTX 570 Rev. 2]\n\t1087  GF110 [GeForce GTX 560 Ti 448 Cores]\n\t1088  GF110 [GeForce GTX 590]\n\t1089  GF110 [GeForce GTX 580 Rev. 2]\n\t108b  GF110 [GeForce GTX 580]\n\t108e  GF110GL [Tesla C2090]\n\t1091  GF110GL [Tesla M2090]\n\t\t10de 088e  Tesla X2090\n\t\t10de 0891  Tesla X2090\n\t\t10de 0974  Tesla X2090\n\t\t10de 098d  Tesla X2090\n\t1094  GF110GL [Tesla M2075]\n\t\t10de 0888  Tesla M2075\n\t1096  GF110GL [Tesla C2050 / C2075]\n\t\t10de 0910  Tesla C2075\n\t\t10de 0911  Tesla C2050\n\t109a  GF100GLM [Quadro 5010M]\n\t109b  GF100GL [Quadro 7000]\n\t\t10de 0918  Quadro 7000\n\t10c0  GT218 [GeForce 9300 GS Rev. 2]\n\t10c3  GT218 [GeForce 8400 GS Rev. 3]\n\t10c5  GT218 [GeForce 405]\n\t10d8  GT218 [NVS 300]\n\t10ef  GP102 HDMI Audio Controller\n\t10f0  GP104 High Definition Audio Controller\n\t10f1  GP106 High Definition Audio Controller\n\t10f7  TU102 High Definition Audio Controller\n\t10f9  TU106 High Definition Audio Controller\n\t\t1043 8673  TURBO-RTX2070-8G\n\t1140  GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M]\n\t\t1019 0799  GeForce 820M\n\t\t1019 999f  GeForce GT 720M\n\t\t1025 0600  GeForce GT 620M\n\t\t1025 0606  GeForce GT 620M\n\t\t1025 064a  GeForce GT 620M\n\t\t1025 064c  GeForce GT 620M\n\t\t1025 067a  GeForce GT 620M\n\t\t1025 0680  GeForce GT 620M\n\t\t1025 0686  GeForce 710M\n\t\t1025 0689  GeForce 710M\n\t\t1025 068b  GeForce 710M\n\t\t1025 068d  GeForce 710M\n\t\t1025 068e  GeForce 710M\n\t\t1025 0691  GeForce 710M\n\t\t1025 0692  GeForce GT 620M\n\t\t1025 0694  GeForce GT 620M\n\t\t1025 0702  GeForce GT 620M\n\t\t1025 0719  GeForce GT 620M\n\t\t1025 0725  GeForce GT 620M\n\t\t1025 0728  GeForce GT 620M\n\t\t1025 072b  GeForce GT 620M\n\t\t1025 072e  GeForce GT 620M\n\t\t1025 0732  GeForce GT 620M\n\t\t1025 0763  GeForce GT 720M\n\t\t1025 0773  GeForce 710M\n\t\t1025 0774  GeForce 710M\n\t\t1025 0776  GeForce GT 720M\n\t\t1025 077a  GeForce 710M\n\t\t1025 077b  GeForce 710M\n\t\t1025 077c  GeForce 710M\n\t\t1025 077d  GeForce 710M\n\t\t1025 077e  GeForce 710M\n\t\t1025 077f  GeForce 710M\n\t\t1025 0781  GeForce GT 720M\n\t\t1025 0798  GeForce GT 720M\n\t\t1025 0799  GeForce GT 720M\n\t\t1025 079b  GeForce GT 720M\n\t\t1025 079c  GeForce GT 720M\n\t\t1025 0807  GeForce GT 720M\n\t\t1025 0821  GeForce GT 720M\n\t\t1025 0823  GeForce GT 720M\n\t\t1025 0830  GeForce GT 720M\n\t\t1025 0833  GeForce GT 720M\n\t\t1025 0837  GeForce GT 720M\n\t\t1025 083e  GeForce 820M\n\t\t1025 0841  GeForce 710M\n\t\t1025 0854  GeForce 820M\n\t\t1025 0855  GeForce 820M\n\t\t1025 0856  GeForce 820M\n\t\t1025 0857  GeForce 820M\n\t\t1025 0858  GeForce 820M\n\t\t1025 0863  GeForce 820M\n\t\t1025 0868  GeForce 820M\n\t\t1025 0869  GeForce 810M\n\t\t1025 0873  GeForce 820M\n\t\t1025 0878  GeForce 820M\n\t\t1025 087b  GeForce 820M\n\t\t1025 087c  GeForce 810M\n\t\t1025 0881  GeForce 820M\n\t\t1025 088a  GeForce 820M\n\t\t1025 089b  GeForce 820M\n\t\t1025 090f  GeForce 820M\n\t\t1025 0921  GeForce 820M\n\t\t1025 092e  GeForce 810M\n\t\t1025 092f  GeForce 820M\n\t\t1025 0932  GeForce 820M\n\t\t1025 093a  GeForce 820M\n\t\t1025 093c  GeForce 820M\n\t\t1025 093f  GeForce 820M\n\t\t1025 0941  GeForce 820M\n\t\t1025 0945  GeForce 820M\n\t\t1025 0954  GeForce 820M\n\t\t1025 0965  GeForce 820M\n\t\t1028 054d  GeForce GT 630M\n\t\t1028 054e  GeForce GT 630M\n\t\t1028 0554  GeForce GT 620M\n\t\t1028 0557  GeForce GT 620M\n\t\t1028 0562  GeForce GT 625M\n\t\t1028 0565  GeForce GT 630M\n\t\t1028 0568  GeForce GT 630M\n\t\t1028 0590  GeForce GT 630M\n\t\t1028 0592  GeForce GT 625M\n\t\t1028 0594  GeForce GT 625M\n\t\t1028 0595  GeForce GT 625M\n\t\t1028 05a2  GeForce GT 625M\n\t\t1028 05b1  GeForce GT 625M\n\t\t1028 05b3  GeForce GT 625M\n\t\t1028 05da  GeForce GT 630M\n\t\t1028 05de  GeForce GT 720M\n\t\t1028 05e0  GeForce GT 720M\n\t\t1028 05e8  GeForce GT 630M\n\t\t1028 05f4  GeForce GT 720M\n\t\t1028 060f  GeForce GT 720M\n\t\t1028 064e  GeForce 820M\n\t\t1028 0652  GeForce 820M\n\t\t1028 0653  GeForce 820M\n\t\t1028 0655  GeForce 820M\n\t\t1028 065e  GeForce 820M\n\t\t1028 0662  GeForce 820M\n\t\t1028 068d  GeForce 820M\n\t\t1028 06ad  GeForce 820M\n\t\t1028 06ae  GeForce 820M\n\t\t1028 06af  GeForce 820M\n\t\t1028 06b0  GeForce 820M\n\t\t1028 06c0  GeForce 820M\n\t\t1028 06c1  GeForce 820M\n\t\t103c 18ef  GeForce GT 630M\n\t\t103c 18f9  GeForce GT 630M\n\t\t103c 18fb  GeForce GT 630M\n\t\t103c 18fd  GeForce GT 630M\n\t\t103c 18ff  GeForce GT 630M\n\t\t103c 218a  GeForce 820M\n\t\t103c 21bb  GeForce 820M\n\t\t103c 21bc  GeForce 820M\n\t\t103c 220e  GeForce 820M\n\t\t103c 2210  GeForce 820M\n\t\t103c 2212  GeForce 820M\n\t\t103c 2214  GeForce 820M\n\t\t103c 2218  GeForce 820M\n\t\t103c 225b  GeForce 820M\n\t\t103c 225d  GeForce 820M\n\t\t103c 226d  GeForce 820M\n\t\t103c 226f  GeForce 820M\n\t\t103c 22d2  GeForce 820M\n\t\t103c 22d9  GeForce 820M\n\t\t103c 2335  GeForce 820M\n\t\t103c 2337  GeForce 820M\n\t\t103c 2aef  GeForce GT 720A\n\t\t103c 2af9  GeForce 710A\n\t\t1043 10dd  NVS 5200M\n\t\t1043 10ed  NVS 5200M\n\t\t1043 11fd  GeForce GT 720M\n\t\t1043 124d  GeForce GT 720M\n\t\t1043 126d  GeForce GT 720M\n\t\t1043 131d  GeForce GT 720M\n\t\t1043 13fd  GeForce GT 720M\n\t\t1043 14c7  GeForce GT 720M\n\t\t1043 1507  GeForce GT 620M\n\t\t1043 15ad  GeForce 820M\n\t\t1043 15ed  GeForce 820M\n\t\t1043 160d  GeForce 820M\n\t\t1043 163d  GeForce 820M\n\t\t1043 166d  GeForce 820M\n\t\t1043 16cd  GeForce 820M\n\t\t1043 16dd  GeForce 820M\n\t\t1043 170d  GeForce 820M\n\t\t1043 176d  GeForce 820M\n\t\t1043 178d  GeForce 820M\n\t\t1043 179d  GeForce 820M\n\t\t1043 17dd  GeForce 820M\n\t\t1043 2132  GeForce GT 620M\n\t\t1043 2136  NVS 5200M\n\t\t1043 21ba  GeForce GT 720M\n\t\t1043 21fa  GeForce GT 720M\n\t\t1043 220a  GeForce GT 720M\n\t\t1043 221a  GeForce GT 720M\n\t\t1043 223a  GeForce GT 710M\n\t\t1043 224a  GeForce GT 710M\n\t\t1043 227a  GeForce 820M\n\t\t1043 228a  GeForce 820M\n\t\t1043 232a  GeForce 820M\n\t\t1043 233a  GeForce 820M\n\t\t1043 235a  GeForce 820M\n\t\t1043 236a  GeForce 820M\n\t\t1043 238a  GeForce 820M\n\t\t1043 8595  GeForce GT 720M\n\t\t1043 85ea  GeForce GT 720M\n\t\t1043 85eb  GeForce 820M\n\t\t1043 85ec  GeForce 820M\n\t\t1043 85ee  GeForce GT 720M\n\t\t1043 85f3  GeForce 820M\n\t\t1043 860e  GeForce 820M\n\t\t1043 861a  GeForce 820M\n\t\t1043 861b  GeForce 820M\n\t\t1043 8628  GeForce 820M\n\t\t1043 8643  GeForce 820M\n\t\t1043 864c  GeForce 820M\n\t\t1043 8652  GeForce 820M\n\t\t1043 8660  GeForce 820M\n\t\t1043 8661  GeForce 820M\n\t\t105b 0dac  GeForce GT 720M\n\t\t105b 0dad  GeForce GT 720M\n\t\t105b 0ef3  GeForce GT 720M\n\t\t1072 152d  GeForce GT 720M\n\t\t10cf 17f5  GeForce GT 720M\n\t\t1179 fa01  GeForce 710M\n\t\t1179 fa02  GeForce 710M\n\t\t1179 fa03  GeForce 710M\n\t\t1179 fa05  GeForce 710M\n\t\t1179 fa11  GeForce 710M\n\t\t1179 fa13  GeForce 710M\n\t\t1179 fa18  GeForce 710M\n\t\t1179 fa19  GeForce 710M\n\t\t1179 fa21  GeForce 710M\n\t\t1179 fa23  GeForce 710M\n\t\t1179 fa2a  GeForce 710M\n\t\t1179 fa32  GeForce 710M\n\t\t1179 fa33  GeForce 710M\n\t\t1179 fa36  GeForce 710M\n\t\t1179 fa38  GeForce 710M\n\t\t1179 fa42  GeForce 710M\n\t\t1179 fa43  GeForce 710M\n\t\t1179 fa45  GeForce 710M\n\t\t1179 fa47  GeForce 710M\n\t\t1179 fa49  GeForce 710M\n\t\t1179 fa58  GeForce 710M\n\t\t1179 fa59  GeForce 710M\n\t\t1179 fa88  GeForce 710M\n\t\t1179 fa89  GeForce 710M\n\t\t144d b092  GeForce GT 620M\n\t\t144d c0d5  GeForce GT 630M\n\t\t144d c0d7  GeForce GT 620M\n\t\t144d c0e2  NVS 5200M\n\t\t144d c0e3  NVS 5200M\n\t\t144d c0e4  NVS 5200M\n\t\t144d c10d  GeForce 820M\n\t\t144d c652  GeForce GT 620M on NP300E5C series laptop\n\t\t144d c709  GeForce 710M\n\t\t144d c711  GeForce 710M\n\t\t144d c736  GeForce 710M\n\t\t144d c737  GeForce 710M\n\t\t144d c745  GeForce 820M\n\t\t144d c750  GeForce 820M\n\t\t1462 10b8  GeForce GT 710M\n\t\t1462 10e9  GeForce GT 720M\n\t\t1462 1116  GeForce 820M\n\t\t1462 aa33  GeForce 720M\n\t\t1462 aaa2  GeForce GT 720M\n\t\t1462 aaa3  GeForce 820M\n\t\t1462 acb2  GeForce GT 720M\n\t\t1462 acc1  GeForce GT 720M\n\t\t1462 ae61  GeForce 720M\n\t\t1462 ae65  GeForce GT 720M\n\t\t1462 ae6a  GeForce 820M\n\t\t1462 ae71  GeForce GT 720M\n\t\t14c0 0083  GeForce 820M\n\t\t152d 0926  GeForce 620M\n\t\t152d 0982  GeForce GT 630M\n\t\t152d 0983  GeForce GT 630M\n\t\t152d 1005  GeForce GT 820M\n\t\t152d 1012  GeForce 710M\n\t\t152d 1019  GeForce 820M\n\t\t152d 1030  GeForce GT 630M\n\t\t152d 1055  GeForce 710M\n\t\t152d 1067  GeForce GT 720M\n\t\t152d 1072  GeForce GT 720M\n\t\t152d 1086  GeForce 820M\n\t\t152d 1092  GeForce 820M\n\t\t17aa 2200  NVS 5200M\n\t\t17aa 2213  GeForce GT 720M\n\t\t17aa 2220  GeForce GT 720M\n\t\t17aa 309c  GeForce GT 720A\n\t\t17aa 30b4  GeForce 820A\n\t\t17aa 30b7  GeForce 720A\n\t\t17aa 30e4  GeForce 820A\n\t\t17aa 361b  GeForce 820A\n\t\t17aa 361c  GeForce 820A\n\t\t17aa 361d  GeForce 820A\n\t\t17aa 3656  GeForce GT 620M\n\t\t17aa 365a  GeForce 705M\n\t\t17aa 365e  GeForce 800M\n\t\t17aa 3661  GeForce 820A\n\t\t17aa 366c  GeForce 800M\n\t\t17aa 3685  GeForce 800M\n\t\t17aa 3686  GeForce 800M\n\t\t17aa 3687  GeForce 705A\n\t\t17aa 3696  GeForce 820A\n\t\t17aa 369b  GeForce 820A\n\t\t17aa 369c  GeForce 820A\n\t\t17aa 369d  GeForce 820A\n\t\t17aa 369e  GeForce 820A\n\t\t17aa 36a9  GeForce 820A\n\t\t17aa 36af  GeForce 820A\n\t\t17aa 36b0  GeForce 820A\n\t\t17aa 36b6  GeForce 820A\n\t\t17aa 3800  GeForce GT 720M\n\t\t17aa 3801  GeForce GT 720M\n\t\t17aa 3802  GeForce GT 720M\n\t\t17aa 3803  GeForce GT 720M\n\t\t17aa 3804  GeForce GT 720M\n\t\t17aa 3806  GeForce GT 720M\n\t\t17aa 3808  GeForce GT 720M\n\t\t17aa 380d  GeForce 820M\n\t\t17aa 380e  GeForce 820M\n\t\t17aa 380f  GeForce 820M\n\t\t17aa 3811  GeForce 820M\n\t\t17aa 3812  GeForce 820M\n\t\t17aa 3813  GeForce 820M\n\t\t17aa 3816  GeForce 820M\n\t\t17aa 3818  GeForce 820M\n\t\t17aa 381a  GeForce 820M\n\t\t17aa 381c  GeForce 820M\n\t\t17aa 3901  GeForce 610M / GT 620M\n\t\t17aa 3902  GeForce 710M\n\t\t17aa 3903  GeForce 610M/710M\n\t\t17aa 3904  GeForce GT 620M/625M\n\t\t17aa 3905  GeForce GT 720M\n\t\t17aa 3907  GeForce 820M\n\t\t17aa 3910  GeForce 720M\n\t\t17aa 3912  GeForce 720M\n\t\t17aa 3913  GeForce 820M\n\t\t17aa 3915  GeForce 820M\n\t\t17aa 3977  GeForce GT 720M\n\t\t17aa 3983  GeForce 610M\n\t\t17aa 5001  GeForce 610M\n\t\t17aa 5003  GeForce GT 720M\n\t\t17aa 5005  GeForce 705M\n\t\t17aa 500d  GeForce GT 620M\n\t\t17aa 5014  GeForce 710M\n\t\t17aa 5017  GeForce 710M\n\t\t17aa 5019  GeForce 710M\n\t\t17aa 501a  GeForce 710M\n\t\t17aa 501f  GeForce GT 720M\n\t\t17aa 5025  GeForce 710M\n\t\t17aa 5027  GeForce 710M\n\t\t17aa 502a  GeForce 710M\n\t\t17aa 502b  GeForce GT 720M\n\t\t17aa 502d  GeForce 710M\n\t\t17aa 502e  GeForce GT 720M\n\t\t17aa 502f  GeForce GT 720M\n\t\t17aa 5030  GeForce 705M\n\t\t17aa 5031  GeForce 705M\n\t\t17aa 5032  GeForce 820M\n\t\t17aa 5033  GeForce 820M\n\t\t17aa 503e  GeForce 710M\n\t\t17aa 503f  GeForce 820M\n\t\t17aa 5040  GeForce 820M\n\t\t1854 0177  GeForce 710M\n\t\t1854 0180  GeForce 710M\n\t\t1854 0190  GeForce GT 720M\n\t\t1854 0192  GeForce GT 720M\n\t\t1854 0224  GeForce 820M\n\t\t1b0a 01c0  GeForce 820M\n\t\t1b0a 20dd  GeForce GT 620M\n\t\t1b0a 20df  GeForce GT 620M\n\t\t1b0a 210e  GeForce 820M\n\t\t1b0a 2202  GeForce GT 720M\n\t\t1b0a 90d7  GeForce 820M\n\t\t1b0a 90dd  GeForce 820M\n\t\t1b50 5530  GeForce 820M\n\t\t1b6c 5531  GeForce GT 720M\n\t\t1bab 0106  GeForce 820M\n\t\t1d05 1013  GeForce 810M\n\t1180  GK104 [GeForce GTX 680]\n\t\t1043 83f1  GTX680-DC2-2GD5\n\t\t3842 3682  GeForce GTX 680 Mac Edition\n\t1182  GK104 [GeForce GTX 760 Ti]\n\t1183  GK104 [GeForce GTX 660 Ti]\n\t1184  GK104 [GeForce GTX 770]\n\t1185  GK104 [GeForce GTX 660 OEM]\n\t\t10de 106f  GK104 [GeForce GTX 760 OEM]\n\t1187  GK104 [GeForce GTX 760]\n\t1188  GK104 [GeForce GTX 690]\n\t1189  GK104 [GeForce GTX 670]\n\t\t10de 1074  GK104 [GeForce GTX 760 Ti OEM]\n\t118a  GK104GL [GRID K520]\n\t118b  GK104GL [GRID K2 GeForce USM]\n\t118c  GK104 [GRID K2 NVS USM]\n# GRID K2 USM\n\t118d  GK104GL [GRID K200 vGPU]\n\t\t10de 101d  GRID K200\n\t118e  GK104 [GeForce GTX 760 OEM]\n\t118f  GK104GL [Tesla K10]\n\t1191  GK104 [GeForce GTX 760 Rev. 2]\n\t1193  GK104 [GeForce GTX 760 Ti OEM]\n\t1194  GK104GL [Tesla K8]\n\t1195  GK104 [GeForce GTX 660 Rev. 2]\n\t1198  GK104M [GeForce GTX 880M]\n\t1199  GK104M [GeForce GTX 870M]\n\t119a  GK104M [GeForce GTX 860M]\n\t119d  GK104M [GeForce GTX 775M Mac Edition]\n\t119e  GK104M [GeForce GTX 780M Mac Edition]\n\t119f  GK104M [GeForce GTX 780M]\n\t11a0  GK104M [GeForce GTX 680M]\n\t11a1  GK104M [GeForce GTX 670MX]\n\t11a2  GK104M [GeForce GTX 675MX Mac Edition]\n\t11a3  GK104M [GeForce GTX 680MX]\n\t\t106b 010d  iMac 13,2\n\t11a7  GK104M [GeForce GTX 675MX]\n\t11af  GK104GLM [GRID IceCube]\n\t11b0  GK104GL [GRID K240Q / K260Q vGPU]\n\t\t10de 101a  GRID K240Q\n\t\t10de 101b  GRID K260Q\n\t11b1  GK104GL [GRID K2 Tesla USM]\n\t11b4  GK104GL [Quadro K4200]\n\t11b6  GK104GLM [Quadro K3100M]\n\t11b7  GK104GLM [Quadro K4100M]\n\t11b8  GK104GLM [Quadro K5100M]\n\t11b9  GK104GLM\n\t11ba  GK104GL [Quadro K5000]\n\t11bb  GK104GL [Quadro 4100]\n\t11bc  GK104GLM [Quadro K5000M]\n\t11bd  GK104GLM [Quadro K4000M]\n\t11be  GK104GLM [Quadro K3000M]\n\t11bf  GK104GL [GRID K2]\n\t11c0  GK106 [GeForce GTX 660]\n\t11c2  GK106 [GeForce GTX 650 Ti Boost]\n\t\t1043 845b  GeForce GTX 650 Ti Boost DirectCU II OC\n\t\t1462 2874  GeForce GTX 650 Ti Boost TwinFrozr II OC\n\t\t1569 11c2  GeForce GTX 650 Ti Boost OC\n\t\t19da 1281  GeForce GTX 650 Ti Boost OC\n\t\t3842 3657  GeForce GTX 650 Ti Boost\n\t\t3842 3658  GeForce GTX 650 Ti Boost Superclocked\n\t11c3  GK106 [GeForce GTX 650 Ti OEM]\n\t\t10de 1030  GeForce GTX 650 Ti OEM\n\t11c4  GK106 [GeForce GTX 645 OEM]\n\t11c5  GK106 [GeForce GT 740]\n\t11c6  GK106 [GeForce GTX 650 Ti]\n\t11c7  GK106 [GeForce GTX 750 Ti]\n\t11c8  GK106 [GeForce GTX 650 OEM]\n\t11cb  GK106 [GeForce GT 740]\n\t11e0  GK106M [GeForce GTX 770M]\n\t11e1  GK106M [GeForce GTX 765M]\n\t11e2  GK106M [GeForce GTX 765M]\n\t11e3  GK106M [GeForce GTX 760M]\n\t\t17aa 3683  GeForce GTX 760A\n\t11e7  GK106M\n\t11fa  GK106GL [Quadro K4000]\n\t11fc  GK106GLM [Quadro K2100M]\n\t1200  GF114 [GeForce GTX 560 Ti]\n\t1201  GF114 [GeForce GTX 560]\n\t1202  GF114 [GeForce GTX 560 Ti OEM]\n\t1203  GF114 [GeForce GTX 460 SE v2]\n\t1205  GF114 [GeForce GTX 460 v2]\n\t1206  GF114 [GeForce GTX 555]\n\t1207  GF114 [GeForce GT 645 OEM]\n\t1208  GF114 [GeForce GTX 560 SE]\n\t1210  GF114M [GeForce GTX 570M]\n\t1211  GF114M [GeForce GTX 580M]\n\t1212  GF114M [GeForce GTX 675M]\n\t1213  GF114M [GeForce GTX 670M]\n\t1241  GF116 [GeForce GT 545 OEM]\n\t1243  GF116 [GeForce GT 545]\n\t1244  GF116 [GeForce GTX 550 Ti]\n\t1245  GF116 [GeForce GTS 450 Rev. 2]\n\t1246  GF116M [GeForce GT 550M]\n\t1247  GF116M [GeForce GT 555M/635M]\n\t\t1043 1752  GeForce GT 555M\n\t\t1043 2050  GeForce GT 555M\n\t\t1043 2051  GeForce GT 555M\n\t\t1043 212a  GeForce GT 635M\n\t\t1043 212b  GeForce GT 635M\n\t\t1043 212c  GeForce GT 635M\n\t\t152d 0930  GeForce GT 635M\n\t1248  GF116M [GeForce GT 555M/635M]\n\t\t152d 0930  GeForce GT 635M\n\t\t17c0 10e7  GeForce GT 555M\n\t\t17c0 10e8  GeForce GT 555M\n\t\t17c0 10ea  GeForce GT 555M\n\t\t1854 0890  GeForce GT 555M\n\t\t1854 0891  GeForce GT 555M\n\t\t1854 1795  GeForce GT 555M\n\t\t1854 1796  GeForce GT 555M\n\t\t1854 3005  GeForce GT 555M\n\t1249  GF116 [GeForce GTS 450 Rev. 3]\n\t124b  GF116 [GeForce GT 640 OEM]\n\t124d  GF116M [GeForce GT 555M/635M]\n\t\t1028 0491  GeForce GT 555M\n\t\t1028 0570  GeForce GT 555M\n\t\t1028 0571  GeForce GT 555M\n\t\t1462 108d  GeForce GT 555M\n\t\t1462 10cc  GeForce GT 635M\n\t1251  GF116M [GeForce GT 560M]\n\t1280  GK208 [GeForce GT 635]\n\t1281  GK208 [GeForce GT 710]\n\t1282  GK208 [GeForce GT 640 Rev. 2]\n\t1284  GK208 [GeForce GT 630 Rev. 2]\n\t1286  GK208 [GeForce GT 720]\n\t1287  GK208B [GeForce GT 730]\n\t1288  GK208B [GeForce GT 720]\n\t1289  GK208 [GeForce GT 710]\n\t128b  GK208B [GeForce GT 710]\n\t\t1043 85f7  GT710-SL-1GD5\n\t1290  GK208M [GeForce GT 730M]\n\t\t103c 2afa  GeForce GT 730A\n\t\t103c 2b04  GeForce GT 730A\n\t\t1043 13ad  GeForce GT 730M\n\t\t1043 13cd  GeForce GT 730M\n\t1291  GK208M [GeForce GT 735M]\n\t1292  GK208M [GeForce GT 740M]\n\t\t17aa 3675  GeForce GT 740A\n\t\t17aa 367c  GeForce GT 740A\n\t\t17aa 3684  GeForce GT 740A\n\t1293  GK208M [GeForce GT 730M]\n\t1294  GK208M [GeForce GT 740M]\n\t1295  GK208M [GeForce 710M]\n\t\t103c 2b0d  GeForce 710A\n\t\t103c 2b0f  GeForce 710A\n\t\t103c 2b11  GeForce 710A\n\t\t103c 2b20  GeForce 810A\n\t\t103c 2b21  GeForce 810A\n\t\t103c 2b22  GeForce 810A\n\t\t17aa 367a  GeForce 805A\n\t\t17aa 367c  GeForce 710A\n\t1296  GK208M [GeForce 825M]\n\t1298  GK208M [GeForce GT 720M]\n\t1299  GK208BM [GeForce 920M]\n\t\t17aa 30bb  GeForce 920A\n\t\t17aa 30df  GeForce 920A\n\t\t17aa 36a7  GeForce 920A\n\t\t17aa 36af  GeForce 920M\n\t129a  GK208BM [GeForce 910M]\n\t12a0  GK208\n\t12b9  GK208GLM [Quadro K610M]\n\t12ba  GK208GLM [Quadro K510M]\n\t1340  GM108M [GeForce 830M]\n\t\t103c 2b2b  GeForce 830A\n\t1341  GM108M [GeForce 840M]\n\t\t17aa 3697  GeForce 840A\n\t\t17aa 3699  GeForce 840A\n\t\t17aa 369c  GeForce 840A\n\t1344  GM108M [GeForce 845M]\n\t1346  GM108M [GeForce 930M]\n\t1347  GM108M [GeForce 940M]\n\t1348  GM108M [GeForce 945M / 945A]\n\t1349  GM108M [GeForce 930M]\n\t134b  GM108M [GeForce 940MX]\n\t134d  GM108M [GeForce 940MX]\n\t\t17aa 2248  ThinkPad T570\n\t134e  GM108M [GeForce 930MX]\n\t134f  GM108M [GeForce 920MX]\n\t137a  GM108GLM [Quadro K620M / Quadro M500M]\n\t\t17aa 505a  Quadro M500M\n\t137b  GM108GLM [Quadro M520 Mobile]\n\t137d  GM108M [GeForce 940A]\n\t1380  GM107 [GeForce GTX 750 Ti]\n\t1381  GM107 [GeForce GTX 750]\n\t1382  GM107 [GeForce GTX 745]\n\t1389  GM107GL [GRID M30]\n\t1390  GM107M [GeForce 845M]\n\t1391  GM107M [GeForce GTX 850M]\n\t\t17aa 3697  GeForce GTX 850A\n\t\t17aa a125  GeForce GTX 850A\n\t1392  GM107M [GeForce GTX 860M]\n\t1393  GM107M [GeForce 840M]\n\t1398  GM107M [GeForce 845M]\n\t1399  GM107M [GeForce 945M]\n\t139a  GM107M [GeForce GTX 950M]\n\t\t17aa 362c  GeForce GTX 950A\n\t\t17aa 362f  GeForce GTX 950A\n\t\t17aa 363f  GeForce GTX 950A\n\t\t17aa 3640  GeForce GTX 950A\n\t\t17aa 3647  GeForce GTX 950A\n\t\t17aa 36b9  GeForce GTX 950A\n\t139b  GM107M [GeForce GTX 960M]\n\t\t1028 06e4  XPS 15 9550\n\t\t103c 2b4c  GeForce GTX 960A\n\t139c  GM107M [GeForce 940M]\n\t139d  GM107M [GeForce GTX 750 Ti]\n\t13b0  GM107GLM [Quadro M2000M]\n\t13b1  GM107GLM [Quadro M1000M]\n\t13b2  GM107GLM [Quadro M600M]\n\t13b3  GM107GLM [Quadro K2200M]\n\t13b4  GM107GLM [Quadro M620 Mobile]\n\t13b6  GM107GLM [Quadro M1200 Mobile]\n\t13b9  GM107GL [NVS 810]\n\t13ba  GM107GL [Quadro K2200]\n\t13bb  GM107GL [Quadro K620]\n\t13bc  GM107GL [Quadro K1200]\n\t13bd  GM107GL [Tesla M10]\n\t\t10de 110a  GRID M40\n\t\t10de 1160  Tesla M10\n\t\t10de 11d2  GRID M10-8Q\n\t13c0  GM204 [GeForce GTX 980]\n\t\t1043 8504  GTX980-4GD5\n\t13c1  GM204\n\t13c2  GM204 [GeForce GTX 970]\n\t13c3  GM204\n\t13d7  GM204M [GeForce GTX 980M]\n\t13d8  GM204M [GeForce GTX 970M]\n\t13d9  GM204M [GeForce GTX 965M]\n\t13da  GM204M [GeForce GTX 980 Mobile]\n\t13e7  GM204GL [GeForce GTX 980 Engineering Sample]\n\t13f0  GM204GL [Quadro M5000]\n\t13f1  GM204GL [Quadro M4000]\n\t13f2  GM204GL [Tesla M60]\n\t\t10de 114d  GRID M60-1Q\n\t\t10de 114e  GRID M60-2Q\n\t\t10de 1150  GRID M60-8Q\n\t\t10de 11b0  GRID M60-4A\n\t13f3  GM204GL [Tesla M6]\n\t\t10de 1184  GRID M6-8Q\n\t13f8  GM204GLM [Quadro M5000M / M5000 SE]\n\t13f9  GM204GLM [Quadro M4000M]\n\t13fa  GM204GLM [Quadro M3000M]\n\t\t10de 11c9  Quadro M3000 SE\n\t13fb  GM204GLM [Quadro M5500]\n\t1401  GM206 [GeForce GTX 960]\n\t1402  GM206 [GeForce GTX 950]\n\t1406  GM206 [GeForce GTX 960 OEM]\n\t1407  GM206 [GeForce GTX 750 v2]\n\t1427  GM206M [GeForce GTX 965M]\n\t1430  GM206GL [Quadro M2000]\n\t1431  GM206GL [Tesla M4]\n\t1436  GM206GLM [Quadro M2200 Mobile]\n\t15f0  GP100GL [Quadro GP100]\n\t15f1  GP100GL\n\t15f7  GP100GL [Tesla P100 PCIe 12GB]\n\t15f8  GP100GL [Tesla P100 PCIe 16GB]\n\t15f9  GP100GL [Tesla P100 SXM2 16GB]\n\t1617  GM204M [GeForce GTX 980M]\n\t1618  GM204M [GeForce GTX 970M]\n\t1619  GM204M [GeForce GTX 965M]\n\t161a  GM204M [GeForce GTX 980 Mobile]\n\t1667  GM204M [GeForce GTX 965M]\n\t1725  GP100\n\t172e  GP100\n\t172f  GP100\n\t174d  GM108M [GeForce MX130]\n\t174e  GM108M [GeForce MX110]\n\t1789  GM107GL [GRID M3-3020]\n\t179c  GM107 [GeForce 940MX]\n\t17c2  GM200 [GeForce GTX TITAN X]\n\t17c8  GM200 [GeForce GTX 980 Ti]\n\t17f0  GM200GL [Quadro M6000]\n\t\t10de 1141  VCA 6000\n\t17f1  GM200GL [Quadro M6000 24GB]\n\t17fd  GM200GL [Tesla M40]\n\t1ad6  TU102 USB 3.1 Host Controller\n\t1ad7  TU102 USB Type-C UCSI Controller\n\t1ad8  TU104 USB 3.1 Host Controller\n\t1ad9  TU104 USB Type-C UCSI Controller\n\t1ada  TU106 USB 3.1 Host Controller\n\t\t1043 8673  TURBO-RTX2070-8G\n\t1adb  TU106 USB Type-C UCSI Controller\n\t\t1043 8673  TURBO-RTX2070-8G\n\t1aeb  TU116 High Definition Audio Controller\n\t1b00  GP102 [TITAN X]\n\t1b01  GP102 [GeForce GTX 1080 Ti 10GB]\n\t1b02  GP102 [TITAN Xp]\n\t1b04  GP102\n\t1b06  GP102 [GeForce GTX 1080 Ti]\n\t1b07  GP102 [P102-100]\n\t1b30  GP102GL [Quadro P6000]\n\t1b38  GP102GL [Tesla P40]\n\t1b70  GP102GL\n\t1b78  GP102GL\n\t1b80  GP104 [GeForce GTX 1080]\n\t1b81  GP104 [GeForce GTX 1070]\n\t1b82  GP104 [GeForce GTX 1070 Ti]\n\t1b83  GP104 [GeForce GTX 1060 6GB]\n\t1b84  GP104 [GeForce GTX 1060 3GB]\n\t1b87  GP104 [P104-100]\n\t1ba0  GP104M [GeForce GTX 1080 Mobile]\n\t1ba1  GP104M [GeForce GTX 1070 Mobile]\n\t\t1458 1651  GeForce GTX 1070 Max-Q\n\t\t1462 11e8  GeForce GTX 1070 Max-Q\n\t\t1462 11e9  GeForce GTX 1070 Max-Q\n\t\t1558 9501  GeForce GTX 1070 Max-Q\n\t1ba2  GP104M [GeForce GTX 1070 Mobile]\n\t1ba9  GP104M\n\t1baa  GP104M\n\t1bad  GP104 [GeForce GTX 1070 Engineering Sample]\n\t1bb0  GP104GL [Quadro P5000]\n\t1bb1  GP104GL [Quadro P4000]\n\t1bb3  GP104GL [Tesla P4]\n\t1bb4  GP104GL [Tesla P6]\n\t1bb5  GP104GLM [Quadro P5200 Mobile]\n\t\t103c 842f  P5200 [Zbook 17 G5 mobile workstation]\n\t1bb6  GP104GLM [Quadro P5000 Mobile]\n\t1bb7  GP104GLM [Quadro P4000 Mobile]\n\t\t1462 11e9  Quadro P4000 Max-Q\n\t1bb8  GP104GLM [Quadro P3000 Mobile]\n\t1bb9  GP104GLM [Quadro P4200 Mobile]\n\t\t103c 842f  P4200 [Zbook 17 G5 mobile workstation]\n\t1bbb  GP104GLM [Quadro P3200 Mobile]\n\t\t103c 842f  P3200 [Zbook 17 G5 moble workstation]\n\t1bc7  GP104 [P104-101]\n\t1be0  GP104BM [GeForce GTX 1080 Mobile]\n\t\t1028 07c0  GeForce GTX 1080 Max-Q\n\t\t1458 355b  GeForce GTX 1080 Max-Q\n\t1be1  GP104BM [GeForce GTX 1070 Mobile]\n\t1c00  GP106\n\t1c01  GP106\n\t1c02  GP106 [GeForce GTX 1060 3GB]\n\t1c03  GP106 [GeForce GTX 1060 6GB]\n\t1c04  GP106 [GeForce GTX 1060 5GB]\n\t1c06  GP106 [GeForce GTX 1060 6GB Rev. 2]\n\t1c07  GP106 [P106-100]\n\t1c09  GP106 [P106-090]\n\t1c20  GP106M [GeForce GTX 1060 Mobile]\n\t\t17aa 39b9  GeForce GTX 1060 Max-Q 3GB\n\t1c21  GP106M [GeForce GTX 1050 Ti Mobile]\n\t1c22  GP106M [GeForce GTX 1050 Mobile]\n\t1c23  GP106M [GeForce GTX 1060 Mobile Rev. 2]\n\t\t1414 0020  GTX 1060 Mobile\n\t1c2d  GP106M\n\t1c30  GP106GL [Quadro P2000]\n\t1c31  GP106GL [Quadro P2200]\n\t1c35  GP106\n\t1c60  GP106BM [GeForce GTX 1060 Mobile 6GB]\n\t\t103c 8390  GeForce GTX 1060 Max-Q 6GB\n\t1c61  GP106BM [GeForce GTX 1050 Ti Mobile]\n\t1c62  GP106BM [GeForce GTX 1050 Mobile]\n\t1c70  GP106GL\n\t1c81  GP107 [GeForce GTX 1050]\n\t1c82  GP107 [GeForce GTX 1050 Ti]\n\t1c83  GP107 [GeForce GTX 1050 3GB]\n\t1c8c  GP107M [GeForce GTX 1050 Ti Mobile]\n\t1c8d  GP107M [GeForce GTX 1050 Mobile]\n\t1c8e  GP107M\n\t1c8f  GP107M [GeForce GTX 1050 Ti Max-Q]\n\t1c90  GP107M [GeForce MX150]\n\t1c91  GP107M [GeForce GTX 1050 3 GB Max-Q]\n\t1c92  GP107M [GeForce GTX 1050 Mobile]\n\t1ca7  GP107GL\n\t1ca8  GP107GL\n\t1caa  GP107GL\n\t1cb1  GP107GL [Quadro P1000]\n\t1cb2  GP107GL [Quadro P600]\n\t1cb3  GP107GL [Quadro P400]\n\t1cb6  GP107GL [Quadro P620]\n\t1cba  GP107GLM [Quadro P2000 Mobile]\n\t\t103c 842c  P2000 [Zbook 15 G5 mobile workstation]\n\t\t103c 842f  P2000 [Zbook 17 G5 mobile workstation]\n\t1cbb  GP107GLM [Quadro P1000 Mobile]\n\t\t103c 8429  P1000 [Zbook Studio G5 mobile workstation]\n\t\t103c 842c  P1000 [Zbook 15 G5 mobile workstation]\n\t\t103c 842f  P1000 [Zbook 17 G5 mobile workstation]\n\t\t103c 8451  P1000 [Zbook Studio x360 G5 mobile workstation]\n\t1cbc  GP107GLM [Quadro P600 Mobile]\n\t1cbd  GP107GLM [Quadro P620]\n\t1ccc  GP107BM [GeForce GTX 1050 Ti Mobile]\n\t1ccd  GP107BM [GeForce GTX 1050 Mobile]\n\t1d01  GP108 [GeForce GT 1030]\n\t1d10  GP108M [GeForce MX150]\n\t\t17aa 225e  ThinkPad T480\n\t1d11  GP108M [GeForce MX230]\n\t1d12  GP108M [GeForce MX150]\n\t\t1d72 1701  Mi Notebook Pro [GeForce MX150]\n\t1d13  GP108M [GeForce MX250]\n\t1d33  GP108GLM [Quadro P500 Mobile]\n\t1d34  GP108GLM [Quadro P520]\n\t1d52  GP108BM [GeForce MX250]\n\t1d81  GV100 [TITAN V]\n\t1db1  GV100GL [Tesla V100 SXM2 16GB]\n\t1db2  GV100GL [Tesla V100-DGXS-16GB]\n\t1db3  GV100GL [Tesla V100 FHHL 16GB]\n\t1db4  GV100GL [Tesla V100 PCIe 16GB]\n\t1db5  GV100GL [Tesla V100 SXM2 32GB]\n\t1db6  GV100GL [Tesla V100 PCIe 32GB]\n\t1db7  GV100GL [Tesla V100 DGXS 32GB]\n\t1db8  GV100GL [Tesla V100-SXM3-32GB]\n\t\t10de 131d  Tesla V100-SXM3-32GB-H\n\t1dba  GV100GL [Quadro GV100]\n\t\t10de 12eb  TITAN V CEO Edition\n\t1df5  GV100GL [Tesla V100-SXM2-16GB]\n\t1df6  GV100GL [Tesla V100S-PCIE-32GB]\n\t1e02  TU102 [TITAN RTX]\n\t1e04  TU102 [GeForce RTX 2080 Ti]\n\t1e07  TU102 [GeForce RTX 2080 Ti Rev. A]\n\t\t1462 3715  RTX 2080 Ti GAMING X TRIO\n\t1e2d  TU102B\n\t1e2e  TU102B\n\t1e30  TU102GL [Quadro RTX 6000/8000]\n\t\t10de 129e  Quadro RTX 8000\n\t\t10de 12ba  Quadro RTX 6000\n\t1e38  TU102GL\n\t1e3c  TU102GL\n\t1e3d  TU102GL\n\t1e3e  TU102GL\n\t1e78  TU102GL [Quadro RTX 6000/8000]\n\t\t10de 13d8  Quadro RTX 8000\n\t\t10de 13d9  Quadro RTX 6000\n\t1e81  TU104 [GeForce RTX 2080 SUPER]\n\t1e82  TU104 [GeForce RTX 2080]\n\t1e84  TU104 [GeForce RTX 2070 SUPER]\n\t1e87  TU104 [GeForce RTX 2080 Rev. A]\n\t1e89  TU104 [GeForce RTX 2060]\n\t1e90  TU104M [GeForce RTX 2080 Mobile]\n\t1eab  TU104M\n\t1eae  TU104M\n\t1eb0  TU104GL [Quadro RTX 5000]\n\t1eb1  TU104GL [Quadro RTX 4000]\n\t1eb5  TU104GLM [Quadro RTX 5000 Mobile / Max-Q]\n\t1eb6  TU104GLM [Quadro RTX 4000 Mobile / Max-Q]\n\t1eb8  TU104GL [Tesla T4]\n\t1eb9  TU104GL\n\t1ebe  TU104GL\n\t1ec2  TU104 [GeForce RTX 2070 SUPER]\n\t1ec7  TU104 [GeForce RTX 2070 SUPER]\n\t1ed0  TU104BM [GeForce RTX 2080 Mobile]\n\t1f02  TU106 [GeForce RTX 2070]\n\t\t1043 8673  TURBO RTX 2070\n\t1f04  TU106\n\t1f06  TU106 [GeForce RTX 2060 SUPER]\n\t1f07  TU106 [GeForce RTX 2070 Rev. A]\n\t1f08  TU106 [GeForce RTX 2060 Rev. A]\n\t1f10  TU106M [GeForce RTX 2070 Mobile]\n\t1f11  TU106M [GeForce RTX 2060 Mobile]\n\t1f2e  TU106M\n\t1f36  TU106GLM [Quadro RTX 3000 Mobile / Max-Q]\n\t1f42  TU106 [GeForce RTX 2060 SUPER]\n\t1f47  TU106 [GeForce RTX 2060 SUPER]\n\t1f50  TU106BM [GeForce RTX 2070 Mobile]\n\t1f51  TU106BM [GeForce RTX 2060 Mobile]\n\t1f81  TU117\n\t1f82  TU117 [GeForce GTX 1650]\n\t1f91  TU117M [GeForce GTX 1650 Mobile / Max-Q]\n\t1f92  TU117M [GeForce GTX 1650 Mobile]\n\t1f96  TU117M [GeForce GTX 1650 Mobile / Max-Q]\n\t1fae  TU117GL\n\t1fb8  TU117GLM [Quadro T2000 Mobile / Max-Q]\n\t1fb9  TU117GLM [Quadro T1000 Mobile]\n\t1fbf  TU117GL\n\t2182  TU116 [GeForce GTX 1660 Ti]\n\t2183  TU116\n\t2184  TU116 [GeForce GTX 1660]\n\t2191  TU116M [GeForce GTX 1660 Ti Mobile]\n\t21ae  TU116GL\n\t21bf  TU116GL\n\t21c4  TU116 [GeForce GTX 1660 SUPER]\n\t21d1  TU116BM [GeForce GTX 1660 Ti Mobile]\n10df  Emulex Corporation\n\t0720  OneConnect NIC (Skyhawk)\n\t\t103c 1934  FlexFabric 20Gb 2-port 650M Adapter\n\t\t103c 1935  FlexFabric 20Gb 2-port 650FLB Adapter\n\t\t103c 21d4  StoreFabric CN1200E 10Gb Converged Network Adapter\n\t\t103c 220a  FlexFabric 10Gb 2-port 556FLR-SFP+ Adapter\n\t\t103c 803f  Ethernet 10Gb 2-port 557SFP+ Adapter\n\t\t103c 8144  FlexFabric 10GB 2-port 556FLR-T Adapter\n\t\t17aa 1056  ThinkServer OCm14102-UX-L AnyFabric\n\t\t17aa 1057  ThinkServer OCm14104-UX-L AnyFabric\n\t\t17aa 1059  ThinkServer OCm14104-UT-L AnyFabric\n\t\t17aa 4014  ThinkServer OCm14102-NX-L AnyFabric\n\t0722  OneConnect iSCSI Initiator (Skyhawk)\n\t0723  OneConnect iSCSI Initiator + Target (Skyhawk)\n\t0724  OneConnect FCoE Initiator (Skyhawk)\n\t0728  OneConnect NIC (Skyhawk-VF)\n\t072a  OneConnect iSCSI Initiator (Skyhawk-VF)\n\t072b  OneConnect iSCSI Initiator + Target (Skyhawk-VF)\n\t072c  OneConnect FCoE Initiator (Skyhawk-VF)\n\t1ae5  LP6000 Fibre Channel Host Adapter\n\te100  Proteus-X: LightPulse IOV Fibre Channel Host Adapter\n\te131  LightPulse 8Gb/s PCIe Shared I/O Fibre Channel Adapter\n\te180  Proteus-X: LightPulse IOV Fibre Channel Host Adapter\n\te200  LPe15000/LPe16000 Series 8Gb/16Gb Fibre Channel Adapter\n\t\t1014 03f1  PCIe2 2-Port 16Gb Fibre Channel Adapter for POWER (FC EL5B; CCIN 577F)\n\t\t1014 04e3  PCIe3 4-Port 10GbE SR Adapter for POWER (FC EN15/EN16; CCIN 2CE3)\n\t\t1014 04e4  PCIe3 4-Port 10GbE SFP+ Adapter for POWER (FC EN18; CCIN 2CE4)\n\t\t10df e280  LPe16002B-M6 2-Port 16Gb Fibre Channel Adapter\n\t\t10df e281  LPe16000B-M6 1-Port 16Gb Fibre Channel Adapter\n\t\t10df e282  Flex System FC5054 4-port 16Gb FC Adapter\n\te208  LightPulse 16Gb Fibre Channel Host Adapter (Lancer-VF)\n\te220  OneConnect NIC (Lancer)\n\t\t17aa 1054  ThinkServer LPm16002B-M6-L AnyFabric\n\t\t17aa 1055  ThinkServer LPm16004B-M8-L AnyFabric\n\te240  OneConnect iSCSI Initiator (Lancer)\n\te260  OneConnect FCoE Initiator (Lancer)\n\te268  OneConnect 10Gb FCoE Converged Network Adapter (Lancer-VF)\n\te300  LPe31000/LPe32000 Series 16Gb/32Gb Fibre Channel Adapter\n\t\t1014 0614  PCIe3 4-Port 16Gb Fibre Channel Adapter for POWER (FC EN1C/EN1D; CCIN 578E)\n\t\t1014 0615  PCIe3 2-Port 32Gb Fibre Channel Adapter for POWER (FC EN1A/EN1B; CCIN 578F)\n\t\t10df e300  LPe32002-M2 2-Port 32Gb Fibre Channel Adapter\n\t\t10df e301  LPe32000-M2 1-Port 32Gb Fibre Channel Adapter\n\t\t10df e310  LPe31002-M6 2-Port 16Gb Fibre Channel Adapter\n\t\t10df e311  LPe31000-M6 1-Port 16Gb Fibre Channel Adapter\n\t\t10df e312  LPe31004-M6 4-Port 16Gb Fibre Channel Adapter\n\t\t10df e320  LPe32002-M2-D 2-Port 32Gb Fibre Channel Adapter\n\t\t10df e321  LPe32000-M2-D 1-Port 32Gb Fibre Channel Adapter\n\t\t10df e322  LPe31002-M6-D 2-Port 16Gb Fibre Channel Adapter\n\t\t10df e323  LPe31000-M6-D 1-Port 16Gb Fibre Channel Adapter\n\t\t10df e324  LPm32002-D 2-Port 32Gb Fibre Channel Mezz Card\n\t\t10df e325  LPm31002-D 2-Port 16Gb Fibre Channel Mezz Card\n\t\t10df e330  LPe32002-M2-L 2-Port 32Gb PCIe Fibre Channel Adapter\n\t\t10df e331  LPe32000-M2-L 1-Port 32Gb PCIe Fibre Channel Adapter\n\t\t10df e332  LPe31002-M6-L 2-Port 16Gb PCIe Fibre Channel Adapter\n\t\t10df e333  LPe31000-M6-L 1-Port 16Gb PCIe Fibre Channel Adapter\n\t\t1590 0201  StoreFabric SN1600E 1-Port 32Gb Fibre Channel Adapter\n\t\t1590 0202  StoreFabric SN1600E 2-Port 32Gb Fibre Channel Adapter\n\t\t1590 0213  StoreFabric SN1200E 1-Port 16Gb Fibre Channel Adapter\n\t\t1590 0214  StoreFabric SN1200E 2-Port 16Gb Fibre Channel Adapter\n\t\t1590 022e  Synergy 5330C 2-Port 32Gb Fibre Channel Mezz Card\n\tf011  Saturn: LightPulse Fibre Channel Host Adapter\n\tf015  Saturn: LightPulse Fibre Channel Host Adapter\n\tf085  LP850 Fibre Channel Host Adapter\n\tf095  LP952 Fibre Channel Host Adapter\n\tf098  LP982 Fibre Channel Host Adapter\n\tf0a1  Thor LightPulse Fibre Channel Host Adapter\n\tf0a5  Thor LightPulse Fibre Channel Host Adapter\n\tf0b5  Viper LightPulse Fibre Channel Host Adapter\n\tf0d1  Helios LightPulse Fibre Channel Host Adapter\n\tf0d5  Helios LightPulse Fibre Channel Host Adapter\n\tf0e1  Zephyr LightPulse Fibre Channel Host Adapter\n\tf0e5  Zephyr LightPulse Fibre Channel Host Adapter\n\tf0f5  Neptune LightPulse Fibre Channel Host Adapter\n\tf100  LPe12000 Series 8Gb Fibre Channel Adapter\n\t\t1014 038a  8Gb PCI Express Dual Port FC Adapter for POWER\n\t\t103c 3282  8Gb Dual-port PCI-e FC HBA\n\t\t10df f140  LPe12000-M8-L 1-Port 8Gb PCIe Fibre Channel Adapter\n\t\t10df f141  LPe12002-M8-L 2-Port 8Gb PCIe Fibre Channel Adapter\n\tf111  Saturn-X LightPulse Fibre Channel Host Adapter\n\tf112  Saturn-X LightPulse Fibre Channel Host Adapter\n\tf180  LPSe12002 EmulexSecure Fibre Channel Adapter\n\tf400  LPe35000/LPe36000 Series 32Gb/64Gb Fibre Channel Adapter\n\t\t10df f401  LPe35000-M2 1-Port 32Gb Fibre Channel Adapter\n\t\t10df f402  LPe35002-M2 2-Port 32Gb Fibre Channel Adapter\n\t\t10df f403  LPe36000-M64 1-Port 64Gb Fibre Channel Adapter\n\t\t10df f404  LPe36002-M64 2-Port 64Gb Fibre Channel Adapter\n\t\t10df f405  LPe35004-M2 4-Port 32Gb Fibre Channel Adapter\n\t\t10df f406  LPe35004-X6 4-Port Fibre Channel Adapter\n\t\t10df f410  LPe35002-M2-D 2-Port 32Gb Fibre Channel Adapter\n\t\t10df f411  LPe35000-M2-D 1-Port 32Gb Fibre Channel Adapter\n\t\t10df f418  LPe35000-M2-L 1-Port 32Gb PCIe Fibre Channel Adapter\n\t\t10df f419  LPe35002-M2-L 2-Port 32Gb PCIe Fibre Channel Adapter\n\t\t1590 02d5  StoreFabric SN1610E 1-Port 32Gb Fibre Channel Adapter\n\t\t1590 02d6  StoreFabric SN1610E 2-Port 32Gb Fibre Channel Adapter\n\tf700  LP7000 Fibre Channel Host Adapter\n\tf701  LP7000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2)\n\tf800  LP8000 Fibre Channel Host Adapter\n\tf801  LP8000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2)\n\tf900  LP9000 Fibre Channel Host Adapter\n\tf901  LP9000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2)\n\tf980  LP9802 Fibre Channel Host Adapter\n\tf981  LP9802 Fibre Channel Host Adapter Alternate ID\n\tf982  LP9802 Fibre Channel Host Adapter Alternate ID\n\tfa00  Thor-X LightPulse Fibre Channel Host Adapter\n\tfb00  Viper LightPulse Fibre Channel Host Adapter\n\tfc00  Thor-X LightPulse Fibre Channel Host Adapter\n\t\t10df fc00  LP10000 LightPulse Fibre Channel Host Adapter\n\tfc10  Helios-X LightPulse Fibre Channel Host Adapter\n\tfc20  Zephyr-X LightPulse Fibre Channel Host Adapter\n\tfc40  Saturn-X: LightPulse Fibre Channel Host Adapter\n\tfc50  Proteus-X: LightPulse IOV Fibre Channel Host Adapter\n\tfd00  Helios-X LightPulse Fibre Channel Host Adapter\n# Also IBM FC 5759 / FC 1910 for POWER\n\t\t10df fd02  LightPulse LP11002 Dual-port 4Gigabit PCI Fibre Channel Adapter\n\tfd11  Helios-X LightPulse Fibre Channel Host Adapter\n\tfd12  Helios-X LightPulse Fibre Channel Host Adapter\n\tfe00  Zephyr-X LightPulse Fibre Channel Host Adapter\n\tfe05  Zephyr-X: LightPulse FCoE Adapter\n\tfe11  Zephyr-X LightPulse Fibre Channel Host Adapter\n\tfe12  Zephyr-X LightPulse FCoE Adapter\n\tff00  Neptune LightPulse Fibre Channel Host Adapter\n10e0  Integrated Micro Solutions Inc.\n\t5026  IMS5026/27/28\n\t5027  IMS5027\n\t5028  IMS5028\n\t8849  IMS8849\n\t8853  IMS8853\n\t9128  IMS9128 [Twin turbo 128]\n10e1  Tekram Technology Co.,Ltd.\n\t0391  TRM-S1040\n\t\t10e1 0391  DC-315U SCSI-3 Host Adapter\n\t690c  DC-690c\n\tdc29  DC-290\n10e2  Aptix Corporation\n10e3  Tundra Semiconductor Corp.\n\t0000  CA91C042 [Universe]\n\t0108  Tsi108 Host Bridge for Single PowerPC\n\t0148  Tsi148 [Tempe]\n\t\t1775 1100  VR11 Single Board Computer\n\t0860  CA91C860 [QSpan]\n\t0862  CA91C862A [QSpan-II]\n\t8111  Tsi381 PCIe to PCI Bridge\n\t8260  CA91L8200B [Dual PCI PowerSpan II]\n\t8261  CA91L8260B [Single PCI PowerSpan II]\n\ta108  Tsi109 Host Bridge for Dual PowerPC\n10e4  Tandem Computers\n\t8029  Realtek 8029 Network Card\n10e5  Micro Industries Corporation\n10e6  Gainbery Computer Products Inc.\n10e7  Vadem\n10e8  Applied Micro Circuits Corp.\n\t1072  INES GPIB-PCI (AMCC5920 based)\n\t2011  Q-Motion Video Capture/Edit board\n\t4750  S5930 [Matchmaker]\n\t5920  S5920\n\t8043  LANai4.x [Myrinet LANai interface chip]\n\t8062  S5933_PARASTATION\n\t807d  S5933 [Matchmaker]\n\t8088  Kongsberg Spacetec Format Synchronizer\n\t8089  Kongsberg Spacetec Serial Output Board\n\t809c  S5933_HEPC3\n\t80b9  Harmonix Hi-Card P8 (4x active ISDN BRI)\n\t80d7  PCI-9112\n\t80d8  PCI-7200\n\t80d9  PCI-9118\n\t80da  PCI-9812\n\t80fc  APCI1500 Signal processing controller (16 dig. inputs + 16 dig. outputs)\n\t811a  PCI-IEEE1355-DS-DE Interface\n\t814c  Fastcom ESCC-PCI (Commtech, Inc.)\n\t8170  S5933 [Matchmaker] (Chipset Development Tool)\n\t81e6  Multimedia video controller\n\t828d  APCI3001 Signal processing controller (up to 16 analog inputs)\n\t8291  Fastcom 232/8-PCI (Commtech, Inc.)\n\t82c4  Fastcom 422/4-PCI (Commtech, Inc.)\n\t82c5  Fastcom 422/2-PCI (Commtech, Inc.)\n\t82c6  Fastcom IG422/1-PCI (Commtech, Inc.)\n\t82c7  Fastcom IG232/2-PCI (Commtech, Inc.)\n\t82ca  Fastcom 232/4-PCI (Commtech, Inc.)\n\t82db  AJA HDNTV HD SDI Framestore\n\t82e2  Fastcom DIO24H-PCI (Commtech, Inc.)\n\t8406  PCIcanx/PCIcan CAN interface [Kvaser AB]\n\t8407  PCIcan II CAN interface (A1021, PCB-07, PCB-08) [Kvaser AB]\n\t8851  S5933 on Innes Corp FM Radio Capture card\n\te004  X-Gene PCIe bridge\n10e9  Alps Electric Co., Ltd.\n10ea  Integraphics\n\t1680  IGA-1680\n\t1682  IGA-1682\n\t1683  IGA-1683\n\t2000  CyberPro 2000\n\t2010  CyberPro 2000A\n\t5000  CyberPro 5000\n\t5050  CyberPro 5050\n\t5202  CyberPro 5202\n# CyberPro5202 Audio Function\n\t5252  CyberPro5252\n10eb  Artists Graphics\n\t0101  3GA\n\t8111  Twist3 Frame Grabber\n10ec  Realtek Semiconductor Co., Ltd.\n\t0139  RTL-8139/8139C/8139C+ Ethernet Controller\n\t5208  RTS5208 PCI Express Card Reader\n\t5209  RTS5209 PCI Express Card Reader\n\t5227  RTS5227 PCI Express Card Reader\n\t\t17aa 220e  ThinkPad T440p\n\t\t17aa 2214  ThinkPad X240\n\t5229  RTS5229 PCI Express Card Reader\n\t\t1025 0813  Aspire R7-571\n\t\t103c 194e  ProBook 455 G1 Notebook\n\t\t103c 1985  Pavilion 17-e163sg Notebook PC\n\t\t17aa 3832  Yoga 520\n\t522a  RTS522A PCI Express Card Reader\n\t\t103c 8079  EliteBook 840 G3\n\t5249  RTS5249 PCI Express Card Reader\n\t\t103c 1909  ZBook 15\n\t524a  RTS524A PCI Express Card Reader\n\t5250  RTS5250 PCI Express Card Reader\n\t525a  RTS525A PCI Express Card Reader\n\t\t1028 06dc  Latitude E7470\n\t\t1028 06e4  XPS 15 9550\n\t\t17aa 224f  ThinkPad X1 Carbon 5th Gen\n\t5260  RTS5260 PCI Express Card Reader\n\t5286  RTS5286 PCI Express Card Reader\n\t5287  RTL8411B PCI Express Card Reader\n\t5288  RTS5288 PCI Express Card Reader\n\t5289  RTL8411 PCI Express Card Reader\n\t\t1043 1457  K55A Laptop\n\t8029  RTL-8029(AS)\n\t\t10b8 2011  EZ-Card (SMC1208)\n\t\t10ec 8029  RTL-8029(AS)\n\t\t1113 1208  EN1208\n\t\t1186 0300  DE-528\n\t\t1259 2400  AT-2400\n\t\t1af4 1100  QEMU Virtual Machine\n\t8125  RTL8125 2.5GbE Controller\n\t8129  RTL-8129\n\t\t10ec 8129  RT8129 Fast Ethernet Adapter\n\t\t11ec 8129  RTL8111/8168 PCIe Gigabit Ethernet (misconfigured)\n\t8136  RTL810xE PCI Express Fast Ethernet controller\n\t\t103c 1985  RTL8106E on Pavilion 17-e163sg Notebook PC\n\t\t103c 2a8c  Compaq 500B Microtower\n\t\t103c 2ab1  Pavilion p6774\n\t\t103c 30cc  Pavilion dv6700\n\t\t1179 ff64  RTL8102E PCI-E Fast Ethernet NIC\n\t\t17c0 1053  RTL8101e Medion WIM 2210 Notebook PC [MD96850]\n\t8137  RTL8104E PCIe Fast Ethernet Controller\n\t8138  RT8139 (B/C) Cardbus Fast Ethernet Adapter\n\t\t10ec 8138  RT8139 (B/C) Fast Ethernet Adapter\n\t8139  RTL-8100/8101L/8139 PCI Fast Ethernet Adapter\n\t\t0357 000a  TTP-Monitoring Card V2.0\n\t\t1025 005a  TravelMate 290\n\t\t1025 8920  ALN-325\n\t\t1025 8921  ALN-325\n\t\t103c 006a  NX9500\n\t\t103c 2a20  Pavilion t3030.de Desktop PC\n\t\t103c 30d9  Presario C700\n\t\t1043 1045  L8400B or L3C/S notebook\n\t\t1043 8109  P5P800-MX Mainboard\n\t\t1071 8160  MIM2000\n\t\t10bd 0320  EP-320X-R\n\t\t10ec 8139  RTL-8100/8101L/8139 PCI Fast Ethernet Adapter\n\t\t10f7 8338  Panasonic CF-Y5 laptop\n\t\t1113 ec01  LevelOne FNC-0107TX/FNC-0109TX\n\t\t1186 1104  DFE-520TX Fast Ethernet PCI Adapter (rev. D1)\n\t\t1186 1300  DFE-538TX\n\t\t1186 1320  SN5200\n\t\t1186 8139  DRN-32TX\n\t\t11f6 8139  FN22-3(A) LinxPRO Ethernet Adapter\n\t\t1259 2500  AT-2500TX\n\t\t1259 2503  AT-2500TX/ACPI\n\t\t1385 f31d  FA311 v2\n\t\t1395 2100  AMB2100\n\t\t1429 d010  ND010/ND012\n\t\t1432 9130  EN-9130TX\n\t\t1436 8139  RT8139\n\t\t144d c00c  P30/P35 notebook\n\t\t1458 e000  GA-7VM400M/7VT600 Motherboard\n\t\t1462 0131  MS-1013 Notebook\n\t\t1462 217c  Aspire L250\n\t\t1462 788c  865PE Neo2-V Mainboard\n\t\t146c 1439  FE-1439TX\n\t\t1489 6001  GF100TXRII\n\t\t1489 6002  GF100TXRA\n\t\t149c 139a  LFE-8139ATX\n\t\t149c 8139  LFE-8139TX\n\t\t14cb 0200  LNR-100 Family 10/100 Base-TX Ethernet\n\t\t1565 2300  P4TSV Onboard LAN (RTL8100B)\n\t\t1631 7003  Onboard RTL8111 on GA-8SIML Rev1.0 Mainboard\n\t\t1695 9001  Onboard RTL8101L 10/100 MBit\n\t\t16ec 00ff  USR997900A\n\t\t1799 5000  F5D5000 PCI Card/Desktop Network PCI Card\n\t\t1799 5010  F5D5010 CardBus Notebook Network Card\n\t\t187e 3303  FN312\n\t\t1904 8139  RTL8139D Fast Ethernet Adapter\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t2646 0001  KNE120TX\n\t\t8e2e 7000  KF-230TX\n\t\t8e2e 7100  KF-230TX/2\n\t\ta0a0 0007  ALN-325C\n\t8167  RTL-8110SC/8169SC Gigabit Ethernet\n\t\t105b 0e10  RTL-8110SC-GR on a N15235/A74MX mainboard\n\t\t1458 e000  GA-MA69G-S3H Motherboard\n\t\t1462 235c  P965 Neo MS-7235 mainboard\n\t\t1462 236c  945P Neo3-F motherboard\n\t8168  RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller\n\t\t1019 8168  RTL8111/8168 PCI Express Gigabit Ethernet controller\n\t\t1028 0283  Vostro 220\n\t\t1028 04b2  Vostro 3350\n\t\t1028 04da  Vostro 3750\n\t\t1028 06f2  Latitude 3470\n\t\t1028 06f3  Latitude 3570\n\t\t103c 1611  Pavilion DM1Z-3000\n\t\t103c 1950  ProBook 450/455\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t103c 8615  Pavilion Laptop 15-cw1xxx\n\t\t1043 11f5  Notebook motherboard (one of many models)\n\t\t1043 16d5  U6V/U31J laptop\n\t\t1043 81aa  P5B\n\t\t1043 82c6  M3A78 Series Motherboard\n\t\t1043 83a3  M4A785/P7P55 Motherboard\n\t\t1043 8432  P8P67 and other motherboards\n\t\t1043 8505  P8 series motherboard\n\t\t105b 0d7c  D270S/D250S Motherboard\n\t\t10ec 8168  RTL8111/8168 PCI Express Gigabit Ethernet controller\n\t\t144d c652  RTL8168 on a NP300E5C series laptop\n\t\t1458 e000  Onboard Ethernet\n\t\t1462 238c  Onboard RTL8111b on MSI P965 Platinum Mainboard\n\t\t1462 345c  RTL8111B on MS-7345 Motherboard\n\t\t1462 368c  K9AG Neo2\n\t\t1462 4180  Wind PC MS-7418\n\t\t1462 7522  X58 Pro-E\n\t\t1775 11cc  CC11/CL11\n\t\t1849 8168  Motherboard (one of many)\n\t\t7470 3468  TG-3468 Gigabit PCI Express Network Adapter\n\t\t8086 2055  NUC Kit DN2820FYKH\n\t\t8086 d615  Desktop Board D510MO/D525MW\n\t8169  RTL8169 PCI Gigabit Ethernet Controller\n\t\t1025 0079  Aspire 5024WLMi\n\t\t10bd 3202  EP-320G-TX1 32-bit PCI Gigabit Ethernet Adapter\n\t\t10ec 8169  RTL8169/8110 Family PCI Gigabit Ethernet NIC\n\t\t1259 c107  CG-LAPCIGT\n\t\t1371 434e  ProG-2000L\n\t\t1385 311a  GA311\n\t\t1385 5200  GA511 Gigabit PC Card\n\t\t1458 e000  GA-8I915ME-G Mainboard\n\t\t1462 030c  K8N Neo-FSR v2.0 mainboard\n\t\t1462 065c  Hetis 865GV-E (MS-7065)\n\t\t1462 702c  K8T NEO 2 motherboard\n\t\t1462 7094  K8T Neo2-F V2.0\n\t\t16ec 011f  USR997903\n\t\t1734 1091  D2030-A1\n\t\ta0a0 0449  AK86-L motherboard\n\t8171  RTL8191SEvA Wireless LAN Controller\n\t8172  RTL8191SEvB Wireless LAN Controller\n\t8173  RTL8192SE Wireless LAN Controller\n\t8174  RTL8192SE Wireless LAN Controller\n\t8176  RTL8188CE 802.11b/g/n WiFi Adapter\n\t\t1043 84b5  PCE-N10\n\t\t1a3b 1139  AW-NE139H Half-size Mini PCIe Card\n\t8177  RTL8191CE PCIe Wireless Network Adapter\n\t8178  RTL8192CE PCIe Wireless Network Adapter\n\t8179  RTL8188EE Wireless Network Adapter\n\t\t103c 197d  RTL8188EE mini-PCIe card\n\t8180  RTL8180L 802.11b MAC\n\t\t1385 4700  MA521 802.11b Wireless PC Card\n\t\t1737 0019  WPC11v4 802.11b Wireless-B Notebook Adapter\n\t8185  RTL-8185 IEEE 802.11a/b/g Wireless LAN Controller\n\t818b  RTL8192EE PCIe Wireless Network Adapter\n\t8190  RTL8190 802.11n PCI Wireless Network Adapter\n\t8191  RTL8192CE PCIe Wireless Network Adapter\n\t8192  RTL8192E/RTL8192SE Wireless LAN Controller\n\t8193  RTL8192DE Wireless LAN Controller\n\t8196  RTL8196 Integrated PCI-e Bridge\n\t8197  SmartLAN56 56K Modem\n\t8199  RTL8187SE Wireless LAN Controller\n\t\t1462 6894  MN54G2 / MS-6894 Wireless Mini PCIe Card\n\t8723  RTL8723AE PCIe Wireless Network Adapter\n\t8812  RTL8812AE 802.11ac PCIe Wireless Network Adapter\n\t8813  RTL8813AE 802.11ac PCIe Wireless Network Adapter\n\t8821  RTL8821AE 802.11ac PCIe Wireless Network Adapter\n\tb723  RTL8723BE PCIe Wireless Network Adapter\n\t\t10ec 8739  Dell Wireless 1801\n\tb822  RTL8822BE 802.11a/b/g/n/ac WiFi adapter\n\t\t103c 831b  Realtek RTL8822BE 802.11ac 2 × 2 Wi-Fi + Bluetooth 4.2 Combo Adapter (MU-MIMO supported)\n\tc821  RTL8821CE 802.11ac PCIe Wireless Network Adapter\n\td723  RTL8723DE 802.11b/g/n PCIe Adapter\n10ed  Ascii Corporation\n\t7310  V7310\n10ee  Xilinx Corporation\n\t0001  EUROCOM for PCI (ECOMP)\n\t0002  Octal E1/T1 for PCI ETP Card\n\t0007  Default PCIe endpoint ID\n\t0205  Wildcard TE205P\n\t0210  Wildcard TE210P\n\t0300  Spartan 3 Designs (Xilinx IP)\n\t0314  Wildcard TE405P/TE410P (1st Gen)\n\t0405  Wildcard TE405P (2nd Gen)\n\t0410  Wildcard TE410P (2nd Gen)\n\t0600  Xilinx 6 Designs (Xilinx IP)\n\t3fc0  RME Digi96\n\t3fc1  RME Digi96/8\n\t3fc2  RME Digi96/8 Pro\n\t3fc3  RME Digi96/8 Pad\n\t3fc4  RME Digi9652 (Hammerfall)\n\t3fc5  RME Hammerfall DSP\n\t3fc6  RME Hammerfall DSP MADI\n\t7038  FPGA Card XC7VX690T\n\t\t17aa 402f  FPGA XC7VX690T-3FFG1157E\n\t8380  Ellips ProfiXpress Profibus Master\n\t8381  Ellips Santos Frame Grabber\n\td154  Copley Controls CAN card (PCI-CAN-02)\n# SED is assigned Xilinx PCI device IDs ebf0 through ebff\n\tebf0  SED Systems Modulator/Demodulator\n\tebf1  SED Systems Audio Interface Card\n\tebf2  SED Systems Common PCI Interface\n\tebf3  SED Systems PCIe-AXI Bridge\n10ef  Racore Computer Products, Inc.\n\t8154  M815x Token Ring Adapter\n10f0  Peritek Corporation\n10f1  Tyan Computer\n\t2865  Tyan Thunder K8E S2865\n\t5300  Tyan S5380 Mainboard\n10f2  Achme Computer, Inc.\n10f3  Alaris, Inc.\n10f4  S-MOS Systems, Inc.\n10f5  NKK Corporation\n\ta001  NDR4000 [NR4600 Bridge]\n10f6  Creative Electronic Systems SA\n10f7  Matsushita Electric Industrial Co., Ltd.\n10f8  Altos India Ltd\n10f9  PC Direct\n10fa  Truevision\n\t000c  TARGA 1000\n10fb  Thesys Gesellschaft fuer Mikroelektronik mbH\n\t186f  TH 6255\n10fc  I-O Data Device, Inc.\n# What's in the cardbus end of a Sony ACR-A01 card, comes with newer Vaio CD-RW drives\n\t0003  Cardbus IDE Controller\n\t0005  Cardbus SCSI CBSC II\n10fd  Soyo Computer, Inc\n10fe  Fast Multimedia AG\n10ff  NCube\n1100  Jazz Multimedia\n1101  Initio Corporation\n\t0002  INI-920 Ultra SCSI Adapter\n\t1060  INI-A100U2W\n\t1622  INI-1623 PCI SATA-II Controller\n\t9100  INI-9100/9100W\n\t9400  INI-940 Fast Wide SCSI Adapter\n\t9401  INI-935 Fast Wide SCSI Adapter\n\t9500  INI-950 SCSI Adapter\n\t9502  INI-950P Ultra Wide SCSI Adapter\n1102  Creative Labs\n\t0002  EMU10k1 [Sound Blaster Live! Series]\n\t\t100a 1102  SB Live! 5.1 Digital OEM SB0220 EMU10K1-JFF\n\t\t1102 0020  CT4670/4850 SBLive! Value\n\t\t1102 0021  CT4620 SBLive!\n\t\t1102 002f  M002/M003 Integrated SBLive!\n\t\t1102 100a  SB0220/0229 SBLive! 5.1 Digital OEM\n\t\t1102 4001  E-mu APS\n\t\t1102 8022  CT4780 SBLive! Value\n\t\t1102 8023  CT4790 SoundBlaster PCI512\n\t\t1102 8024  CT4760 SBLive!\n\t\t1102 8025  CT1140/SB0040 Integrated SBLive!\n\t\t1102 8026  CT4830 SBLive! Value\n\t\t1102 8027  CT4832 SBLive! Value\n\t\t1102 8028  CT4870 SBLive! Value\n\t\t1102 8029  CT4872 SBLive! Value\n\t\t1102 802a  CT4890 SoundBlaster PCI256\n\t\t1102 802b  CT4891 SoundBlaster PCI256\n\t\t1102 8031  CT4831 SBLive! Value\n\t\t1102 8032  CT4871 SBLive! Value\n\t\t1102 8033  CT4893 SoundBlaster PCI256\n\t\t1102 8035  CT0060 SBLive!\n\t\t1102 8040  CT4760 SBLive!\n\t\t1102 8050  CT4750 SoundBlaster PCI512\n\t\t1102 8051  CT4850 SBLive! Value\n\t\t1102 8061  SB060 SBLive! Player 5.1\n\t\t1102 8062  SB0100 SBLive! 5.1\n\t\t1102 8063  DXW Integrated SBLive! 5.1\n\t\t1102 8064  SB0100/SB0102 SBLive! 5.1\n\t\t1102 8065  SB0220/0222 SBLive! 5.1 Digital\n\t\t1102 8066  SB0228 SBLive! 5.1 Digital\n\t\t1102 8067  SB0220 SBLive! 5.1\n\t\t1102 8068  CT0061 SBLive!\n\t\t1102 8069  SB0101 SBLive! 5.1 Value\n\t\t1102 806a  SB0103 SBLive! 5.1\n\t\t1102 806b  SB0105 SBLive! 5.1\n\t\t1102 806c  SB0221 SBLive! 5.1\n\t\t1102 8071  SB0150 SoundBlaster PCI512\n# EMU8008 PCI version of emu8000 chip\n\t0003  SB AWE64(D)\n\t0004  EMU10k2/CA0100/CA0102/CA10200 [Sound Blaster Audigy Series]\n\t\t1102 0040  SB0090 Audigy Player\n# Probably an early engineering sample\n\t\t1102 0041  CT4820 SBLive!2\n\t\t1102 0042  CT0070 Audigy\n\t\t1102 0043  CT0072 Audigy\n\t\t1102 0051  SB0090 Audigy Player/Platinum (EX)\n\t\t1102 0052  SB0162 Audigy ES\n\t\t1102 0053  CT0090/SB0092 Audigy Player/OEM\n\t\t1102 0054  SB0161 Audigy ES\n\t\t1102 0055  SB0192 Audigy\n\t\t1102 0056  SB0191 Audigy\n\t\t1102 0057  SB0091 Audigy\n\t\t1102 0058  SB0095 Audigy Player/OEM\n\t\t1102 0059  SB0230 Audigy\n\t\t1102 005a  SB0231 Audigy\n\t\t1102 005b  SB0232 Audigy\n\t\t1102 005c  SB0238 Audigy\n\t\t1102 1002  SB0240 Audigy 2 Platinum 6.1\n\t\t1102 1003  SB0350 Audigy 2 / SB0243 Audigy 2 OEM\n\t\t1102 1004  SB0242 Audigy 2\n\t\t1102 1005  SB0280 Audigy 2 Platinum Ex\n\t\t1102 1006  SB0245 Audigy 2 OEM\n\t\t1102 1007  SB0240/SB0244 Audigy 2 Platinum\n\t\t1102 1008  SB0320 Audigy 2\n\t\t1102 1009  SB0249 Audigy 2 OEM\n\t\t1102 100a  SB0246 Audigy 2\n\t\t1102 2001  SB0360 Audigy 2 ZS Platinum Pro\n\t\t1102 2002  SB0350 Audigy 2 ZS\n\t\t1102 2003  SB0352 Audigy 2 ZS\n\t\t1102 2004  SB0355 Audigy 2 ZS\n\t\t1102 2005  SB0359 Audigy 2 ZS\n\t\t1102 2006  SB035x Audigy 2 OEM\n\t\t1102 2007  SB0380 Audigy 4 Pro\n\t\t1102 4001  E-MU 1010 [MAEM8810]\n\t\t1102 4002  E-MU 0404\n\t\t1102 4003  E-MU 1010\n\t0005  EMU20k1 [Sound Blaster X-Fi Series]\n\t\t1102 0021  X-Fi Platinum\n\t\t1102 002c  X-Fi XtremeGamer FATAL1TY PRO\n\t\t1102 1003  X-Fi XtremeMusic\n\t0006  EMU10k1X [SB Live! Value/OEM Series]\n\t0007  CA0106/CA0111 [SB Live!/Audigy/X-Fi Series]\n\t\t1102 0007  SBLive! 24bit\n\t\t1102 1001  SB0310 Audigy LS\n\t\t1102 1002  SB0312 Audigy LS\n\t\t1102 1006  SB0410 SBLive! 24-bit\n\t\t1102 100a  SB0570 [SB Audigy SE]\n\t\t1102 1012  SB0790 X-Fi XA\n\t\t1102 1013  Soundblaster X-Fi Xtreme Audio\n\t\t1462 1009  K8N Diamond\n\t0008  CA0108/CA10300 [Sound Blaster Audigy Series]\n\t\t1102 0008  EMU0404 Digital Audio System\n\t\t1102 1001  SB0400 Audigy 2 Value\n\t\t1102 1021  SB0610 Audigy 4 Value\n\t\t1102 1022  SBxxx Audigy 2/4 Value\n\t\t1102 1023  SB0612 Audigy 2 LS\n\t\t1102 1024  SB1550 Audigy 5/Rx\n\t\t1102 1101  SBxxxx Audigy 2 SA\n\t\t1102 2001  SB0530 Audigy 2 ZS Notebook\n\t\t1102 2021  SBxxxx Audigy 4 Notebook\n\t\t1102 4002  E-MU 0404\n\t\t1102 4003  E-MU 1010\n\t\t1102 4004  EMU1010 Digital Audio System [MAEM8960]\n\t\t1102 4005  E-MU 0404 [MAEM8984]\n\t\t1102 4007  E-MU 1010 [MAEM8982]\n\t\t1102 4201  E-MU 0202 [MAEM8950]\n\t0009  CA0110 [Sound Blaster X-Fi Xtreme Audio]\n\t\t1102 0010  MB0820 Integrated\n\t\t1102 0018  SB1040 PCI Express\n\t000b  EMU20k2 [Sound Blaster X-Fi Titanium Series]\n\t\t1102 0041  SB0880 [SoundBlaster X-Fi Titanium PCI-e]\n\t\t1102 0062  SB1270 [SoundBlaster X-Fi Titanium HD]\n\t0012  Sound Core3D [Sound Blaster Recon3D / Z-Series]\n\t\t1102 0010  SB1570 SB Audigy Fx\n\t4001  SB Audigy FireWire Port\n\t\t1102 0010  SB Audigy FireWire Port\n\t7002  SB Live! Game Port\n\t\t1102 0020  Gameport Joystick\n\t7003  SB Audigy Game Port\n\t\t1102 0040  SB Audigy Game Port\n\t\t1102 0060  SB Audigy2 MIDI/Game Port\n\t7004  [SB Live! Value] Input device controller\n\t7005  SB Audigy LS Game Port\n\t\t1102 1001  SB0310 Audigy LS MIDI/Game port\n\t\t1102 1002  SB0312 Audigy LS MIDI/Game port\n\t7006  [SB X-Fi Xtreme Audio] CA0110-IBG PCIe to PCI Bridge\n\t8938  Ectiva EV1938\n\t\t1033 80e5  SlimTower-Jim (NEC)\n\t\t1071 7150  Mitac 7150\n\t\t110a 5938  Siemens Scenic Mobile 510PIII\n\t\t13bd 100c  Ceres-C (Sharp, Intel BX)\n\t\t13bd 100d  Sharp, Intel Banister\n\t\t13bd 100e  TwinHead P09S/P09S3 (Sharp)\n\t\t13bd f6f1  Marlin (Sharp)\n\t\t14ff 0e70  P88TE (TWINHEAD INTERNATIONAL Corp)\n\t\t14ff c401  Notebook 9100/9200/2000 (TWINHEAD INTERNATIONAL Corp)\n\t\t156d b400  G400 - Geo (AlphaTop (Taiwan))\n\t\t156d b550  G560  (AlphaTop (Taiwan))\n\t\t156d b560  G560  (AlphaTop (Taiwan))\n\t\t156d b700  G700/U700  (AlphaTop (Taiwan))\n\t\t156d b795  G795  (AlphaTop (Taiwan))\n\t\t156d b797  G797  (AlphaTop (Taiwan))\n# nee Triones Technologies, Inc.\n1103  HighPoint Technologies, Inc.\n\t0003  HPT343/345/346/363\n\t0004  HPT366/368/370/370A/372/372N\n\t\t1103 0001  HPT370A\n\t\t1103 0004  HPT366 UDMA66 (r1) / HPT368 UDMA66 (r2) / HPT370 UDMA100 (r3) / HPT370 UDMA100 RAID (r4)\n\t\t1103 0005  HPT370 UDMA100\n\t\t1103 0006  HPT302/302N\n\t0005  HPT372A/372N\n\t0006  HPT302/302N\n\t0007  HPT371/371N\n\t0008  HPT374\n\t0009  HPT372N\n\t0620  RocketRAID 620 2 Port SATA-III Controller\n\t0622  RocketRAID 622 2 Port SATA-III Controller\n\t0640  RocketRAID 640 4 Port SATA-III Controller\n\t0641  RocketRAID 640L 4 Port SATA-III Controller\n\t0642  RocketRAID 642L SATA-III Controller (2 eSATA ports + 2 internal SATA ports)\n\t0644  RocketRAID 644 4 Port SATA-III Controller (eSATA)\n\t0645  RocketRAID 644L 4 Port SATA-III Controller (eSATA)\n\t0646  RocketRAID 644LS SATA-III Controller (4 eSATA devices connected by 1 SAS cable)\n\t1720  RocketRAID 1720 (2x SATA II RAID Controller)\n\t1740  RocketRAID 1740\n\t1742  RocketRAID 1742\n\t2210  RocketRAID 2210 SATA-II Controller\n\t\t11ab 11ab  88SX6042\n\t2300  RocketRAID 230x 4 Port SATA-II Controller\n\t2310  RocketRAID 2310 4 Port SATA-II Controller\n\t2320  RocketRAID 2320 SATA-II Controller\n\t2322  RocketRAID 2322 SATA-II Controller\n\t2340  RocketRAID 2340 16 Port SATA-II Controller\n\t2640  RocketRAID 2640 SAS/SATA Controller\n\t2722  RocketRAID 2722\n# SFF-8087 Mini-SAS 16 port internal\n\t2740  RocketRAID 2740\n# SFF-8088 Mini-SAS 16 port external\n\t2744  RocketRaid 2744\n# SFF-8088 8 port external / SFF-8087 24 port internal\n\t2782  RocketRAID 2782\n\t3120  RocketRAID 3120\n\t3220  RocketRAID 3220\n\t3320  RocketRAID 3320\n\t4310  RocketRaid 4310\n1104  RasterOps Corp.\n1105  Sigma Designs, Inc.\n\t1105  REALmagic Xcard MPEG 1/2/3/4 DVD Decoder\n\t8300  REALmagic Hollywood Plus DVD Decoder\n\t8400  EM840x REALmagic DVD/MPEG-2 Audio/Video Decoder\n\t8401  EM8401 REALmagic DVD/MPEG-2 A/V Decoder\n\t8470  EM8470 REALmagic DVD/MPEG-4 A/V Decoder\n\t8471  EM8471 REALmagic DVD/MPEG-4 A/V Decoder\n\t8475  EM8475 REALmagic DVD/MPEG-4 A/V Decoder\n\t\t1105 0001  REALmagic X-Card\n\t8476  EM8476 REALmagic DVD/MPEG-4 A/V Decoder\n\t\t127d 0000  CineView II\n\t8485  EM8485 REALmagic DVD/MPEG-4 A/V Decoder\n\t8486  EM8486 REALmagic DVD/MPEG-4 A/V Decoder\n# Found in Cisco DMP-4305G\n\tc621  EM8621L Digital Media Processor\n\tc622  EM8622L MPEG-4.10 (H.264) and SMPTE 421M (VC-1) A/V Decoder\n1106  VIA Technologies, Inc.\n\t0102  Embedded VIA Ethernet Controller\n\t0130  VT6305 1394.A Controller\n\t0198  P4X600 Host Bridge\n\t0204  K8M800 Host Bridge\n\t0208  PT890 Host Bridge\n\t0238  K8T890 Host Bridge\n\t0258  PT880 Host Bridge\n\t0259  CN333/CN400/PM880 Host Bridge\n\t0269  KT880 Host Bridge\n\t0282  K8T800Pro Host Bridge\n\t\t1043 80a3  A8V Deluxe\n\t0290  K8M890 Host Bridge\n\t0293  PM896 Host Bridge\n\t0296  P4M800 Host Bridge\n\t0305  VT8363/8365 [KT133/KM133]\n\t\t1019 0987  K7VZA Mainboard\n\t\t1043 8033  A7V Mainboard\n\t\t1043 803e  A7V-E Mainboard\n\t\t1043 8042  A7V133/A7V133-C Mainboard\n\t\t147b a401  KT7/KT7-RAID/KT7A/KT7A-RAID Mainboard\n\t0308  PT880 Ultra/PT894 Host Bridge\n\t\t1043 8199  P4V800D-X Mainboard\n\t\t1849 0308  Motherboard\n\t0314  CN700/VN800/P4M800CE/Pro Host Bridge\n\t0324  CX700/VX700 Host Bridge\n\t0327  P4M890 Host Bridge\n\t0336  K8M890CE Host Bridge\n\t0340  PT900 Host Bridge\n\t0351  K8T890CF Host Bridge\n\t0353  VX800 Host Bridge\n\t0364  CN896/VN896/P4M900 Host Bridge\n\t\t1043 81ce  P5VD2-VM mothervoard\n\t0391  VT8371 [KX133]\n\t0409  VX855/VX875 Host Bridge: Host Control\n\t0410  VX900 Host Bridge: Host Control\n\t0415  VT6415 PATA IDE Host Controller\n\t\t1043 838f  Motherboard\n\t0501  VT8501 [Apollo MVP4]\n\t0505  VT82C505\n# Shares chip with :0576. The VT82C576M has :1571 instead of :0561.\n\t0561  VT82C576MV\n\t0571  VT82C586A/B/VT82C686/A/B/VT823x/A/C PIPC Bus Master IDE\n\t\t1019 0985  P6VXA Motherboard\n\t\t1019 0a81  L7VTA v1.0 Motherboard (KT400-8235)\n\t\t1043 8052  VT8233A Bus Master ATA100/66/33 IDE\n\t\t1043 808c  A7V8X / A7V333 motherboard\n\t\t1043 80a1  A7V8X-X motherboard rev. 1.01\n\t\t1043 80ed  A7V600/K8V-X/A8V Deluxe motherboard\n\t\t1106 0571  VT82C586/B/VT82C686/A/B/VT8233/A/C/VT8235 PIPC Bus Master IDE\n\t\t1179 0001  Magnia Z310\n\t\t1297 f641  FX41 motherboard\n\t\t1458 5002  GA-7VAX Mainboard\n\t\t1462 5901  KT6 Delta-FIS2R (MS-6590)\n\t\t1462 7020  K8T NEO 2 motherboard\n\t\t1462 7094  K8T Neo2-F V2.0\n\t\t1462 7120  KT4AV motherboard\n\t\t1462 7181  K8MM3-V mainboard\n\t\t147b 1407  KV8-MAX3 motherboard\n# probably all K7VT2/4*/6\n\t\t1849 0571  K7VT series Motherboards\n\t0576  VT82C576 3V [Apollo Master]\n\t0581  CX700/VX700 RAID Controller\n# Upgrade bios to get correct ID: 5324 instead of 0581\n\t\t1106 0581  Wrong IDE ID\n\t0585  VT82C585VP [Apollo VP1/VPX]\n\t0586  VT82C586/A/B PCI-to-ISA [Apollo VP]\n\t\t1106 0000  MVP3 ISA Bridge\n\t0591  VT8237A SATA 2-Port Controller\n\t0595  VT82C595 [Apollo VP2]\n\t0596  VT82C596 ISA [Mobile South]\n\t\t1106 0000  VT82C596/A/B PCI to ISA Bridge\n\t\t1458 0596  VT82C596/A/B PCI to ISA Bridge\n\t0597  VT82C597 [Apollo VP3]\n\t0598  VT82C598 [Apollo MVP3]\n\t0601  VT8601 [Apollo ProMedia]\n\t0605  VT8605 [ProSavage PM133]\n\t\t103c 1254  D9840-60001 [Brio BA410 Motherboard]\n\t\t1043 802c  CUV4X mainboard\n\t0680  VT82C680 [Apollo P6]\n\t0686  VT82C686 [Apollo Super South]\n\t\t1019 0985  P6VXA Motherboard\n\t\t103c 1256  D9840-60001 [Brio BA410 Motherboard]\n\t\t1043 802c  CUV4X mainboard\n\t\t1043 8033  A7V Mainboard\n\t\t1043 803e  A7V-E Mainboard\n\t\t1043 8040  A7M266 Mainboard\n\t\t1043 8042  A7V133/A7V133-C Mainboard\n\t\t1106 0000  VT82C686/A PCI to ISA Bridge\n\t\t1106 0686  VT82C686/A PCI to ISA Bridge\n\t\t1179 0001  Magnia Z310\n\t\t147b a702  KG7-Lite Mainboard\n\t0691  VT82C693A/694x [Apollo PRO133x]\n\t\t1019 0985  P6VXA Motherboard\n\t\t1179 0001  Magnia Z310\n\t\t1458 0691  VT82C691 Apollo Pro System Controller\n\t0693  VT82C693 [Apollo Pro Plus]\n\t0698  VT82C693A [Apollo Pro133 AGP]\n\t0709  VX11 Standard Host Bridge\n\t070a  VX11 PCI Express Root Port\n\t070b  VX11 PCI Express Root Port\n\t070c  VX11 PCI Express Root Port\n\t070d  VX11 PCI Express Root Port\n\t070e  VX11 PCI Express Root Port\n\t0926  VT82C926 [Amazon]\n\t1000  VT82C570MV\n\t1106  VT82C570MV\n\t1122  VX800/VX820 Chrome 9 HC3 Integrated Graphics\n\t1204  K8M800 Host Bridge\n\t1208  PT890 Host Bridge\n\t1238  K8T890 Host Bridge\n\t1258  PT880 Host Bridge\n\t1259  CN333/CN400/PM880 Host Bridge\n\t1269  KT880 Host Bridge\n\t1282  K8T800Pro Host Bridge\n\t1290  K8M890 Host Bridge\n\t1293  PM896 Host Bridge\n\t1296  P4M800 Host Bridge\n\t1308  PT894 Host Bridge\n\t1314  CN700/VN800/P4M800CE/Pro Host Bridge\n\t1324  CX700/VX700 Host Bridge\n\t1327  P4M890 Host Bridge\n\t1336  K8M890CE Host Bridge\n\t1340  PT900 Host Bridge\n\t1351  VT3351 Host Bridge\n\t1353  VX800/VX820 Error Reporting\n\t1364  CN896/VN896/P4M900 Host Bridge\n\t1409  VX855/VX875 Error Reporting\n\t1410  VX900 Error Reporting\n\t1571  VT82C576M/VT82C586\n\t1595  VT82C595/97 [Apollo VP2/97]\n\t1732  VT1732 [Envy24 II] PCI Multi-Channel Audio Controller\n\t2106  VIA Rhine Family Fast Ethernet Adapter (VT6105)\n\t2204  K8M800 Host Bridge\n\t2208  PT890 Host Bridge\n\t2238  K8T890 Host Bridge\n\t2258  PT880 Host Bridge\n\t2259  CN333/CN400/PM880 CPU Host Bridge\n\t2269  KT880 Host Bridge\n\t2282  K8T800Pro Host Bridge\n\t2290  K8M890 Host Bridge\n\t2293  PM896 Host Bridge\n\t2296  P4M800 Host Bridge\n\t2308  PT894 Host Bridge\n\t2314  CN700/VN800/P4M800CE/Pro Host Bridge\n\t2324  CX700/VX700 Host Bridge\n\t2327  P4M890 Host Bridge\n\t2336  K8M890CE Host Bridge\n\t2340  PT900 Host Bridge\n\t2351  VT3351 Host Bridge\n\t2353  VX800/VX820 Host Bus Control\n\t2364  CN896/VN896/P4M900 Host Bridge\n\t2409  VX855/VX875 Host Bus Control\n\t2410  VX900 CPU Bus Controller\n\t287a  VT8251 PCI to PCI Bridge\n\t287b  VT8251 Host Bridge\n\t287c  VT8251 PCIE Root Port\n\t287d  VT8251 PCIE Root Port\n\t287e  VT8237/8251 Ultra VLINK Controller\n\t3022  CLE266\n\t3038  VT82xx/62xx UHCI USB 1.1 Controller\n\t\t0925 1234  onboard UHCI USB 1.1 Controller\n\t\t1019 0985  P6VXA Motherboard\n\t\t1019 0a81  L7VTA v1.0 Motherboard (KT400-8235)\n\t\t1043 8080  A7V333 motherboard\n\t\t1043 808c  VT6202 USB2.0 4 port controller\n\t\t1043 80a1  A7V8X-X motherboard\n\t\t1043 80ed  A7V600/K8V-X/A8V Deluxe motherboard\n\t\t1179 0001  Magnia Z310\n\t\t1458 5004  GA-7VAX Mainboard\n\t\t1462 5901  KT6 Delta-FIS2R (MS-6590)\n\t\t1462 7020  K8T NEO 2 motherboard\n\t\t1462 7094  K8T Neo2-F V2.0\n\t\t1462 7120  KT4AV motherboard\n\t\t1462 7181  K8MM3-V mainboard\n\t\t147b 1407  KV8-MAX3 motherboard\n\t\t182d 201d  CN-029 USB2.0 4 port PCI Card\n# probably all K7VT2/4*/6\n\t\t1849 3038  K7VT series Motherboards\n\t\t19da a179  ZBOX nano VD01\n\t\t1af4 1100  QEMU Virtual Machine\n\t3040  VT82C586B ACPI\n\t3043  VT86C100A [Rhine]\n\t\t10bd 0000  VT86C100A Fast Ethernet Adapter\n\t\t1106 0100  VT86C100A Fast Ethernet Adapter\n\t\t1186 1400  DFE-530TX PCI Fast Ethernet Adapter (rev. A)\n\t3044  VT6306/7/8 [Fire II(M)] IEEE 1394 OHCI Controller\n\t\t0010 0001  IEEE 1394 4port DCST 1394-3+1B\n\t\t1025 005a  TravelMate 290\n\t\t103c 2a20  Pavilion t3030.de Desktop PC\n\t\t103c 2a3b  Media Center PC m7590n\n\t\t1043 808a  A8V/A8N/P4P800/P5SD2 series motherboard\n\t\t1043 81fe  Motherboard\n\t\t1458 1000  GA-7VT600-1394 Motherboard\n\t\t1462 207d  K8NGM2 series motherboard\n\t\t1462 217d  Aspire L250\n\t\t1462 590d  KT6 Delta-FIS2R (MS-6590)\n\t\t1462 702d  K8T NEO 2 motherboard\n\t\t1462 971d  MS-6917\n\t3050  VT82C596 Power Management\n\t3051  VT82C596 Power Management\n\t3053  VT6105M [Rhine-III]\n\t\t1186 1404  DFE-530TX PCI Fast Ethernet Adapter (rev. D)\n\t3057  VT82C686 [Apollo Super ACPI]\n\t\t1019 0985  P6VXA Motherboard\n\t\t1019 0987  K7VZA Motherboard\n\t\t1043 8033  A7V Mainboard\n\t\t1043 803e  A7V-E Mainboard\n\t\t1043 8040  A7M266 Mainboard\n\t\t1043 8042  A7V133/A7V133-C Mainboard\n\t\t1179 0001  Magnia Z310\n\t3058  VT82C686 AC97 Audio Controller\n\t\t0e11 0097  SoundMax Digital Integrated Audio\n\t\t0e11 b194  Soundmax integrated digital audio\n\t\t1019 0985  P6VXA Motherboard\n\t\t1019 0987  K7VZA Motherboard\n\t\t103c 1251  D9840-60001 [Brio BA410 Motherboard]\n\t\t1043 1106  A7V133/A7V133-C Mainboard\n\t\t1106 4511  Onboard Audio on EP7KXA\n\t\t1106 aa03  VT1612A AC'97 Audio Controller\n\t\t11d4 5348  AD1881A audio\n\t\t1458 7600  Onboard Audio\n\t\t1462 3091  MS-6309 Onboard Audio\n\t\t1462 3092  MS-6309 v2.x Mainboard (VIA VT1611A codec)\n\t\t1462 3300  MS-6330 Onboard Audio\n\t\t1462 3400  MS-6340 (VT8363) motherboard\n\t\t15dd 7609  Onboard Audio\n\t3059  VT8233/A/8235/8237 AC97 Audio Controller\n\t\t1019 0a81  L7VTA v1.0 Motherboard (KT400-8235)\n\t\t1019 1841  M811 (VT8367/VT8235/VT6103) [KT333] motherboard\n\t\t1019 1877  K8M800-M2 (V2.0) onboard audio\n\t\t1043 8095  A7V8X Motherboard (Realtek ALC650 codec)\n\t\t1043 80a1  A7V8X-X Motherboard\n\t\t1043 80b0  A7V600/K8V-X/K8V Deluxe motherboard (ADI AD1980 codec [SoundMAX])\n\t\t1043 80f3  SK8V motherboard\n\t\t1043 810d  P5VD1-X (AD1888 codec [SoundMax])\n\t\t1043 812a  A8V Deluxe motherboard (Realtek ALC850 codec)\n\t\t10ec 8168  High Definition Audio\n\t\t1106 3059  L7VMM2 Motherboard\n\t\t1106 4161  K7VT2 motherboard\n\t\t1106 4170  PCPartner P4M800-8237R Motherboard\n\t\t1106 4552  Soyo KT-600 Dragon Plus (Realtek ALC 650)\n\t\t1297 c160  FX41 motherboard (Realtek ALC650 codec)\n\t\t1413 147b  KV8 Pro motherboard onboard audio\n\t\t1458 a002  GA-7VAX Onboard Audio (Realtek ALC650)\n\t\t1462 0080  K8T NEO 2 motherboard\n\t\t1462 3800  KT266 onboard audio\n\t\t1462 5901  KT6 Delta-FIS2R (MS-6590)\n\t\t1462 7181  K8MM3-V mainboard\n\t\t147b 1407  KV8-MAX3 motherboard\n\t\t1695 300c  Realtek ALC655 audio on EP-8KRA series mainboard\n\t\t1849 0850  ASRock 775Dual-880 Pro onboard audio (Realtek ALC850)\n\t\t1849 9739  P4VT8 Mainboard (C-Media CMI9739A codec)\n# probably all K7VT2/4*/6\n\t\t1849 9761  K7VT series Motherboards\n\t\t4005 4710  MSI K7T266 Pro2-RU (MSI-6380 v2) onboard audio (Realtek/ALC 200/200P)\n\t\ta0a0 01b6  AK77-8XN onboard audio\n\t\ta0a0 0342  AK86-L motherboard\n\t3065  VT6102/VT6103 [Rhine-II]\n\t\t1043 80a1  A7V8X-X Motherboard\n\t\t1043 80ed  A7V600-X Motherboard\n\t\t1106 0102  VT6102/6103 [Rhine II] Ethernet Controller\n\t\t1186 1400  DFE-530TX PCI Fast Ethernet Adapter (rev. A)\n\t\t1186 1401  DFE-530TX PCI Fast Ethernet Adapter (rev. B)\n\t\t1186 1402  DFE-530TX PCI Fast Ethernet Adapter (rev. B)\n\t\t13b9 1421  LD-10/100AL PCI Fast Ethernet Adapter (rev.B)\n\t\t1462 7061  MS-7061\n\t\t1462 7181  K8MM3-V mainboard\n\t\t147b 1c09  NV7 Motherboard\n\t\t1695 3005  VT6103\n# probably all K7VT2/4*/6\n\t\t1849 3065  K7VT series Motherboards\n# This hosts more than just the Intel 537 codec, it also hosts PCtel (SIL33) and SmartLink (SIL34) codecs\n\t3068  AC'97 Modem Controller\n\t\t1462 309e  MS-6309 Saturn Motherboard\n\t3074  VT8233 PCI to ISA Bridge\n\t\t1043 8052  VT8233A\n\t3091  VT8633 [Apollo Pro266]\n\t3099  VT8366/A/7 [Apollo KT266/A/333]\n\t\t1019 1841  M811 (VT8367/VT8235/VT6103) [KT333] motherboard\n\t\t1043 8064  A7V266-E Mainboard\n\t\t1043 807f  A7V333 Mainboard\n\t\t1849 3099  K7VT2 motherboard\n\t3101  VT8653 Host Bridge\n\t3102  VT8662 Host Bridge\n\t3103  VT8615 Host Bridge\n\t3104  USB 2.0\n\t\t0925 1234  onboard EHCI USB 2.0 Controller\n\t\t1019 0a81  L7VTA v1.0 Motherboard (KT400-8235)\n\t\t1043 808c  A7V8X motherboard\n\t\t1043 80a1  A7V8X-X motherboard rev 1.01\n\t\t1043 80ed  A7V600/K8V-X/A8V Deluxe motherboard\n\t\t1106 3104  USB 2.0 Controller\n\t\t1297 f641  FX41 motherboard\n\t\t1458 5004  GA-7VAX Mainboard\n\t\t1462 5901  KT6 Delta-FIS2R (MS-6590)\n\t\t1462 7020  K8T NEO 2 motherboard\n\t\t1462 7094  K8T Neo2-F V2.0\n\t\t1462 7120  KT4AV motherboard\n\t\t1462 7181  K8MM3-V mainboard\n\t\t147b 1407  KV8-MAX3 motherboard\n\t\t182d 201d  CN-029 USB 2.0 4 port PCI Card\n# probably all K7VT2/4*/6\n\t\t1849 3104  K7VT series Motherboards\n\t\t19da a179  ZBOX nano VD01\n\t3106  VT6105/VT6106S [Rhine-III]\n\t\t1106 0105  VT6106S [Rhine-III]\n\t\t1186 1403  DFE-530TX PCI Fast Ethernet Adapter (rev. C)\n\t\t1186 1405  DFE-520TX Fast Ethernet PCI Adapter\n\t\t1186 1406  DFE-530TX+ rev F2\n\t\t1186 1407  DFE-538TX\n\t3108  K8M800/K8N800/K8N800A [S3 UniChrome Pro]\n\t3109  VT8233C PCI to ISA Bridge\n\t3112  VT8361 [KLE133] Host Bridge\n\t3113  VPX/VPX2 PCI to PCI Bridge Controller\n\t3116  VT8375 [KM266/KL266] Host Bridge\n\t\t1297 f641  FX41 motherboard\n\t3118  CN400/PM800/PM880/PN800/PN880 [S3 UniChrome Pro]\n\t3119  VT6120/VT6121/VT6122 Gigabit Ethernet Adapter\n\t3122  VT8623 [Apollo CLE266] integrated CastleRock graphics\n\t3123  VT8623 [Apollo CLE266]\n\t3128  VT8753 [P4X266 AGP]\n\t3133  VT3133 Host Bridge\n\t3142  VT6651 WiFi Adapter, 802.11b\n\t3147  VT8233A ISA Bridge\n\t\t1043 808c  A7V333 motherboard\n\t3148  P4M266 Host Bridge\n\t3149  VIA VT6420 SATA RAID Controller\n\t\t1043 80ed  A7V600/K8V Deluxe/K8V-X/A8V Deluxe motherboard\n\t\t1458 b003  GA-7VM400AM(F) Motherboard\n\t\t1462 5901  KT6 Delta-FIS2R (MS-6590)\n\t\t1462 7020  K8T Neo 2 Motherboard\n\t\t1462 7094  K8T Neo2-F V2.0\n\t\t1462 7181  K8MM3-V mainboard\n\t\t147b 1407  KV8-MAX3 motherboard\n\t\t147b 1408  KV7\n\t\t1849 3149  K7VT6 motherboard\n\t\ta0a0 04ad  AK86-L motherboard\n\t3156  P/KN266 Host Bridge\n\t3157  CX700/VX700 [S3 UniChrome Pro]\n\t3164  VT6410 ATA133 RAID controller\n\t\t1043 80f4  P4P800 Mainboard Deluxe ATX\n\t\t1462 7028  915P/G Neo2\n\t3168  P4X333/P4X400/PT800 AGP Bridge\n\t\t1849 3168  P4VT8 Mainboard\n\t3177  VT8235 ISA Bridge\n\t\t1019 0a81  L7VTA v1.0 Motherboard (KT400-8235)\n\t\t1019 1841  M811 (VT8367/VT8235/VT6103) [KT333] motherboard\n\t\t1043 808c  A7V8X motherboard\n\t\t1043 80a1  A7V8X-X motherboard\n\t\t1106 0000  KT4AV motherboard\n\t\t1297 f641  FX41 motherboard\n\t\t1458 5001  GA-7VAX Mainboard\n# probably all K7VT2/4*/6\n\t\t1849 3177  K7VT series Motherboards\n\t3178  ProSavageDDR P4N333 Host Bridge\n\t3188  VT8385 [K8T800 AGP] Host Bridge\n\t\t1043 80a3  K8V Deluxe/K8V-X motherboard\n\t\t147b 1407  KV8-MAX3 motherboard\n\t3189  VT8377 [KT400/KT600 AGP] Host Bridge\n\t\t1043 807f  A7V8X motherboard\n\t\t1106 0000  KT4AV motherboard (KT400A)\n\t\t1458 5000  GA-7VAX Mainboard\n# probably all K7VT2/4*/6\n\t\t1849 3189  K7VT series Motherboards\n\t31b0  VX11 Standard Host Bridge\n\t31b1  VX11 Standard Host Bridge\n\t31b2  VX11 DRAM Controller\n\t31b3  VX11 Power Management Controller\n\t31b4  VX11 I/O APIC\n\t31b5  VX11 Scratch Device\n\t31b7  VX11 Standard Host Bridge\n\t31b8  VX11 PCI to PCI Bridge\n\t3204  K8M800 Host Bridge\n\t3205  VT8378 [KM400/A] Chipset Host Bridge\n\t\t1458 5000  GA-7VM400M Motherboard\n\t3208  PT890 Host Bridge\n\t3213  VPX/VPX2 PCI to PCI Bridge Controller\n\t3218  K8T800M Host Bridge\n\t3227  VT8237 ISA bridge [KT600/K8T800/K8T890 South]\n\t\t1043 80ed  A7V600/K8V-X/A8V Deluxe motherboard\n\t\t1106 3227  DFI KT600-AL / Soltek SL-B9D-FGR Motherboard\n\t\t1458 5001  GA-7VT600 Motherboard\n\t\t147b 1407  KV8-MAX3 motherboard\n\t\t1849 3227  K7VT4 motherboard\n\t3230  K8M890CE/K8N890CE [Chrome 9]\n\t3238  K8T890 Host Bridge\n\t3249  VT6421 IDE/SATA Controller\n\t\t1106 3249  VT6421 IDE/SATA Controller\n\t324a  CX700/VX700 PCI to PCI Bridge\n\t324b  CX700/VX700 Host Bridge\n\t324e  CX700/VX700 Internal Module Bus\n\t3253  VT6655 WiFi Adapter, 802.11a/b/g\n\t3258  PT880 Host Bridge\n\t3259  CN333/CN400/PM880 Host Bridge\n\t3260  VIA Chrome9 HC IGP\n\t3269  KT880 Host Bridge\n\t3282  K8T800Pro Host Bridge\n\t3287  VT8251 PCI to ISA Bridge\n\t3288  VT8237A/VT8251 HDA Controller\n\t\t19da a179  ZBOX VD01\n\t3290  K8M890 Host Bridge\n\t3296  P4M800 Host Bridge\n\t3324  CX700/VX700 Host Bridge\n\t3327  P4M890 Host Bridge\n\t3336  K8M890CE Host Bridge\n\t3337  VT8237A PCI to ISA Bridge\n\t3340  PT900 Host Bridge\n\t3343  P4M890 [S3 UniChrome Pro]\n\t3344  CN700/P4M800 Pro/P4M800 CE/VN800 Graphics [S3 UniChrome Pro]\n\t3349  VT8251 AHCI/SATA 4-Port Controller\n\t3351  VT3351 Host Bridge\n\t3353  VX800 PCI to PCI Bridge\n\t3364  CN896/VN896/P4M900 Host Bridge\n\t3371  CN896/VN896/P4M900 [Chrome 9 HC]\n\t3372  VT8237S PCI to ISA Bridge\n\t337a  VT8237A PCI to PCI Bridge\n\t337b  VT8237A Host Bridge\n\t3403  VT6315 Series Firewire Controller\n\t\t1043 8374  M5A88-V EVO\n\t\t1043 8384  P8P67 Deluxe Motherboard\n\t3409  VX855/VX875 DRAM Bus Control\n\t3410  VX900 DRAM Bus Control\n\t\t19da a179  ZBOX nano VD01\n\t3432  VL80x xHCI USB 3.0 Controller\n\t3456  VX11 Standard Host Bridge\n\t345b  VX11 Miscellaneous Bus\n\t3483  VL805 USB 3.0 Host Controller\n\t3a01  VX11 Graphics [Chrome 645/640]\n\t4149  VIA VT6420 (ATA133) Controller\n\t4204  K8M800 Host Bridge\n\t4208  PT890 Host Bridge\n\t4238  K8T890 Host Bridge\n\t4258  PT880 Host Bridge\n\t4259  CN333/CN400/PM880 Host Bridge\n\t4269  KT880 Host Bridge\n\t4282  K8T800Pro Host Bridge\n\t4290  K8M890 Host Bridge\n\t4293  PM896 Host Bridge\n\t4296  P4M800 Host Bridge\n\t4308  PT894 Host Bridge\n\t4314  CN700/VN800/P4M800CE/Pro Host Bridge\n\t4324  CX700/VX700 Host Bridge\n\t4327  P4M890 Host Bridge\n\t4336  K8M890CE Host Bridge\n\t4340  PT900 Host Bridge\n\t4351  VT3351 Host Bridge\n\t4353  VX800/VX820 Power Management Control\n\t4364  CN896/VN896/P4M900 Host Bridge\n\t4409  VX855/VX875 Power Management Control\n\t4410  VX900 Power Management and Chip Testing Control\n\t\t19da a179  ZBOX nano VD01\n\t5030  VT82C596 ACPI [Apollo PRO]\n\t5122  VX855/VX875 Chrome 9 HCM Integrated Graphics\n\t5208  PT890 I/O APIC Interrupt Controller\n\t5238  K8T890 I/O APIC Interrupt Controller\n\t5287  VT8251 Serial ATA Controller\n\t5290  K8M890 I/O APIC Interrupt Controller\n\t5308  PT894 I/O APIC Interrupt Controller\n\t5324  VX800 Serial ATA and EIDE Controller\n\t5327  P4M890 I/O APIC Interrupt Controller\n\t5336  K8M890CE I/O APIC Interrupt Controller\n\t5340  PT900 I/O APIC Interrupt Controller\n\t5351  VT3351 I/O APIC Interrupt Controller\n\t5353  VX800/VX820 APIC and Central Traffic Control\n\t5364  CN896/VN896/P4M900 I/O APIC Interrupt Controller\n\t5372  VT8237/8251 Serial ATA Controller\n\t5409  VX855/VX875 APIC and Central Traffic Control\n\t5410  VX900 APIC and Central Traffic Control\n\t6100  VT85C100A [Rhine II]\n\t6287  SATA RAID Controller\n\t6290  K8M890CE Host Bridge\n\t6327  P4M890 Security Device\n\t6353  VX800/VX820 Scratch Registers\n\t6364  CN896/VN896/P4M900 Security Device\n\t6409  VX855/VX875 Scratch Registers\n\t6410  VX900 Scratch Registers\n\t\t19da a179  ZBOX nano VD01\n\t7122  VX900 Graphics [Chrome9 HD]\n\t7204  K8M800 Host Bridge\n\t7205  KM400/KN400/P4M800 [S3 UniChrome]\n\t\t1458 d000  Gigabyte GA-7VM400(A)M(F) Motherboard\n\t\t1462 7061  MS-7061\n\t7208  PT890 Host Bridge\n\t7238  K8T890 Host Bridge\n\t7258  PT880 Host Bridge\n\t7259  CN333/CN400/PM880 Host Bridge\n\t7269  KT880 Host Bridge\n\t7282  K8T800Pro Host Bridge\n\t7290  K8M890 Host Bridge\n\t7293  PM896 Host Bridge\n\t7296  P4M800 Host Bridge\n\t7308  PT894 Host Bridge\n\t7314  CN700/VN800/P4M800CE/Pro Host Bridge\n\t7324  CX700/VX700 Host Bridge\n\t7327  P4M890 Host Bridge\n\t7336  K8M890CE Host Bridge\n\t7340  PT900 Host Bridge\n\t7351  VT3351 Host Bridge\n\t7353  VX800/VX820 North-South Module Interface Control\n\t7364  CN896/VN896/P4M900 Host Bridge\n\t7409  VX855/VX875 North-South Module Interface Control\n\t7410  VX900 North-South Module Interface Control\n\t\t19da a179  ZBOX nano VD01\n\t8231  VT8231 [PCI-to-ISA Bridge]\n\t8235  VT8235 ACPI\n\t8305  VT8363/8365 [KT133/KM133 AGP]\n\t8324  CX700/VX700 PCI to ISA Bridge\n\t8353  VX800/VX820 Bus Control and Power Management\n\t8391  VT8371 [KX133 AGP]\n\t8400  MVP4\n\t8409  VX855/VX875 Bus Control and Power Management\n\t8410  VX900 Bus Control and Power Management\n\t\t19da a179  ZBOX VD01\n\t8500  KLE133/PLE133/PLE133T\n\t8501  VT8501 [Apollo MVP4 AGP]\n\t8596  VT82C596 [Apollo PRO AGP]\n\t8597  VT82C597 [Apollo VP3 AGP]\n\t8598  VT82C598/694x [Apollo MVP3/Pro133x AGP]\n\t\t1019 0985  P6VXA Motherboard\n\t8601  VT8601 [Apollo ProMedia AGP]\n\t8605  VT8605 [PM133 AGP]\n\t8691  VT82C691 [Apollo Pro]\n\t8693  VT82C693 [Apollo Pro Plus] PCI Bridge\n\t8a25  PL133/PL133T [S3 ProSavage]\n\t8a26  KL133/KL133A/KM133/KM133A [S3 ProSavage]\n\t8d01  PN133/PN133T [S3 Twister]\n\t8d04  KM266/P4M266/P4M266A/P4N266 [S3 ProSavageDDR]\n\t9001  VX900 Serial ATA Controller\n\t9082  Standard AHCI 1.0 SATA Controller\n\t9140  HDMI Audio Device\n\t9201  USB3.0 Controller\n\t9530  Secure Digital Memory Card Controller\n\t95d0  SDIO Host Controller\n\ta208  PT890 PCI to PCI Bridge Controller\n\ta238  K8T890 PCI to PCI Bridge Controller\n\ta327  P4M890 PCI to PCI Bridge Controller\n\ta353  VX8xx South-North Module Interface Control\n\ta364  CN896/VN896/P4M900 PCI to PCI Bridge Controller\n\ta409  VX855/VX875 USB Device Controller\n\ta410  VX900 PCI Express Root Port 0\n\tb091  VT8633 [Apollo Pro266 AGP]\n\tb099  VT8366/A/7 [Apollo KT266/A/333 AGP]\n\tb101  VT8653 AGP Bridge\n\tb102  VT8362 AGP Bridge\n\tb103  VT8615 AGP Bridge\n\tb112  VT8361 [KLE133] AGP Bridge\n\tb113  VPX/VPX2 I/O APIC Interrupt Controller\n\tb115  VT8363/8365 [KT133/KM133] PCI Bridge\n\tb168  VT8235 PCI Bridge\n\tb188  VT8237/8251 PCI bridge [K8M890/K8T800/K8T890 South]\n\t\t147b 1407  KV8-MAX3 motherboard\n\tb198  VT8237/VX700 PCI Bridge\n\tb213  VPX/VPX2 I/O APIC Interrupt Controller\n\tb353  VX855/VX875/VX900 PCI to PCI Bridge\n\tb410  VX900 PCI Express Root Port 1\n\tb999  [K8T890 North / VT8237 South] PCI Bridge\n\tc208  PT890 PCI to PCI Bridge Controller\n\tc238  K8T890 PCI to PCI Bridge Controller\n\tc327  P4M890 PCI to PCI Bridge Controller\n\tc340  PT900 PCI to PCI Bridge Controller\n\tc353  VX800/VX820 PCI Express Root Port\n\tc364  CN896/VN896/P4M900 PCI to PCI Bridge Controller\n\tc409  VX855/VX875 EIDE Controller\n\tc410  VX900 PCI Express Root Port 2\n\td104  VT8237R USB UDCI Controller\n\td208  PT890 PCI to PCI Bridge Controller\n\td213  VPX/VPX2 PCI to PCI Bridge Controller\n\td238  K8T890 PCI to PCI Bridge Controller\n\td340  PT900 PCI to PCI Bridge Controller\n\td410  VX900 PCI Express Root Port 3\n\te208  PT890 PCI to PCI Bridge Controller\n\te238  K8T890 PCI to PCI Bridge Controller\n\te340  PT900 PCI to PCI Bridge Controller\n\te353  VX800/VX820 PCI Express Root Port\n\te410  VX900 PCI Express Physical Layer Electrical Sub-block\n\tf208  PT890 PCI to PCI Bridge Controller\n\tf238  K8T890 PCI to PCI Bridge Controller\n\tf340  PT900 PCI to PCI Bridge Controller\n\tf353  VX800/VX820 PCI Express Root Port\n1107  Stratus Computers\n\t0576  VIA VT82C570MV [Apollo] (Wrong vendor ID!)\n1108  Proteon, Inc.\n\t0100  p1690plus_AA\n\t0101  p1690plus_AB\n\t0105  P1690Plus\n\t0108  P1690Plus\n\t0138  P1690Plus\n\t0139  P1690Plus\n\t013c  P1690Plus\n\t013d  P1690Plus\n1109  Cogent Data Technologies, Inc.\n\t1400  EM110TX [EX110TX]\n110a  Siemens AG\n\t0002  Pirahna 2-port\n\t0005  Tulip controller, power management, switch extender\n\t0006  FSC PINC (I/O-APIC)\n\t0015  FSC Multiprocessor Interrupt Controller\n\t001d  FSC Copernicus Management Controller\n\t007b  FSC Remote Service Controller, mailbox device\n\t007c  FSC Remote Service Controller, shared memory device\n\t007d  FSC Remote Service Controller, SMIC device\n\t2101  HST SAPHIR V Primary PCI (ISDN/PMx)\n# Superfastcom-PCI (Commtech, Inc.) or DSCC4 WAN Adapter\n\t2102  DSCC4 PEB/PEF 20534 DMA Supported Serial Communication Controller with 4 Channels\n\t2104  Eicon Diva 2.02 compatible passive ISDN card\n\t3141  SIMATIC NET CP 5611 / 5621\n\t3142  SIMATIC NET CP 5613 / 5614\n\t3143  SIMATIC NET CP 1613\n\t4021  SIMATIC NET CP 5512 (Profibus and MPI Cardbus Adapter)\n\t4029  SIMATIC NET CP 5613 A2\n\t\t110a 4029  SIMATIC NET CP 5613 A2\n\t\t110a c029  SIMATIC NET CP 5614 A2\n\t4035  SIMATIC NET CP 1613 A2\n\t4036  SIMATIC NET CP 1616\n\t4038  SIMATIC NET CP 1604\n\t4069  SIMATIC NET CP 5623\n\t\t110a 4069  SIMATIC NET CP 5623\n\t\t110a c069  SIMATIC NET CP 5624\n\t407c  SIMATIC NET CP 5612\n\t407d  SIMATIC NET CP 5613 A3\n\t407e  SIMATIC NET CP 5622\n\t4083  SIMATIC NET CP 5614 A3\n\t4084  SIMATIC NET CP 1626\n\t4942  FPGA I-Bus Tracer for MBD\n\t6120  SZB6120\n110b  Chromatic Research Inc.\n\t0001  Mpact Media Processor\n\t0004  Mpact 2\n110c  Mini-Max Technology, Inc.\n110d  Znyx Advanced Systems\n110e  CPU Technology\n110f  Ross Technology\n1110  Powerhouse Systems\n\t6037  Firepower Powerized SMP I/O ASIC\n\t6073  Firepower Powerized SMP I/O ASIC\n1111  Santa Cruz Operation\n# Also claimed to be RNS or Rockwell International, current PCISIG records list Osicom\n1112  Osicom Technologies Inc\n\t2200  FDDI Adapter\n\t2300  Fast Ethernet Adapter\n\t2340  4 Port Fast Ethernet Adapter\n\t2400  ATM Adapter\n1113  Accton Technology Corporation\n\t1211  SMC2-1211TX\n\t\t103c 1207  EN-1207D Fast Ethernet Adapter\n\t\t1113 1211  EN-1207D Fast Ethernet Adapter\n\t1216  EN-1216 Ethernet Adapter\n\t\t1113 1216  EN1207F series PCI Fast Ethernet Adapter\n\t\t1113 2220  EN2220A Cardbus Fast Ethernet Adapter\n\t\t1113 2242  EN2242 10/100 Ethernet Mini-PCI Card\n\t\t111a 1020  SpeedStream 1020 PCI 10/100 Ethernet Adaptor [EN-1207F-TX ?]\n\t1217  EN-1217 Ethernet Adapter\n\t5105  10Mbps Network card\n\t9211  EN-1207D Fast Ethernet Adapter\n\t\t1113 9211  EN-1207D Fast Ethernet Adapter\n\t9511  21x4x DEC-Tulip compatible Fast Ethernet\n\td301  CPWNA100 (Philips wireless PCMCIA)\n\tec02  SMC 1244TX v3\n\tee23  SMCWPCIT-G 108Mbps Wireless PCI adapter\n1114  Atmel Corporation\n\t0506  at76c506 802.11b Wireless Network Adaptor\n1115  3D Labs\n1116  Data Translation\n\t0022  DT3001\n\t0023  DT3002\n\t0024  DT3003\n\t0025  DT3004\n\t0026  DT3005\n\t0027  DT3001-PGL\n\t0028  DT3003-PGL\n\t0051  DT322\n\t0060  DT340\n\t0069  DT332\n\t80c2  DT3162\n1117  Datacube, Inc\n\t9500  Max-1C SVGA card\n\t9501  Max-1C image processing\n1118  Berg Electronics\n1119  ICP Vortex Computersysteme GmbH\n\t0000  GDT 6000/6020/6050\n\t0001  GDT 6000B/6010\n\t0002  GDT 6110/6510\n\t0003  GDT 6120/6520\n\t0004  GDT 6530\n\t0005  GDT 6550\n\t0006  GDT 6117/6517\n\t0007  GDT 6127/6527\n\t0008  GDT 6537\n\t0009  GDT 6557/6557-ECC\n\t000a  GDT 6115/6515\n\t000b  GDT 6125/6525\n\t000c  GDT 6535\n\t000d  GDT 6555/6555-ECC\n\t0100  GDT 6117RP/6517RP\n\t0101  GDT 6127RP/6527RP\n\t0102  GDT 6537RP\n\t0103  GDT 6557RP\n\t0104  GDT 6111RP/6511RP\n\t0105  GDT 6121RP/6521RP\n\t0110  GDT 6117RD/6517RD\n\t0111  GDT 6127RD/6527RD\n\t0112  GDT 6537RD\n\t0113  GDT 6557RD\n\t0114  GDT 6111RD/6511RD\n\t0115  GDT 6121RD/6521RD\n\t0118  GDT 6118RD/6518RD/6618RD\n\t0119  GDT 6128RD/6528RD/6628RD\n\t011a  GDT 6538RD/6638RD\n\t011b  GDT 6558RD/6658RD\n\t0120  GDT 6117RP2/6517RP2\n\t0121  GDT 6127RP2/6527RP2\n\t0122  GDT 6537RP2\n\t0123  GDT 6557RP2\n\t0124  GDT 6111RP2/6511RP2\n\t0125  GDT 6121RP2/6521RP2\n\t0136  GDT 6113RS/6513RS\n\t0137  GDT 6123RS/6523RS\n\t0138  GDT 6118RS/6518RS/6618RS\n\t0139  GDT 6128RS/6528RS/6628RS\n\t013a  GDT 6538RS/6638RS\n\t013b  GDT 6558RS/6658RS\n\t013c  GDT 6533RS/6633RS\n\t013d  GDT 6543RS/6643RS\n\t013e  GDT 6553RS/6653RS\n\t013f  GDT 6563RS/6663RS\n\t0166  GDT 7113RN/7513RN/7613RN\n\t0167  GDT 7123RN/7523RN/7623RN\n\t0168  GDT 7118RN/7518RN/7518RN\n\t0169  GDT 7128RN/7528RN/7628RN\n\t016a  GDT 7538RN/7638RN\n\t016b  GDT 7558RN/7658RN\n\t016c  GDT 7533RN/7633RN\n\t016d  GDT 7543RN/7643RN\n\t016e  GDT 7553RN/7653RN\n\t016f  GDT 7563RN/7663RN\n\t01d6  GDT 4x13RZ\n\t01d7  GDT 4x23RZ\n\t01f6  GDT 8x13RZ\n\t01f7  GDT 8x23RZ\n\t01fc  GDT 8x33RZ\n\t01fd  GDT 8x43RZ\n\t01fe  GDT 8x53RZ\n\t01ff  GDT 8x63RZ\n\t0210  GDT 6519RD/6619RD\n\t0211  GDT 6529RD/6629RD\n\t0260  GDT 7519RN/7619RN\n\t0261  GDT 7529RN/7629RN\n\t02ff  GDT MAXRP\n\t0300  GDT NEWRX\n\t0301  GDT NEWRX2\n111a  Efficient Networks, Inc\n\t0000  155P-MF1 (FPGA)\n\t0002  155P-MF1 (ASIC)\n\t0003  ENI-25P ATM\n\t\t111a 0000  ENI-25p Miniport ATM Adapter\n\t0005  SpeedStream (LANAI)\n\t\t111a 0001  ENI-3010 ATM\n\t\t111a 0009  ENI-3060 ADSL (VPI=0)\n\t\t111a 0101  ENI-3010 ATM\n\t\t111a 0109  ENI-3060CO ADSL (VPI=0)\n\t\t111a 0809  ENI-3060 ADSL (VPI=0 or 8)\n\t\t111a 0909  ENI-3060CO ADSL (VPI=0 or 8)\n\t\t111a 0a09  ENI-3060 ADSL (VPI=<0..15>)\n\t0007  SpeedStream ADSL\n\t\t111a 1001  ENI-3061 ADSL [ASIC]\n\t1020  SpeedStream PCI 10/100 Network Card\n\t1203  SpeedStream 1023 Wireless PCI Adapter\n111b  Teledyne Electronic Systems\n111c  Tricord Systems Inc.\n\t0001  Powerbis Bridge\n# now owned by Microchip Technology\n111d  Microsemi / PMC / IDT\n\t0001  IDT77201/77211 155Mbps ATM SAR Controller [NICStAR]\n\t0003  IDT77222/77252 155Mbps ATM MICRO ABR SAR Controller\n\t0004  IDT77V252 155Mbps ATM MICRO ABR SAR Controller\n\t0005  IDT77V222 155Mbps ATM MICRO ABR SAR Controller\n\t8018  PES12N3A 12-lane 3-Port PCI Express Switch\n\t801c  PES24N3A PCI Express Switch\n\t8028  PES4T4 PCI Express Switch\n\t802b  PES8T5A PCI Express Switch\n\t802c  PES16T4 PCI Express Switch\n\t802d  PES16T7 PCI Express Switch\n\t802e  PES24T6 PCI Express Switch\n\t802f  PES32T8 PCI Express Switch\n\t8032  PES48T12 PCI Express Switch\n\t8034  PES16/22/34H16 PCI Express Switch\n\t8035  PES32H8 PCI Express Switch\n\t8036  PES48H12 PCI Express Switch\n\t8037  PES64H16 PCI Express Switch\n\t8039  PES3T3 PCI Express Switch\n\t803a  PES4T4 PCI Express Switch\n\t803c  PES5T5 PCI Express Switch\n\t803d  PES6T5 PCI Express Switch\n\t8048  PES8NT2 PCI Express Switch\n\t8049  PES8NT2 PCI Express Switch\n\t804a  PES8NT2 PCI Express Internal NTB\n\t804b  PES8NT2 PCI Express External NTB\n\t804c  PES16NT2 PCI Express Switch\n\t804d  PES16NT2 PCI Express Switch\n\t804e  PES16NT2 PCI Express Internal NTB\n\t804f  PES16NT2 PCI Express External NTB\n\t8058  PES12NT3 PCI Express Switch\n\t8059  PES12NT3 PCI Express Switch\n\t805a  PES12NT3 PCI Express Internal NTB\n\t805b  PES12NT3 PCI Express External NTB\n\t805c  PES24NT3 PCI Express Switch\n\t805d  PES24NT3 PCI Express Switch\n\t805e  PES24NT3 PCI Express Internal NTB\n\t805f  PES24NT3 PCI Express External NTB\n\t8060  PES16T4G2 PCI Express Gen2 Switch\n\t8061  PES12T3G2 PCI Express Gen2 Switch\n\t8068  PES6T6G2 PCI Express Gen2 Switch\n\t806a  PES24T3G2 PCI Express Gen2 Switch\n\t\t14c1 000c  10G-PCIE2-8B2\n\t806c  PES16T4A/4T4G2 PCI Express Gen2 Switch\n\t806e  PES24T6G2 PCI Express Gen2 Switch\n\t806f  HIO524G2 PCI Express Gen2 Switch\n\t8077  89HPES64H16G2 64-Lane 16-Port PCIe Gen2 System Interconnect Switch\n\t8088  PES32NT8BG2 PCI Express Switch\n\t\t1093 752f  PXIe-8383mc Device\n\t\t1093 7543  PXIe-8383mc System Host\n\t\t1093 755c  PXIe-8364\n\t\t1093 755d  PXIe-8374\n\t\t1093 75ff  PXIe-8383mc DMA\n\t\t1093 7600  PXIe-8383mc DMA\n\t\t1093 7602  PXIe-8384\n# 32-lanes 24-ports Gen.2\n\t808a  89HPES32NT24BG2 PCI Express Switch\n# 32-lanes 24-ports Gen.2\n\t808c  89HPES32NT24AG2 PCI Express Switch\n\t808e  PES24NT24G2 PCI Express Switch\n\t808f  89HPES32NT8AG2 32-Lane 8-Port PCIe Gen2 System Interconnect Switch with Non-Transparent Bridging\n\t8090  89HPES16NT16G2 16-Lane 16-Port PCIe Gen2 System Interconnect Switch\n\t8092  89HPES12NT12G2 12-Lane 12-Port PCIe Gen2 System Interconnect Switch\n\t80cf  F32P08xG3 [PCIe boot mode]\n\t80d2  F32P08xG3 NVMe controller\n111e  Eldec\n111f  Precision Digital Images\n\t4a47  Precision MX Video engine interface\n\t5243  Frame capture bus interface\n# formerly EMC Corporation\n1120  Dell EMC\n\t2306  Unity Fibre Channel Controller\n\t2501  Unity Ethernet Controller\n\t2505  Unity Fibre Channel Controller\n1121  Zilog\n1122  Multi-tech Systems, Inc.\n1123  Excellent Design, Inc.\n1124  Leutron Vision AG\n\t2581  Picport Monochrome\n1125  Eurocore\n1126  Vigra\n1127  FORE Systems Inc\n\t0200  ForeRunner PCA-200 ATM\n\t0210  PCA-200PC\n\t0250  ATM\n\t0300  ForeRunner PCA-200EPC ATM\n\t0310  ATM\n\t0400  ForeRunnerHE ATM Adapter\n\t\t1127 0400  ForeRunnerHE ATM\n1129  Firmworks\n112a  Hermes Electronics Company, Ltd.\n# nee Linotype - Hell AG\n112b  Heidelberger Druckmaschinen AGHeidelberger Druckmaschinen AG\n112c  Zenith Data Systems\n112d  Ravicad\n112e  Infomedia Microelectronics Inc.\n112f  Dalsa Inc.\n\t0000  MVC IC-PCI\n\t0001  MVC IM-PCI Video frame grabber/processor\n\t0004  PCDig Digital Image Capture\n\t0008  PC-CamLink PCI framegrabber\n1130  Computervision\n1131  Philips Semiconductors\n\t1561  USB 1.1 Host Controller\n\t\t1775 c200  C2K onboard USB 1.1 host controller\n\t1562  USB 2.0 Host Controller\n\t\t1775 c200  C2K onboard USB 2.0 host controller\n\t3400  SmartPCI56(UCB1500) 56K Modem\n\t5400  TriMedia TM1000/1100\n\t\t12ca 0000  BlueICE\n\t5402  TriMedia TM1300\n\t\t1244 0f00  Fritz!Card DSL\n\t\t15eb 1300  DT1300\n\t\t15eb 1302  DT1302\n\t\t15eb 1304  DT1304\n\t\t15eb 1305  DT1305\n\t\t15eb 1306  PMCDT1306\n\t\t15eb 1308  DT1308\n\t\t15eb 1331  DT1301 with SAA7121\n\t\t15eb 1337  DT1301 with SAA7127\n\t\t15eb 2d3d  X3D\n\t\t15eb 7022  PTM1300\n\t5405  TriMedia TM1500\n\t\t1136 0005  LCP-1500\n\t5406  TriMedia TM1700\n\t540b  PNX1005 Media Processor\n\t\t1131 0020  PNXLite PCI Demo Board\n\t7130  SAA7130 Video Broadcast Decoder\n\t\t0000 4016  Behold TV 401\n\t\t0000 4051  Behold TV 405 FM\n\t\t0000 5051  Behold TV 505 RDS\n\t\t0000 505b  Behold TV 505 RDS\n\t\t102b 48d0  Matrox CronosPlus\n\t\t1048 226b  ELSA EX-VISION 300TV\n\t\t107d 6655  WinFast DTV1000S\n\t\t1131 0000  SAA7130-based TV tuner card\n\t\t1131 2001  10MOONS PCI TV CAPTURE CARD\n\t\t1131 2005  Techcom (India) TV Tuner Card (SSD-TV-670)\n\t\t1458 9006  GT-PS700 DVB-S tuner\n\t\t1461 050c  Nagase Sangyo TransGear 3000TV\n\t\t1461 10ff  AVerMedia DVD EZMaker\n\t\t1461 2108  AverMedia AverTV/305\n\t\t1461 2115  AverMedia AverTV Studio 305\n\t\t153b 1152  Terratec Cinergy 200 TV\n\t\t185b c100  Compro VideoMate TV PVR/FM\n\t\t185b c901  Videomate DVB-T200\n\t\t5168 0138  LifeView FlyVIDEO2000\n\t\t5ace 5010  Behold TV 501\n\t\t5ace 5050  Behold TV 505 FM\n\t7133  SAA7131/SAA7133/SAA7135 Video Broadcast Decoder\n\t\t0000 4091  Beholder BeholdTV 409 FM\n\t\t0000 5071  Behold TV 507 RDS\n\t\t0000 507b  Behold TV 507 RDS\n\t\t0000 5201  Behold TV Columbus\n\t\t0070 6701  WinTV HVR-1110\n\t\t1019 4cb5  Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM)\n\t\t1043 0210  FlyTV mini Asus Digimatrix\n\t\t1043 4843  TV-FM 7133\n\t\t1043 4845  TV-FM 7135\n\t\t1043 4862  P7131 Dual\n\t\t1043 4876  My Cinema-P7131 Hybrid\n\t\t1131 0000  SAA713x-based TV tuner card\n\t\t1131 2001  Proteus Pro [philips reference design]\n\t\t1131 2018  Tiger reference design\n\t\t1131 4ee9  MonsterTV Mobile\n\t\t1131 7133  Pinnacle PCTV 301i\n\t\t11bd 002b  PCTV Stereo\n\t\t11bd 002e  PCTV 110i (saa7133)\n\t\t12ab 0800  PURPLE TV\n\t\t13c2 2804  Technotrend Budget T-3000 Hybrid\n\t\t1421 0335  Instant TV DVB-T Cardbus\n\t\t1421 1370  Instant TV (saa7135)\n\t\t1435 7330  VFG7330\n\t\t1435 7350  VFG7350\n\t\t1458 9001  GC-PTV-TAF Hybrid TV card\n\t\t1458 9002  GT-PTV-TAF-RH DVB-T/Analog TV/FM tuner\n\t\t1458 9003  GT-PTV-AF-RH Analog TV/FM tuner\n\t\t1458 9004  GT-P8000 DVB-T/Analog TV/FM tuner\n\t\t1458 9005  GT-P6000 Analog TV/FM tuner\n\t\t1458 9008  GT-P5100 Analog TV tuner\n\t\t1461 1044  AVerTVHD MCE A180\n\t\t1461 4836  M10D Hybrid DVBT\n\t\t1461 861e  M105 PAL/SECAM/NTSC/FM Tuner\n\t\t1461 a14b  AVerTV Studio 509\n\t\t1461 a836  M115 DVB-T, PAL/SECAM/NTSC Tuner\n\t\t1461 f01d  DVB-T Super 007\n\t\t1461 f31f  Avermedia AVerTV GO 007 FM\n\t\t1461 f936  Hybrid+FM PCI (rev A16D)\n\t\t1462 6231  TV@nywhere Plus\n\t\t1489 0214  LifeView FlyTV Platinum FM\n\t\t14c0 1212  LifeView FlyTV Platinum Mini2\n\t\t153b 1160  Cinergy 250 PCI TV\n\t\t153b 1162  Terratec Cinergy 400 mobile\n\t\t17de 7256  PlusTV All In One PI610 card\n\t\t17de 7350  ATSC 110 Digital / Analog HDTV Tuner\n\t\t17de 7352  ATSC 115 Digital / Analog HDTV Tuner\n\t\t185b c100  VideoMate TV\n\t\t185b c900  VideoMate T750\n\t\t5168 0306  LifeView FlyDVB-T DUO\n\t\t5168 0319  LifeView FlyDVB Trio\n\t\t5168 0502  LifeView FlyDVB-T Duo CardBus\n\t\t5168 0520  LifeView FlyDVB Trio CardBus\n\t\t5168 1502  LifeView FlyTV CardBus\n\t\t5168 2502  LifeView FlyDVB-T CardBus\n\t\t5168 2520  LifeView FlyDVB-S Duo CardBus\n\t\t5168 3502  LifeView FlyDVB-T Hybrid CardBus\n\t\t5168 3520  LifeView FlyDVB Trio N CardBus\n\t\t5ace 5030  Behold TV 503 FM\n\t\t5ace 5090  Behold TV 509 FM\n\t\t5ace 6090  Behold TV 609 FM\n\t\t5ace 6091  Behold TV 609 FM\n\t\t5ace 6092  Behold TV 609 RDS\n\t\t5ace 6093  Behold TV 609 RDS\n\t\t5ace 6190  Behold TV M6\n\t\t5ace 6191  Behold TV M63\n\t\t5ace 6193  Behold TV M6 Extra\n\t\t5ace 6290  Behold TV H6\n\t\t5ace 7090  Behold TV A7\n\t\t5ace 7150  Behold TV H75\n\t\t5ace 7151  Behold TV H75\n\t\t5ace 7190  Behold TV H7\n\t\t5ace 7191  Behold TV H7\n\t\t5ace 7290  Behold TV T7\n\t\t5ace 7591  Behold TV X7\n\t\t5ace 7595  Behold TV X7\n\t7134  SAA7134/SAA7135HL Video Broadcast Decoder\n\t\t0000 4036  Behold TV 403\n\t\t0000 4037  Behold TV 403 FM\n\t\t0000 4071  Behold TV 407 FM\n\t\t1019 4cb4  Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM)\n\t\t1043 0210  Digimatrix TV\n\t\t1043 4840  TV-FM 7134\n\t\t1043 4842  TV-FM 7134\n\t\t1131 0000  SAA713x-based TV tuner card\n\t\t1131 2004  EUROPA V3 reference design\n\t\t1131 4e85  SKNet Monster TV\n\t\t1131 6752  EMPRESS\n\t\t11bd 002b  PCTV Stereo\n\t\t11bd 002d  PCTV 300i DVB-T + PAL\n\t\t1461 2c00  AverTV Hybrid+FM PCI\n\t\t1461 9715  AVerTV Studio 307\n\t\t1461 a70a  Avermedia AVerTV 307\n\t\t1461 a70b  AverMedia M156 / Medion 2819\n\t\t1461 d6ee  Cardbus TV/Radio (E500)\n\t\t1471 b7e9  AVerTV Cardbus plus\n\t\t153b 1142  Terratec Cinergy 400 TV\n\t\t153b 1143  Terratec Cinergy 600 TV\n\t\t153b 1158  Terratec Cinergy 600 TV MK3\n\t\t1540 9524  ProVideo PV952\n\t\t16be 0003  Medion 7134\n\t\t185b c200  Compro VideoMate Gold+ Pal\n\t\t185b c900  Videomate DVB-T300\n\t\t1894 a006  KNC One TV-Station DVR\n\t\t1894 fe01  KNC One TV-Station RDS / Typhoon TV Tuner RDS\n\t\t5168 0138  FLY TV PRIME 34FM\n\t\t5168 0300  FlyDVB-S\n\t\t5ace 5070  Behold TV 507 FM\n\t\t5ace 6070  Behold TV 607 FM\n\t\t5ace 6071  Behold TV 607 FM\n\t\t5ace 6072  Behold TV 607 RDS\n\t\t5ace 6073  Behold TV 607 RDS\n\t7145  SAA7145\n\t7146  SAA7146\n\t\t110a 0000  Fujitsu/Siemens DVB-C card rev1.5\n\t\t110a ffff  Fujitsu/Siemens DVB-C card rev1.5\n\t\t1124 2581  Leutron Vision PicPort\n\t\t1131 4f56  KNC1 DVB-S Budget\n\t\t1131 4f60  Fujitsu-Siemens Activy DVB-S Budget Rev AL\n\t\t1131 4f61  Activy DVB-S Budget Rev GR\n\t\t1131 5f61  Activy DVB-T Budget\n\t\t114b 2003  DVRaptor Video Edit/Capture Card\n\t\t1159 0040  MuTech M-Vision 500 (MV-500 rev. E)\n\t\t1159 0050  MuTech M-Vision 500 (MV-500 rev. F)\n\t\t11bd 0006  DV500 Overlay\n\t\t11bd 000a  DV500 Overlay\n\t\t11bd 000f  DV500 Overlay\n\t\t13c2 0000  Siemens/Technotrend/Hauppauge DVB card rev1.3 or rev1.5\n\t\t13c2 0001  Technotrend/Hauppauge DVB card rev1.3 or rev1.6\n\t\t13c2 0002  Technotrend/Hauppauge DVB card rev2.1\n\t\t13c2 0003  Technotrend/Hauppauge DVB card rev2.1\n\t\t13c2 0004  Technotrend/Hauppauge DVB card rev2.1\n\t\t13c2 0006  Technotrend/Hauppauge DVB card rev1.3 or rev1.6\n\t\t13c2 0008  Technotrend/Hauppauge DVB-T\n\t\t13c2 000a  Octal/Technotrend DVB-C for iTV\n\t\t13c2 000e  Technotrend/Hauppauge DVB card rev2.3\n\t\t13c2 1003  Technotrend-Budget/Hauppauge WinTV-NOVA-S DVB card\n\t\t13c2 1004  Technotrend-Budget/Hauppauge WinTV-NOVA-C DVB card\n\t\t13c2 1005  Technotrend-Budget/Hauppauge WinTV-NOVA-T DVB card\n\t\t13c2 100c  Technotrend-Budget/Hauppauge WinTV-NOVA-CI DVB card\n\t\t13c2 100f  Technotrend-Budget/Hauppauge WinTV-NOVA-CI DVB card\n\t\t13c2 1010  DVB C-1500\n\t\t13c2 1011  Technotrend-Budget/Hauppauge WinTV-NOVA-T DVB card\n\t\t13c2 1012  DVB T-1500\n\t\t13c2 1013  SATELCO Multimedia DVB\n\t\t13c2 1016  WinTV-NOVA-SE DVB card\n\t\t13c2 1018  DVB S-1401\n\t\t13c2 1019  S2-3200\n\t\t13c2 1102  Technotrend/Hauppauge DVB card rev2.1\n\t\t153b 1155  Cinergy 1200 DVB-S\n\t\t153b 1156  Cinergy 1200 DVB-C\n\t\t153b 1157  Cinergy 1200 DVB-T\n\t\t153b 1176  Cinergy 1200 DVB-C (MK3)\n\t\t1894 0020  KNC One DVB-C V1.0\n\t\t1894 0023  TVStation DVB-C plus\n# http://www.knc1.com/gb.htm\n\t\t1894 0054  TV-Station DVB-S\n\t7160  SAA7160\n\t\t1458 9009  E8000 DVB-T/Analog TV/FM tuner\n\t\t1461 1455  AVerTV Hybrid Speedy PCI-E (H788)\n\t7162  SAA7162\n\t\t11bd 0101  Pinnacle PCTV 7010iX TV Card\n\t7164  SAA7164\n\t\t0070 8800  WinTV HVR-2250\n\t\t0070 8810  WinTV HVR-2250\n\t\t0070 8851  WinTV HVR-2250\n\t\t0070 8853  WinTV HVR-2250\n\t\t0070 8880  WinTV HVR-2250\n\t\t0070 8891  WinTV HVR-2250\n\t\t0070 88a0  WinTV HVR-2250\n\t\t0070 88a1  WinTV HVR-2250\n\t\t0070 8900  WinTV HVR-2200\n\t\t0070 8901  WinTV HVR-2200\n\t\t0070 8940  WinTV HVR-2200 (submodel 89619)\n\t\t0070 8951  WinTV HVR-2200\n\t\t0070 8953  WinTV HVR-2200\n\t\t0070 8980  WinTV HVR-2200\n\t\t0070 8991  WinTV HVR-2200\n\t\t0070 8993  WinTV HVR-2200\n\t\t0070 89a0  WinTV HVR-2200\n\t\t0070 89a1  WinTV HVR-2200\n\t\t0070 f120  WinTV HVR-2205\n\t\t0070 f123  WinTV HVR-2215\n\t7231  SAA7231\n\t\t5ace 8000  Behold TV H8\n\t\t5ace 8001  Behold TV H8\n\t\t5ace 8050  Behold TV H85\n\t\t5ace 8051  Behold TV H85\n\t\t5ace 8100  Behold TV A8\n\t\t5ace 8101  Behold TV A8\n\t\t5ace 8150  Behold TV A85\n\t\t5ace 8151  Behold TV A85\n\t\t5ace 8201  Behold TV T8\n\t9730  SAA9730 Integrated Multimedia and Peripheral Controller\n\t\t1131 0000  Integrated Multimedia and Peripheral Controller\n1132  Mitel Corp.\n1133  Dialogic Corporation\n\t7701  Eiconcard C90\n\t7711  Eiconcard C91\n\t7901  EiconCard S90\n\t7902  EiconCard S90\n\t7911  EiconCard S91\n\t7912  EiconCard S91\n\t7921  Eiconcard S92\n\t7941  EiconCard S94\n\t7942  EiconCard S94\n\t7943  EiconCard S94\n\t7944  EiconCard S94\n\t7945  Eiconcard S94\n\t7948  Eiconcard S94 64bit/66MHz\n\t9711  Eiconcard S91 V2\n\t9911  Eiconcard S91 V2\n\t9941  Eiconcard S94 V2\n\t9a41  Eiconcard S94 PCIe\n\tb921  EiconCard P92\n\tb922  EiconCard P92\n\tb923  EiconCard P92\n\te001  Diva Pro 2.0 S/T\n\te002  Diva 2.0 S/T PCI\n\te003  Diva Pro 2.0 U\n\te004  Diva 2.0 U PCI\n\te005  Diva 2.01 S/T PCI\n\te006  Diva CT S/T PCI\n\te007  Diva CT U PCI\n\te008  Diva CT Lite S/T PCI\n\te009  Diva CT Lite U PCI\n\te00a  Diva ISDN+V.90 PCI\n\te00b  Diva ISDN PCI 2.02\n\te00c  Diva 2.02 PCI U\n\te00d  Diva Pro 3.0 PCI\n\te00e  Diva ISDN+CT S/T PCI Rev 2\n\te010  Diva Server BRI-2M PCI\n\t\t110a 0021  Fujitsu Siemens ISDN S0\n\te011  Diva Server BRI S/T Rev 2\n\te012  Diva Server 4BRI-8M PCI\n\te013  4BRI\n\t\t1133 1300  Diva V-4BRI-8 PCI v2\n\t\t1133 e013  Diva 4BRI-8 PCI v2\n\te014  Diva Server PRI-30M PCI\n\te015  Diva PRI PCI v2\n\te016  Diva Server Voice 4BRI PCI\n\te017  Diva Server Voice 4BRI Rev 2\n\t\t1133 e017  Diva Server Voice 4BRI-8M 2.0 PCI\n\te018  BRI\n\t\t1133 1800  Diva V-BRI-2 PCI v2\n\t\t1133 e018  Diva BRI-2 PCI v2\n\te019  Diva Server Voice PRI Rev 2\n\t\t1133 e019  Diva Server Voice PRI 2.0 PCI\n\te01a  Diva BRI-2FX PCI v2\n\te01b  Diva Server Voice BRI-2M 2.0 PCI\n\t\t1133 e01b  Diva Server Voice BRI-2M 2.0 PCI\n\te01c  PRI\n\t\t1133 1c01  Diva PRI/E1/T1-8 PCI v3\n\t\t1133 1c02  Diva PRI/T1-24 PCI(e) v3\n\t\t1133 1c03  Diva PRI/E1-30 PCI(e) v3\n\t\t1133 1c04  Diva PRI/E1/T1-CTI PCI(e) v3\n\t\t1133 1c05  Diva V-PRI/T1-24 PCI(e) v3\n\t\t1133 1c06  Diva V-PRI/E1-30 PCI(e) v3\n\t\t1133 1c07  Diva Server PRI/E1/T1-8 Cornet NQ\n\t\t1133 1c08  Diva Server PRI/T1-24 Cornet NQ\n\t\t1133 1c09  Diva Server PRI/E1-30 Cornet NQ\n\t\t1133 1c0a  Diva Server PRI/E1/T1 Cornet NQ\n\t\t1133 1c0b  Diva Server V-PRI/T1-24 Cornet NQ\n\t\t1133 1c0c  Diva Server V-PRI/E1-30 Cornet NQ\n\te01e  2PRI\n\t\t1133 1e01  Diva 2PRI/E1/T1-60 PCI v1\n\t\t1133 e01e  Diva V-2PRI/E1/T1-60 PCI v1\n\te020  4PRI\n\t\t1133 2001  Diva 4PRI/E1/T1-120 PCI v1\n\t\t1133 e020  Diva V-4PRI/E1/T1-120 PCI v1\n\te022  Analog-2\n\t\t1133 2200  Diva V-Analog-2 PCI v1\n\t\t1133 e022  Diva Analog-2 PCI v1\n\te024  Analog-4\n\t\t1133 2400  Diva V-Analog-4 PCI v1\n\t\t1133 e024  Diva Analog-4 PCI v1\n\te028  Analog-8\n\t\t1133 2800  Diva V-Analog-8 PCI v1\n\t\t1133 e028  Diva Analog-8 PCI v1\n\te02a  Diva IPM-300 PCI v1\n\te02c  Diva IPM-600 PCI v1\n\te02e  4BRI\n\t\t1133 2e01  Diva V-4BRI-8 PCIe v2\n\t\t1133 e02e  Diva 4BRI-8 PCIe v2\n\te032  BRI\n\t\t1133 3201  Diva V-BRI-2 PCIe v2\n\t\t1133 e032  Diva BRI-2 PCIe v2\n\te034  Diva BRI-CTI PCI v2\n1134  Mercury Computer Systems\n\t0001  Raceway Bridge\n\t0002  Dual PCI to RapidIO Bridge\n\t000b  POET Serial RapidIO Bridge\n\t000d  POET PSDMS Device\n1135  Fuji Xerox Co Ltd\n\t0001  Printer controller\n1136  Momentum Data Systems\n\t0002  PCI-JTAG\n1137  Cisco Systems Inc\n\t0023  VIC 81 PCIe Upstream Port\n\t0040  VIC PCIe Upstream Port\n\t\t1137 004f  VIC 1280 Dual 40Gb Mezzanine\n\t\t1137 0084  VIC 1240 Dual 40Gb MLOM\n\t\t1137 0085  VIC 1225 Dual 10Gb SFP+ PCIe\n\t\t1137 00cd  VIC 1285 Dual 40Gb QSFP+ PCIe\n\t\t1137 00ce  VIC 1225T Dual 10GBaseT PCIe\n\t\t1137 012a  VIC M4308 Dual 40Gb\n\t\t1137 012c  VIC 1340 Dual 40Gb MLOM\n\t\t1137 012e  VIC 1227 Dual 10Gb SFP+ PCIe\n\t\t1137 0137  VIC 1380 Dual 40Gb Mezzanine\n\t\t1137 014d  VIC 1385 Dual 40Gb PCIe\n\t0041  VIC PCIe Downstream Port\n\t0042  VIC Management Controller\n\t\t1137 0047  VIC P81E PCIe Management Controller\n\t\t1137 0085  VIC 1225 PCIe Management Controller\n\t\t1137 00cd  VIC 1285 PCIe Management Controller\n\t\t1137 00ce  VIC 1225T PCIe Management Controller\n\t\t1137 012e  VIC 1227 PCIe Management Controller\n\t\t1137 014d  VIC 1385 PCIe Management Controller\n\t0043  VIC Ethernet NIC\n\t\t1137 0047  VIC P81E PCIe Ethernet NIC\n\t\t1137 0048  VIC M81KR Mezzanine Ethernet NIC\n\t\t1137 004f  VIC 1280 Mezzanine Ethernet NIC\n\t\t1137 0084  VIC 1240 MLOM Ethernet NIC\n\t\t1137 0085  VIC 1225 PCIe Ethernet NIC\n\t\t1137 00cd  VIC 1285 PCIe Ethernet NIC\n\t\t1137 00ce  VIC 1225T PCIe Ethernet NIC\n\t\t1137 012a  VIC M4308 Ethernet NIC\n\t\t1137 012c  VIC 1340 MLOM Ethernet NIC\n\t\t1137 012e  VIC 1227 PCIe Ethernet NIC\n\t\t1137 0137  VIC 1380 Mezzanine Ethernet NIC\n\t\t1137 014d  VIC 1385 PCIe Ethernet NIC\n\t\t1137 015d  VIC 1387 MLOM Ethernet NIC\n\t\t1137 0215  VIC 1440 Mezzanine Ethernet NIC\n\t\t1137 0216  VIC 1480 MLOM Ethernet NIC\n\t\t1137 0217  VIC 1455 PCIe Ethernet NIC\n\t\t1137 0218  VIC 1457 MLOM Ethernet NIC\n\t\t1137 0219  VIC 1485 PCIe Ethernet NIC\n\t\t1137 021a  VIC 1487 MLOM Ethernet NIC\n\t\t1137 024a  VIC 1495 PCIe Ethernet NIC\n\t\t1137 024b  VIC 1497 MLOM Ethernet NIC\n\t0044  VIC Ethernet NIC Dynamic\n\t\t1137 0047  VIC P81E PCIe Ethernet NIC Dynamic\n\t\t1137 0048  VIC M81KR Mezzanine Ethernet NIC Dynamic\n\t\t1137 004f  VIC 1280 Mezzanine Ethernet NIC Dynamic\n\t\t1137 0084  VIC 1240 MLOM Ethernet NIC Dynamic\n\t\t1137 0085  VIC 1225 PCIe Ethernet NIC Dynamic\n\t\t1137 00cd  VIC 1285 PCIe Ethernet NIC Dynamic\n\t\t1137 00ce  VIC 1225T PCIe Ethernet NIC Dynamic\n\t\t1137 012a  VIC M4308 Ethernet NIC Dynamic\n\t\t1137 012c  VIC 1340 MLOM Ethernet NIC Dynamic\n\t\t1137 012e  VIC 1227 PCIe Ethernet NIC Dynamic\n\t\t1137 0137  VIC 1380 Mezzanine Ethernet NIC Dynamic\n\t\t1137 014d  VIC 1385 PCIe Ethernet NIC Dynamic\n\t0045  VIC FCoE HBA\n\t\t1137 0047  VIC P81E PCIe FCoE HBA\n\t\t1137 0048  VIC M81KR Mezzanine FCoE HBA\n\t\t1137 004f  VIC 1280 Mezzanine FCoE HBA\n\t\t1137 0084  VIC 1240 MLOM FCoE HBA\n\t\t1137 0085  VIC 1225 PCIe FCoE HBA\n\t\t1137 00cd  VIC 1285 PCIe FCoE HBA\n\t\t1137 00ce  VIC 1225T PCIe FCoE HBA\n\t\t1137 012a  VIC M4308 FCoE HBA\n\t\t1137 012c  VIC 1340 MLOM FCoE HBA\n\t\t1137 012e  VIC 1227 PCIe FCoE HBA\n\t\t1137 0137  VIC 1380 Mezzanine FCoE HBA\n\t\t1137 014d  VIC 1385 PCIe FCoE HBA\n\t0046  VIC SCSI Controller\n\t\t1137 012a  VIC M4308 SCSI Controller\n\t004e  VIC 82 PCIe Upstream Port\n\t0071  VIC SR-IOV VF\n\t007a  VIC 1300 PCIe Upstream Port\n\t\t1137 012a  VIC M4308 Dual 40Gb\n\t\t1137 012c  VIC 1340 Dual 40Gb MLOM\n\t\t1137 0137  VIC 1380 Dual 40Gb Mezzanine\n\t\t1137 014d  VIC 1385 Dual 40Gb PCIe\n\t00cf  VIC Userspace NIC\n\t\t1137 004f  VIC 1280 Mezzanine Userspace NIC\n\t\t1137 0084  VIC 1240 MLOM Userspace NIC\n\t\t1137 0085  VIC 1225 PCIe Userspace NIC\n\t\t1137 00cd  VIC 1285 PCIe Userspace NIC\n\t\t1137 00ce  VIC 1225T PCIe Userspace NIC\n\t\t1137 012a  VIC M4308 Userspace NIC\n\t\t1137 012c  VIC 1340 MLOM Userspace NIC\n\t\t1137 012e  VIC 1227 PCIe Userspace NIC\n\t\t1137 0137  VIC 1380 Mezzanine Userspace NIC\n\t023e  1GigE I350 LOM\n1138  Ziatech Corporation\n\t8905  8905 [STD 32 Bridge]\n1139  Dynamic Pictures, Inc\n\t0001  VGA Compatible 3D Graphics\n113a  FWB Inc\n113b  Network Computing Devices\n113c  Cyclone Microsystems, Inc.\n\t0000  PCI-9060 i960 Bridge\n\t0001  PCI-SDK [PCI i960 Evaluation Platform]\n\t0911  PCI-911 [i960Jx-based Intelligent I/O Controller]\n\t0912  PCI-912 [i960CF-based Intelligent I/O Controller]\n\t0913  PCI-913\n\t0914  PCI-914 [I/O Controller w/ secondary PCI bus]\n113d  Leading Edge Products Inc\n113e  Sanyo Electric Co - Computer Engineering Dept\n113f  Equinox Systems, Inc.\n\t0808  SST-64P Adapter\n\t1010  SST-128P Adapter\n\t80c0  SST-16P DB Adapter\n\t80c4  SST-16P RJ Adapter\n\t80c8  SST-16P Adapter\n\t8888  SST-4P Adapter\n\t9090  SST-8P Adapter\n1140  Intervoice Inc\n1141  Crest Microsystem Inc\n1142  Alliance Semiconductor Corporation\n\t3210  AP6410\n\t6422  ProVideo 6422\n\t6424  ProVideo 6424\n\t6425  ProMotion AT25\n\t643d  ProMotion AT3D\n1143  NetPower, Inc\n1144  Cincinnati Milacron\n\t0001  Noservo controller\n1145  Workbit Corporation\n\t8007  NinjaSCSI-32 Workbit\n\tf007  NinjaSCSI-32 KME\n\tf010  NinjaSCSI-32 Workbit\n\tf012  NinjaSCSI-32 Logitec\n\tf013  NinjaSCSI-32 Logitec\n\tf015  NinjaSCSI-32 Melco\n\tf020  NinjaSCSI-32 Sony PCGA-DVD51\n\tf021  NinjaPATA-32 Delkin Cardbus UDMA\n\tf024  NinjaPATA-32 Delkin Cardbus UDMA\n\tf103  NinjaPATA-32 Delkin Cardbus UDMA\n1146  Force Computers\n1147  Interface Corp\n# Nee Schneider & Koch\n1148  SysKonnect\n\t4000  FDDI Adapter\n\t\t0e11 b03b  Netelligent 100 FDDI DAS Fibre SC\n\t\t0e11 b03c  Netelligent 100 FDDI SAS Fibre SC\n\t\t0e11 b03d  Netelligent 100 FDDI DAS UTP\n\t\t0e11 b03e  Netelligent 100 FDDI SAS UTP\n\t\t0e11 b03f  Netelligent 100 FDDI SAS Fibre MIC\n\t\t1148 5521  FDDI SK-5521 (SK-NET FDDI-UP)\n\t\t1148 5522  FDDI SK-5522 (SK-NET FDDI-UP DAS)\n\t\t1148 5541  FDDI SK-5541 (SK-NET FDDI-FP)\n\t\t1148 5543  FDDI SK-5543 (SK-NET FDDI-LP)\n\t\t1148 5544  FDDI SK-5544 (SK-NET FDDI-LP DAS)\n\t\t1148 5821  FDDI SK-5821 (SK-NET FDDI-UP64)\n\t\t1148 5822  FDDI SK-5822 (SK-NET FDDI-UP64 DAS)\n\t\t1148 5841  FDDI SK-5841 (SK-NET FDDI-FP64)\n\t\t1148 5843  FDDI SK-5843 (SK-NET FDDI-LP64)\n\t\t1148 5844  FDDI SK-5844 (SK-NET FDDI-LP64 DAS)\n\t4200  Token Ring adapter\n\t4300  SK-9872 Gigabit Ethernet Server Adapter (SK-NET GE-ZX dual link)\n\t\t1148 9821  SK-9821 Gigabit Ethernet Server Adapter (SK-NET GE-T)\n\t\t1148 9822  SK-9822 Gigabit Ethernet Server Adapter (SK-NET GE-T dual link)\n\t\t1148 9841  SK-9841 Gigabit Ethernet Server Adapter (SK-NET GE-LX)\n\t\t1148 9842  SK-9842 Gigabit Ethernet Server Adapter (SK-NET GE-LX dual link)\n\t\t1148 9843  SK-9843 Gigabit Ethernet Server Adapter (SK-NET GE-SX)\n\t\t1148 9844  SK-9844 Gigabit Ethernet Server Adapter (SK-NET GE-SX dual link)\n\t\t1148 9861  SK-9861 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition)\n\t\t1148 9862  SK-9862 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition dual link)\n\t\t1148 9871  SK-9871 Gigabit Ethernet Server Adapter (SK-NET GE-ZX)\n\t\t1148 9872  SK-9872 Gigabit Ethernet Server Adapter (SK-NET GE-ZX dual link)\n\t\t1259 2970  AT-2970SX Gigabit Ethernet Adapter\n\t\t1259 2971  AT-2970LX Gigabit Ethernet Adapter\n\t\t1259 2972  AT-2970TX Gigabit Ethernet Adapter\n\t\t1259 2973  AT-2971SX Gigabit Ethernet Adapter\n\t\t1259 2974  AT-2971T Gigabit Ethernet Adapter\n\t\t1259 2975  AT-2970SX/2SC Gigabit Ethernet Adapter\n\t\t1259 2976  AT-2970LX/2SC Gigabit Ethernet Adapter\n\t\t1259 2977  AT-2970TX/2TX Gigabit Ethernet Adapter\n\t4320  SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter, PCI64, Fiber ZX/SC\n\t\t1148 0121  Marvell RDK-8001 Adapter\n\t\t1148 0221  Marvell RDK-8002 Adapter\n\t\t1148 0321  Marvell RDK-8003 Adapter\n\t\t1148 0421  Marvell RDK-8004 Adapter\n\t\t1148 0621  Marvell RDK-8006 Adapter\n\t\t1148 0721  Marvell RDK-8007 Adapter\n\t\t1148 0821  Marvell RDK-8008 Adapter\n\t\t1148 0921  Marvell RDK-8009 Adapter\n\t\t1148 1121  Marvell RDK-8011 Adapter\n\t\t1148 1221  Marvell RDK-8012 Adapter\n\t\t1148 3221  SK-9521 V2.0 10/100/1000Base-T Adapter\n\t\t1148 5021  SK-9821 V2.0 Gigabit Ethernet 10/100/1000Base-T Adapter\n\t\t1148 5041  SK-9841 V2.0 Gigabit Ethernet 1000Base-LX Adapter\n\t\t1148 5043  SK-9843 V2.0 Gigabit Ethernet 1000Base-SX Adapter\n\t\t1148 5051  SK-9851 V2.0 Gigabit Ethernet 1000Base-SX Adapter\n\t\t1148 5061  SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter\n\t\t1148 5071  SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter\n\t\t1148 9521  SK-9521 10/100/1000Base-T Adapter\n\t4400  SK-9Dxx Gigabit Ethernet Adapter\n\t4500  SK-9Mxx Gigabit Ethernet Adapter\n\t9000  SK-9S21 10/100/1000Base-T Server Adapter, PCI-X, Copper RJ-45\n\t9843  [Fujitsu] Gigabit Ethernet\n\t9e00  SK-9E21D 10/100/1000Base-T Adapter, Copper RJ-45\n\t\t1148 2100  SK-9E21 Server Adapter\n\t\t1148 21d0  SK-9E21D 10/100/1000Base-T Adapter\n\t\t1148 2200  SK-9E22 Server Adapter\n\t\t1148 8100  SK-9E81 Server Adapter\n\t\t1148 8200  SK-9E82 Server Adapter\n\t\t1148 9100  SK-9E91 Server Adapter\n\t\t1148 9200  SK-9E92 Server Adapter\n\t9e01  SK-9E21M 10/100/1000Base-T Adapter\n1149  Win System Corporation\n114a  VMIC\n\t5565  GE-IP PCI5565,PMC5565 Reflective Memory Node\n\t5579  VMIPCI-5579 (Reflective Memory Card)\n\t5587  VMIPCI-5587 (Reflective Memory Card)\n\t6504  VMIC PCI 7755 FPGA\n\t7587  VMIVME-7587\n114b  Canopus Co., Ltd\n114c  Annabooks\n114d  IC Corporation\n114e  Nikon Systems Inc\n114f  Digi International\n\t0002  AccelePort EPC\n\t0003  RightSwitch SE-6\n\t0004  AccelePort Xem\n\t0005  AccelePort Xr\n\t0006  AccelePort Xr,C/X\n\t0009  AccelePort Xr/J\n\t000a  AccelePort EPC/J\n\t000c  DataFirePRIme T1 (1-port)\n\t000d  SyncPort 2-Port (x.25/FR)\n\t0011  AccelePort 8r EIA-232 (IBM)\n\t0012  AccelePort 8r EIA-422\n\t0013  AccelePort Xr\n\t0014  AccelePort 8r EIA-422\n\t0015  AccelePort Xem\n\t0016  AccelePort EPC/X\n\t0017  AccelePort C/X\n\t001a  DataFirePRIme E1 (1-port)\n\t001b  AccelePort C/X (IBM)\n\t001c  AccelePort Xr (SAIP)\n\t001d  DataFire RAS T1/E1/PRI\n\t\t114f 0050  DataFire RAS E1 Adapter\n\t\t114f 0051  DataFire RAS Dual E1 Adapter\n\t\t114f 0052  DataFire RAS T1 Adapter\n\t\t114f 0053  DataFire RAS Dual T1 Adapter\n\t0023  AccelePort RAS\n\t0024  DataFire RAS B4 ST/U\n\t\t114f 0030  DataFire RAS BRI U Adapter\n\t\t114f 0031  DataFire RAS BRI S/T Adapter\n\t0026  AccelePort 4r 920\n\t0027  AccelePort Xr 920\n\t0028  ClassicBoard 4\n\t0029  ClassicBoard 8\n\t0034  AccelePort 2r 920\n\t0035  DataFire DSP T1/E1/PRI cPCI\n\t0040  AccelePort Xp\n\t\t114f 0042  AccelePort 2p PCI\n\t\t114f 0043  AccelePort 4p PCI\n\t\t114f 0044  AccelePort 8p PCI\n\t\t114f 0045  AccelePort 16p PCI\n\t\t114f 004e  AccelePort 32p PCI\n\t0042  AccelePort 2p\n\t0043  AccelePort 4p\n\t0044  AccelePort 8p\n\t0045  AccelePort 16p\n\t004e  AccelePort 32p\n\t0070  Datafire Micro V IOM2 (Europe)\n\t0071  Datafire Micro V (Europe)\n\t0072  Datafire Micro V IOM2 (North America)\n\t0073  Datafire Micro V (North America)\n\t00b0  Digi Neo 4\n\t00b1  Digi Neo 8\n\t00c8  Digi Neo 2 DB9\n\t00c9  Digi Neo 2 DB9 PRI\n\t00ca  Digi Neo 2 RJ45\n\t00cb  Digi Neo 2 RJ45 PRI\n\t00cc  Digi Neo 1 422\n\t00cd  Digi Neo 1 422 485\n\t00ce  Digi Neo 2 422 485\n\t00d0  ClassicBoard 4 422\n\t00d1  ClassicBoard 8 422\n\t00f1  Digi Neo PCI-E 4 port\n\t00f4  Digi Neo 4 (IBM version)\n\t6001  Avanstar\n1150  Thinking Machines Corp\n1151  JAE Electronics Inc.\n1152  Megatek\n1153  Land Win Electronic Corp\n1154  Melco Inc\n1155  Pine Technology Ltd\n1156  Periscope Engineering\n1157  Avsys Corporation\n1158  Voarx R & D Inc\n\t3011  Tokenet/vg 1001/10m anylan\n\t9050  Lanfleet/Truevalue\n\t9051  Lanfleet/Truevalue\n1159  MuTech Corporation\n\t0001  MV-1000\n\t0002  MV-1500\n115a  Harlequin Ltd\n115b  Parallax Graphics\n115c  Photron Ltd.\n115d  Xircom\n\t0003  Cardbus Ethernet 10/100\n\t\t1014 0181  10/100 EtherJet Cardbus Adapter\n\t\t1014 1181  10/100 EtherJet Cardbus Adapter\n\t\t1014 8181  10/100 EtherJet Cardbus Adapter\n\t\t1014 9181  10/100 EtherJet Cardbus Adapter\n\t\t115d 0181  Cardbus Ethernet 10/100\n\t\t115d 0182  RealPort2 CardBus Ethernet 10/100 (R2BE-100)\n\t\t115d 1181  Cardbus Ethernet 10/100\n\t\t1179 0181  Cardbus Ethernet 10/100\n\t\t8086 8181  EtherExpress PRO/100 Mobile CardBus 32 Adapter\n\t\t8086 9181  EtherExpress PRO/100 Mobile CardBus 32 Adapter\n\t0005  Cardbus Ethernet 10/100\n\t\t1014 0182  10/100 EtherJet Cardbus Adapter\n\t\t1014 1182  10/100 EtherJet Cardbus Adapter\n\t\t115d 0182  Cardbus Ethernet 10/100\n\t\t115d 1182  Cardbus Ethernet 10/100\n\t0007  Cardbus Ethernet 10/100\n\t\t1014 0182  10/100 EtherJet Cardbus Adapter\n\t\t1014 1182  10/100 EtherJet Cardbus Adapter\n\t\t115d 0182  Cardbus Ethernet 10/100\n\t\t115d 1182  Cardbus Ethernet 10/100\n\t000b  Cardbus Ethernet 10/100\n\t\t1014 0183  10/100 EtherJet Cardbus Adapter\n\t\t115d 0183  Cardbus Ethernet 10/100\n\t000c  Mini-PCI V.90 56k Modem\n\t000f  Cardbus Ethernet 10/100\n\t\t1014 0183  10/100 EtherJet Cardbus Adapter\n\t\t115d 0183  Cardbus Ethernet 10/100\n\t00d4  Mini-PCI K56Flex Modem\n\t0101  Cardbus 56k modem\n\t\t115d 1081  Cardbus 56k Modem\n\t0103  Cardbus Ethernet + 56k Modem\n\t\t1014 9181  Cardbus 56k Modem\n\t\t1115 1181  Cardbus Ethernet 100 + 56k Modem\n\t\t115d 1181  CBEM56G-100 Ethernet + 56k Modem\n\t\t8086 9181  PRO/100 LAN + Modem56 CardBus\n115e  Peer Protocols Inc\n115f  Maxtor Corporation\n1160  Megasoft Inc\n1161  PFU Limited\n1162  OA Laboratory Co Ltd\n1163  Rendition\n\t0001  Verite 1000\n\t2000  Verite V2000/V2100/V2200\n\t\t1092 2000  Stealth II S220\n1164  Advanced Peripherals Technologies\n1165  Imagraph Corporation\n\t0001  Motion TPEG Recorder/Player with audio\n# nee ServerWorks\n1166  Broadcom\n\t0000  CMIC-LE\n\t0005  CNB20-LE Host Bridge\n\t0006  CNB20HE Host Bridge\n\t0007  CNB20-LE Host Bridge\n\t0008  CNB20HE Host Bridge\n\t0009  CNB20LE Host Bridge\n\t0010  CIOB30\n\t0011  CMIC-HE\n\t0012  CMIC-WS Host Bridge (GC-LE chipset)\n\t0013  CNB20-HE Host Bridge\n\t0014  CMIC-LE Host Bridge (GC-LE chipset)\n\t0015  CMIC-GC Host Bridge\n\t0016  CMIC-GC Host Bridge\n\t0017  GCNB-LE Host Bridge\n\t0031  HT1100 HPX0 HT Host Bridge\n\t0036  BCM5785 [HT1000] PCI/PCI-X Bridge\n\t0101  CIOB-X2 PCI-X I/O Bridge\n\t0103  EPB PCI-Express to PCI-X Bridge\n\t0104  BCM5785 [HT1000] PCI/PCI-X Bridge\n\t0110  CIOB-E I/O Bridge with Gigabit Ethernet\n\t0130  BCM5780 [HT2000] PCI-X bridge\n\t0132  BCM5780 [HT2000] PCI-Express Bridge\n\t\t1166 0132  HT2000 PCI-Express bridge\n\t0140  HT2100 PCI-Express Bridge\n\t0141  HT2100 PCI-Express Bridge\n\t0142  HT2100 PCI-Express Bridge\n\t0144  HT2100 PCI-Express Bridge\n\t0200  OSB4 South Bridge\n\t0201  CSB5 South Bridge\n\t\t4c53 1080  CT8 mainboard\n\t0203  CSB6 South Bridge\n\t\t1734 1012  PRIMERGY RX/TX series\n\t0205  BCM5785 [HT1000] Legacy South Bridge\n\t0211  OSB4 IDE Controller\n\t0212  CSB5 IDE Controller\n\t\t1028 014a  PowerEdge 1750\n\t\t1028 810b  PowerEdge 1650/2550\n\t\t4c53 1080  CT8 mainboard\n\t0213  CSB6 RAID/IDE Controller\n\t\t1028 4134  PowerEdge 600SC\n\t\t1028 c134  Poweredge SC600\n\t\t1734 1012  PRIMERGY RX/TX series onboard IDE\n\t0214  BCM5785 [HT1000] IDE\n\t\t1028 0205  PowerEdge 2970 HT1000 IDE\n\t0217  CSB6 IDE Controller\n\t\t1028 4134  Poweredge SC600\n\t021b  HT1100 HD Audio\n\t0220  OSB4/CSB5 OHCI USB Controller\n\t\t4c53 1080  CT8 mainboard\n\t0221  CSB6 OHCI USB Controller\n\t\t1734 1012  PRIMERGY RX/TX series onboard OHCI\n\t0223  BCM5785 [HT1000] USB\n\t\t1028 0205  PowerEdge 2970 HT1000 USB Controller\n\t\t1028 020b  PowerEdge T605 HT1000 USB Controller\n\t0225  CSB5 LPC bridge\n\t0227  GCLE-2 Host Bridge\n\t\t1734 1012  PRIMERGY RX/TX series\n\t0230  CSB5 LPC bridge\n\t\t4c53 1080  CT8 mainboard\n\t0234  BCM5785 [HT1000] LPC\n\t\t1028 0205  PowerEdge 2970 HT1000 LPC\n\t\t1028 020b  PowerEdge T605 HT1000 LPC\n\t0235  BCM5785 [HT1000] XIOAPIC0-2\n\t0238  BCM5785 [HT1000] WDTimer\n\t0240  K2 SATA\n\t0241  RAIDCore RC4000\n\t0242  RAIDCore BC4000\n\t024a  BCM5785 [HT1000] SATA (Native SATA Mode)\n\t\t1028 020b  PowerEdge T605 onboard SATA Controller\n# The device starts as 024A, and changes to 024B if set to PATA mode in BIOS\n\t024b  BCM5785 [HT1000] SATA (PATA/IDE Mode)\n\t\t1028 0205  PowerEdge 2970 HT1000 SATA controller\n\t0406  HT1100 PCI-X Bridge\n\t0408  HT1100 Legacy Device\n\t040a  HT1100 ISA-LPC Bridge\n\t\t1028 0223  PowerEdge R905 HT1100 ISA-LPC Bridge\n\t0410  HT1100 SATA Controller (Native SATA Mode)\n\t0411  HT1100 SATA Controller (PATA / IDE Mode)\n\t0412  HT1100 USB OHCI Controller\n\t0414  HT1100 USB EHCI Controller\n\t0416  HT1100 USB EHCI Controller (with Debug Port)\n\t0420  HT1100 PCI-Express Bridge\n\t0421  HT1100 SAS/SATA Controller\n\t0422  HT1100 PCI-Express Bridge\n1167  Mutoh Industries Inc\n1168  Thine Electronics Inc\n1169  Centre for Development of Advanced Computing\n# nee Polaris Communications\n116a  Luminex Software, Inc.\n\t6100  Bus/Tag Channel\n\t6800  Escon Channel\n\t7100  Bus/Tag Channel\n\t7800  Escon Channel\n116b  Connectware Inc\n116c  Intelligent Resources Integrated Systems\n116d  Martin-Marietta\n116e  Electronics for Imaging\n116f  Workstation Technology\n1170  Inventec Corporation\n1171  Loughborough Sound Images Plc\n1172  Altera Corporation\n\t00a7  Stratix V\n\t0530  Stratix IV\n1173  Adobe Systems, Inc\n1174  Bridgeport Machines\n1175  Mitron Computer Inc.\n1176  SBE Incorporated\n1177  Silicon Engineering\n1178  Alfa, Inc.\n\tafa1  Fast Ethernet Adapter\n1179  Toshiba Corporation\n\t0102  Extended IDE Controller\n\t0103  EX-IDE Type-B\n\t010f  NVMe Controller\n\t0110  NVMe SSD Controller Cx5\n\t\t1028 1ffb  Express Flash NVMe 960G (RI) U.2 (CD5)\n\t\t1028 1ffc  Express Flash NVMe 1.92T (RI) U.2 (CD5)\n\t\t1028 1ffd  Express Flash NVMe 3.84T (RI) U.2 (CD5)\n\t\t1028 1ffe  Express Flash NVMe 7.68T (RI) U.2 (CD5)\n\t\t1179 0001  KIOXIA CM5-R series SSD\n\t\t1179 0021  KIOXIA CD5 series SSD\n\t\t1d49 4039  Thinksystem U.2 CM5 NVMe SSD\n\t\t1d49 403a  Thinksystem AIC CM5 NVMe SSD\n\t0113  BG3 NVMe SSD Controller\n\t0115  XG4 NVMe SSD Controller\n\t0404  DVD Decoder card\n\t0406  Tecra Video Capture device\n\t0407  DVD Decoder card (Version 2)\n\t0601  CPU to PCI bridge\n\t\t1179 0001  Satellite Pro\n\t0602  PCI to ISA bridge\n\t0603  ToPIC95 PCI to CardBus Bridge for Notebooks\n\t0604  PCI-Docking Host bridge\n\t060a  ToPIC95\n\t\t1179 0001  Satellite Pro\n\t060f  ToPIC97\n\t\t1179 0001  Satellite 4010\n\t0617  ToPIC100 PCI to Cardbus Bridge with ZV Support\n\t0618  CPU to PCI and PCI to ISA bridge\n\t0701  FIR Port Type-O\n\t0803  TC6371AF SD Host Controller\n\t0804  TC6371AF SmartMedia Controller\n\t0805  SD TypA Controller\n\t0d01  FIR Port Type-DO\n\t\t1179 0001  FIR Port Type-DO\n117a  A-Trend Technology\n117b  L G Electronics, Inc.\n117c  ATTO Technology, Inc.\n\t002c  ExpressSAS R380\n\t002d  ExpressSAS R348\n\t0030  Ultra320 SCSI Host Adapter\n\t\t117c 8013  ExpressPCI UL4D\n\t\t117c 8014  ExpressPCI UL4S\n\t\t117c 8027  ExpressPCI UL5D\n\t\t117c 802f  ExpressPCI UL5D Low Profile\n\t0033  SAS Adapter\n\t0041  ExpressSAS R30F\n\t0042  ExpressSAS 6Gb/s SAS/SATA HBA\n\t\t117c 0042  ExpressSAS H680\n\t\t117c 0043  ExpressSAS H608\n\t\t117c 0044  ExpressSAS H60F\n\t\t117c 0045  ExpressSAS H6F0\n\t\t117c 0046  ExpressSAS H644\n\t\t117c 004f  ExpressSAS M608\n\t\t117c 0057  ExpressSAS M680\n\t\t117c 0058  ExpressSAS M644\n\t\t117c 0059  ExpressSAS W608\n\t\t117c 005a  ExpressSAS W680\n\t\t117c 005b  ExpressSAS W644\n\t0049  ExpressSAS 6Gb SAS/SATA RAID Adapter\n\t\t117c 0049  ExpressSAS R680\n\t\t117c 004a  ExpressSAS R608\n\t\t117c 004b  ExpressSAS R60F\n\t\t117c 004c  ExpressSAS R6F0\n\t\t117c 004d  ExpressSAS R644\n\t\t117c 004e  ExpressSAS R648\n\t0064  Celerity FC 16Gb/s Gen 5 Fibre Channel HBA\n\t\t117c 0063  Celerity FC-161E\n\t\t117c 0064  Celerity FC-162E\n\t\t117c 0065  Celerity FC-164E\n\t0094  Celerity FC 16/32Gb/s Gen 6 Fibre Channel HBA\n\t\t117c 0094  Celerity FC-162P\n\t\t117c 00a0  Celerity FC-161P\n\t\t117c 00a1  Celerity FC-164P\n\t\t117c 00a2  Celerity FC-321E\n\t\t117c 00a3  Celerity FC-322E\n\t\t117c 00ac  Celerity FC-324E\n\t8013  ExpressPCI UL4D\n\t8014  ExpressPCI UL4S\n\t8027  ExpressPCI UL5D\n\t8070  ExpressSAS 12Gb/s SAS/SATA HBA\n\t\t117c 0070  ExpressSAS H1280\n\t\t117c 0071  ExpressSAS H1208\n\t\t117c 0080  ExpressSAS H1244\n\t8072  ExpressSAS 12Gb/s SAS/SATA HBA\n\t\t117c 0072  ExpressSAS H12F0\n\t\t117c 0073  ExpressSAS H120F\n\t\t117c 0082  ExpressSAS H1288\n117d  Becton & Dickinson\n117e  T/R Systems\n117f  Integrated Circuit Systems\n1180  Ricoh Co Ltd\n\t0465  RL5c465\n\t0466  RL5c466\n\t0475  RL5c475\n\t\t144d c006  vpr Matrix 170B4 CardBus bridge\n\t0476  RL5c476 II\n\t\t1014 0185  ThinkPad A/T/X Series\n\t\t1014 0555  ThinkPad X41\n\t\t1014 056c  ThinkPad Z60t\n\t\t1028 014f  Latitude X300 laptop\n\t\t1028 0188  Inspiron 6000 laptop\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30c1  Compaq 6910p\n\t\t1043 1237  A6J-Q008\n\t\t1043 1967  V6800V\n\t\t1043 1987  A4K and Z81K notebooks, possibly others ( mid-2005 machines )\n\t\t104d 80df  Vaio PCG-FX403\n\t\t104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP\n\t\t104d 814e  VAIO GRZ390Z\n\t\t10f7 8338  Panasonic CF-Y5 laptop\n\t\t144d c005  X10 Laptop\n\t\t144d c00c  P30/P35 notebook\n\t\t14ef 0220  PCD-RP-220S\n\t\t17aa 201c  ThinkPad X60/X60s\n\t\t17aa 20c4  ThinkPad T61/R61\n\t\t17aa 20c6  ThinkPad R61/T400\n\t0477  RL5c477\n\t0478  RL5c478\n\t\t1014 0184  ThinkPad A30p\n\t0511  R5C511\n\t0522  R5C522 IEEE 1394 Controller\n\t\t1014 01cf  ThinkPad A30p\n\t\t1043 1967  V6800V\n\t0551  R5C551 IEEE 1394 Controller\n\t\t144d c006  vpr Matrix 170B4\n\t0552  R5C552 IEEE 1394 Controller\n\t\t1014 0511  ThinkPad A/T/X Series\n\t\t1028 014f  Latitude X300 laptop\n\t\t1028 0188  Inspiron 6000 laptop\n\t\t1043 1237  A6J-Q008\n\t\t1043 1757  M2400N laptop\n\t\t144d c005  X10 Laptop\n\t\t144d c00c  P30/P35 notebook\n\t\t17aa 201e  ThinkPad X60/X60s\n\t0554  R5C554\n\t0575  R5C575 SD Bus Host Adapter\n\t0576  R5C576 SD Bus Host Adapter\n\t0592  R5C592 Memory Stick Bus Host Adapter\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01d7  XPS M1210\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 1521  HP EliteBook 8540w\n\t\t103c 30b5  Presario V3242AU\n\t\t103c 30b7  Presario V6133CL\n\t\t103c 30cc  Pavilion dv6700\n\t\t103c 30cf  Pavilion dv95xx/96xx/97xx/98xx series\n\t\t1043 1237  A6J-Q008\n\t\t1043 1967  V6800V\n\t\t104d 9035  VAIO VGN-FW11ZRU\n\t\t144d c018  X20 IV\n\t\t17aa 20ca  ThinkPad T61/T400\n\t0811  R5C811\n\t0822  R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter\n\t\t1014 0556  ThinkPad X40 / X41 / X60s / Z60t\n\t\t1014 0598  ThinkPad Z60m\n\t\t1025 0121  Aspire 5920G\n\t\t1028 0188  Inspiron 6000 laptop\n\t\t1028 01a2  Inspiron 9200\n\t\t1028 01d7  XPS M1210\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 03b5  Presario V3242AU\n\t\t103c 30b7  Presario V6133CL\n\t\t103c 30c1  Compaq 6910p\n\t\t103c 30cc  Pavilion dv6700\n\t\t103c 30cf  Pavilion dv9668eg Laptop\n\t\t1043 1237  A6J-Q008\n\t\t1043 1967  V6800V\n\t\t10f7 8338  Panasonic CF-Y5 laptop\n\t\t144d c018  X20 IV\n\t\t17aa 201d  ThinkPad X60/X60s\n\t\t17aa 20c7  ThinkPad T61\n\t\t17aa 20c8  ThinkPad T400/W500\n\t0832  R5C832 IEEE 1394 Controller\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01d7  XPS M1210\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t1028 024d  Latitude E4300\n\t\t103c 30b5  Presario V3242AU\n\t\t103c 30b7  Presario V6133CL\n\t\t103c 30c1  Compaq 6910p\n\t\t103c 30cc  Pavilion dv6700\n\t\t103c 30cf  Pavilion dv9668eg Laptop\n\t\t17aa 20c5  ThinkPad R61\n\t\t17aa 20c7  ThinkPad R61\n\t0841  R5C841 CardBus/SD/SDIO/MMC/MS/MSPro/xD/IEEE1394\n\t0843  R5C843 MMC Host Controller\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01d7  XPS M1210\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 01f5  Inspiron 1501\n\t\t1028 024f  Latitude e6500\n\t\t103c 03b5  Presario V3242AU\n\t\t103c 1521  HP EliteBook 8540w\n\t\t103c 30b7  Presario V6133CL\n\t\t103c 30cf  Pavilion dv9500/9600/9700 series\n\t\t1183 0843  Alienware Aurora m9700\n\t0852  xD-Picture Card Controller\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30b5  Presario V3242AU\n\t\t103c 30b7  Presario V6133CL\n\t\t103c 30cc  Pavilion dv6700\n\t\t103c 30cf  Pavilion dv9668eg Laptop\n\t\t1043 1967  V6800V\n\t\t1180 0852  Pavilion 2410us\n\t\t1324 10cf  P7120\n\t\t17aa 20cb  ThinkPad T400\n\te230  R5U2xx (R5U230 / R5U231 / R5U241) [Memory Stick Host Controller]\n\te476  CardBus bridge\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\te822  MMC/SD Host Controller\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\t17aa 21cf  ThinkPad T520\n\te823  PCIe SDXC/MMC Host Controller\n\t\t17aa 21cf  ThinkPad T520\n\te832  R5C832 PCIe IEEE 1394 Controller\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\t17aa 21cf  ThinkPad T520\n\te852  PCIe xD-Picture Card Controller\n1181  Telmatics International\n1183  Fujikura Ltd\n1184  Forks Inc\n1185  Dataworld International Ltd\n1186  D-Link System Inc\n\t1002  DL10050 Sundance Ethernet\n\t\t1186 1002  DFE-550TX/FX\n\t\t1186 1012  DFE-580TX\n\t1025  AirPlus Xtreme G DWL-G650 Adapter\n\t1026  AirXpert DWL-AG650 Wireless Cardbus Adapter\n\t1043  AirXpert DWL-AG650 Wireless Cardbus Adapter\n\t1300  RTL8139 Ethernet\n\t\t1186 1300  DFE-538TX 10/100 Ethernet Adapter\n\t\t1186 1301  DFE-530TX+ 10/100 Ethernet Adapter\n\t\t1186 1303  DFE-528TX 10/100 Fast Ethernet PCI Adapter\n\t1340  DFE-690TXD CardBus PC Card\n\t1540  DFE-680TX\n\t1541  DFE-680TXD CardBus PC Card\n\t1561  DRP-32TXD Cardbus PC Card\n\t3300  DWL-510 / DWL-610 802.11b [Realtek RTL8180L]\n\t\t1186 3300  DWL-610 Wireless Cardbus Adapter\n\t\t1186 3301  DWL-510 Wireless PCI Adapter\n\t3a10  AirXpert DWL-AG650 Wireless Cardbus Adapter(rev.B)\n\t3a11  AirXpert DWL-AG520 Wireless PCI Adapter(rev.B)\n\t4000  DL2000-based Gigabit Ethernet\n\t4001  DGE-550SX PCI-X Gigabit Ethernet Adapter\n\t4200  DFE-520TX Fast Ethernet PCI Adapter\n\t\t1186 1103  DFE-520TX Fast Ethernet PCI Adapter (rev. C1)\n\t4300  DGE-528T Gigabit Ethernet Adapter\n\t\t1186 4300  DGE-528T PCI Gigabit Ethernet Adapter\n# rev. B1; RealTek RTL8168E.\n\t\t1186 4b10  DGE-560T PCI Express (x1) Gigabit Ethernet Adapter\n\t4302  DGE-530T Gigabit Ethernet Adapter (rev.C1) [Realtek RTL8169]\n\t4b00  DGE-560T PCI Express Gigabit Ethernet Adapter\n\t4b01  DGE-530T Gigabit Ethernet Adapter (rev 11)\n\t4b02  DGE-560SX PCI Express Gigabit Ethernet Adapter\n\t4b03  DGE-550T Gigabit Ethernet Adapter V.B1\n\t4c00  Gigabit Ethernet Adapter\n\t\t1186 4c00  DGE-530T Gigabit Ethernet Adapter\n\t8400  D-Link DWL-650+ CardBus PC Card\n1187  Advanced Technology Laboratories, Inc.\n1188  Shima Seiki Manufacturing Ltd.\n1189  Matsushita Electronics Co Ltd\n118a  Hilevel Technology\n118b  Hypertec Pty Limited\n118c  Corollary, Inc\n\t0014  PCIB [C-bus II to PCI bus host bridge chip]\n\t1117  Intel 8-way XEON Profusion Chipset [Cache Coherency Filter]\n118d  BitFlow Inc\n\t0001  Raptor-PCI framegrabber\n\t0012  Model 12 Road Runner Frame Grabber\n\t0014  Model 14 Road Runner Frame Grabber\n\t0024  Model 24 Road Runner Frame Grabber\n\t0044  Model 44 Road Runner Frame Grabber\n\t0112  Model 12 Road Runner Frame Grabber\n\t0114  Model 14 Road Runner Frame Grabber\n\t0124  Model 24 Road Runner Frame Grabber\n\t0144  Model 44 Road Runner Frame Grabber\n\t0212  Model 12 Road Runner Frame Grabber\n\t0214  Model 14 Road Runner Frame Grabber\n\t0224  Model 24 Road Runner Frame Grabber\n\t0244  Model 44 Road Runner Frame Grabber\n\t0312  Model 12 Road Runner Frame Grabber\n\t0314  Model 14 Road Runner Frame Grabber\n\t0324  Model 24 Road Runner Frame Grabber\n\t0344  Model 44 Road Runner Frame Grabber\n118e  Hermstedt GmbH\n118f  Green Logic\n1190  Tripace\n\tc731  TP-910/920/940 PCI Ultra(Wide) SCSI Adapter\n1191  Artop Electronic Corp\n\t0003  SCSI Cache Host Adapter\n\t0004  ATP8400\n\t0005  ATP850UF\n\t0006  ATP860 NO-BIOS\n\t0007  ATP860\n\t0008  ATP865 NO-ROM\n\t0009  ATP865\n\t000a  ATP867-A\n\t000b  ATP867-B\n\t000d  ATP8620\n\t000e  ATP8620\n\t8002  AEC6710 SCSI-2 Host Adapter\n\t8010  AEC6712UW SCSI\n\t8020  AEC6712U SCSI\n\t8030  AEC6712S SCSI\n\t8040  AEC6712D SCSI\n\t8050  AEC6712SUW SCSI\n\t8060  AEC6712 SCSI\n\t8080  AEC67160 SCSI\n\t8081  AEC67160S SCSI\n\t808a  AEC67162 2-ch. LVD SCSI\n1192  Densan Company Ltd\n1193  Zeitnet Inc.\n\t0001  1221\n\t0002  1225\n1194  Toucan Technology\n1195  Ratoc System Inc\n1196  Hytec Electronics Ltd\n1197  Gage Applied Sciences, Inc.\n\t010c  CompuScope 82G 8bit 2GS/s Analog Input Card\n1198  Lambda Systems Inc\n1199  Attachmate Corporation\n\t0101  Advanced ISCA/PCI Adapter\n119a  Mind Share, Inc.\n119b  Omega Micro Inc.\n\t1221  82C092G\n119c  Information Technology Inst.\n119d  Bug, Inc. Sapporo Japan\n119e  Fujitsu Microelectronics Ltd.\n\t0001  FireStream 155\n\t0003  FireStream 50\n119f  Bull HN Information Systems\n\t1081  BXI Host Channel Adapter\n# BXI stands for Bull eXascale Interconnect\n\t1101  BXI Host Channel Adapter v1.2\n# BXI stands for Bull eXascale Interconnect\n\t1121  BXI Host Channel Adapter v1.3\n11a0  Convex Computer Corporation\n11a1  Hamamatsu Photonics K.K.\n11a2  Sierra Research and Technology\n11a3  Deuretzbacher GmbH & Co. Eng. KG\n11a4  Barco Graphics NV\n11a5  Microunity Systems Eng. Inc\n11a6  Pure Data Ltd.\n11a7  Power Computing Corp.\n11a8  Systech Corp.\n11a9  InnoSys Inc.\n\t4240  AMCC S933Q Intelligent Serial Card\n11aa  Actel\n# Nee Galileo Technology, Inc.\n11ab  Marvell Technology Group Ltd.\n\t0146  GT-64010/64010A System Controller\n\t0f53  88E6318 Link Street network controller\n\t11ab  MV88SE614x SATA II PCI-E controller\n\t138f  W8300 802.11 Adapter (rev 07)\n\t1fa6  Marvell W8300 802.11 Adapter\n\t\t1186 3b08  AirPlus G DWL-G630 Wireless Cardbus Adapter (rev.A1)\n\t1fa7  88W8310 and 88W8000G [Libertas] 802.11g client chipset\n\t1faa  88w8335 [Libertas] 802.11b/g Wireless\n\t\t1385 4e00  WG511v2 54 Mbps Wireless PC Card\n\t\t1385 6b00  WG311v3 802.11g Wireless PCI Adapter\n\t\t1737 0040  WPC54G v5 802.11g Wireless-G Notebook Adapter\n\t2211  88SB2211 PCI Express to PCI Bridge\n\t2a01  88W8335 [Libertas] 802.11b/g Wireless\n\t2a02  88W8361 [TopDog] 802.11n Wireless\n\t\t07d1 3b02  DIR-615 rev. A1 Mini PCI Wireless Module\n\t\t1385 7c00  WN511T RangeMax Next 300 Mbps Wireless PC Card\n\t\t1385 7c01  WN511T RangeMax Next 300 Mbps Wireless Notebook Adapter\n\t\t1385 7e00  WN311T RangeMax Next 300 Mbps Wireless PCI Adapter\n\t\t1799 801b  F5D8011 v2 802.11n N1 Wireless Notebook Card\n\t2a08  88W8362e [TopDog] 802.11a/b/g/n Wireless\n\t2a0a  88W8363 [TopDog] 802.11n Wireless\n\t2a0c  88W8363 [TopDog] 802.11n Wireless\n\t2a24  88W8363 [TopDog] 802.11n Wireless\n\t2a2b  88W8687 [TopDog] 802.11b/g Wireless\n\t2a30  88W8687 [TopDog] 802.11b/g Wireless\n\t2a40  88W8366 [TopDog] 802.11n Wireless\n\t2a41  88W8366 [TopDog] 802.11n Wireless\n\t2a42  88W8366 [TopDog] 802.11n Wireless\n\t2a43  88W8366 [TopDog] 802.11n Wireless\n\t2a55  88W8864 [Avastar] 802.11ac Wireless\n\t2b36  88W8764 [Avastar] 802.11n Wireless\n\t2b38  88W8897 [AVASTAR] 802.11ac Wireless\n\t2b40  88W8964 [Avastar] 802.11ac Wireless\n\t4101  OLPC Cafe Controller Secure Digital Controller\n\t4320  88E8001 Gigabit Ethernet Controller\n\t\t1019 0f38  Marvell 88E8001 Gigabit Ethernet Controller (ECS)\n\t\t1019 8001  Marvell 88E8001 Gigabit Ethernet Controller (ECS)\n\t\t1043 173c  Marvell 88E8001 Gigabit Ethernet Controller (Asus)\n\t\t1043 811a  Marvell 88E8001 Gigabit Ethernet Controller (Asus)\n\t\t105b 0c19  Marvell 88E8001 Gigabit Ethernet Controller (Foxconn)\n\t\t10b8 b452  EZ Card 1000 (SMC9452TXV.2)\n\t\t11ab 0121  Marvell RDK-8001\n\t\t11ab 0321  Marvell RDK-8003\n\t\t11ab 1021  Marvell RDK-8010\n\t\t11ab 4320  Marvell Yukon Gigabit Ethernet 10/100/1000Baset-T Constroller (Asus)\n\t\t11ab 5021  Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Controller (64 bit)\n\t\t11ab 9521  Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Controller (32 bit)\n\t\t1458 e000  Marvell 88E8001 Gigabit Ethernet Controller (Gigabyte)\n\t\t147b 1406  Marvell 88E8001 Gigabit Ethernet Controller (Abit)\n\t\t15d4 0047  Marvell 88E8001 Gigabit Ethernet Controller (Iwill)\n\t\t1695 9025  Marvell 88E8001 Gigabit Ethernet Controller (Epox)\n\t\t17f2 1c03  Marvell 88E8001 Gigabit Ethernet Controller (Albatron)\n\t\t270f 2803  Marvell 88E8001 Gigabit Ethernet Controller (Chaintech)\n\t4340  88E8021 PCI-X IPMI Gigabit Ethernet Controller\n\t4341  88E8022 PCI-X IPMI Gigabit Ethernet Controller\n\t4342  88E8061 PCI-E IPMI Gigabit Ethernet Controller\n\t4343  88E8062 PCI-E IPMI Gigabit Ethernet Controller\n\t4344  88E8021 PCI-X IPMI Gigabit Ethernet Controller\n\t4345  88E8022 PCI-X IPMI Gigabit Ethernet Controller\n\t4346  88E8061 PCI-E IPMI Gigabit Ethernet Controller\n\t4347  88E8062 PCI-E IPMI Gigabit Ethernet Controller\n\t\t4c53 10d0  Telum ASLP10 PrAMC Gigabit Ethernet\n\t4350  88E8035 PCI-E Fast Ethernet Controller\n\t\t1179 0001  Marvell 88E8035 Fast Ethernet Controller (Toshiba)\n\t\t11ab 3521  Marvell RDK-8035\n\t\t1854 000d  Marvell 88E8035 Fast Ethernet Controller (LGE)\n\t\t1854 000e  Marvell 88E8035 Fast Ethernet Controller (LGE)\n\t\t1854 000f  Marvell 88E8035 Fast Ethernet Controller (LGE)\n\t\t1854 0011  Marvell 88E8035 Fast Ethernet Controller (LGE)\n\t\t1854 0012  Marvell 88E8035 Fast Ethernet Controller (LGE)\n\t\t1854 0016  Marvell 88E8035 Fast Ethernet Controller (LGE)\n\t\t1854 0017  Marvell 88E8035 Fast Ethernet Controller (LGE)\n\t\t1854 0018  Marvell 88E8035 Fast Ethernet Controller (LGE)\n\t\t1854 0019  Marvell 88E8035 Fast Ethernet Controller (LGE)\n\t\t1854 001c  Marvell 88E8035 Fast Ethernet Controller (LGE)\n\t\t1854 001e  Marvell 88E8035 Fast Ethernet Controller (LGE)\n\t\t1854 0020  Marvell 88E8035 Fast Ethernet Controller (LGE)\n\t4351  88E8036 PCI-E Fast Ethernet Controller\n\t\t107b 4009  Marvell 88E8036 Fast Ethernet Controller (Wistron)\n\t\t10f7 8338  Marvell 88E8036 Fast Ethernet Controller (Panasonic)\n\t\t1179 0001  Marvell 88E8036 Fast Ethernet Controller (Toshiba)\n\t\t1179 ff00  Marvell 88E8036 Fast Ethernet Controller (Compal)\n\t\t1179 ff10  Marvell 88E8036 Fast Ethernet Controller (Inventec)\n\t\t11ab 3621  Marvell RDK-8036\n\t\t13d1 ac12  Abocom EFE3K - 10/100 Ethernet Expresscard\n\t\t161f 203d  Marvell 88E8036 Fast Ethernet Controller (Arima)\n\t\t1854 000d  Marvell 88E8036 Fast Ethernet Controller (LGE)\n\t\t1854 000e  Marvell 88E8036 Fast Ethernet Controller (LGE)\n\t\t1854 000f  Marvell 88E8036 Fast Ethernet Controller (LGE)\n\t\t1854 0011  Marvell 88E8036 Fast Ethernet Controller (LGE)\n\t\t1854 0012  Marvell 88E8036 Fast Ethernet Controller (LGE)\n\t\t1854 0016  Marvell 88E8036 Fast Ethernet Controller (LGE)\n\t\t1854 0017  Marvell 88E8036 Fast Ethernet Controller (LGE)\n\t\t1854 0018  Marvell 88E8036 Fast Ethernet Controller (LGE)\n\t\t1854 0019  Marvell 88E8036 Fast Ethernet Controller (LGE)\n\t\t1854 001c  Marvell 88E8036 Fast Ethernet Controller (LGE)\n\t\t1854 001e  Marvell 88E8036 Fast Ethernet Controller (LGE)\n\t\t1854 0020  Marvell 88E8036 Fast Ethernet Controller (LGE)\n\t4352  88E8038 PCI-E Fast Ethernet Controller\n\t4353  88E8039 PCI-E Fast Ethernet Controller\n\t\t104d 902d  VAIO VGN-NR120E\n\t4354  88E8040 PCI-E Fast Ethernet Controller\n\t\t1028 022f  Inspiron 1525\n\t\t144d c06a  R730 Laptop\n\t\t144d c072  Notebook N150P\n\t4355  88E8040T PCI-E Fast Ethernet Controller\n\t\t1179 ff50  Satellite P305D-S8995E\n\t4356  88EC033 PCI-E Fast Ethernet Controller\n\t4357  88E8042 PCI-E Fast Ethernet Controller\n\t435a  88E8048 PCI-E Fast Ethernet Controller\n\t4360  88E8052 PCI-E ASF Gigabit Ethernet Controller\n\t\t1043 8134  Marvell 88E8052 Gigabit Ethernet Controller (Asus)\n\t\t107b 4009  Marvell 88E8052 Gigabit Ethernet Controller (Wistron)\n\t\t11ab 5221  Marvell RDK-8052\n\t\t1458 e000  Marvell 88E8052 Gigabit Ethernet Controller (Gigabyte)\n\t\t1462 052c  Marvell 88E8052 Gigabit Ethernet Controller (MSI)\n\t\t1849 8052  Marvell 88E8052 Gigabit Ethernet Controller (ASRock)\n\t\ta0a0 0509  Marvell 88E8052 Gigabit Ethernet Controller (Aopen)\n\t4361  88E8050 PCI-E ASF Gigabit Ethernet Controller\n\t\t107b 3015  Marvell 88E8050 Gigabit Ethernet Controller (Gateway)\n\t\t11ab 5021  Marvell 88E8050 Gigabit Ethernet Controller (Intel)\n\t\t8086 3063  D925XCVLK mainboard\n\t\t8086 3439  Marvell 88E8050 Gigabit Ethernet Controller (Intel)\n\t4362  88E8053 PCI-E Gigabit Ethernet Controller\n\t\t103c 2a0d  Marvell 88E8053 Gigabit Ethernet Controller (Asus)\n\t\t1043 8142  Marvell 88E8053 Gigabit Ethernet controller PCIe (Asus)\n\t\t109f 3197  Marvell 88E8053 Gigabit Ethernet Controller (Trigem)\n\t\t10f7 8338  Marvell 88E8053 Gigabit Ethernet Controller (Panasonic)\n\t\t10fd a430  Marvell 88E8053 Gigabit Ethernet Controller (SOYO)\n\t\t1179 0001  Marvell 88E8053 Gigabit Ethernet Controller (Toshiba)\n\t\t1179 ff00  Marvell 88E8053 Gigabit Ethernet Controller (Compal)\n\t\t1179 ff10  Marvell 88E8053 Gigabit Ethernet Controller (Inventec)\n\t\t11ab 5321  Marvell RDK-8053\n\t\t1297 c240  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)\n\t\t1297 c241  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)\n\t\t1297 c242  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)\n\t\t1297 c243  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)\n\t\t1297 c244  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)\n\t\t13d1 ac11  EGE5K - Giga Ethernet Expresscard\n\t\t1458 e000  Marvell 88E8053 Gigabit Ethernet Controller (Gigabyte)\n\t\t1462 058c  Marvell 88E8053 Gigabit Ethernet Controller (MSI)\n\t\t14c0 0012  Marvell 88E8053 Gigabit Ethernet Controller (Compal)\n\t\t1558 04a0  Marvell 88E8053 Gigabit Ethernet Controller (Clevo)\n\t\t15bd 1003  Marvell 88E8053 Gigabit Ethernet Controller (DFI)\n\t\t161f 203c  Marvell 88E8053 Gigabit Ethernet Controller (Arima)\n\t\t161f 203d  Marvell 88E8053 Gigabit Ethernet Controller (Arima)\n\t\t1695 9029  Marvell 88E8053 Gigabit Ethernet Controller (Epox)\n\t\t17f2 2c08  Marvell 88E8053 Gigabit Ethernet Controller (Albatron)\n\t\t17ff 0585  Marvell 88E8053 Gigabit Ethernet Controller (Quanta)\n\t\t1849 8053  Marvell 88E8053 Gigabit Ethernet Controller (ASRock)\n\t\t1854 000b  Marvell 88E8053 Gigabit Ethernet Controller (LGE)\n\t\t1854 000c  Marvell 88E8053 Gigabit Ethernet Controller (LGE)\n\t\t1854 0010  Marvell 88E8053 Gigabit Ethernet Controller (LGE)\n\t\t1854 0013  Marvell 88E8053 Gigabit Ethernet Controller (LGE)\n\t\t1854 0014  Marvell 88E8053 Gigabit Ethernet Controller (LGE)\n\t\t1854 0015  Marvell 88E8053 Gigabit Ethernet Controller (LGE)\n\t\t1854 001a  Marvell 88E8053 Gigabit Ethernet Controller (LGE)\n\t\t1854 001b  Marvell 88E8053 Gigabit Ethernet Controller (LGE)\n\t\t1854 001d  Marvell 88E8053 Gigabit Ethernet Controller (LGE)\n\t\t1854 001f  Marvell 88E8053 Gigabit Ethernet Controller (LGE)\n\t\t1854 0021  Marvell 88E8053 Gigabit Ethernet Controller (LGE)\n\t\t1854 0022  Marvell 88E8053 Gigabit Ethernet Controller (LGE)\n\t\t270f 2801  Marvell 88E8053 Gigabit Ethernet Controller (Chaintech)\n\t\ta0a0 0506  Marvell 88E8053 Gigabit Ethernet Controller (Aopen)\n\t4363  88E8055 PCI-E Gigabit Ethernet Controller\n\t4364  88E8056 PCI-E Gigabit Ethernet Controller\n\t\t1043 81f8  Motherboard\n\t\t11ba 00ba  8056 Gigabit Ethernet Controller\n\t4365  88E8070 based Ethernet Controller\n\t4366  88EC036 PCI-E Gigabit Ethernet Controller\n\t4367  88EC032 Ethernet Controller\n\t4368  88EC034 Ethernet Controller\n\t4369  88EC042 Ethernet Controller\n\t436a  88E8058 PCI-E Gigabit Ethernet Controller\n\t\t11ab 00ba  Imac 8,1 Wired Ethernet Adapter\n\t436b  88E8071 PCI-E Gigabit Ethernet Controller\n\t436c  88E8072 PCI-E Gigabit Ethernet Controller\n\t436d  88E8055 PCI-E Gigabit Ethernet Controller\n\t4370  88E8075 PCI-E Gigabit Ethernet Controller\n\t4380  88E8057 PCI-E Gigabit Ethernet Controller\n# AVB = \"Audio Video Bridging\"\n\t4381  Yukon Optima 88E8059 [PCIe Gigabit Ethernet Controller with AVB]\n\t4611  GT-64115 System Controller\n\t4620  GT-64120/64120A/64121A System Controller\n\t4801  GT-48001\n\t5005  Belkin F5D5005 Gigabit Desktop Network PCI Card\n\t5040  MV88SX5040 4-port SATA I PCI-X Controller\n\t5041  MV88SX5041 4-port SATA I PCI-X Controller\n\t5080  MV88SX5080 8-port SATA I PCI-X Controller\n\t5081  MV88SX5081 8-port SATA I PCI-X Controller\n\t5181  88f5181 [Orion-1] ARM SoC\n\t5182  88f5182 [Orion-NAS] ARM SoC\n\t5281  88f5281 [Orion-2] ARM SoC\n\t6041  MV88SX6041 4-port SATA II PCI-X Controller\n\t6042  88SX6042 PCI-X 4-Port SATA-II\n\t6081  MV88SX6081 8-port SATA II PCI-X Controller\n\t6101  88SE6101/6102 single-port PATA133 interface\n\t\t1043 82e0  P5K PRO Motherboard\n\t6121  88SE6111/6121 SATA II / PATA Controller\n# 6111: 1 SATA port; 6121: 2 SATA ports\n\t\t11ab 6121  88SE6111/6121 1/2 port SATA II + 1 port PATA Controller\n\t6141  88SE614x SATA II PCI-E controller\n\t6145  88SE6145 SATA II PCI-E controller\n\t6180  88F6180 [Kirkwood] ARM SoC\n\t6192  88F6190/6192 [Kirkwood] ARM SoC\n\t6281  88F6281 [Kirkwood] ARM SoC\n# This device ID was used for earlier chips.\n\t6381  MV78xx0 [Discovery Innovation] ARM SoC\n\t6440  88SE6440 SAS/SATA PCIe controller\n\t6450  64560 System Controller\n\t6460  MV64360/64361/64362 System Controller\n\t6480  MV64460/64461/64462 System Controller\n\t\t1775 c200  C2K CompactPCI single board computer\n\t6485  MV64460/64461/64462 System Controller, Revision B\n\t7042  88SX7042 PCI-e 4-port SATA-II\n\t\t16b8 434b  Tempo SATA E4P\n\t7810  MV78100 [Discovery Innovation] ARM SoC\n\t7820  MV78200 [Discovery Innovation] ARM SoC\n\t7823  MV78230 [Armada XP] ARM SoC\n\t7846  88F6820 [Armada 385] ARM SoC\n\td40f  Bobcat3 Ethernet Switch\n\tf003  GT-64010 Primary Image Piranha Image Generator\n11ac  Canon Information Systems Research Aust.\n11ad  Lite-On Communications Inc\n\t0002  LNE100TX\n\t\t11ad 0002  LNE100TX\n\t\t11ad 0003  LNE100TX\n\t\t11ad f003  LNE100TX\n\t\t11ad ffff  LNE100TX\n\t\t1385 f004  FA310TX\n\t\t2646 f002  KNE110TX EtheRx Fast Ethernet\n\tc115  LNE100TX [Linksys EtherFast 10/100]\n\t\t11ad c001  LNE100TX [ver 2.0]\n\t\t2646 000b  KNE111TX\n11ae  Aztech System Ltd\n11af  Avid Technology Inc.\n\t0001  Cinema\n\tee40  Digidesign Audiomedia III\n11b0  V3 Semiconductor Inc.\n\t0002  V300PSC\n\t0292  V292PBC [Am29030/40 Bridge]\n\t0960  V96xPBC\n\t880a  Deltacast Delta-HD-22\n\tc960  V96DPC\n11b1  Apricot Computers\n11b2  Eastman Kodak\n11b3  Barr Systems Inc.\n11b4  Leitch Technology International\n11b5  Radstone Technology Plc\n11b6  United Video Corp\n11b7  Motorola\n11b8  XPoint Technologies, Inc\n\t0001  Quad PeerMaster\n11b9  Pathlight Technology Inc.\n\tc0ed  SSA Controller\n11ba  Videotron Corp\n11bb  Pyramid Technology\n11bc  Network Peripherals Inc\n\t0001  NP-PCI\n11bd  Pinnacle Systems Inc.\n\t002e  PCTV 40i\n\t0040  Royal TS Function 1\n\t\t11bd 0044  PCTV 2000i Dual DVB-T Pro PCI Tuner 1\n\t\t11bd 0045  PCTV Dual Sat Pro PCI 4000i Tuner 1\n\t0041  RoyalTS Function 2\n\t\t11bd 0044  PCTV 2000i Dual DVB-T Pro PCI Tuner 2\n\t\t11bd 0045  PCTV Dual Sat Pro PCI 4000i Tuner 2\n\t0042  Royal TS Function 3\n\t\t11bd 0044  PCTV 2000i Dual DVB-T Pro PCI Common\n\t\t11bd 0045  PCTV Dual Sat Pro PCI 4000i Common\n\t0051  PCTV HD 800i\n\tbede  AV/DV Studio Capture Card\n11be  International Microcircuits Inc\n11bf  Astrodesign, Inc.\n11c0  Hewlett Packard\n# nee Agere Systems nee Lucent Microelectronics\n11c1  LSI Corporation\n\t0440  56k WinModem\n\t\t1033 8015  LT WinModem 56k Data+Fax+Voice+Dsvd\n\t\t1033 8047  LT WinModem 56k Data+Fax+Voice+Dsvd\n\t\t1033 804f  LT WinModem 56k Data+Fax+Voice+Dsvd\n\t\t10cf 102c  LB LT Modem V.90 56k\n\t\t10cf 104a  BIBLO LT Modem 56k\n\t\t10cf 105f  LB2 LT Modem V.90 56k\n\t\t1179 0001  Internal V.90 Modem\n\t\t11c1 0440  LT WinModem 56k Data+Fax+Voice+Dsvd\n\t\t122d 4101  MDP7800-U Modem\n\t\t122d 4102  MDP7800SP-U Modem\n\t\t13e0 0040  LT WinModem 56k Data+Fax+Voice+Dsvd\n\t\t13e0 0440  LT WinModem 56k Data+Fax+Voice+Dsvd\n\t\t13e0 0441  LT WinModem 56k Data+Fax+Voice+Dsvd\n\t\t13e0 0450  LT WinModem 56k Data+Fax+Voice+Dsvd\n\t\t13e0 f100  LT WinModem 56k Data+Fax+Voice+Dsvd\n\t\t13e0 f101  LT WinModem 56k Data+Fax+Voice+Dsvd\n\t\t144d 2101  LT56PV Modem\n\t\t149f 0440  LT WinModem 56k Data+Fax+Voice+Dsvd\n\t0441  56k WinModem\n\t\t1033 804d  LT WinModem 56k Data+Fax\n\t\t1033 8065  LT WinModem 56k Data+Fax\n\t\t1092 0440  Supra 56i\n\t\t1179 0001  Internal V.90 Modem\n\t\t11c1 0440  LT WinModem 56k Data+Fax\n\t\t11c1 0441  LT WinModem 56k Data+Fax\n\t\t122d 4100  MDP7800-U Modem\n\t\t13e0 0040  LT WinModem 56k Data+Fax\n\t\t13e0 0100  LT WinModem 56k Data+Fax\n\t\t13e0 0410  LT WinModem 56k Data+Fax\n\t\t13e0 0420  TelePath Internet 56k WinModem\n\t\t13e0 0440  LT WinModem 56k Data+Fax\n\t\t13e0 0443  LT WinModem 56k Data+Fax\n\t\t13e0 f102  LT WinModem 56k Data+Fax\n\t\t1416 9804  CommWave 56k Modem\n\t\t141d 0440  LT WinModem 56k Data+Fax\n\t\t144f 0441  Lucent 56k V.90 DF Modem\n\t\t144f 0449  Lucent 56k V.90 DF Modem\n\t\t144f 110d  Lucent Win Modem\n\t\t1468 0441  Presario 56k V.90 DF Modem\n\t\t1668 0440  Lucent Win Modem\n\t0442  56k WinModem\n\t\t11c1 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd\n\t\t11c1 0442  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd\n\t\t13e0 0412  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd\n\t\t13e0 0442  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd\n\t\t13fc 2471  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd\n\t\t144d 2104  LT56PT Modem\n\t\t144f 1104  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd\n\t\t149f 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd\n\t\t1668 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd\n\t0443  LT WinModem\n\t0444  LT WinModem\n\t0445  LT WinModem\n\t\t8086 2203  PRO/100+ MiniPCI (probably an Ambit U98.003.C.00 combo card)\n\t\t8086 2204  PRO/100+ MiniPCI on Armada E500\n\t0446  LT WinModem\n\t0447  LT WinModem\n\t0448  WinModem 56k\n\t\t1014 0131  Lucent Win Modem\n\t\t1033 8066  LT WinModem 56k Data+Fax+Voice+Dsvd\n\t\t13e0 0030  56k Voice Modem\n\t\t13e0 0040  LT WinModem 56k Data+Fax+Voice+Dsvd\n# Actiontech eth+modem card as used by Dell &c.\n\t\t1668 2400  LT WinModem 56k (MiniPCI Ethernet+Modem)\n\t0449  L56xM+S [Mars-2] WinModem 56k\n\t\t0e11 b14d  56k V.90 Modem\n\t\t1014 018c  ThinkPad 600X\n\t\t13e0 0020  LT WinModem 56k Data+Fax\n\t\t13e0 0041  TelePath Internet 56k WinModem\n\t\t1436 0440  Lucent Win Modem\n\t\t144f 0449  Lucent 56k V.90 DFi Modem\n\t\t1468 0410  IBM ThinkPad T23\n\t\t1468 0440  Lucent Win Modem\n\t\t1468 0449  Presario 56k V.90 DFi Modem\n\t044a  F-1156IV WinModem (V90, 56KFlex)\n\t\t10cf 1072  LB Global LT Modem\n\t\t13e0 0012  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd\n\t\t13e0 0042  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd\n\t\t144f 1005  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd\n\t044b  LT WinModem\n\t044c  LT WinModem\n\t044d  LT WinModem\n\t044e  LT WinModem\n\t044f  V90 WildWire Modem\n\t0450  LT WinModem\n\t\t1033 80a8  Versa Note Vxi\n\t\t144f 4005  Magnia SG20\n\t\t1468 0450  Evo N600c\n\t0451  LT WinModem\n\t0452  LT WinModem\n\t0453  LT WinModem\n\t0454  LT WinModem\n\t0455  LT WinModem\n\t0456  LT WinModem\n\t0457  LT WinModem\n\t0458  LT WinModem\n\t0459  LT WinModem\n\t045a  LT WinModem\n\t045c  LT WinModem\n\t0461  V90 WildWire Modem\n\t0462  V90 WildWire Modem\n\t0480  Venus Modem (V90, 56KFlex)\n\t048c  V.92 56K WinModem\n# InPorte Home Internal 56k Modem/fax/answering machine/SMS Features\n\t048f  V.92 56k WinModem\n\t0620  Lucent V.92 Data/Fax Modem\n\t2600  StarPro26XX family (SP2601, SP2603, SP2612) DSP\n\t5400  OR3TP12 FPSC\n\t5656  Venus Modem\n\t5801  USB\n\t5802  USS-312 USB Controller\n\t5803  USS-344S USB Controller\n\t5811  FW322/323 [TrueFire] 1394a Controller\n\t\t103c 2a34  Pavilion a1677c\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t103c 2a9e  Pavilion p6310f\n\t\t1043 8294  LSI FW322/323 IEEE 1394a FireWire Controller\n\t\t11bd 000e  LSI FW323\n\t\t8086 524c  D865PERL mainboard\n\t\t9005 0033  Adaptec AFW-2100 (HP) 2102900-R\n\t\tdead 0800  FireWire Host Bus Adapter\n\t5901  FW643 [TrueFire] PCIe 1394b Controller\n\t\t11c1 5900  FW643 [TrueFire] PCIe 1394b Controller\n\t\t1443 0643  FireBoard800-e V.2\n\t\t1546 0643  FWB-PCIE1X2x\n\t5903  FW533 [TrueFire] PCIe 1394a Controller\n\t8110  T8110 H.100/H.110 TDM switch\n\t\t12d9 000c  E1/T1 PMXc cPCI carrier card\n\tab10  WL60010 Wireless LAN MAC\n\tab11  WL60040 Multimode Wireles LAN MAC\n\t\t11c1 ab12  WaveLAN 11abg Cardbus card (Model 1102)\n\t\t11c1 ab13  WaveLAN 11abg MiniPCI card (Model 0512)\n\t\t11c1 ab15  WaveLAN 11abg Cardbus card (Model 1106)\n\t\t11c1 ab16  WaveLAN 11abg MiniPCI card (Model 0516)\n\tab20  ORiNOCO PCI Adapter\n\tab21  Agere Wireless PCI Adapter\n\tab30  Hermes2 Mini-PCI WaveLAN a/b/g\n\t\t14cd 2012  Hermes2 Mini-PCI WaveLAN a/b/g\n\ted00  ET-131x PCI-E Ethernet Controller\n\ted01  ET-131x PCI-E Ethernet Controller\n11c2  Sand Microelectronics\n11c3  NEC Corporation\n11c4  Document Technologies, Inc\n11c5  Shiva Corporation\n11c6  Dainippon Screen Mfg. Co. Ltd\n11c7  D.C.M. Data Systems\n11c8  Dolphin Interconnect Solutions AS\n\t0658  PSB32 SCI-Adapter D31x\n\td665  PSB64 SCI-Adapter D32x\n\td667  PSB66 SCI-Adapter D33x\n11c9  Magma\n\t0010  16-line serial port w/- DMA\n\t0011  4-line serial port w/- DMA\n11ca  LSI Systems, Inc\n11cb  Specialix Research Ltd.\n\t2000  PCI_9050\n\t\t11cb 0200  SX\n\t\t11cb b008  I/O8+\n\t4000  SUPI_1\n\t8000  T225\n11cc  Michels & Kleberhoff Computer GmbH\n11cd  HAL Computer Systems, Inc.\n11ce  Netaccess\n11cf  Pioneer Electronic Corporation\n11d0  Lockheed Martin Federal Systems-Manassas\n11d1  Auravision\n\t01f7  VxP524\n\t01f9  VxP951\n11d2  Intercom Inc.\n11d3  Trancell Systems Inc\n11d4  Analog Devices\n\t1535  Blackfin BF535 processor\n\t1805  SM56 PCI modem\n11d5  Ikon Corporation\n\t0115  10115\n\t0117  10117\n11d6  Tekelec Telecom\n11d7  Trenton Technology, Inc.\n11d8  Image Technologies Development\n11d9  TEC Corporation\n11da  Novell\n11db  Sega Enterprises Ltd\n11dc  Questra Corporation\n11dd  Crosfield Electronics Limited\n11de  Zoran Corporation\n\t6017  miroVIDEO DC30\n\t6057  ZR36057PQC Video cutting chipset\n\t\t1031 7efe  DC10 Plus\n\t\t1031 fc00  MiroVIDEO DC50, Motion JPEG Capture/CODEC Board\n\t\t12f8 8a02  Tekram Video Kit\n\t\t13ca 4231  JPEG/TV Card\n\t6120  ZR36120\n\t\t1328 f001  Cinemaster C DVD Decoder\n\t\t13c2 0000  MediaFocus Satellite TV Card\n\t\t1de1 9fff  Video Kit C210\n11df  New Wave PDG\n11e0  Cray Communications A/S\n11e1  GEC Plessey Semi Inc.\n11e2  Samsung Information Systems America\n11e3  Quicklogic Corporation\n\t0001  COM-ON-AIR Dosch&Amand DECT\n\t0560  QL5064 Companion Design Demo Board\n\t5030  PC Watchdog\n\t8417  QL5064 [QuickPCI] PCI v2.2 bridge for SMT417 Dual TMS320C6416T PMC Module\n11e4  Second Wave Inc\n11e5  IIX Consulting\n11e6  Mitsui-Zosen System Research\n11e7  Toshiba America, Elec. Company\n11e8  Digital Processing Systems Inc.\n11e9  Highwater Designs Ltd.\n11ea  Elsag Bailey\n11eb  Formation Inc.\n11ec  Coreco Inc\n\t000d  Oculus-F/64P\n\t1800  Cobra/C6\n11ed  Mediamatics\n11ee  Dome Imaging Systems Inc\n11ef  Nicolet Technologies B.V.\n11f0  Compu-Shack\n\t4231  FDDI\n\t4232  FASTline UTP Quattro\n\t4233  FASTline FO\n\t4234  FASTline UTP\n\t4235  FASTline-II UTP\n\t4236  FASTline-II FO\n\t4731  GIGAline\n11f1  Symbios Logic Inc\n11f2  Picture Tel Japan K.K.\n11f3  Keithley Metrabyte\n\t0011  KPCI-PIO24\n11f4  Kinetic Systems Corporation\n\t2915  CAMAC controller\n11f5  Computing Devices International\n11f6  Compex\n\t0112  ENet100VG4\n\t0113  FreedomLine 100\n\t1401  ReadyLink 2000\n\t2011  RL100-ATX 10/100\n\t\t11f6 2011  RL100-ATX\n\t2201  ReadyLink 100TX (Winbond W89C840)\n\t\t11f6 2011  ReadyLink 100TX\n\t9881  RL100TX Fast Ethernet\n11f7  Scientific Atlanta\n11f8  PMC-Sierra Inc.\n\t5220  BR522x [PMC-Sierra maxRAID SAS Controller]\n\t7364  PM7364 [FREEDM - 32 Frame Engine & Datalink Mgr]\n\t7375  PM7375 [LASAR-155 ATM SAR]\n\t7384  PM7384 [FREEDM - 84P672 Frm Engine & Datalink Mgr]\n\t8000  PM8000  [SPC - SAS Protocol Controller]\n\t8009  PM8009 SPCve 8x6G\n\t8018  PM8018 Adaptec SAS Adaptor ASA-70165H PCIe Gen3 x8 6 Gbps 16-lane 4x SFF-8644\n\t8032  PM8032 Tachyon QE8\n\t\t117c 003a  Celerity FC-81EN Fibre Channel Adapter\n\t\t117c 003b  Celerity FC-82EN Fibre Channel Adapter\n\t\t117c 003c  Celerity FC-84EN Fibre Channel Adapter\n\t\t117c 403b  ThunderLink FC 1082 Fibre Channel Adapter\n\t8053  PM8053 SXP 12G 24-port SAS/SATA expander\n\t8054  PM8054 SXP 12G 36-port SAS/SATA expander\n\t8055  PM8055 SXP 12G 48-port SAS/SATA expander\n\t8056  PM8056 SXP 12G 68-port SAS/SATA expander\n\t8060  PM8060 SRCv 12G eight-port SAS/SATA RoC\n\t8063  PM8063 SRCv 12G 16-port SAS/SATA RoC\n\t8070  PM8070 Tachyon SPCv 12G eight-port SAS/SATA controller\n\t8071  PM8071 Tachyon SPCve 12G eight-port SAS/SATA controller\n\t8072  PM8072 Tachyon SPCv 12G 16-port SAS/SATA controller\n\t8073  PM8073 Tachyon SPCve 12G 16-port SAS/SATA controller\n\t8531  PM8531 PFX 24xG3 Fanout PCIe Switches\n\t8546  PM8546 B-FEIP PSX 96xG3 PCIe Storage Switch\n11f9  I-Cube Inc\n11fa  Kasan Electronics Company, Ltd.\n11fb  Datel Inc\n11fc  Silicon Magic\n11fd  High Street Consultants\n11fe  Pepperl+Fuchs Comtrol, Inc.\n\t0001  RocketPort PCI 32-port w/external I/F\n\t0002  RocketPort PCI 8-port w/external I/F\n\t0003  RocketPort PCI 16-port w/external I/F\n\t0004  RocketPort PCI 4-port w/Quad Cable\n\t0005  RocketPort PCI 8-port w/Octa Cable\n\t0006  RocketPort PCI 8-port w/RJ11 connectors\n\t0007  RocketPort PCI 4-port w/RJ45 connectors\n\t0008  RocketPort PCI 8-port w/DB78 SNI connector (Siemens)\n\t0009  RocketPort PCI 16-port w/DB78 SNI connector (Siemens)\n\t000a  RocketPort PCI Plus 4-port w/Quad Cable\n\t000b  RocketPort PCI Plus 8-port w/Octa Cable\n\t000c  RocketModem II 6-port\n\t000d  RocketModem 4-port\n\t000e  RocketPort PCI Plus 2-port RS-232 w/DB9 connectors\n\t000f  RocketPort PCI Plus 2-port SMPTE w/DB9 connectors\n\t0040  RocketPort INFINITY 8-port w/Octa Cable RJ45\n\t0041  RocketPort INFINITY 32-port w/external I/F\n\t0042  RocketPort INFINITY 8-port w/external I/F\n\t0043  RocketPort INFINITY 16-port w/external I/F\n\t0044  RocketPort INFINITY 4-port w/Quad Cable DB\n\t0045  RocketPort INFINITY 8-port w/Octa Cable DB\n\t0046  RocketPort INFINITY 4-port w/external I/F\n\t0047  RocketPort INFINITY 4J (4-port) w/RJ45 connectors\n\t0048  RocketPort INFINITY 4J (4-port) w/RJ45 connectors\n\t004a  RocketPort INFINITY Plus 4-port\n\t004b  RocketPort INFINITY Plus 8-port\n\t004c  RocketModem INFINITY III 8-port\n\t004d  RocketModem INFINITY III 4-port\n\t004e  RocketPort INFINITY Plus 2-port\n\t004f  RocketPort INFINITY 2-port SMPTE w/DB9 connectors\n\t0050  RocketPort INFINITY Plus 4-port RJ45\n\t0051  RocketPort INFINITY Plus 8-port RJ11\n\t0052  RocketPort INFINITY 8-port SMPTE w/DB9 Connectors\n\t0060  RocketPort EXPRESS 8-port w/Octa Cable\n\t0061  RocketPort EXPRESS 32-port w/external I/F\n\t0062  RocketPort EXPRESS 8-Port w/external I/F\n\t0063  RocketPort EXPRESS 16-port w/external I/F\n\t0064  RocketPort EXPRESS 4-port w/Quad Cable\n\t0065  RocketPort EXPRESS 8-port w/Octa Cable\n\t0066  RocketPort EXPRESS 4-port w/external I/F\n\t0067  RocketPort EXPRESS 4J (4-port) w/RJ45 connectors\n\t0068  RocketPort EXPRESS 8J (8-port) w/RJ11 connectors\n\t006f  RocketPort EXPRESS SMPTE 2-port\n\t0072  RocketPort EXPRESS SMPTE 8-port w/external I/F\n\t0801  RocketPort uPCI 32-port w/external I/F\n\t0802  RocketPort uPCI 8-port w/external I/F\n\t0803  RocketPort uPCI 16-port w/external I/F\n\t0805  RocketPort uPCI 8-port w/Octa Cable\n\t080b  RocketPort Plus uPCI 8-port w/Octa Cable\n\t080c  RocketModem III 8-port\n\t080d  RocketModem III 4-port\n\t080e  RocketPort uPCI 2-port RS232 w/DB9 connectors\n\t080f  RocketPort uPCI SMPTE 2-port\n\t0810  RocketPort Plus uPCI 4J (4-port) w/RJ45 connectors\n\t0811  RocketPort Plus uPCI 8J (8-port) w/RJ11 connectors\n\t0812  RocketPort Plus uPCI 422 8-port\n\t0813  RocketModem IV uPCI 8-port\n\t0814  RocketModem IV uPCI 4-port\n\t0903  RocketPort Compact PCI 16 port w/external I/F\n# 16954 UART\n\t8015  RocketPort 550 4-port\n\t8805  RocketPort uPCI 4-port w/Quad Cable\n\t880b  RocketPort Plus uPCI 4-port w/Quad Cable\n\t8812  RocketPort Plus uPCI 4-port RS422 w/Quad Cable\n11ff  Scion Corporation\n\t0003  AG-5\n1200  CSS Corporation\n1201  Vista Controls Corp\n1202  Network General Corp.\n\t4300  Gigabit Ethernet Adapter\n\t\t1202 9841  SK-9841 LX\n\t\t1202 9842  SK-9841 LX dual link\n\t\t1202 9843  SK-9843 SX\n\t\t1202 9844  SK-9843 SX dual link\n1203  Bayer Corporation, Agfa Division\n1204  Lattice Semiconductor Corporation\n\t1965  SB6501 802.11ad Wireless Network Adapter\n1205  Array Corporation\n1206  Amdahl Corporation\n1208  Parsytec GmbH\n\t4853  HS-Link Device\n1209  SCI Systems Inc\n120a  Synaptel\n120b  Adaptive Solutions\n120c  Technical Corp.\n120d  Compression Labs, Inc.\n120e  Cyclades Corporation\n\t0100  Cyclom-Y below first megabyte\n\t0101  Cyclom-Y above first megabyte\n\t0102  Cyclom-4Y below first megabyte\n\t0103  Cyclom-4Y above first megabyte\n\t0104  Cyclom-8Y below first megabyte\n\t0105  Cyclom-8Y above first megabyte\n\t0200  Cyclades-Z below first megabyte\n\t0201  Cyclades-Z above first megabyte\n\t0300  PC300/RSV or /X21 (2 ports)\n\t0301  PC300/RSV or /X21 (1 port)\n\t0310  PC300/TE (2 ports)\n\t0311  PC300/TE (1 port)\n\t0320  PC300/TE-M (2 ports)\n\t0321  PC300/TE-M (1 port)\n\t0400  PC400\n120f  Essential Communications\n\t0001  Roadrunner serial HIPPI\n1210  Hyperparallel Technologies\n1211  Braintech Inc\n1213  Applied Intelligent Systems, Inc.\n1214  Performance Technologies, Inc.\n1215  Interware Co., Ltd\n1216  Purup Prepress A/S\n1217  O2 Micro, Inc.\n\t00f7  Firewire (IEEE 1394)\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t1179 ff50  Satellite P305D-S8995E\n\t10f7  1394 OHCI Compliant Host Controller\n\t11f7  OZ600 1394a-2000 Controller\n\t\t1028 04a3  Precision M4600\n\t13f7  1394 OHCI Compliant Host Controller\n\t6729  OZ6729\n\t673a  OZ6730\n\t6832  OZ6832/6833 CardBus Controller\n\t6836  OZ6836/6860 CardBus Controller\n\t6872  OZ6812 CardBus Controller\n\t6925  OZ6922 CardBus Controller\n\t6933  OZ6933/711E1 CardBus/SmartCardBus Controller\n\t\t1025 1016  Travelmate 612 TX\n\t6972  OZ601/6912/711E0 CardBus/SmartCardBus Controller\n\t\t1014 020c  ThinkPad R30\n\t\t1028 0152  Latitude D500\n\t\t1179 0001  Magnia Z310\n\t7110  OZ711Mx 4-in-1 MemoryCardBus Accelerator\n\t\t103c 088c  NC8000 laptop\n\t\t103c 0890  NC6000 laptop\n\t\t1734 106c  Amilo A1645\n\t7112  OZ711EC1/M1 SmartCardBus/MemoryCardBus Controller\n\t7113  OZ711EC1 SmartCardBus Controller\n\t\t1025 0035  TravelMate 660\n\t7114  OZ711M1/MC1 4-in-1 MemoryCardBus Controller\n\t7120  Integrated MMC/SD Controller\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t1179 ff50  Satellite P305D-S8995E\n\t7130  Integrated MS/xD Controller\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t1179 ff50  Satellite P305D-S8995E\n\t7134  OZ711MP1/MS1 MemoryCardBus Controller\n\t7135  Cardbus bridge\n\t7136  OZ711SP1 Memory CardBus Controller\n\t71e2  OZ711E2 SmartCardBus Controller\n\t7212  OZ711M2 4-in-1 MemoryCardBus Controller\n\t7213  OZ6933E CardBus Controller\n\t7223  OZ711M3/MC3 4-in-1 MemoryCardBus Controller\n\t\t103c 088c  NC8000 laptop\n\t\t103c 0890  NC6000 laptop\n\t\t10cf 11c4  Lifebook P5020D Laptop\n\t7233  OZ711MP3/MS3 4-in-1 MemoryCardBus Controller\n\t8120  Integrated MMC/SD Controller\n\t8130  Integrated MS/MSPRO/xD Controller\n\t8220  OZ600FJ1/OZ900FJ1 SD/MMC Card Reader Controller\n\t8221  OZ600FJ0/OZ900FJ0/OZ600FJS SD/MMC Card Reader Controller\n\t8320  OZ600RJ1/OZ900RJ1 SD/MMC Card Reader Controller\n\t\t1028 04a3  Precision M4600\n\t8321  OZ600RJ0/OZ900RJ0/OZ600RJS SD/MMC Card Reader Controller\n\t8330  OZ600 MS/xD Controller\n\t\t1028 04a3  Precision M4600\n\t8331  O2 Flash Memory Card\n\t8520  SD/MMC Card Reader Controller\n\t8621  SD/MMC Card Reader Controller\n1218  Hybricon Corp.\n1219  First Virtual Corporation\n121a  3Dfx Interactive, Inc.\n\t0001  Voodoo\n\t0002  Voodoo 2\n\t0003  Voodoo Banshee\n\t\t1092 0003  Monster Fusion\n\t\t1092 4000  Monster Fusion\n\t\t1092 4002  Monster Fusion\n\t\t1092 4801  Monster Fusion AGP\n\t\t1092 4803  Monster Fusion AGP\n\t\t1092 8030  Monster Fusion\n\t\t1092 8035  Monster Fusion AGP\n\t\t10b0 0001  Dragon 4000\n\t\t1102 1017  3D Blaster Banshee PCI (CT6760)\n\t\t1102 1018  3D Blaster Banshee VE\n\t\t121a 0001  Voodoo Banshee AGP\n\t\t121a 0003  Voodoo Banshee AGP SGRAM\n\t\t121a 0004  Voodoo Banshee\n\t\t139c 0016  Raven\n\t\t139c 0017  Raven\n\t\t14af 0002  Maxi Gamer Phoenix\n\t0004  Voodoo Banshee [Velocity 100]\n\t0005  Voodoo 3\n\t\t121a 0004  Voodoo3 AGP\n\t\t121a 0030  Voodoo3 AGP\n\t\t121a 0031  Voodoo3 AGP\n\t\t121a 0034  Voodoo3 AGP\n\t\t121a 0036  Voodoo3 2000 PCI\n\t\t121a 0037  Voodoo3 AGP\n\t\t121a 0038  Voodoo3 AGP\n\t\t121a 003a  Voodoo3 AGP\n\t\t121a 0044  Voodoo3\n\t\t121a 004b  Velocity 100\n\t\t121a 004c  Velocity 200\n\t\t121a 004d  Voodoo3 AGP\n\t\t121a 004e  Voodoo3 AGP\n\t\t121a 0051  Voodoo3 AGP\n\t\t121a 0052  Voodoo3 AGP\n\t\t121a 0057  Voodoo3 3000 PCI\n\t\t121a 0060  Voodoo3 3500 TV (NTSC)\n\t\t121a 0061  Voodoo3 3500 TV (PAL)\n\t\t121a 0062  Voodoo3 3500 TV (SECAM)\n\t0009  Voodoo 4 / Voodoo 5\n\t\t121a 0003  Voodoo5 PCI 5500\n\t\t121a 0009  Voodoo5 AGP 5500/6000\n\t0057  Voodoo 3/3000 [Avenger]\n121b  Advanced Telecommunications Modules\n121c  Nippon Texaco., Ltd\n121d  LiPPERT ADLINK Technology GmbH\n121e  CSPI\n\t0201  Myrinet 2000 Scalable Cluster Interconnect\n121f  Arcus Technology, Inc.\n1220  Ariel Corporation\n\t1220  AMCC 5933 TMS320C80 DSP/Imaging board\n1221  Contec Co., Ltd\n\t9172  PO-64L(PCI)H [Isolated Digital Output Board for PCI]\n\t91a2  PO-32L(PCI)H [Isolated Digital Output Board for PCI]\n\t91c3  DA16-16(LPCI)L [Un-insulated highly precise analog output board for Low Profile PCI]\n\tb152  DIO-96D2-LPCI\n\tc103  ADA16-32/2(PCI)F [High-Speed Analog I/O Board for PCI]\n1222  Ancor Communications, Inc.\n1223  Artesyn Communication Products\n\t0003  PM/Link\n\t0004  PM/T1\n\t0005  PM/E1\n\t0008  PM/SLS\n\t0009  BajaSpan Resource Target\n\t000a  BajaSpan Section 0\n\t000b  BajaSpan Section 1\n\t000c  BajaSpan Section 2\n\t000d  BajaSpan Section 3\n\t000e  PM/PPC\n1224  Interactive Images\n1225  Power I/O, Inc.\n1227  Tech-Source\n\t0006  Raptor GFX 8P\n\t0023  Raptor GFX [1100T]\n\t0045  Raptor 4000-L [Linux version]\n\t004a  Raptor 4000-LR-L [Linux version]\n1228  Norsk Elektro Optikk A/S\n1229  Data Kinesis Inc.\n122a  Integrated Telecom\n122b  LG Industrial Systems Co., Ltd\n122c  Sican GmbH\n122d  Aztech System Ltd\n\t1206  368DSP\n\t1400  Trident PCI288-Q3DII (NX)\n\t50dc  3328 Audio\n\t\t122d 0001  3328 Audio\n\t80da  3328 Audio\n\t\t122d 0001  3328 Audio\n122e  Xyratex\n\t7722  Napatech XL1\n\t7724  Napatech XL2/XA\n\t7729  Napatech XD\n122f  Andrew Corporation\n1230  Fishcamp Engineering\n1231  Woodward McCoach, Inc.\n\t04e1  Desktop PCI Telephony 4\n\t05e1  Desktop PCI Telephony 5/6\n\t0d00  LightParser\n\t0d02  LightParser 2\n\t0d13  Desktop PCI L1/L3 Telephony\n1232  GPT Limited\n1233  Bus-Tech, Inc.\n# nee Risq Modular Systems, Inc.\n1235  SMART Modular Technologies\n1236  Sigma Designs Corporation\n\t0000  RealMagic64/GX\n\t6401  REALmagic 64/GX (SD 6425)\n1237  Alta Technology Corporation\n1238  Adtran\n1239  3DO Company\n123a  Visicom Laboratories, Inc.\n123b  Seeq Technology, Inc.\n123c  Century Systems, Inc.\n123d  Engineering Design Team, Inc.\n\t0000  EasyConnect 8/32\n\t0002  EasyConnect 8/64\n\t0003  EasyIO\n123e  Simutech, Inc.\n# nee C-Cube Microsystems / acquired by Magnum Semiconductor\n123f  LSI Logic\n\t00e4  MPEG\n\t8120  DVxplore Codec\n\t\t10de 01e1  NVTV PAL\n\t\t10de 01e2  NVTV NTSC\n\t\t10de 01e3  NVTV PAL\n\t\t10de 0248  NVTV NTSC\n\t\t10de 0249  NVTV PAL\n\t\t11bd 0006  DV500 E4\n\t\t11bd 000a  DV500 E4\n\t\t11bd 000f  DV500 E4\n\t\t1809 0016  Emuzed MAUI-III PCI PVR FM TV\n\t8888  Cinemaster C 3.0 DVD Decoder\n\t\t1002 0001  Cinemaster C 3.0 DVD Decoder\n\t\t1002 0002  Cinemaster C 3.0 DVD Decoder\n\t\t1328 0001  Cinemaster C 3.0 DVD Decoder\n1240  Marathon Technologies Corp.\n1241  DSC Communications\n# Formerly Jaycor Networks, Inc.\n1242  JNI Corporation\n\t1560  JNIC-1560 PCI-X Fibre Channel Controller\n\t\t1242 6562  FCX2-6562 Dual Channel PCI-X Fibre Channel Adapter\n\t\t1242 656a  FCX-6562 PCI-X Fibre Channel Adapter\n\t4643  FCI-1063 Fibre Channel Adapter\n\t6562  FCX2-6562 Dual Channel PCI-X Fibre Channel Adapter\n\t656a  FCX-6562 PCI-X Fibre Channel Adapter\n1243  Delphax\n# Audio-Visuelles Marketing und Computersysteme\n1244  AVM GmbH\n\t0700  B1 ISDN\n\t0800  C4 ISDN\n\t0a00  A1 ISDN [Fritz]\n\t\t1244 0a00  FRITZ!Card ISDN Controller\n\t0e00  Fritz!Card PCI v2.0 ISDN\n\t0e80  Fritz!Card PCI v2.1 ISDN\n\t\t1244 0e00  PSB 3100F (AVM KAFKA) [Fritz!Card PCI v2.1]\n\t1100  C2 ISDN\n\t1200  T1 ISDN\n\t2700  Fritz!Card DSL SL\n\t2900  Fritz!Card DSL v2.0\n1245  A.P.D., S.A.\n1246  Dipix Technologies, Inc.\n1247  Xylon Research, Inc.\n1248  Central Data Corporation\n1249  Samsung Electronics Co., Ltd.\n124a  AEG Electrocom GmbH\n124b  SBS/Greenspring Modular I/O\n\t0040  PCI-40A or cPCI-200 Quad IndustryPack carrier\n\t\t124b 9080  PCI9080 Bridge\n124c  Solitron Technologies, Inc.\n124d  Stallion Technologies, Inc.\n\t0000  EasyConnection 8/32\n\t0002  EasyConnection 8/64\n\t0003  EasyIO\n\t0004  EasyConnection/RA\n124e  Cylink\n124f  Infortrend Technology, Inc.\n\t0041  IFT-2000 Series RAID Controller\n1250  Hitachi Microcomputer System Ltd\n1251  VLSI Solutions Oy\n1253  Guzik Technical Enterprises\n1254  Linear Systems Ltd.\n\t0065  DVB Master FD\n\t007c  DVB Master Quad/o\n1255  Optibase Ltd\n\t1110  MPEG Forge\n\t1210  MPEG Fusion\n\t2110  VideoPlex\n\t2120  VideoPlex CC\n\t2130  VideoQuest\n1256  Perceptive Solutions, Inc.\n\t4201  PCI-2220I\n\t4401  PCI-2240I\n\t5201  PCI-2000\n1257  Vertex Networks, Inc.\n1258  Gilbarco, Inc.\n# nee Allied Telesyn International\n1259  Allied Telesis\n\t2560  AT-2560 Fast Ethernet Adapter (i82557B)\n\t2801  AT-2801FX (RTL-8139)\n\ta117  RTL81xx Fast Ethernet\n\ta11e  RTL81xx Fast Ethernet\n\ta120  21x4x DEC-Tulip compatible 10/100 Ethernet\n125a  ABB Power Systems\n125b  Asix Electronics Corporation\n\t1400  AX88141 Fast Ethernet Controller\n\t\t1186 1100  AX8814X Based PCI Fast Ethernet Adapter\n125c  Aurora Technologies, Inc.\n\t0101  Saturn 4520P\n\t0640  Aries 16000P\n125d  ESS Technology\n\t0000  ES336H Fax Modem (Early Model)\n\t1948  ES1948 Maestro-1\n\t1968  ES1968 Maestro 2\n\t\t1028 0085  ES1968 Maestro-2 PCI\n\t\t1033 8051  ES1968 Maestro-2 Audiodrive\n\t1969  ES1938/ES1946/ES1969 Solo-1 Audiodrive\n\t\t1014 0166  ES1969 SOLO-1 AudioDrive on IBM Aptiva Mainboard\n\t\t125d 8888  Solo-1 Audio Adapter\n\t\t125d 8898  ES1938S TTSOLO1-SL [TerraTec 128i PCI]\n\t\t153b 111b  Terratec 128i PCI\n\t1978  ES1978 Maestro 2E\n\t\t0e11 b112  Armada M700/E500\n\t\t1033 803c  ES1978 Maestro-2E Audiodrive\n\t\t1033 8058  ES1978 Maestro-2E Audiodrive\n\t\t1092 4000  Monster Sound MX400\n\t\t1179 0001  ES1978 Maestro-2E Audiodrive\n\t1988  ES1988 Allegro-1\n\t\t0e11 0098  Evo N600c\n\t\t1092 4100  Sonic Impact S100\n\t\t125d 0431  Allegro AudioDrive\n\t\t125d 1988  ESS Allegro-1 Audiodrive\n\t\t125d 1998  Allegro AudioDrive\n\t\t125d 1999  Allegro-1 AudioDrive\n\t1989  ESS Modem\n\t\t125d 1989  ESS Modem\n\t1998  ES1983S Maestro-3i PCI Audio Accelerator\n\t\t1028 00b1  Latitude C600\n\t\t1028 00e5  Latitude C810\n\t\t1028 00e6  ES1983S Maestro-3i (Dell Inspiron 8100)\n\t1999  ES1983S Maestro-3i PCI Modem Accelerator\n\t199a  ES1983S Maestro-3i PCI Audio Accelerator\n\t199b  ES1983S Maestro-3i PCI Modem Accelerator\n\t2808  ES336H Fax Modem (Later Model)\n\t2838  ES2838/2839 SuperLink Modem\n\t2898  ES2898 Modem\n\t\t125d 0424  ES56-PI Data Fax Modem\n\t\t125d 0425  ES56T-PI Data Fax Modem\n\t\t125d 0426  ES56V-PI Data Fax Modem\n\t\t125d 0427  VW-PI Data Fax Modem\n\t\t125d 0428  ES56ST-PI Data Fax Modem\n\t\t125d 0429  ES56SV-PI Data Fax Modem\n\t\t147a c001  ES56-PI Data Fax Modem\n\t\t148d 1030  HCF WV-PI56 [ESS ES56-PI Data Fax Modem]\n\t\t14fe 0428  ES56-PI Data Fax Modem\n\t\t14fe 0429  ES56-PI Data Fax Modem\n125e  Specialvideo Engineering SRL\n125f  Concurrent Technologies, Inc.\n# 4 x serial ports, 2 x printer ports\n\t2071  CC PMC/232\n# 4 x serial ports, 2 x printer ports\n\t2084  CC PMC/23P\n# 4 x serial ports, RS422\n\t2091  CC PMC/422\n1260  Intersil Corporation\n\t3872  ISL3872 [Prism 3]\n\t\t1468 0202  LAN-Express IEEE 802.11b Wireless LAN\n\t3873  ISL3874 [Prism 2.5]/ISL3872 [Prism 3]\n\t\t10cf 1169  MBH7WM01-8734 802.11b Wireless Mini PCI Card [ISL3874]\n\t\t1186 3501  DWL-520 Wireless PCI Adapter (rev A or B) [ISL3874]\n\t\t1186 3700  DWL-520 Wireless PCI Adapter (rev E1) [ISL3872]\n\t\t1385 4105  MA311 802.11b wireless adapter [ISL3874]\n\t\t1668 0414  HWP01170-01 802.11b PCI Wireless Adapter\n\t\t16a5 1601  AIR.mate PC-400 PCI Wireless LAN Adapter\n\t\t1737 3874  WMP11 v1 802.11b Wireless-B PCI Adapter [ISL3874]\n\t\t4033 7033  PCW200 802.11b Wireless PCI Adapter [ISL3874]\n\t\t8086 2510  M3AWEB Wireless 802.11b MiniPCI Adapter\n\t\t8086 2513  Wireless 802.11b MiniPCI Adapter\n\t3877  ISL3877 [Prism Indigo]\n\t3886  ISL3886 [Prism Javelin/Prism Xbow]\n\t\t17cf 0037  XG-901 and clones Wireless Adapter\n\t3890  ISL3890 [Prism GT/Prism Duette]/ISL3886 [Prism Javelin/Prism Xbow]\n\t\t10b8 2802  SMC2802W V1 Wireless PCI Adapter [ISL3890]\n\t\t10b8 2835  SMC2835W Wireless Cardbus Adapter\n\t\t10b8 a835  SMC2835W V2 Wireless Cardbus Adapter\n\t\t1113 4203  WN4201B\n\t\t1113 8201  T-Com T-Sinus 154pcicard Wireless PCI Adapter\n\t\t1113 b301  T-Sinus 154card Cardbus\n\t\t1113 ee03  SMC2802W V2 Wireless PCI Adapter [ISL3886]\n\t\t1113 ee08  SMC2835W V3 EU Wireless Cardbus Adapter\n\t\t1186 3202  DWL-G650 A1 Wireless Adapter\n\t\t1259 c104  CG-WLCB54GT Wireless Adapter\n\t\t1260 0000  WG511 v1 54 Mbps Wireless PC Card\n\t\t1385 4800  WG511 v2/v3 54 Mbps Wireless PC Card\n\t\t16a5 1605  ALLNET ALL0271 Wireless PCI Adapter\n\t\t17cf 0014  XG-600 and clones Wireless Adapter\n\t\t17cf 0020  XG-900 and clones Wireless Adapter\n\t\t187e 3403  G-110 802.11g Wireless Cardbus Adapter\n\t8130  HMP8130 NTSC/PAL Video Decoder\n\t8131  HMP8131 NTSC/PAL Video Decoder\n# This is probably more likely a HW fault, but I am keeping it for now --mj\n\tffff  ISL3886IK\n\t\t1260 0000  Senao 3054MP+ (J) mini-PCI WLAN 802.11g adapter\n1261  Matsushita-Kotobuki Electronics Industries, Ltd.\n1262  ES Computer Company, Ltd.\n1263  Sonic Solutions\n1264  Aval Nagasaki Corporation\n1265  Casio Computer Co., Ltd.\n1266  Microdyne Corporation\n\t0001  NE10/100 Adapter (i82557B)\n\t1910  NE2000Plus (RT8029) Ethernet Adapter\n\t\t1266 1910  NE2000Plus Ethernet Adapter\n1267  S. A. Telecommunications\n\t5352  PCR2101\n\t5a4b  Telsat Turbo\n1268  Tektronix\n1269  Thomson-CSF/TTM\n126a  Lexmark International, Inc.\n126b  Adax, Inc.\n126c  Northern Telecom\n\t1211  10/100BaseTX [RTL81xx]\n\t126c  802.11b Wireless Ethernet Adapter\n126d  Splash Technology, Inc.\n126e  Sumitomo Metal Industries, Ltd.\n126f  Silicon Motion, Inc.\n\t0501  SM501 VoyagerGX Rev. AA\n\t0510  SM501 VoyagerGX Rev. B\n\t0710  SM710 LynxEM\n\t0712  SM712 LynxEM+\n\t0718  SM718 LynxSE+\n\t0720  SM720 Lynx3DM\n\t0730  SM731 Cougar3DR\n\t0750  SM750\n\t0810  SM810 LynxE\n\t0811  SM811 LynxE\n\t0820  SM820 Lynx3D\n\t0910  SM910\n1270  Olympus Optical Co., Ltd.\n1271  GW Instruments\n1272  Telematics International\n1273  Hughes Network Systems\n\t0002  DirecPC\n1274  Ensoniq\n\t1171  ES1373 / Creative Labs CT5803 [AudioPCI]\n\t1371  ES1371/ES1373 / Creative Labs CT2518\n\t\t0e11 0024  AudioPCI on Motherboard Compaq Deskpro\n\t\t0e11 b1a7  ES1371, ES1373 AudioPCI\n\t\t1033 80ac  ES1371, ES1373 AudioPCI\n\t\t1042 1854  Tazer\n\t\t107b 8054  Tabor2\n\t\t1274 1371  Audio PCI 64V/128/5200 / Creative CT4810/CT5803/CT5806 [Sound Blaster PCI]\n\t\t1274 8001  CT4751 board\n\t\t1462 6470  ES1371, ES1373 AudioPCI On Motherboard MS-6147 1.1A\n\t\t1462 6560  ES1371, ES1373 AudioPCI On Motherboard MS-6156 1.10\n\t\t1462 6630  ES1371, ES1373 AudioPCI On Motherboard MS-6163BX 1.0A\n\t\t1462 6631  ES1371, ES1373 AudioPCI On Motherboard MS-6163VIA 1.0A\n\t\t1462 6632  ES1371, ES1373 AudioPCI On Motherboard MS-6163BX 2.0A\n\t\t1462 6633  ES1371, ES1373 AudioPCI On Motherboard MS-6163VIA 2.0A\n\t\t1462 6820  ES1371, ES1373 AudioPCI On Motherboard MS-6182 1.00\n\t\t1462 6822  ES1371, ES1373 AudioPCI On Motherboard MS-6182 1.00A\n\t\t1462 6830  ES1371, ES1373 AudioPCI On Motherboard MS-6183 1.00\n\t\t1462 6880  ES1371, ES1373 AudioPCI On Motherboard MS-6188 1.00\n\t\t1462 6900  ES1371, ES1373 AudioPCI On Motherboard MS-6190 1.00\n\t\t1462 6910  ES1371, ES1373 AudioPCI On Motherboard MS-6191\n\t\t1462 6930  ES1371, ES1373 AudioPCI On Motherboard MS-6193\n\t\t1462 6990  ES1371, ES1373 AudioPCI On Motherboard MS-6199BX 2.0A\n\t\t1462 6991  ES1371, ES1373 AudioPCI On Motherboard MS-6199VIA 2.0A\n\t\t14a4 2077  ES1371, ES1373 AudioPCI On Motherboard KR639\n\t\t14a4 2105  ES1371, ES1373 AudioPCI On Motherboard MR800\n\t\t14a4 2107  ES1371, ES1373 AudioPCI On Motherboard MR801\n\t\t14a4 2172  ES1371, ES1373 AudioPCI On Motherboard DR739\n\t\t1509 9902  ES1371, ES1373 AudioPCI On Motherboard KW11\n\t\t1509 9903  ES1371, ES1373 AudioPCI On Motherboard KW31\n\t\t1509 9904  ES1371, ES1373 AudioPCI On Motherboard KA11\n\t\t1509 9905  ES1371, ES1373 AudioPCI On Motherboard KC13\n\t\t152d 8801  ES1371, ES1373 AudioPCI On Motherboard CP810E\n\t\t152d 8802  ES1371, ES1373 AudioPCI On Motherboard CP810\n\t\t152d 8803  ES1371, ES1373 AudioPCI On Motherboard P3810E\n\t\t152d 8804  ES1371, ES1373 AudioPCI On Motherboard P3810-S\n\t\t152d 8805  ES1371, ES1373 AudioPCI On Motherboard P3820-S\n\t\t270f 2001  ES1371, ES1373 AudioPCI On Motherboard 6CTR\n\t\t270f 2200  ES1371, ES1373 AudioPCI On Motherboard 6WTX\n\t\t270f 3000  ES1371, ES1373 AudioPCI On Motherboard 6WSV\n\t\t270f 3100  ES1371, ES1373 AudioPCI On Motherboard 6WIV2\n\t\t270f 3102  ES1371, ES1373 AudioPCI On Motherboard 6WIV\n\t\t270f 7060  ES1371, ES1373 AudioPCI On Motherboard 6ASA2\n\t\t8086 4249  ES1371, ES1373 AudioPCI On Motherboard BI440ZX\n\t\t8086 424c  ES1371, ES1373 AudioPCI On Motherboard BL440ZX\n\t\t8086 425a  ES1371, ES1373 AudioPCI On Motherboard BZ440ZX\n\t\t8086 4341  ES1371, ES1373 AudioPCI On Motherboard Cayman\n\t\t8086 4343  ES1371, ES1373 AudioPCI On Motherboard Cape Cod\n\t\t8086 4541  D815EEA Motherboard\n\t\t8086 4649  ES1371, ES1373 AudioPCI On Motherboard Fire Island\n\t\t8086 464a  ES1371, ES1373 AudioPCI On Motherboard FJ440ZX\n\t\t8086 4d4f  ES1371, ES1373 AudioPCI On Motherboard Montreal\n\t\t8086 4f43  ES1371, ES1373 AudioPCI On Motherboard OC440LX\n\t\t8086 5243  ES1371, ES1373 AudioPCI On Motherboard RC440BX\n\t\t8086 5352  ES1371, ES1373 AudioPCI On Motherboard SunRiver\n\t\t8086 5643  ES1371, ES1373 AudioPCI On Motherboard Vancouver\n\t\t8086 5753  ES1371, ES1373 AudioPCI On Motherboard WS440BX\n\t5000  ES1370 [AudioPCI]\n\t5880  5880B / Creative Labs CT5880\n\t\t1274 2000  Creative CT4810 [Sound Blaster AudioPCI 128]\n\t\t1274 2003  Creative SoundBlaster AudioPCI 128\n\t\t1274 5880  Creative CT4750 [Sound Blaster PCI 128]\n\t\t1274 8001  Sound Blaster 16PCI 4.1ch\n\t\t1458 a000  5880 AudioPCI On Motherboard 6OXET\n\t\t1462 6880  5880 AudioPCI On Motherboard MS-6188 1.00\n\t\t270f 2001  5880 AudioPCI On Motherboard 6CTR\n\t\t270f 2200  5880 AudioPCI On Motherboard 6WTX\n\t\t270f 7040  5880 AudioPCI On Motherboard 6ATA4\n\t8001  CT5880 [AudioPCI]\n\t8002  5880A [AudioPCI]\n1275  Network Appliance Corporation\n1276  Switched Network Technologies, Inc.\n1277  Comstream\n1278  Transtech Parallel Systems Ltd.\n\t0701  TPE3/TM3 PowerPC Node\n\t0710  TPE5 PowerPC PCI board\n\t1100  PMC-FPGA02\n\t1101  TS-C43 card with 4 ADSP-TS101 processors\n1279  Transmeta Corporation\n\t0060  TM8000 Northbridge\n\t0061  TM8000 AGP bridge\n\t0295  Northbridge\n\t0395  LongRun Northbridge\n\t0396  SDRAM controller\n\t0397  BIOS scratchpad\n127a  Rockwell International\n\t1002  HCF 56k Data/Fax Modem\n\t\t1092 094c  SupraExpress 56i PRO [Diamond SUP2380]\n\t\t122d 4002  HPG / MDP3858-U\n\t\t122d 4005  MDP3858-E\n\t\t122d 4007  MDP3858-A/-NZ\n\t\t122d 4012  MDP3858-SA\n\t\t122d 4017  MDP3858-W\n\t\t122d 4018  MDP3858-W\n\t\t127a 1002  Rockwell 56K D/F HCF Modem\n\t1003  HCF 56k Data/Fax Modem\n\t\t0e11 b0bc  229-DF Zephyr\n\t\t0e11 b114  229-DF Cheetah\n\t\t1033 802b  229-DF\n\t\t13df 1003  PCI56RX Modem\n\t\t13e0 0117  IBM\n\t\t13e0 0147  IBM F-1156IV+/R3 Spain V.90 Modem\n\t\t13e0 0197  IBM\n\t\t13e0 01c7  IBM F-1156IV+/R3 WW V.90 Modem\n\t\t13e0 01f7  IBM\n\t\t1436 1003  IBM\n\t\t1436 1103  IBM 5614PM3G V.90 Modem\n\t\t1436 1602  Compaq 229-DF Ducati\n\t1004  HCF 56k Data/Fax/Voice Modem\n\t\t1048 1500  MicroLink 56k Modem\n\t\t10cf 1059  Fujitsu 229-DFRT\n\t1005  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem\n\t\t1005 127a  AOpen FM56-P\n\t\t1033 8029  229-DFSV\n\t\t1033 8054  Modem\n\t\t10cf 103c  Fujitsu\n\t\t10cf 1055  Fujitsu 229-DFSV\n\t\t10cf 1056  Fujitsu 229-DFSV\n\t\t122d 4003  MDP3858SP-U\n\t\t122d 4006  Packard Bell MDP3858V-E\n\t\t122d 4008  MDP3858SP-A/SP-NZ\n\t\t122d 4009  MDP3858SP-E\n\t\t122d 4010  MDP3858V-U\n\t\t122d 4011  MDP3858SP-SA\n\t\t122d 4013  MDP3858V-A/V-NZ\n\t\t122d 4015  MDP3858SP-W\n\t\t122d 4016  MDP3858V-W\n\t\t122d 4019  MDP3858V-SA\n\t\t13df 1005  PCI56RVP Modem\n\t\t13e0 0187  IBM\n\t\t13e0 01a7  IBM\n\t\t13e0 01b7  IBM DF-1156IV+/R3 Spain V.90 Modem\n\t\t13e0 01d7  IBM DF-1156IV+/R3 WW V.90 Modem\n\t\t1436 1005  IBM\n\t\t1436 1105  IBM\n\t\t1437 1105  IBM 5614PS3G V.90 Modem\n\t1022  HCF 56k Modem\n\t\t1436 1303  M3-5614PM3G V.90 Modem\n\t1023  HCF 56k Data/Fax Modem\n\t\t122d 4020  Packard Bell MDP3858-WE\n\t\t122d 4023  MDP3858-UE\n\t\t13e0 0247  IBM F-1156IV+/R6 Spain V.90 Modem\n\t\t13e0 0297  IBM\n\t\t13e0 02c7  IBM F-1156IV+/R6 WW V.90 Modem\n\t\t1436 1203  IBM\n\t\t1436 1303  IBM\n\t1024  HCF 56k Data/Fax/Voice Modem\n\t1025  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem\n\t\t10cf 106a  Fujitsu 235-DFSV\n\t\t122d 4021  Packard Bell MDP3858V-WE\n\t\t122d 4022  MDP3858SP-WE\n\t\t122d 4024  MDP3858V-UE\n\t\t122d 4025  MDP3858SP-UE\n\t1026  HCF 56k PCI Speakerphone Modem\n\t1032  HCF 56k Modem\n\t1033  HCF 56k Modem\n\t1034  HCF 56k Modem\n\t1035  HCF 56k PCI Speakerphone Modem\n\t1036  HCF 56k Modem\n\t1085  HCF 56k Volcano PCI Modem\n\t2004  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem\n\t2005  HCF 56k Data/Fax Modem\n\t\t104d 8044  229-DFSV\n\t\t104d 8045  229-DFSV\n\t\t104d 8055  PBE/Aztech 235W-DFSV\n\t\t104d 8056  235-DFSV\n\t\t104d 805a  Modem\n\t\t104d 805f  Modem\n\t\t104d 8074  Modem\n\t2013  HSF 56k Data/Fax Modem\n\t\t1179 0001  Modem\n\t\t1179 ff00  Modem\n\t2014  HSF 56k Data/Fax/Voice Modem\n\t\t10cf 1057  Fujitsu Citicorp III\n\t\t122d 4050  MSP3880-U\n\t\t122d 4055  MSP3880-W\n\t2015  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem\n\t\t10cf 1063  Fujitsu\n\t\t10cf 1064  Fujitsu\n\t\t1468 2015  Fujitsu\n\t2016  HSF 56k Data/Fax/Voice/Spkp Modem\n\t\t122d 4051  MSP3880V-W\n\t\t122d 4052  MSP3880SP-W\n\t\t122d 4054  MSP3880V-U\n\t\t122d 4056  MSP3880SP-U\n\t\t122d 4057  MSP3880SP-A\n\t4311  Riptide HSF 56k PCI Modem\n\t\t127a 4311  Ring Modular? Riptide HSF RT HP Dom\n\t\t13e0 0210  HP-GVC\n\t4320  Riptide PCI Audio Controller\n\t\t1235 4320  Riptide PCI Audio Controller\n\t4321  Riptide HCF 56k PCI Modem\n\t\t1235 4321  Hewlett Packard DF\n\t\t1235 4324  Hewlett Packard DF\n\t\t13e0 0210  Hewlett Packard DF\n\t\t144d 2321  Riptide\n\t4322  Riptide PCI Game Controller\n\t\t1235 4322  Riptide PCI Game Controller\n\t8234  RapidFire 616X ATM155 Adapter\n\t\t108d 0022  RapidFire 616X ATM155 Adapter\n\t\t108d 0027  RapidFire 616X ATM155 Adapter\n127b  Pixera Corporation\n127c  Crosspoint Solutions, Inc.\n127d  Vela Research\n127e  Winnov, L.P.\n\t0010  Videum 1000 Plus\n127f  Fujifilm\n1280  Photoscript Group Ltd.\n1281  Yokogawa Electric Corporation\n1282  Davicom Semiconductor, Inc.\n\t6585  DM562P V90 Modem\n\t9009  Ethernet 100/10 MBit\n\t9100  21x4x DEC-Tulip compatible 10/100 Ethernet\n\t9102  21x4x DEC-Tulip compatible 10/100 Ethernet\n# Subsystem ID is main ID reveresed.\n\t\t0291 8212  DM9102A (DM9102AE, SM9102AF) Ethernet 100/10 MBit\n\t9132  Ethernet 100/10 MBit\n1283  Integrated Technology Express, Inc.\n\t673a  IT8330G\n\t8152  IT8152F/G Advanced RISC-to-PCI Companion Chip\n\t8211  ITE 8211F Single Channel UDMA 133\n\t\t1043 8138  P5GD1-VW Mainboard\n\t8212  IT8212 Dual channel ATA RAID controller\n\t\t1283 0001  IT/ITE8212 Dual channel ATA RAID controller\n\t8213  IT8213 IDE Controller\n\t\t1458 b000  GA-EG45M-DS2H Mainboard\n\t8330  IT8330G\n\t8872  IT887xF PCI to ISA I/O chip with SMB, GPIO, Serial or Parallel Port\n\t8888  IT8888F/G PCI to ISA Bridge with SMB [Golden Gate]\n\t8889  IT8889F PCI to ISA Bridge\n\t8892  IT8892E PCIe to PCI Bridge\n\t8893  IT8893E PCIe to PCI Bridge\n\te886  IT8330G\n1284  Sahara Networks, Inc.\n1285  Platform Technologies, Inc.\n\t0100  AGOGO sound chip (aka ESS Maestro 1)\n1286  Mazet GmbH\n1287  M-Pact, Inc.\n\t001e  LS220D DVD Decoder\n\t001f  LS220C DVD Decoder\n1288  Timestep Corporation\n1289  AVC Technology, Inc.\n128a  Asante Technologies, Inc.\n128b  Transwitch Corporation\n128c  Retix Corporation\n128d  G2 Networks, Inc.\n\t0021  ATM155 Adapter\n128e  Hoontech Corporation/Samho Multi Tech Ltd.\n\t0008  ST128 WSS/SB\n\t0009  ST128 SAM9407\n\t000a  ST128 Game Port\n\t000b  ST128 MPU Port\n\t000c  ST128 Ctrl Port\n128f  Tateno Dennou, Inc.\n1290  Sord Computer Corporation\n1291  NCS Computer Italia\n1292  Tritech Microelectronics Inc\n\tfc02  Pyramid3D TR25202\n1293  Media Reality Technology\n1294  Rhetorex, Inc.\n1295  Imagenation Corporation\n\t0800  PXR800\n\t1000  PXD1000\n1296  Kofax Image Products\n1297  Holco Enterprise Co, Ltd/Shuttle Computer\n1298  Spellcaster Telecommunications Inc.\n1299  Knowledge Technology Lab.\n129a  VMetro, inc.\n\t0615  PBT-615 PCI-X Bus Analyzer\n\t1100  PMC-FPGA05\n\t1106  XMC-FPGA05F, PCI interface\n\t1107  XMC-FPGA05F, PCIe interface\n\t1108  XMC-FPGA05D, PCI interface\n\t1109  XMC-FPGA05D, PCIe interface\n129b  Image Access\n129c  Jaycor\n129d  Compcore Multimedia, Inc.\n129e  Victor Company of Japan, Ltd.\n129f  OEC Medical Systems, Inc.\n12a0  Allen-Bradley Company\n12a1  Simpact Associates, Inc.\n12a2  Newgen Systems Corporation\n12a3  Lucent Technologies\n\t8105  T8105 H100 Digital Switch\n12a4  NTT Electronics Corporation\n12a5  Vision Dynamics Ltd.\n12a6  Scalable Networks, Inc.\n12a7  AMO GmbH\n12a8  News Datacom\n12a9  Xiotech Corporation\n12aa  SDL Communications, Inc.\n12ab  YUAN High-Tech Development Co., Ltd.\n\t0000  MPG160/Kuroutoshikou ITVC15-STVLP\n\t0002  AU8830 [Vortex2] Based Sound Card With A3D Support\n\t0003  T507 (DVB-T) TV tuner/capture device\n\t2300  Club-3D Zap TV2100\n\t3000  MPG-200C PCI DVD Decoder Card\n\t4789  MPC788 MiniPCI Hybrid TV Tuner\n\tfff3  MPG600/Kuroutoshikou ITVC16-STVLP\n\tffff  MPG600/Kuroutoshikou ITVC16-STVLP\n12ac  Measurex Corporation\n12ad  Multidata GmbH\n12ae  Alteon Networks Inc.\n\t0001  AceNIC Gigabit Ethernet\n\t\t1014 0104  Gigabit Ethernet-SX PCI Adapter\n\t\t12ae 0001  Gigabit Ethernet-SX (Universal)\n\t0002  AceNIC Gigabit Ethernet (Copper)\n\t\t10a9 8002  Acenic Gigabit Ethernet\n\t\t12ae 0002  Gigabit Ethernet-T (3C986-T)\n\t00fa  Farallon PN9100-T Gigabit Ethernet\n12af  TDK USA Corp\n12b0  Jorge Scientific Corp\n12b1  GammaLink\n12b2  General Signal Networks\n12b3  Inter-Face Co Ltd\n12b4  FutureTel Inc\n12b5  Granite Systems Inc.\n12b6  Natural Microsystems\n12b7  Cognex Corporation\n12b8  Korg\n# Nee US Robotics\n12b9  3Com Corp, Modem Division\n\t1006  WinModem\n\t\t12b9 005c  USR 56k Internal Voice WinModem (Model 3472)\n\t\t12b9 005e  USR 56k Internal WinModem (Models 662975)\n\t\t12b9 0062  USR 56k Internal Voice WinModem (Model 662978)\n\t\t12b9 0068  USR 56k Internal Voice WinModem (Model 5690)\n\t\t12b9 007a  USR 56k Internal Voice WinModem (Model 662974)\n\t\t12b9 007f  USR 56k Internal WinModem (Models 5698, 5699)\n\t\t12b9 0080  USR 56k Internal WinModem (Models 2975, 3528)\n\t\t12b9 0081  USR 56k Internal Voice WinModem (Models 2974, 3529)\n\t\t12b9 0091  USR 56k Internal Voice WinModem (Model 2978)\n\t1007  USR 56k Internal WinModem\n\t\t12b9 00a3  USR 56k Internal WinModem (Model 3595)\n\t\t12b9 00c4  U.S. Robotics V.92 Voice Faxmodem (2884A/B/C)\n\t1008  56K FaxModem Model 5610\n\t\t12b9 00a2  USR 56k Internal FAX Modem (Model 2977)\n\t\t12b9 00aa  USR 56k Internal Voice Modem (Model 2976)\n\t\t12b9 00ab  USR 56k Internal Voice Modem (Model 5609)\n\t\t12b9 00ac  USR 56k Internal Voice Modem (Model 3298)\n\t\t12b9 00ad  USR 56k Internal FAX Modem (Model 5610)\n\t\t12b9 00d3  USR 56K Internal V92 FAX Modem (Model 5610)\n\t\t12b9 baba  USR 56K Internal Voice Modem 3CP3298-DEL (Model 5601) [Hawk]\n12ba  BittWare, Inc.\n12bb  Nippon Unisoft Corporation\n12bc  Array Microsystems\n12bd  Computerm Corp.\n12be  Anchor Chips Inc.\n\t3041  AN3041Q CO-MEM\n\t3042  AN3042Q CO-MEM Lite\n\t\t12be 3042  Anchor Chips Lite Evaluation Board\n12bf  Fujifilm Microdevices\n12c0  Infimed\n12c1  GMM Research Corp\n12c2  Mentec Limited\n12c3  Holtek Microelectronics Inc\n\t0058  PCI NE2K Ethernet\n\t5598  PCI NE2K Ethernet\n12c4  Connect Tech Inc\n\t0001  Blue HEAT/PCI 8 (RS232/CL/RJ11)\n\t0002  Blue HEAT/PCI 4 (RS232)\n\t0003  Blue HEAT/PCI 2 (RS232)\n\t0004  Blue HEAT/PCI 8 (UNIV, RS485)\n\t0005  Blue HEAT/PCI 4+4/6+2 (UNIV, RS232/485)\n\t0006  Blue HEAT/PCI 4 (OPTO, RS485)\n\t0007  Blue HEAT/PCI 2+2 (RS232/485)\n\t0008  Blue HEAT/PCI 2 (OPTO, Tx, RS485)\n\t0009  Blue HEAT/PCI 2+6 (RS232/485)\n\t000a  Blue HEAT/PCI 8 (Tx, RS485)\n\t000b  Blue HEAT/PCI 4 (Tx, RS485)\n\t000c  Blue HEAT/PCI 2 (20 MHz, RS485)\n\t000d  Blue HEAT/PCI 2 PTM\n\t0100  NT960/PCI\n\t0201  cPCI Titan - 2 Port\n\t0202  cPCI Titan - 4 Port\n\t0300  CTI PCI UART 2 (RS232)\n\t0301  CTI PCI UART 4 (RS232)\n\t0302  CTI PCI UART 8 (RS232)\n\t0310  CTI PCI UART 1+1 (RS232/485)\n\t0311  CTI PCI UART 2+2 (RS232/485)\n\t0312  CTI PCI UART 4+4 (RS232/485)\n\t0320  CTI PCI UART 2\n\t0321  CTI PCI UART 4\n\t0322  CTI PCI UART 8\n\t0330  CTI PCI UART 2 (RS485)\n\t0331  CTI PCI UART 4 (RS485)\n\t0332  CTI PCI UART 8 (RS485)\n12c5  Picture Elements Incorporated\n\t007e  Imaging/Scanning Subsystem Engine\n\t007f  Imaging/Scanning Subsystem Engine\n\t0081  PCIVST [Grayscale Thresholding Engine]\n\t0085  Video Simulator/Sender\n\t0086  THR2 Multi-scale Thresholder\n12c6  Mitani Corporation\n12c7  Dialogic Corp\n# 12 Line, 6 port, CT-BUS/SC-BUS, loopstart FXO adaptor.\n\t0546  Springware D/120JCT-LS\n# 24 Channel, 1 Port, CT-BUS/SC-BUS, T1/PRI adaptor.\n\t0647  Springware D/240JCT-T1\n# 4 Line, 4 port, CT-BUS/SC-BUS, loopstart FXO adaptor. Revision 01\n\t0676  Springware D/41JCT-LS\n# 48 Channel, 2 Port, CT-BUS/SC-BUS, T1/PRI adaptor.\n\t0685  Springware D/480JCT-2T1\n12c8  G Force Co, Ltd\n12c9  Gigi Operations\n12ca  Integrated Computing Engines\n12cb  Antex Electronics Corporation\n\t0027  SC4 (StudioCard)\n\t002e  StudioCard 2000\n12cc  Pluto Technologies International\n12cd  Aims Lab\n12ce  Netspeed Inc.\n12cf  Prophet Systems, Inc.\n12d0  GDE Systems, Inc.\n12d1  PSITech\n12d2  NVidia / SGS Thomson (Joint Venture)\n\t0008  NV1\n\t0009  DAC64\n\t0018  Riva128\n\t\t1048 0c10  VICTORY Erazor\n\t\t107b 8030  STB Velocity 128\n\t\t1092 0350  Viper V330\n\t\t1092 1092  Viper V330\n\t\t10b4 1b1b  STB Velocity 128\n\t\t10b4 1b1d  STB Velocity 128\n\t\t10b4 1b1e  STB Velocity 128, PAL TV-Out\n\t\t10b4 1b20  STB Velocity 128 Sapphire\n\t\t10b4 1b21  STB Velocity 128\n\t\t10b4 1b22  STB Velocity 128 AGP, NTSC TV-Out\n\t\t10b4 1b23  STB Velocity 128 AGP, PAL TV-Out\n\t\t10b4 1b27  STB Velocity 128 DVD\n\t\t10b4 1b88  MVP Pro 128\n\t\t10b4 222a  STB Velocity 128 AGP\n\t\t10b4 2230  STB Velocity 128\n\t\t10b4 2232  STB Velocity 128\n\t\t10b4 2235  STB Velocity 128 AGP\n\t\t2a15 54a3  3DVision-SAGP / 3DexPlorer 3000\n\t0019  Riva128ZX\n\t0020  TNT\n\t0028  TNT2\n\t0029  UTNT2\n\t002c  VTNT2\n\t00a0  ITNT2\n12d3  Vingmed Sound A/S\n12d4  Ulticom (Formerly DGM&S)\n\t0200  T1 Card\n12d5  Equator Technologies Inc\n\t0003  BSP16\n\t1000  BSP15\n12d6  Analogic Corp\n12d7  Biotronic SRL\n# acquired by Diodes Inc.\n12d8  Pericom Semiconductor\n\t01a7  7C21P100 2-port PCI-X to PCI-X Bridge\n\t2304  PI7C9X2G304 EL/SL PCIe2 3-Port/4-Lane Packet Switch\n\t2404  PI7C9X2G404 EL/SL PCIe2 4-Port/4-Lane Packet Switch\n\t2608  PI7C9X2G608GP PCIe2 6-Port/8-Lane Packet Switch\n\t400a  PI7C9X442SL PCI Express Bridge Port\n\t400e  PI7C9X442SL USB OHCI Controller\n\t400f  PI7C9X442SL USB EHCI Controller\n\t71e2  PI7C7300A/PI7C7300D PCI-to-PCI Bridge\n\t71e3  PI7C7300A/PI7C7300D PCI-to-PCI Bridge (Secondary Bus 2)\n\t8140  PI7C8140A PCI-to-PCI Bridge\n\t8148  PI7C8148A/PI7C8148B PCI-to-PCI Bridge\n\t8150  PCI to PCI Bridge\n\t8152  PI7C8152A/PI7C8152B/PI7C8152BI PCI-to-PCI Bridge\n\t8154  PI7C8154A/PI7C8154B/PI7C8154BI PCI-to-PCI Bridge\n\te110  PI7C9X110 PCI Express to PCI bridge\n\t\t1775 11cc  CC11/CL11 CompactPCI Bridge\n\te111  PI7C9X111SL PCIe-to-PCI Reversible Bridge\n\te130  PCI Express to PCI-XPI7C9X130 PCI-X Bridge\n12d9  Aculab PLC\n\t0002  PCI Prosody\n\t0004  cPCI Prosody\n\t0005  Aculab E1/T1 PCI card\n\t1078  Prosody X class e1000 device\n\t\t12d9 000d  Prosody X PCI\n\t\t12d9 000e  Prosody X cPCI\n12da  True Time Inc.\n12db  Annapolis Micro Systems, Inc\n12dc  Symicron Computer Communication Ltd.\n12dd  Management Graphics\n12de  Rainbow Technologies\n\t0200  CryptoSwift CS200\n12df  SBS Technologies Inc\n12e0  Chase Research\n\t0010  ST16C654 Quad UART\n\t0020  ST16C654 Quad UART\n\t0030  ST16C654 Quad UART\n12e1  Nintendo Co, Ltd\n12e2  Datum Inc. Bancomm-Timing Division\n12e3  Imation Corp - Medical Imaging Systems\n12e4  Brooktrout Technology Inc\n12e5  Apex Semiconductor Inc\n12e6  Cirel Systems\n12e7  Sunsgroup Corporation\n12e8  Crisc Corp\n12e9  GE Spacenet\n12ea  Zuken\n12eb  Aureal Semiconductor\n\t0001  Vortex 1\n\t\t104d 8036  AU8820 Vortex Digital Audio Processor\n\t\t1092 2000  Sonic Impact A3D\n\t\t1092 2100  Sonic Impact A3D\n\t\t1092 2110  Sonic Impact A3D\n\t\t1092 2200  Sonic Impact A3D\n\t\t122d 1002  AU8820 Vortex Digital Audio Processor\n\t\t12eb 0001  AU8820 Vortex Digital Audio Processor\n\t\t5053 3355  Montego\n\t\t50b2 1111  XLerate\n\t0002  Vortex 2\n\t\t104d 8049  AU8830 Vortex 3D Digital Audio Processor\n\t\t104d 807b  AU8830 Vortex 3D Digital Audio Processor\n\t\t1092 3000  Monster Sound II\n\t\t1092 3001  Monster Sound II\n\t\t1092 3002  Monster Sound II\n\t\t1092 3003  Monster Sound II\n\t\t1092 3004  Monster Sound II\n\t\t12eb 0002  AU8830 Vortex 3D Digital Audio Processor\n\t\t12eb 0088  AU8830 Vortex 3D Digital Audio Processor\n\t\t144d 3510  AU8830 Vortex 3D Digital Audio Processor\n\t\t5053 3356  Montego II\n\t0003  AU8810 Vortex Digital Audio Processor\n\t\t104d 8049  AU8810 Vortex Digital Audio Processor\n\t\t104d 8077  AU8810 Vortex Digital Audio Processor\n\t\t109f 1000  AU8810 Vortex Digital Audio Processor\n\t\t12eb 0003  AU8810 Vortex Digital Audio Processor\n\t\t1462 6780  AU8810 Vortex Digital Audio Processor\n\t\t14a4 2073  AU8810 Vortex Digital Audio Processor\n\t\t14a4 2091  AU8810 Vortex Digital Audio Processor\n\t\t14a4 2104  AU8810 Vortex Digital Audio Processor\n\t\t14a4 2106  AU8810 Vortex Digital Audio Processor\n\t8803  Vortex 56k Software Modem\n\t\t12eb 8803  Vortex 56k Software Modem\n12ec  3A International, Inc.\n12ed  Optivision Inc.\n12ee  Orange Micro\n12ef  Vienna Systems\n12f0  Pentek\n12f1  Sorenson Vision Inc\n12f2  Gammagraphx, Inc.\n12f3  Radstone Technology\n12f4  Megatel\n12f5  Forks\n12f6  Dawson France\n12f7  Cognex\n12f8  Electronic Design GmbH\n\t0002  VideoMaker\n12f9  Four Fold Ltd\n12fb  Spectrum Signal Processing\n\t0001  PMC-MAI\n\t00f5  F5 Dakar\n\t02ad  PMC-2MAI\n\t2adc  ePMC-2ADC\n\t3100  PRO-3100\n\t3500  PRO-3500\n\t4d4f  Modena\n\t8120  ePMC-8120\n\tda62  Daytona C6201 PCI (Hurricane)\n\tdb62  Ingliston XBIF\n\tdc62  Ingliston PLX9054\n\tdd62  Ingliston JTAG/ISP\n\teddc  ePMC-MSDDC\n\tfa01  ePMC-FPGA\n12fc  Capital Equipment Corp\n12fd  I2S\n12fe  ESD Electronic System Design GmbH\n12ff  Lexicon\n1300  Harman International Industries Inc\n1302  Computer Sciences Corp\n1303  Innovative Integration\n\t0030  X3-SDF 4-channel XMC acquisition board\n1304  Juniper Networks\n1305  Netphone, Inc\n1306  Duet Technologies\n# Nee ComputerBoards\n1307  Measurement Computing\n\t0001  PCI-DAS1602/16\n\t000b  PCI-DIO48H\n\t000c  PCI-PDISO8\n\t000d  PCI-PDISO16\n\t000f  PCI-DAS1200\n\t0010  PCI-DAS1602/12\n\t0014  PCI-DIO24H\n\t0015  PCI-DIO24H/CTR3\n\t0016  PCI-DIO48H/CTR15\n\t0017  PCI-DIO96H\n\t0018  PCI-CTR05\n\t0019  PCI-DAS1200/JR\n\t001a  PCI-DAS1001\n\t001b  PCI-DAS1002\n\t001c  PCI-DAS1602JR/16\n\t001d  PCI-DAS6402/16\n\t001e  PCI-DAS6402/12\n\t001f  PCI-DAS16/M1\n\t0020  PCI-DDA02/12\n\t0021  PCI-DDA04/12\n\t0022  PCI-DDA08/12\n\t0023  PCI-DDA02/16\n\t0024  PCI-DDA04/16\n\t0025  PCI-DDA08/16\n\t0026  PCI-DAC04/12-HS\n\t0027  PCI-DAC04/16-HS\n\t0028  PCI-DIO24\n\t0029  PCI-DAS08\n\t002c  PCI-INT32\n\t0033  PCI-DUAL-AC5\n\t0034  PCI-DAS-TC\n\t0035  PCI-DAS64/M1/16\n\t0036  PCI-DAS64/M2/16\n\t0037  PCI-DAS64/M3/16\n\t004c  PCI-DAS1000\n\t004d  PCI-QUAD04\n\t0052  PCI-DAS4020/12\n\t0053  PCIM-DDA06/16\n\t0054  PCI-DIO96\n\t005d  PCI-DAS6023\n\t005e  PCI-DAS6025\n\t005f  PCI-DAS6030\n\t0060  PCI-DAS6031\n\t0061  PCI-DAS6032\n\t0062  PCI-DAS6033\n\t0063  PCI-DAS6034\n\t0064  PCI-DAS6035\n\t0065  PCI-DAS6040\n\t0066  PCI-DAS6052\n\t0067  PCI-DAS6070\n\t0068  PCI-DAS6071\n\t006f  PCI-DAS6036\n\t0070  PCI-DAC6702\n\t0078  PCI-DAS6013\n\t0079  PCI-DAS6014\n\t0115  PCIe-DAS1602/16\n1308  Jato Technologies Inc.\n\t0001  NetCelerator Adapter\n\t\t1308 0001  NetCelerator Adapter\n1309  AB Semiconductor Ltd\n130a  Mitsubishi Electric Microcomputer\n130b  Colorgraphic Communications Corp\n130c  Ambex Technologies, Inc\n130d  Accelerix Inc\n130e  Yamatake-Honeywell Co. Ltd\n130f  Advanet Inc\n1310  Gespac\n1311  Videoserver, Inc\n1312  Acuity Imaging, Inc\n1313  Yaskawa Electric Co.\n1315  Wavesat\n1316  Teradyne Inc\n1317  ADMtek\n\t0981  21x4x DEC-Tulip compatible 10/100 Ethernet\n\t0985  NC100 Network Everywhere Fast Ethernet 10/100\n\t\t1734 100c  Scenic N300 ADMtek AN983 10/100 Mbps PCI Adapter\n\t1985  21x4x DEC-Tulip compatible 10/100 Ethernet\n\t\t1385 511a  FA511\n\t\t1395 2103  CB100-EZ (4-LED version)\n\t2850  HSP MicroModem 56\n\t5120  ADM5120 OpenGate System-on-Chip\n\t8201  ADM8211 802.11b Wireless Interface\n\t\t10b8 2635  SMC2635W v1 802.11b Wireless Cardbus Adapter\n\t\t1317 8201  SMC2635W v2 802.11b Wireless Cardbus Adapter\n\t8211  ADM8211 802.11b Wireless Interface\n\t9511  21x4x DEC-Tulip compatible 10/100 Ethernet\n1318  Packet Engines Inc.\n\t0911  GNIC-II PCI Gigabit Ethernet [Hamachi]\n1319  Fortemedia, Inc\n\t0801  Xwave QS3000A [FM801]\n\t\t1319 1319  FM801 PCI Audio\n\t0802  Xwave QS3000A [FM801 game port]\n\t\t1319 1319  FM801 PCI Joystick\n\t1000  FM801 PCI Audio\n\t1001  FM801 PCI Joystick\n131a  Finisar Corp.\n131c  Nippon Electro-Sensory Devices Corp\n131d  Sysmic, Inc.\n131e  Xinex Networks Inc\n131f  Siig Inc\n\t1000  CyberSerial (1-port) 16550\n\t1001  CyberSerial (1-port) 16650\n\t1002  CyberSerial (1-port) 16850\n\t1010  Duet 1S(16550)+1P\n\t1011  Duet 1S(16650)+1P\n\t1012  Duet 1S(16850)+1P\n\t1020  CyberParallel (1-port)\n\t1021  CyberParallel (2-port)\n\t1030  CyberSerial (2-port) 16550\n\t1031  CyberSerial (2-port) 16650\n\t1032  CyberSerial (2-port) 16850\n\t1034  Trio 2S(16550)+1P\n\t1035  Trio 2S(16650)+1P\n\t1036  Trio 2S(16850)+1P\n\t1050  CyberSerial (4-port) 16550\n\t1051  CyberSerial (4-port) 16650\n\t1052  CyberSerial (4-port) 16850\n\t2000  CyberSerial (1-port) 16550\n\t2001  CyberSerial (1-port) 16650\n\t2002  CyberSerial (1-port) 16850\n\t2010  Duet 1S(16550)+1P\n\t2011  Duet 1S(16650)+1P\n\t2012  Duet 1S(16850)+1P\n\t2020  CyberParallel (1-port)\n\t2021  CyberParallel (2-port)\n\t2030  CyberSerial (2-port) 16550\n\t\t131f 2030  PCI Serial Card\n\t2031  CyberSerial (2-port) 16650\n\t2032  CyberSerial (2-port) 16850\n\t2040  Trio 1S(16550)+2P\n\t2041  Trio 1S(16650)+2P\n\t2042  Trio 1S(16850)+2P\n\t2050  CyberSerial (4-port) 16550\n\t2051  CyberSerial (4-port) 16650\n\t2052  CyberSerial (4-port) 16850\n\t2060  Trio 2S(16550)+1P\n\t2061  Trio 2S(16650)+1P\n\t2062  Trio 2S(16850)+1P\n\t2081  CyberSerial (8-port) ST16654\n1320  Crypto AG\n1321  Arcobel Graphics BV\n1322  MTT Co., Ltd\n1323  Dome Inc\n1324  Sphere Communications\n1325  Salix Technologies, Inc\n1326  Seachange international\n1327  Voss scientific\n1328  quadrant international\n1329  Productivity Enhancement\n132a  Microcom Inc.\n132b  Broadband Technologies\n132c  Micrel Inc\n132d  Integrated Silicon Solution, Inc.\n1330  MMC Networks\n1331  RadiSys Corporation\n\t0030  ENP-2611\n\t8200  82600 Host Bridge\n\t8201  82600 IDE\n\t8202  82600 USB\n\t8210  82600 PCI Bridge\n1332  Micro Memory\n\t5415  MM-5415CN PCI Memory Module with Battery Backup\n\t5425  MM-5425CN PCI 64/66 Memory Module with Battery Backup\n\t6140  MM-6140D\n1334  Redcreek Communications, Inc\n1335  Videomail, Inc\n1337  Third Planet Publishing\n1338  BT Electronics\n133a  Vtel Corp\n133b  Softcom Microsystems\n133c  Holontech Corp\n133d  SS Technologies\n133e  Virtual Computer Corp\n133f  SCM Microsystems\n1340  Atalla Corp\n1341  Kyoto Microcomputer Co\n1342  Promax Systems Inc\n1343  Phylon Communications Inc\n# nee Crucial Technology\n1344  Micron Technology Inc\n\t5150  RealSSD P320h\n\t5151  RealSSD P320m\n\t5152  RealSSD P320s\n\t5153  RealSSD P325m\n\t5160  RealSSD P420h\n\t5161  RealSSD P420m\n\t5163  RealSSD P425m\n\t5180  9100 PRO NVMe SSD\n\t5181  9100 MAX NVMe SSD\n\t5190  9200 ECO NVMe SSD\n\t5191  9200 PRO NVMe SSD\n\t5192  9200 MAX NVMe SSD\n1345  Arescom Inc\n1347  Odetics\n1349  Sumitomo Electric Industries, Ltd.\n134a  DTC Technology Corp.\n\t0001  Domex 536\n\t0002  Domex DMX3194UP SCSI Adapter\n134b  ARK Research Corp.\n134c  Chori Joho System Co. Ltd\n134d  PCTel Inc\n\t2189  HSP56 MicroModem\n\t2486  2304WT V.92 MDC Modem\n\t7890  HSP MicroModem 56\n\t\t134d 0001  PCT789 adapter\n\t7891  HSP MicroModem 56\n\t\t134d 0001  HSP MicroModem 56\n\t7892  HSP MicroModem 56\n\t7893  HSP MicroModem 56\n\t7894  HSP MicroModem 56\n\t7895  HSP MicroModem 56\n\t7896  HSP MicroModem 56\n\t7897  HSP MicroModem 56\n134e  CSTI\n134f  Algo System Co Ltd\n1350  Systec Co. Ltd\n1351  Sonix Inc\n# nee Thales Idatys\n1353  Vierling Communication SAS\n\t0002  Proserver\n\t0003  PCI-FUT\n\t0004  PCI-S0\n\t0005  PCI-FUT-S0\n1354  Dwave System Inc\n1355  Kratos Analytical Ltd\n1356  The Logical Co\n1359  Prisa Networks\n135a  Brain Boxes\n\t0a61  UC-324 [VELOCITY RS422/485]\n135b  Giganet Inc\n135c  Quatech Inc\n\t0010  QSC-100\n\t0020  DSC-100\n\t0030  DSC-200/300\n\t0040  QSC-200/300\n\t0050  ESC-100D\n\t0060  ESC-100M\n\t00f0  MPAC-100 Synchronous Serial Card (Zilog 85230)\n\t0170  QSCLP-100\n\t0180  DSCLP-100\n\t0190  SSCLP-100\n\t01a0  QSCLP-200/300\n\t01b0  DSCLP-200/300\n\t01c0  SSCLP-200/300\n\t0258  DSPSX-200/300\n135d  ABB Network Partner AB\n135e  Sealevel Systems Inc\n\t5101  Route 56.PCI - Multi-Protocol Serial Interface (Zilog Z16C32)\n\t7101  Single Port RS-232/422/485/530\n\t7201  Dual Port RS-232/422/485 Interface\n\t7202  Dual Port RS-232 Interface\n\t7401  Four Port RS-232 Interface\n\t7402  Four Port RS-422/485 Interface\n\t7801  Eight Port RS-232 Interface\n\t7804  Eight Port RS-232/422/485 Interface\n\t8001  8001 Digital I/O Adapter\n135f  I-Data International A-S\n1360  Meinberg Funkuhren\n\t0101  PCI32 DCF77 Radio Clock\n\t0102  PCI509 DCF77 Radio Clock\n\t0103  PCI510 DCF77 Radio Clock\n\t0104  PCI511 DCF77 Radio Clock\n\t0105  PEX511 DCF77 Radio Clock (PCI Express)\n\t0106  PZF180PEX High Precision DCF77 Radio Clock (PCI Express)\n\t0201  GPS167PCI GPS Receiver\n\t0202  GPS168PCI GPS Receiver\n\t0203  GPS169PCI GPS Receiver\n\t0204  GPS170PCI GPS Receiver\n\t0205  GPS170PEX GPS Receiver (PCI Express)\n\t0206  GPS180PEX GPS Receiver (PCI Express)\n\t0207  GLN180PEX GPS/GLONASS receiver (PCI Express)\n\t0208  GPS180AMC GPS Receiver (PCI Express / MicroTCA / AdvancedMC)\n\t0209  GNS181PEX GPS/Galileo/GLONASS/BEIDOU receiver (PCI Express)\n\t0301  TCR510PCI IRIG Timecode Reader\n\t0302  TCR167PCI IRIG Timecode Reader\n\t0303  TCR511PCI IRIG Timecode Reader\n\t0304  TCR511PEX IRIG Timecode Reader (PCI Express)\n\t0305  TCR170PEX IRIG Timecode Reader (PCI Express)\n\t0306  TCR180PEX IRIG Timecode Reader (PCI Express)\n\t0501  PTP270PEX PTP/IEEE1588 slave card (PCI Express)\n\t0601  FRC511PEX Free Running Clock (PCI Express)\n1361  Soliton Systems K.K.\n1362  Fujifacom Corporation\n1363  Phoenix Technology Ltd\n1364  ATM Communications Inc\n1365  Hypercope GmbH\n1366  Teijin Seiki Co. Ltd\n1367  Hitachi Zosen Corporation\n1368  Skyware Corporation\n1369  Digigram\n136a  High Soft Tech\n\t0004  HST Saphir VII mini PCI\n\t0007  HST Saphir III E MultiLink 4\n\t0008  HST Saphir III E MultiLink 8\n\t000a  HST Saphir III E MultiLink 2\n136b  Kawasaki Steel Corporation\n\tff01  KL5A72002 Motion JPEG\n136c  Adtek System Science Co Ltd\n136d  Gigalabs Inc\n136f  Applied Magic Inc\n1370  ATL Products\n1371  CNet Technology Inc\n\t434e  GigaCard Network Adapter\n\t\t1371 434e  N-Way PCI-Bus Giga-Card 1000/100/10Mbps(L)\n1373  Silicon Vision Inc\n1374  Silicom Ltd.\n\t0024  Silicom Dual port Giga Ethernet BGE Bypass Server Adapter\n\t0025  Silicom Quad port Giga Ethernet BGE Bypass Server Adapter\n\t0026  Silicom Dual port Fiber Giga Ethernet 546 Bypass Server Adapter\n\t0027  Silicom Dual port Fiber LX Giga Ethernet 546 Bypass Server Adapter\n\t0029  Silicom Dual port Copper Giga Ethernet 546GB Bypass Server Adapter\n\t002a  Silicom Dual port Fiber Giga Ethernet 546 TAP/Bypass Server Adapter\n\t002b  Silicom Dual port Copper Fast Ethernet 546 TAP/Bypass Server Adapter (PXE2TBI)\n\t002c  Silicom Quad port Copper Giga Ethernet 546GB Bypass Server Adapter (PXG4BPI)\n\t002d  Silicom Quad port Fiber-SX Giga Ethernet 546GB Bypass Server Adapter (PXG4BPFI)\n\t002e  Silicom Quad port Fiber-LX Giga Ethernet 546GB Bypass Server Adapter (PXG4BPFI-LX)\n\t002f  Silicom Dual port Fiber-SX Giga Ethernet 546GB Low profile Bypass Server Adapter (PXG2BPFIL)\n\t0030  Silicom Dual port Fiber-LX Giga Ethernet 546GB Low profile Bypass Server Adapter\n\t0031  Silicom Quad port Copper Giga Ethernet PCI-E Bypass Server Adapter\n\t0032  Silicom Dual port Copper Fast Ethernet 546 TAP/Bypass Server Adapter\n\t0034  Silicom Dual port Copper Giga Ethernet PCI-E BGE Bypass Server Adapter\n\t0035  Silicom Quad port Copper Giga Ethernet PCI-E BGE Bypass Server Adapter\n\t0036  Silicom Dual port Fiber Giga Ethernet PCI-E BGE Bypass Server Adapter\n\t0037  Silicom Dual port Copper Ethernet PCI-E Intel based Bypass Server Adapter\n\t0038  Silicom Quad port Copper Ethernet PCI-E Intel based Bypass Server Adapter\n\t0039  Silicom Dual port Fiber-SX Ethernet PCI-E Intel based Bypass Server Adapter\n\t003a  Silicom Dual port Fiber-LX Ethernet PCI-E Intel based Bypass Server Adapter\n\t003b  Silicom Dual port Fiber Ethernet PMC Intel based Bypass Server Adapter (PMCX2BPFI)\n\t003c  Silicom Dual port Copper Ethernet PCI-X BGE based Bypass Server Adapter (PXG2BPRB)\n\t003d  2-port Copper GBE Bypass with Caviume 1010 PCI-X\n\t003e  Silicom Dual port Fiber Giga Ethernet PCI-E 571 TAP/Bypass Server Adapter (PEG2TBFI)\n\t003f  Silicom Dual port Copper Giga Ethernet PCI-X 546 TAP/Bypass Server Adapter (PXG2TBI)\n\t0040  Silicom Quad port Fiber-SX Giga Ethernet 571 Bypass Server Adapter (PEG4BPFI)\n\t0042  4-port Copper GBE PMC-X Bypass\n\t0043  Silicom Quad port Fiber-SX Giga Ethernet 546 Bypass Server Adapter (PXG4BPFID)\n\t0045  Silicom 6 port Copper Giga Ethernet 546 Bypass Server Adapter (PXG6BPI)\n\t0046  4-port bypass PCI-E w disconnect low profile\n\t0047  Silicom Dual port Fiber-SX Giga Ethernet 571 Bypass Disconnect Server Adapter (PEG2BPFID)\n\t004a  Silicom Quad port Fiber-LX Giga Ethernet 571 Bypass Server Adapter (PEG4BPFI-LX)\n\t004d  Dual port Copper Giga Ethernet PCI-E Bypass Server Adapter\n\t0401  Gigabit Ethernet ExpressModule Bypass Server Adapter\n\t0420  Gigabit Ethernet ExpressModule Bypass Server Adapter\n\t0460  Gigabit Ethernet Express Module Bypass Server Adapter\n\t0461  Gigabit Ethernet ExpressModule Bypass Server Adapter\n\t0462  Gigabit Ethernet ExpressModule Bypass Server Adapter\n\t0470  Octal-port Copper Gigabit Ethernet Express Module Bypass Server Adapter\n\t0482  Dual-port Fiber (SR) 10 Gigabit Ethernet ExpressModule Bypass Server Adapter\n\t0483  Dual-port Fiber (LR) 10 Gigabit Ethernet ExpressModule Bypass Server Adapter\n1375  Argosystems Inc\n1376  LMC\n1377  Electronic Equipment Production & Distribution GmbH\n1378  Telemann Co. Ltd\n1379  Asahi Kasei Microsystems Co Ltd\n137a  Mark of the Unicorn Inc\n\t0001  PCI-324 Audiowire Interface\n137b  PPT Vision\n137c  Iwatsu Electric Co Ltd\n137d  Dynachip Corporation\n137e  Patriot Scientific Corporation\n137f  Japan Satellite Systems Inc\n1380  Sanritz Automation Co Ltd\n1381  Brains Co. Ltd\n1382  Marian - Electronic & Software\n\t0001  ARC88 audio recording card\n\t2008  Prodif 96 Pro sound system\n\t2048  Prodif Plus sound system\n\t2088  Marc 8 Midi sound system\n\t20c8  Marc A sound system\n\t4008  Marc 2 sound system\n\t4010  Marc 2 Pro sound system\n\t4048  Marc 4 MIDI sound system\n\t4088  Marc 4 Digi sound system\n\t4248  Marc X sound system\n\t4424  TRACE D4 Sound System\n1383  Controlnet Inc\n1384  Reality Simulation Systems Inc\n1385  Netgear\n\t006b  WA301 802.11b Wireless PCI Adapter\n\t4100  MA301 802.11b Wireless PCI Adapter\n\t4601  WAG511 802.11a/b/g Dual Band Wireless PC Card\n\t620a  GA620 Gigabit Ethernet\n\t630a  GA630 Gigabit Ethernet\n1386  Video Domain Technologies\n1387  Systran Corp\n1388  Hitachi Information Technology Co Ltd\n1389  Applicom International\n\t0001  PCI1500PFB [Intelligent fieldbus adaptor]\n138a  Fusion Micromedia Corp\n\t003d  VFS491 Validity Sensor\n138b  Tokimec Inc\n138c  Silicon Reality\n138d  Future Techno Designs pte Ltd\n138e  Basler GmbH\n138f  Patapsco Designs Inc\n1390  Concept Development Inc\n1391  Development Concepts Inc\n1392  Medialight Inc\n1393  Moxa Technologies Co Ltd\n\t0001  UC7000 Serial\n\t1020  CP-102 (2-port RS-232 PCI)\n\t1021  CP-102UL (2-port RS-232 Universal PCI)\n\t1022  CP-102U (2-port RS-232 Universal PCI)\n\t1023  CP-102UF\n\t1024  CP-102E (2-port RS-232 Smart PCI Express Serial Board)\n\t1025  CP-102EL (2-port RS-232 Smart PCI Express Serial Board)\n\t1040  Smartio C104H/PCI\n\t1041  CP104U (4-port RS-232 Universal PCI)\n\t1042  CP104JU (4-port RS-232 Universal PCI)\n\t1043  CP104EL (4-port RS-232 Smart PCI Express)\n\t1044  POS104UL (4-port RS-232 Universal PCI)\n\t1045  CP-104EL-A (4-port RS-232 PCI Express Serial Board)\n\t1080  CB108 (8-port RS-232 PC/104-plus Module)\n\t1140  CT-114 series\n\t1141  Industrio CP-114\n\t1142  CB114 (4-port RS-232/422/485 PC/104-plus Module)\n\t1143  CP-114UL (4-port RS-232/422/485 Smart Universal PCI Serial Board)\n\t1144  CP-114EL (4-port RS-232/422/485 Smart PCI Express Serial Board)\n\t1180  CP118U (8-port RS-232/422/485 Smart Universal PCI)\n\t1181  CP118EL (8-port RS-232/422/485 Smart PCI Express)\n\t1182  CP-118EL-A (8-port RS-232/422/485 PCI Express Serial Board)\n\t1320  CP132 (2-port RS-422/485 PCI)\n\t1321  CP132U (2-Port RS-422/485 Universal PCI)\n\t1322  CP-132EL (2-port RS-422/485 Smart PCI Express Serial Board)\n\t1340  CP134U (4-Port RS-422/485 Universal PCI)\n\t1341  CB134I (4-port RS-422/485 PC/104-plus Module)\n\t1380  CP138U (8-port RS-232/422/485 Smart Universal PCI)\n\t1680  Smartio C168H/PCI\n\t1681  CP-168U V2 Smart Serial Board (8-port RS-232)\n\t1682  CP-168EL (8-port RS-232 Smart PCI Express)\n\t1683  CP-168EL-A (8-port RS-232 PCI Express Serial Board)\n\t2040  Intellio CP-204J\n\t2180  Intellio C218 Turbo PCI\n\t3200  Intellio C320 Turbo PCI\n1394  Level One Communications\n\t0001  LXT1001 Gigabit Ethernet\n\t\t1186 4800  DGE-500SX\n\t\t1394 0001  NetCelerator Adapter\n1395  Ambicom Inc\n1396  Cipher Systems Inc\n1397  Cologne Chip Designs GmbH\n\t08b4  ISDN network Controller [HFC-4S]\n\t\t1397 08b4  HFC-4S [Cologne Chip HFC-4S Eval. Board]\n\t\t1397 b51a  HFC-4S [Allo.com BRI card]\n\t\t1397 b520  HFC-4S [IOB4ST]\n\t\t1397 b540  HFC-4S [Swyx SX2 QuadBri]\n\t\t1397 b550  HFC-4S [Junghanns.NET quadBRI]\n\t\t1397 b556  HFC-4S [Junghanns.NET duoBRI]\n\t\t1397 b559  HFC-4S [Junghanns.NET duoBRI miniPCI]\n\t\t1397 b560  HFC-4S [BeroNet BN4S0]\n\t\t1397 b566  HFC-4S [BeroNet BN2S0]\n\t\t1397 b567  HFC-4S [BeroNet BN1S0 miniPCI]\n\t\t1397 b568  HFC-4S [BeroNet BN4S0 miniPCI]\n\t\t1397 b569  HFC-4S [BeroNet BN2S0 miniPCI]\n\t\t1397 b620  HFC-4S\n\t\t1397 b752  HFC-4S [Junghanns.NET quadBRI PCIe]\n\t\t1397 b761  HFC-4S [BeroNet BN2S0 PCIe]\n\t\t1397 b762  HFC-4S [BeroNet BN4S0 PCIe]\n\t\t1397 e884  HFC-4S [OpenVox B200P]\n\t\t1397 e888  HFC-4S [OpenVox B200P / B400P]\n\t16b8  ISDN network Controller [HFC-8S]\n\t\t1397 16b8  HFC-8S [Cologne Chip HFC-8S Eval. Board]\n\t\t1397 b521  HFC-8S [IOB4ST Recording]\n\t\t1397 b522  HFC-8S [IOB8ST]\n\t\t1397 b552  HFC-8S [Junghanns.NET octoBRI]\n\t\t1397 b55b  HFC-8S [Junghanns.NET octoBRI]\n\t\t1397 b562  HFC-8S [BeroNet BN8S0]\n\t\t1397 b56b  HFC-8S [BeroNet BN8S0+]\n\t\t1397 b622  HFC-8S\n\t\t1397 e998  HFC-8S [OpenVox B800P]\n\t2bd0  ISDN network controller [HFC-PCI]\n\t\t0675 1704  ISDN Adapter (PCI Bus, D, C)\n\t\t0675 1708  ISDN Adapter (PCI Bus, D, C, ACPI)\n\t\t1397 2bd0  ISDN Board\n\t\te4bf 1000  CI1-1-Harp\n\t30b1  ISDN network Controller [HFC-E1]\n\t\t1397 30b1  HFC-E1 [Cologne Chip HFC-E1 Eval. Board]\n\t\t1397 b523  HFC-E1 [IOB1E1]\n\t\t1397 b543  HFC-E1 [Swyx SX2 SinglePRI V2]\n\t\t1397 b544  HFC-E1 [Swyx SX2 DualPRI V2]\n\t\t1397 b553  HFC-E1 [Junghanns.NET singleE1]\n\t\t1397 b554  HFC-E1 [Junghanns.NET doubleE1]\n\t\t1397 b555  HFC-E1 [Junghanns.NET doubleE1 2.0]\n\t\t1397 b55a  HFC-E1 [Junghanns.NET singleE1 miniPCI]\n\t\t1397 b563  HFC-E1 [beroNet BN1E1]\n\t\t1397 b564  HFC-E1 [beroNet BN2E1]\n\t\t1397 b565  HFC-E1 [beroNet BN2E1+]\n\t\t1397 b56a  HFC-E1 [beroNet BN1E1 miniPCI]\n\tb700  ISDN network controller PrimuX S0 [HFC-PCI]\n\tf001  GSM Network Controller [HFC-4GSM]\n1398  Clarion co. Ltd\n1399  Rios systems Co Ltd\n139a  Alacritech Inc\n\t0001  Quad Port 10/100 Server Accelerator\n\t0003  Single Port 10/100 Server Accelerator\n\t0005  Single Port Gigabit Server Accelerator\n139b  Mediasonic Multimedia Systems Ltd\n139c  Quantum 3d Inc\n139d  EPL limited\n139e  Media4\n139f  Aethra s.r.l.\n13a0  Crystal Group Inc\n13a1  Kawasaki Heavy Industries Ltd\n13a2  Ositech Communications Inc\n13a3  Hifn Inc.\n\t0005  7751 Security Processor\n\t0006  6500 Public Key Processor\n\t0007  7811 Security Processor\n\t0012  7951 Security Processor\n\t0014  78XX Security Processor\n\t0016  8065 Security Processor\n\t0017  8165 Security Processor\n\t0018  8154 Security Processor\n\t001d  7956 Security Processor\n\t001f  7855 Security Processor\n\t0020  7955 Security Processor\n\t0026  8155 Security Processor\n\t002e  9630 Compression Processor\n\t002f  9725 Compression and Security Processor\n\t\t13a3 1600  DR1600 Acceleration Card\n\t\t13a3 1605  DR1605 Acceleration Card\n\t\t13a3 1610  DR1610 Acceleration Card\n\t\t13a3 1615  DR1615 Acceleration Card\n\t\t13a3 1620  DR1620 Acceleration Card\n\t\t13a3 1625  DR1625 Acceleration Card\n\t0033  8201 Acceleration Processor\n\t\t13a3 0036  DX1710 Acceleration Card\n\t0034  8202 Acceleration Processor\n\t\t13a3 0036  DX1720 Acceleration Card\n\t0035  8203 Acceleration Processor\n\t\t13a3 0036  DX1730 Acceleration Card\n\t0037  8204 Acceleration Processor\n\t\t13a3 0036  DX1740 Acceleration Card\n13a4  Rascom Inc\n13a5  Audio Digital Imaging Inc\n13a6  Videonics Inc\n13a7  Teles AG\n13a8  Exar Corp.\n\t0152  XR17C/D152 Dual PCI UART\n\t0154  XR17C154 Quad UART\n\t0158  XR17C158 Octal UART\n\t0252  XR17V252 Dual UART PCI controller\n\t0254  XR17V254 Quad UART PCI controller\n\t0258  XR17V258 Octal UART PCI controller\n\t0352  XR17V3521 Dual PCIe UART\n13a9  Siemens Medical Systems, Ultrasound Group\n13aa  Broadband Networks Inc\n13ab  Arcom Control Systems Ltd\n13ac  Motion Media Technology Ltd\n13ad  Nexus Inc\n13ae  ALD Technology Ltd\n13af  T.Sqware\n13b0  Maxspeed Corp\n13b1  Tamura corporation\n13b2  Techno Chips Co. Ltd\n13b3  Lanart Corporation\n13b4  Wellbean Co Inc\n13b5  ARM\n13b6  Dlog GmbH\n13b7  Logic Devices Inc\n13b8  Nokia Telecommunications oy\n13b9  Elecom Co Ltd\n13ba  Oxford Instruments\n13bb  Sanyo Technosound Co Ltd\n13bc  Bitran Corporation\n13bd  Sharp corporation\n13be  Miroku Jyoho Service Co. Ltd\n13bf  Sharewave Inc\n13c0  Microgate Corporation\n\t0010  SyncLink Adapter v1\n\t0020  SyncLink SCC Adapter\n\t0030  SyncLink Multiport Adapter\n\t0070  SyncLink GT Adapter\n\t0080  SyncLink GT4 Adapter\n\t00a0  SyncLink GT2 Adapter\n\t0210  SyncLink Adapter v2\n13c1  3ware Inc\n\t1000  5xxx/6xxx-series PATA-RAID\n\t1001  7xxx/8xxx-series PATA/SATA-RAID\n\t\t13c1 1001  7xxx/8xxx-series PATA/SATA-RAID\n\t1002  9xxx-series SATA-RAID\n\t1003  9550SX SATA-II RAID PCI-X\n\t1004  9650SE SATA-II RAID PCIe\n\t1005  9690SA SAS/SATA-II RAID PCIe\n\t1010  9750 SAS2/SATA-II RAID PCIe\n13c2  Technotrend Systemtechnik GmbH\n\t000e  Technotrend/Hauppauge DVB card rev2.3\n\t1019  TTechnoTrend-budget DVB S2-3200\n13c3  Janz Computer AG\n13c4  Phase Metrics\n13c5  Alphi Technology Corp\n13c6  Condor Engineering Inc\n\t0520  CEI-520 A429 Card\n\t0620  CEI-620 A429 Card\n\t0820  CEI-820 A429 Card\n\t0830  CEI-830 A429 Card\n\t1004  P-SER Multi-channel PMC to RS-485/422/232 adapter\n13c7  Blue Chip Technology Ltd\n\t0adc  PCI-ADC\n\t0b10  PCI-PIO\n\t0d10  PCI-DIO\n\t524c  PCI-RLY\n\t5744  PCI-WDT\n13c8  Apptech Inc\n13c9  Eaton Corporation\n13ca  Iomega Corporation\n13cb  Yano Electric Co Ltd\n13cc  Metheus Corporation\n13cd  Compatible Systems Corporation\n13ce  Cocom A/S\n13cf  Studio Audio & Video Ltd\n13d0  Techsan Electronics Co Ltd\n\t2103  B2C2 FlexCopII DVB chip / Technisat SkyStar2 DVB card\n\t2104  B2C2 FlexCopIII DVB chip / Technisat SkyStar2 DVB card (rev 01)\n\t2200  B2C2 FlexCopIII DVB chip / Technisat SkyStar2 DVB card\n13d1  Abocom Systems Inc\n\tab02  ADMtek Centaur-C rev 17 [D-Link DFE-680TX] CardBus Fast Ethernet Adapter\n\tab03  21x4x DEC-Tulip compatible 10/100 Ethernet\n\tab06  RTL8139 [FE2000VX] CardBus Fast Ethernet Attached Port Adapter\n\tab08  21x4x DEC-Tulip compatible 10/100 Ethernet\n13d2  Shark Multimedia Inc\n13d4  Graphics Microsystems Inc\n13d5  Media 100 Inc\n13d6  K.I. Technology Co Ltd\n13d7  Toshiba Engineering Corporation\n13d8  Phobos corporation\n13d9  Apex PC Solutions Inc\n13da  Intresource Systems pte Ltd\n13db  Janich & Klass Computertechnik GmbH\n13dc  Netboost Corporation\n13dd  Multimedia Bundle Inc\n13de  ABB Robotics Products AB\n13df  E-Tech Inc\n\t0001  PCI56RVP Modem\n\t\t13df 0001  PCI56RVP Modem\n13e0  GVC Corporation\n13e1  Silicom Multimedia Systems Inc\n13e2  Dynamics Research Corporation\n13e3  Nest Inc\n13e4  Calculex Inc\n13e5  Telesoft Design Ltd\n13e6  Argosy research Inc\n13e7  NAC Incorporated\n13e8  Chip Express Corporation\n13e9  Intraserver Technology Inc\n13ea  Dallas Semiconductor\n13eb  Hauppauge Computer Works Inc\n13ec  Zydacron Inc\n\t000a  NPC-RC01 Remote control receiver\n13ed  Raytheion E-Systems\n13ee  Hayes Microcomputer Products Inc\n13ef  Coppercom Inc\n13f0  Sundance Technology Inc / IC Plus Corp\n\t0200  IC Plus IP100A Integrated 10/100 Ethernet MAC + PHY\n\t\t1043 8213  NX1001\n\t0201  ST201 Sundance Ethernet\n\t1021  TC902x Gigabit Ethernet\n\t1023  IP1000 Family Gigabit Ethernet\n\t\t1043 8180  NX1101\n13f1  Oce' - Technologies B.V.\n13f2  Ford Microelectronics Inc\n13f3  Mcdata Corporation\n13f4  Troika Networks, Inc.\n\t1401  Zentai Fibre Channel Adapter\n13f5  Kansai Electric Co. Ltd\n13f6  C-Media Electronics Inc\n\t0011  CMI8738\n\t0100  CM8338A\n\t\t13f6 ffff  CMI8338/C3DX PCI Audio Device\n\t0101  CM8338B\n\t\t13f6 0101  CMI8338-031 PCI Audio Device\n\t0111  CMI8738/CMI8768 PCI Audio\n\t\t1019 0970  P6STP-FL motherboard\n\t\t1043 8035  CUSI-FX motherboard\n\t\t1043 8077  CMI8738 6-channel audio controller\n\t\t1043 80e2  CMI8738 6ch-MX\n\t\t13f6 0111  CMI8738/C3DX PCI Audio Device\n\t\t13f6 9761  Theatron Agrippa\n\t\t153b 1144  Aureon 5.1\n\t\t153b 1170  Aureon 7.1\n\t\t1681 a000  Gamesurround MUSE XL\n\t\t17ab 0604  PSC604 Dynamic Edge\n\t\t17ab 0605  PSC605 Sonic Edge\n\t\t17ab 7777  PSC605 Sonic Edge\n\t\t270f 1103  CT-7NJS Ultra motherboard\n\t\t270f f462  7NJL1 motherboard\n\t\t584d 3731  Digital X-Mystique\n\t\t584d 3741  X-Plosion 7.1\n\t\t584d 3751  X-Raider 7.1\n\t\t584d 3761  X-Mystique 7.1 LP\n\t\t584d 3771  X-Mystique 7.1 LP Value\n\t\t7284 8384  Striker 7.1\n\t0211  CM8738\n\t5011  CM8888 [Oxygen Express]\n\t\t13f6 5011  HDA Controller\n\t8788  CMI8788 [Oxygen HD Audio]\n\t\t1043 8269  Virtuoso 200 (Xonar D2)\n\t\t1043 8275  Virtuoso 100 (Xonar DX)\n\t\t1043 82b7  Virtuoso 200 (Xonar D2X)\n\t\t1043 8314  Virtuoso 200 (Xonar HDAV1.3)\n\t\t1043 8327  Virtuoso 100 (Xonar DX)\n\t\t1043 834f  Virtuoso 100 (Xonar D1)\n\t\t1043 835c  Virtuoso 100 (Xonar Essence STX)\n\t\t1043 835d  Virtuoso 100 (Xonar ST)\n\t\t1043 835e  Virtuoso 200 (Xonar HDAV1.3 Slim)\n\t\t1043 838e  Virtuoso 66 (Xonar DS)\n\t\t1043 8428  Virtuoso 100 (Xonar Xense)\n\t\t1043 8467  CMI8786 (Xonar DG)\n\t\t1043 8521  CMI8786 (Xonar DGX)\n\t\t1043 8522  Xonar DSX\n\t\t1043 85f4  Virtuoso 100 (Xonar Essence STX II)\n\t\t13f6 8782  PCI 2.0 HD Audio\n\t\t13f6 ffff  CMI8787-HG2PCI\n\t\t14c3 1710  HiFier Fantasia\n\t\t14c3 1711  HiFier Serenade\n\t\t14c3 1713  HiFier Serenade III\n\t\t1a58 0910  Barracuda AC-1\n\t\t415a 5431  X-Meridian 7.1\n\t\t5431 017a  X-Meridian 7.1 2G\n\t\t584d 3781  HDA X-Purity 7.1 Platinum\n\t\t7284 9761  CLARO\n\t\t7284 9781  CLARO halo\n\t\t7284 9783  eCLARO\n\t\t7284 9787  CLARO II\n13f7  Wildfire Communications\n13f8  Ad Lib Multimedia Inc\n13f9  NTT Advanced Technology Corp.\n13fa  Pentland Systems Ltd\n13fb  Aydin Corp\n13fc  Computer Peripherals International\n13fd  Micro Science Inc\n13fe  Advantech Co. Ltd\n\t1240  PCI-1240 4-channel stepper motor controller card\n\t1600  PCI-16xx series PCI multiport serial board (function 0)\n# This board has two PCI functions, appears as two PCI devices\n\t\t1601 0002  PCI-1601 2-port unisolated RS-422/485\n# This board has two PCI functions, appears as two PCI devices\n\t\t1602 0002  PCI-1602 2-port isolated RS-422/485\n\t\t1612 0004  PCI-1612 4-port RS-232/422/485\n\t1603  PCI-1603 2-port isolated RS-232/current loop\n\t1604  PCI-1604 2-port RS-232\n\t1680  PCI-1680 Rev.A1 2-port CAN-bus with isolation protection\n\t16ff  PCI-16xx series PCI multiport serial board (function 1: RX/TX steering CPLD)\n\t\t1601 0000  PCI-1601 2-port unisolated RS-422/485 PCI communications card\n\t\t1602 0000  PCI-1602 2-port isolated RS-422/485\n\t\t1612 0000  PCI-1612 4-port RS-232/422/485\n\t1711  PCI-1711 16-channel data acquisition card 12-bit, 100kS/s\n\t1713  PCI-1713 32-channel isolated analog input card\n\t1733  PCI-1733 32-channel isolated digital input card\n\t1734  PCI-1734 32-channel isolated digital output card\n\t1752  PCI-1752 64-channel Isolated Digital Output Card\n\t1754  PCI-1754 64-channel Isolated Digital Input Card\n\t1756  PCI-1756 64-ch Isolated Digital I/O PCI Card\n\ta004  PCI-1612 4-port RS-232/422/485\n# FPGA bridge to two SJA1000\n\tc302  MIOe-3680 2-Port CAN-Bus MIOe Module with Isolation Protection\n13ff  Silicon Spice Inc\n1400  Artx Inc\n\t1401  9432 TX\n1401  CR-Systems A/S\n1402  Meilhaus Electronic GmbH\n\t0630  ME-630\n\t0940  ME-94\n\t0950  ME-95\n\t0960  ME-96\n\t1000  ME-1000\n\t100a  ME-1000\n\t100b  ME-1000\n\t1400  ME-1400\n\t140a  ME-1400A\n\t140b  ME-1400B\n\t140c  ME-1400C\n\t140d  ME-1400D\n\t140e  ME-1400E\n\t14ea  ME-1400EA\n\t14eb  ME-1400EB\n\t1604  ME-1600/4U\n\t1608  ME-1600/8U\n\t160c  ME-1600/12U\n\t160f  ME-1600/16U\n\t168f  ME-1600/16U8I\n\t4610  ME-4610\n\t4650  ME-4650\n\t4660  ME-4660\n\t4661  ME-4660I\n\t4662  ME-4660\n\t4663  ME-4660I\n\t4670  ME-4670\n\t4671  ME-4670I\n\t4672  ME-4670S\n\t4673  ME-4670IS\n\t4680  ME-4680\n\t4681  ME-4680I\n\t4682  ME-4680S\n\t4683  ME-4680IS\n\t6004  ME-6000/4\n\t6008  ME-6000/8\n\t600f  ME-6000/16\n\t6014  ME-6000I/4\n\t6018  ME-6000I/8\n\t601f  ME-6000I/16\n\t6034  ME-6000ISLE/4\n\t6038  ME-6000ISLE/8\n\t603f  ME-6000ISLE/16\n\t6044  ME-6000/4/DIO\n\t6048  ME-6000/8/DIO\n\t604f  ME-6000/16/DIO\n\t6054  ME-6000I/4/DIO\n\t6058  ME-6000I/8/DIO\n\t605f  ME-6000I/16/DIO\n\t6074  ME-6000ISLE/4/DIO\n\t6078  ME-6000ISLE/8/DIO\n\t607f  ME-6000ISLE/16/DIO\n\t6104  ME-6100/4\n\t6108  ME-6100/8\n\t610f  ME-6100/16\n\t6114  ME-6100I/4\n\t6118  ME-6100I/8\n\t611f  ME-6100I/16\n\t6134  ME-6100ISLE/4\n\t6138  ME-6100ISLE/8\n\t613f  ME-6100ISLE/16\n\t6144  ME-6100/4/DIO\n\t6148  ME-6100/8/DIO\n\t614f  ME-6100/16/DIO\n\t6154  ME-6100I/4/DIO\n\t6158  ME-6100I/8/DIO\n\t615f  ME-6100I/16/DIO\n\t6174  ME-6100ISLE/4/DIO\n\t6178  ME-6100ISLE/8/DIO\n\t617f  ME-6100ISLE/16/DIO\n\t6259  ME-6200I/9/DIO\n\t6359  ME-6300I/9/DIO\n\t810a  ME-8100A\n\t810b  ME-8100B\n\t820a  ME-8200A\n\t820b  ME-8200B\n1403  Ascor Inc\n1404  Fundamental Software Inc\n1405  Excalibur Systems Inc\n1406  Oce' Printing Systems GmbH\n1407  Lava Computer mfg Inc\n\t0100  Lava Dual Serial\n\t0101  Lava Quatro A\n\t0102  Lava Quatro B\n\t0110  Lava DSerial-PCI Port A\n\t0111  Lava DSerial-PCI Port B\n\t0120  Quattro-PCI A\n\t0121  Quattro-PCI B\n\t0180  Lava Octo A\n\t0181  Lava Octo B\n\t0200  Lava Port Plus\n\t0201  Lava Quad A\n\t0202  Lava Quad B\n\t0220  Lava Quattro PCI Ports A/B\n\t0221  Lava Quattro PCI Ports C/D\n\t0400  Lava 8255-PIO-PCI\n\t0500  Lava Single Serial\n\t0520  Lava RS422-SS-PCI\n\t0600  Lava Port 650\n\t8000  Lava Parallel\n\t8001  Dual parallel port controller A\n\t8002  Lava Dual Parallel port A\n\t8003  Lava Dual Parallel port B\n\t8800  BOCA Research IOPPAR\n1408  Aloka Co. Ltd\n1409  Timedia Technology Co Ltd\n\t7168  PCI2S550 (Dual 16550 UART)\n\t\t1409 0002  SER4036A3V (2x RS232 port)\n\t\t1409 4027  SER4027A (1x RS232 port)\n\t\t1409 4037  SER4037A(L) [SUNIX SUN1889] (2x RS232 port)\n# Single DC-37 connector\n\t\t1409 4056  SER4056A (4x RS232)\n\t\t1409 5027  SER4027D\n\t\t1409 5037  SER4037D (2x RS232 port)\n# Single DC-62 connector\n\t\t1409 5066  SER4066R (8x RS232)\n# 4x 8p8c connectors\n\t\t1409 6056  SER4056D (4x RS232 port)\n\t7268  SUN1888 (Dual IEEE1284 parallel port)\n\t\t1409 0103  PAR4008A\n\t\t1409 0104  PAR4018A\n140a  DSP Research Inc\n# Formerly RAMiX, GE Fanuc, GE Intelligent Platforms\n140b  Abaco Systems, Inc.\n140c  Elmic Systems Inc\n140d  Matsushita Electric Works Ltd\n140e  Goepel Electronic GmbH\n140f  Salient Systems Corp\n1410  Midas lab Inc\n1411  Ikos Systems Inc\n# Nee IC Ensemble Inc.\n1412  VIA Technologies Inc.\n\t1712  ICE1712 [Envy24] PCI Multi-Channel I/O Controller\n\t\t1412 1712  Hoontech ST Audio DSP 24\n\t\t1412 d630  M-Audio Delta 1010\n\t\t1412 d631  M-Audio Delta DiO\n\t\t1412 d632  M-Audio Delta 66\n\t\t1412 d633  M-Audio Delta 44\n\t\t1412 d634  M-Audio Delta Audiophile 2496\n\t\t1412 d635  M-Audio Delta TDIF\n\t\t1412 d637  M-Audio Delta RBUS\n\t\t1412 d638  M-Audio Delta 410\n\t\t1412 d63b  M-Audio Delta 1010LT\n\t\t1412 d63c  Digigram VX442\n\t\t1416 1712  Hoontech ST Audio DSP 24 Media 7.1\n\t\t153b 1115  EWS88 MT\n\t\t153b 1125  EWS88 MT (Master)\n\t\t153b 112b  EWS88 D\n\t\t153b 112c  EWS88 D (Master)\n\t\t153b 1130  EWX 24/96\n\t\t153b 1138  DMX 6fire 24/96\n\t\t153b 1151  PHASE88\n\t\t16ce 1040  Edirol DA-2496\n\t1724  VT1720/24 [Envy24PT/HT] PCI Multi-Channel Audio Controller\n\t\t10b0 0200  Hollywood@Home 7.1\n\t\t1412 1724  Albatron PX865PE 7.1\n\t\t1412 3630  M-Audio Revolution 7.1\n\t\t1412 3631  M-Audio Revolution 5.1\n\t\t1412 3632  M-Audio Audiophile 192\n\t\t153b 1145  Aureon 7.1 Space\n\t\t153b 1147  Aureon 5.1 Sky\n\t\t153b 1150  PHASE 22\n\t\t153b 1153  Aureon 7.1 Universe\n\t\t17ab 1906  PSC 724 [Ultimate Edge]\n\t\t270f f641  ZNF3-150\n\t\t270f f645  ZNF3-250\n\t\t3130 4154  MAYA 44 MKII\n1413  Addonics\n1414  Microsoft Corporation\n\t0001  MN-120 (ADMtek Centaur-C based)\n\t0002  MN-130 (ADMtek Centaur-P based)\n\t5353  Hyper-V virtual VGA\n\t5801  XMA Decoder (Xenon)\n\t5802  SATA Controller - CdRom (Xenon)\n\t5803  SATA Controller - Disk (Xenon)\n\t5804  OHCI Controller 0 (Xenon)\n\t5805  EHCI Controller 0 (Xenon)\n\t5806  OHCI Controller 1 (Xenon)\n\t5807  EHCI Controller 1 (Xenon)\n\t580a  Fast Ethernet Adapter (Xenon)\n\t580b  Secure Flash Controller (Xenon)\n\t580d  System Management Controller (Xenon)\n\t5811  Xenos GPU (Xenon)\n1415  Oxford Semiconductor Ltd\n\t8401  OX9162 Mode 1 (8-bit bus)\n\t8403  OX9162 Mode 0 (parallel port)\n\t9500  OX16PCI954 (Quad 16950 UART) function 0 (Disabled)\n\t9501  OX16PCI954 (Quad 16950 UART) function 0 (Uart)\n\t\t12c4 0201  Titan/cPCI (2 port)\n\t\t12c4 0202  Titan/cPCI (4 port)\n\t\t12c4 0203  Titan/cPCI (8 port)\n\t\t12c4 0210  Titan/104-Plus (8 port, p1-4)\n\t\t131f 2050  CyberPro (4-port)\n# Model IO1085, Part No: JJ-P46012\n\t\t131f 2051  CyberSerial 4S Plus\n\t\t15ed 2000  MCCR Serial p0-3 of 8\n\t\t15ed 2001  MCCR Serial p0-3 of 16\n\t9505  OXuPCI952 (Dual 16C950 UART)\n\t950a  EXSYS EX-41092 Dual 16950 Serial adapter\n\t950b  OXCB950 Cardbus 16950 UART\n\t9510  OX16PCI954 (Quad 16950 UART) function 1 (Disabled)\n\t\t12c4 0200  Titan/cPCI (Unused)\n\t9511  OX16PCI954 (Quad 16950 UART) function 1 (8bit bus)\n\t\t12c4 0211  Titan/104-Plus (8 port, p5-8)\n\t\t15ed 2000  MCCR Serial p4-7 of 8\n\t\t15ed 2001  MCCR Serial p4-15 of 16\n\t9512  OX16PCI954 (Quad 16950 UART) function 1 (32bit bus)\n\t9513  OX16PCI954 (Quad 16950 UART) function 1 (parallel port)\n\t9521  OX16PCI952 (Dual 16950 UART)\n\t9523  OX16PCI952 Integrated Parallel Port\n\tc158  OXPCIe952 Dual 16C950 UART\n\t\te4bf c504  CP4-SCAT Wireless Technologies Carrier Board\n\t\te4bf d551  DU1-MUSTANG Dual-Port RS-485 Interface\n\tc308  EX-44016 16-port serial\n1416  Multiwave Innovation pte Ltd\n1417  Convergenet Technologies Inc\n1418  Kyushu electronics systems Inc\n1419  Excel Switching Corp\n141a  Apache Micro Peripherals Inc\n141b  Zoom Telephonics Inc\n141d  Digitan Systems Inc\n141e  Fanuc Ltd\n141f  Visiontech Ltd\n1420  Psion Dacom plc\n\t8002  Gold Card NetGlobal 56k+10/100Mb CardBus (Ethernet part)\n\t8003  Gold Card NetGlobal 56k+10/100Mb CardBus (Modem part)\n1421  Ads Technologies Inc\n1422  Ygrec Systems Co Ltd\n1423  Custom Technology Corp.\n1424  Videoserver Connections\n1425  Chelsio Communications Inc\n\t000b  T210 Protocol Engine\n\t000c  T204 Protocol Engine\n\t0022  10GbE Ethernet Adapter\n\t0030  T310 10GbE Single Port Adapter\n\t\t103c 705e  PCIe 10GBase-SR [AD386A]\n\t0031  T320 10GbE Dual Port Adapter\n\t0032  T302 1GbE Dual Port Adapter\n\t0033  T304 1GbE Quad Port Adapter\n\t0034  B320 10GbE Dual Port Adapter\n\t0035  S310-CR 10GbE Single Port Adapter\n\t0036  S320-LP-CR 10GbE Dual Port Adapter\n\t0037  N320-G2-CR 10GbE Dual Port Adapter\n\t4001  T420-CR Unified Wire Ethernet Controller\n\t4002  T422-CR Unified Wire Ethernet Controller\n\t4003  T440-CR Unified Wire Ethernet Controller\n\t4004  T420-BCH Unified Wire Ethernet Controller\n\t4005  T440-BCH Unified Wire Ethernet Controller\n\t4006  T440-CH Unified Wire Ethernet Controller\n\t4007  T420-SO Unified Wire Ethernet Controller\n\t4008  T420-CX Unified Wire Ethernet Controller\n\t4009  T420-BT Unified Wire Ethernet Controller\n\t400a  T404-BT Unified Wire Ethernet Controller\n\t400b  B420-SR Unified Wire Ethernet Controller\n\t400c  B404-BT Unified Wire Ethernet Controller\n\t400d  T480 Unified Wire Ethernet Controller\n\t400e  T440-LP-CR Unified Wire Ethernet Controller\n\t400f  T440 [Amsterdam] Unified Wire Ethernet Controller\n\t4080  T480-4080 T480 Unified Wire Ethernet Controller\n\t4081  T440F-4081 T440-FCoE Unified Wire Ethernet Controller\n\t4082  T420-4082  Unified Wire Ethernet Controller\n\t4083  T420X-4083 Unified Wire Ethernet Controller\n\t4084  T440-4084 Unified Wire Ethernet Controller\n\t4085  T420-4085 SFP+ Unified Wire Ethernet Controller\n\t4086  T440-4086 10Gbase-T Unified Wire Ethernet Controller\n\t4087  T440T-4087 Unified Wire Ethernet Controller\n\t4088  T440-4088 Unified Wire Ethernet Controller\n\t4401  T420-CR Unified Wire Ethernet Controller\n\t4402  T422-CR Unified Wire Ethernet Controller\n\t4403  T440-CR Unified Wire Ethernet Controller\n\t4404  T420-BCH Unified Wire Ethernet Controller\n\t4405  T440-BCH Unified Wire Ethernet Controller\n\t4406  T440-CH Unified Wire Ethernet Controller\n\t4407  T420-SO Unified Wire Ethernet Controller\n\t4408  T420-CX Unified Wire Ethernet Controller\n\t4409  T420-BT Unified Wire Ethernet Controller\n\t440a  T404-BT Unified Wire Ethernet Controller\n\t440b  B420-SR Unified Wire Ethernet Controller\n\t440c  B404-BT Unified Wire Ethernet Controller\n\t440d  T480 Unified Wire Ethernet Controller\n\t440e  T440-LP-CR Unified Wire Ethernet Controller\n\t440f  T440 [Amsterdam] Unified Wire Ethernet Controller\n\t4480  T480-4080 T480 Unified Wire Ethernet Controller\n\t4481  T440F-4081 T440-FCoE Unified Wire Ethernet Controller\n\t4482  T420-4082  Unified Wire Ethernet Controller\n\t4483  T420X-4083 Unified Wire Ethernet Controller\n\t4484  T440-4084 Unified Wire Ethernet Controller\n\t4485  T420-4085 SFP+ Unified Wire Ethernet Controller\n\t4486  T440-4086 10Gbase-T Unified Wire Ethernet Controller\n\t4487  T440T-4087 Unified Wire Ethernet Controller\n\t4488  T440-4088 Unified Wire Ethernet Controller\n\t4501  T420-CR Unified Wire Storage Controller\n\t4502  T422-CR Unified Wire Storage Controller\n\t4503  T440-CR Unified Wire Storage Controller\n\t4504  T420-BCH Unified Wire Storage Controller\n\t4505  T440-BCH Unified Wire Storage Controller\n\t4506  T440-CH Unified Wire Storage Controller\n\t4507  T420-SO Unified Wire Storage Controller\n\t4508  T420-CX Unified Wire Storage Controller\n\t4509  T420-BT Unified Wire Storage Controller\n\t450a  T404-BT Unified Wire Storage Controller\n\t450b  B420-SR Unified Wire Storage Controller\n\t450c  B404-BT Unified Wire Storage Controller\n\t450d  T480 Unified Wire Storage Controller\n\t450e  T440-LP-CR Unified Wire Storage Controller\n\t450f  T440 [Amsterdam] Unified Wire Storage Controller\n\t4580  T480-4080 T480 Unified Wire Storage Controller\n\t4581  T440F-4081 T440-FCoE Unified Wire Storage Controller\n\t4582  T420-4082  Unified Wire Storage Controller\n\t4583  T420X-4083 Unified Wire Storage Controller\n\t4584  T440-4084 Unified Wire Storage Controller\n\t4585  T420-4085 SFP+ Unified Wire Storage Controller\n\t4586  T440-4086 10Gbase-T Unified Wire Storage Controller\n\t4587  T440T-4087 Unified Wire Storage Controller\n\t4588  T440-4088 Unified Wire Storage Controller\n\t4601  T420-CR Unified Wire Storage Controller\n\t4602  T422-CR Unified Wire Storage Controller\n\t4603  T440-CR Unified Wire Storage Controller\n\t4604  T420-BCH Unified Wire Storage Controller\n\t4605  T440-BCH Unified Wire Storage Controller\n\t4606  T440-CH Unified Wire Storage Controller\n\t4607  T420-SO Unified Wire Storage Controller\n\t4608  T420-CX Unified Wire Storage Controller\n\t4609  T420-BT Unified Wire Storage Controller\n\t460a  T404-BT Unified Wire Storage Controller\n\t460b  B420-SR Unified Wire Storage Controller\n\t460c  B404-BT Unified Wire Storage Controller\n\t460d  T480 Unified Wire Storage Controller\n\t460e  T440-LP-CR Unified Wire Storage Controller\n\t460f  T440 [Amsterdam] Unified Wire Storage Controller\n\t4680  T480-4080 T480 Unified Wire Storage Controller\n\t4681  T440F-4081 T440-FCoE Unified Wire Storage Controller\n\t4682  T420-4082  Unified Wire Storage Controller\n\t4683  T420X-4083 Unified Wire Storage Controller\n\t4684  T440-4084 Unified Wire Storage Controller\n\t4685  T420-4085 SFP+ Unified Wire Storage Controller\n\t4686  T440-4086 10Gbase-T Unified Wire Storage Controller\n\t4687  T440T-4087 Unified Wire Storage Controller\n\t4688  T440-4088 Unified Wire Storage Controller\n\t4701  T420-CR Unified Wire Ethernet Controller\n\t4702  T422-CR Unified Wire Ethernet Controller\n\t4703  T440-CR Unified Wire Ethernet Controller\n\t4704  T420-BCH Unified Wire Ethernet Controller\n\t4705  T440-BCH Unified Wire Ethernet Controller\n\t4706  T440-CH Unified Wire Ethernet Controller\n\t4707  T420-SO Unified Wire Ethernet Controller\n\t4708  T420-CX Unified Wire Ethernet Controller\n\t4709  T420-BT Unified Wire Ethernet Controller\n\t470a  T404-BT Unified Wire Ethernet Controller\n\t470b  B420-SR Unified Wire Ethernet Controller\n\t470c  B404-BT Unified Wire Ethernet Controller\n\t470d  T480 Unified Wire Ethernet Controller\n\t470e  T440-LP-CR Unified Wire Ethernet Controller\n\t470f  T440 [Amsterdam] Unified Wire Ethernet Controller\n\t4780  T480-4080 T480 Unified Wire Ethernet Controller\n\t4781  T440F-4081 T440-FCoE Unified Wire Ethernet Controller\n\t4782  T420-4082  Unified Wire Ethernet Controller\n\t4783  T420X-4083 Unified Wire Ethernet Controller\n\t4784  T440-4084 Unified Wire Ethernet Controller\n\t4785  T420-4085 SFP+ Unified Wire Ethernet Controller\n\t4786  T440-4086 10Gbase-T Unified Wire Ethernet Controller\n\t4787  T440T-4087 Unified Wire Ethernet Controller\n\t4788  T440-4088 Unified Wire Ethernet Controller\n\t4801  T420-CR Unified Wire Ethernet Controller [VF]\n\t4802  T422-CR Unified Wire Ethernet Controller [VF]\n\t4803  T440-CR Unified Wire Ethernet Controller [VF]\n\t4804  T420-BCH Unified Wire Ethernet Controller [VF]\n\t4805  T440-BCH Unified Wire Ethernet Controller [VF]\n\t4806  T440-CH Unified Wire Ethernet Controller [VF]\n\t4807  T420-SO Unified Wire Ethernet Controller [VF]\n\t4808  T420-CX Unified Wire Ethernet Controller [VF]\n\t4809  T420-BT Unified Wire Ethernet Controller [VF]\n\t480a  T404-BT Unified Wire Ethernet Controller [VF]\n\t480b  B420-SR Unified Wire Ethernet Controller [VF]\n\t480c  B404-BT Unified Wire Ethernet Controller [VF]\n\t480d  T480 Unified Wire Ethernet Controller [VF]\n\t480e  T440-LP-CR Unified Wire Ethernet Controller [VF]\n\t480f  T440 [Amsterdam] Unified Wire Ethernet Controller [VF]\n\t4880  T480-4080 T480 Unified Wire Ethernet Controller [VF]\n\t4881  T440F-4081 T440-FCoE Unified Wire Ethernet Controller [VF]\n\t4882  T420-4082 Unified Wire Ethernet Controller [VF]\n\t4883  T420X-4083 Unified Wire Ethernet Controller [VF]\n\t4884  T440-4084 Unified Wire Ethernet Controller [VF]\n\t4885  T420-4085 SFP+ Unified Wire Ethernet Controller [VF]\n\t4886  T440-4086 10Gbase-T Unified Wire Ethernet Controller [VF]\n\t4887  T440T-4087 Unified Wire Ethernet Controller [VF]\n\t4888  T440-4088 Unified Wire Ethernet Controller [VF]\n\t5001  T520-CR Unified Wire Ethernet Controller\n\t\t193d 1001  510F-B\n\t5002  T522-CR Unified Wire Ethernet Controller\n\t5003  T540-CR Unified Wire Ethernet Controller\n\t5004  T520-BCH Unified Wire Ethernet Controller\n\t5005  T540-BCH Unified Wire Ethernet Controller\n\t5006  T540-CH Unified Wire Ethernet Controller\n\t5007  T520-SO Unified Wire Ethernet Controller\n\t5008  T520-CX Unified Wire Ethernet Controller\n\t5009  T520-BT Unified Wire Ethernet Controller\n\t500a  T504-BT Unified Wire Ethernet Controller\n\t500b  B520-SR Unified Wire Ethernet Controller\n\t500c  B504-BT Unified Wire Ethernet Controller\n\t500d  T580-CR Unified Wire Ethernet Controller\n\t500e  T540-LP-CR Unified Wire Ethernet Controller\n\t500f  T540 [Amsterdam] Unified Wire Ethernet Controller\n\t5010  T580-LP-CR Unified Wire Ethernet Controller\n\t5011  T520-LL-CR Unified Wire Ethernet Controller\n\t5012  T560-CR Unified Wire Ethernet Controller\n\t5013  T580-CHR Unified Wire Ethernet Controller\n\t5014  T580-SO-CR Unified Wire Ethernet Controller\n\t5015  T502-BT Unified Wire Ethernet Controller\n\t5016  T580-OCP-SO Unified Wire Ethernet Controller\n\t5017  T520-OCP-SO Unified Wire Ethernet Controller\n\t5018  T540-BT Unified Wire Ethernet Controller\n\t5019  T540-LP-BT Unified Wire Ethernet Controller\n\t501a  T540-SO-BT Unified Wire Ethernet Controller\n\t501b  T540-SO-CR Unified Wire Ethernet Controller\n\t5080  T540-5080 Unified Wire Ethernet Controller\n\t5081  T540-5081 Unified Wire Ethernet Controller\n\t5082  T504-5082 Unified Wire Ethernet Controller\n\t5083  T540-5083 Unified Wire Ethernet Controller\n\t5084  T540-5084 Unified Wire Ethernet Controller\n\t5085  T580-5085 Unified Wire Ethernet Controller\n\t5086  T580-5086 Unified Wire Ethernet Controller\n\t5087  T580-5087 Unified Wire Ethernet Controller\n\t5088  T570-5088 Unified Wire Ethernet Controller\n\t5089  T520-5089 Unified Wire Ethernet Controller\n\t5090  T540-5090 Unified Wire Ethernet Controller\n\t5091  T522-5091 Unified Wire Ethernet Controller\n\t5092  T520-5092 Unified Wire Ethernet Controller\n\t5093  T580-5093 Unified Wire Ethernet Controller\n\t5094  T540-5094 Unified Wire Ethernet Controller\n\t5095  T540-5095 Unified Wire Ethernet Controller\n\t5096  T580-5096 Unified Wire Ethernet Controller\n\t5097  T520-5097 Unified Wire Ethernet Controller\n\t5098  T580-5098 Unified Wire Ethernet Controller\n\t5099  T580-5099 Unified Wire Ethernet Controller\n\t509a  T520-509A Unified Wire Ethernet Controller\n\t509b  T540-509B Unified Wire Ethernet Controller\n\t509c  T520-509C Unified Wire Ethernet Controller\n\t509d  T540-509D Unified Wire Ethernet Controller\n\t509e  T520-509E Unified Wire Ethernet Controller\n\t509f  T540-509F Unified Wire Ethernet Controller\n\t50a0  T540-50A0 Unified Wire Ethernet Controller\n\t50a1  T540-50A1 Unified Wire Ethernet Controller\n\t50a2  T580-50A2 Unified Wire Ethernet Controller\n\t50a3  T580-50A3 Unified Wire Ethernet Controller\n\t50a4  T540-50A4 Unified Wire Ethernet Controller\n\t50a5  T522-50A5 Unified Wire Ethernet Controller\n\t50a6  T522-50A6 Unified Wire Ethernet Controller\n\t50a7  T580-50A7 Unified Wire Ethernet Controller\n\t50a8  T580-50A8 Unified Wire Ethernet Controller\n\t50a9  T580-50A9 Unified Wire Ethernet Controller\n\t50aa  T580-50AA Unified Wire Ethernet Controller\n\t50ab  T520-50AB Unified Wire Ethernet Controller\n\t50ac  T540-50AC Unified Wire Ethernet Controller\n\t50ad  T520-50AD Unified Wire Ethernet Controller\n\t50ae  T540-50AE Unified Wire Ethernet Controller\n\t50af  T580-50AF Unified Wire Ethernet Controller\n\t50b0  T520-50B0 Unified Wire Ethernet Controller\n\t5401  T520-CR Unified Wire Ethernet Controller\n\t5402  T522-CR Unified Wire Ethernet Controller\n\t5403  T540-CR Unified Wire Ethernet Controller\n\t5404  T520-BCH Unified Wire Ethernet Controller\n\t5405  T540-BCH Unified Wire Ethernet Controller\n\t5406  T540-CH Unified Wire Ethernet Controller\n\t5407  T520-SO Unified Wire Ethernet Controller\n\t5408  T520-CX Unified Wire Ethernet Controller\n\t5409  T520-BT Unified Wire Ethernet Controller\n\t540a  T504-BT Unified Wire Ethernet Controller\n\t540b  B520-SR Unified Wire Ethernet Controller\n\t540c  B504-BT Unified Wire Ethernet Controller\n\t540d  T580-CR Unified Wire Ethernet Controller\n\t540e  T540-LP-CR Unified Wire Ethernet Controller\n\t540f  T540 [Amsterdam] Unified Wire Ethernet Controller\n\t5410  T580-LP-CR Unified Wire Ethernet Controller\n\t5411  T520-LL-CR Unified Wire Ethernet Controller\n\t5412  T560-CR Unified Wire Ethernet Controller\n\t5413  T580-CHR Unified Wire Ethernet Controller\n\t5414  T580-SO-CR Unified Wire Ethernet Controller\n\t5415  T502-BT Unified Wire Ethernet Controller\n\t5416  T580-OCP-SO Unified Wire Ethernet Controller\n\t5417  T520-OCP-SO Unified Wire Ethernet Controller\n\t5418  T540-BT Unified Wire Ethernet Controller\n\t5419  T540-LP-BT Unified Wire Ethernet Controller\n\t541a  T540-SO-BT Unified Wire Ethernet Controller\n\t541b  T540-SO-CR Unified Wire Ethernet Controller\n\t5480  T540-5080 Unified Wire Ethernet Controller\n\t5481  T540-5081 Unified Wire Ethernet Controller\n\t5482  T504-5082 Unified Wire Ethernet Controller\n\t5483  T540-5083 Unified Wire Ethernet Controller\n\t5484  T540-5084 Unified Wire Ethernet Controller\n\t5485  T580-5085 Unified Wire Ethernet Controller\n\t5486  T580-5086 Unified Wire Ethernet Controller\n\t5487  T580-5087 Unified Wire Ethernet Controller\n\t5488  T570-5088 Unified Wire Ethernet Controller\n\t5489  T520-5089 Unified Wire Ethernet Controller\n\t5490  T540-5090 Unified Wire Ethernet Controller\n\t5491  T522-5091 Unified Wire Ethernet Controller\n\t5492  T520-5092 Unified Wire Ethernet Controller\n\t5493  T580-5093 Unified Wire Ethernet Controller\n\t5494  T540-5094 Unified Wire Ethernet Controller\n\t5495  T540-5095 Unified Wire Ethernet Controller\n\t5496  T580-5096 Unified Wire Ethernet Controller\n\t5497  T520-5097 Unified Wire Ethernet Controller\n\t5498  T580-5098 Unified Wire Ethernet Controller\n\t5499  T580-5099 Unified Wire Ethernet Controller\n\t549a  T520-509A Unified Wire Ethernet Controller\n\t549b  T540-509B Unified Wire Ethernet Controller\n\t549c  T520-509C Unified Wire Ethernet Controller\n\t549d  T540-509D Unified Wire Ethernet Controller\n\t549e  T520-509E Unified Wire Ethernet Controller\n\t549f  T540-509F Unified Wire Ethernet Controller\n\t54a0  T540-50A0 Unified Wire Ethernet Controller\n\t54a1  T540-50A1 Unified Wire Ethernet Controller\n\t54a2  T580-50A2 Unified Wire Ethernet Controller\n\t54a3  T580-50A3 Unified Wire Ethernet Controller\n\t54a4  T540-50A4 Unified Wire Ethernet Controller\n\t54a5  T522-50A5 Unified Wire Ethernet Controller\n\t54a6  T522-50A6 Unified Wire Ethernet Controller\n\t54a7  T580-50A7 Unified Wire Ethernet Controller\n\t54a8  T580-50A8 Unified Wire Ethernet Controller\n\t54a9  T580-50A9 Unified Wire Ethernet Controller\n\t54aa  T580-50AA Unified Wire Ethernet Controller\n\t54ab  T520-50AB Unified Wire Ethernet Controller\n\t54ac  T540-50AC Unified Wire Ethernet Controller\n\t54ad  T520-50AD Unified Wire Ethernet Controller\n\t54ae  T540-50AE Unified Wire Ethernet Controller\n\t54af  T580-50AF Unified Wire Ethernet Controller\n\t54b0  T520-50B0 Unified Wire Ethernet Controller\n\t5501  T520-CR Unified Wire Storage Controller\n\t5502  T522-CR Unified Wire Storage Controller\n\t5503  T540-CR Unified Wire Storage Controller\n\t5504  T520-BCH Unified Wire Storage Controller\n\t5505  T540-BCH Unified Wire Storage Controller\n\t5506  T540-CH Unified Wire Storage Controller\n\t5507  T520-SO Unified Wire Storage Controller\n\t5508  T520-CX Unified Wire Storage Controller\n\t5509  T520-BT Unified Wire Storage Controller\n\t550a  T504-BT Unified Wire Storage Controller\n\t550b  B520-SR Unified Wire Storage Controller\n\t550c  B504-BT Unified Wire Storage Controller\n\t550d  T580-CR Unified Wire Storage Controller\n\t550e  T540-LP-CR Unified Wire Storage Controller\n\t550f  T540 [Amsterdam] Unified Wire Storage Controller\n\t5510  T580-LP-CR Unified Wire Storage Controller\n\t5511  T520-LL-CR Unified Wire Storage Controller\n\t5512  T560-CR Unified Wire Storage Controller\n\t5513  T580-CHR Unified Wire Storage Controller\n\t5514  T580-SO-CR Unified Wire Storage Controller\n\t5515  T502-BT Unified Wire Storage Controller\n\t5516  T580-OCP-SO Unified Wire Storage Controller\n\t5517  T520-OCP-SO Unified Wire Storage Controller\n\t5518  T540-BT Unified Wire Storage Controller\n\t5519  T540-LP-BT Unified Wire Storage Controller\n\t551a  T540-SO-BT Unified Wire Storage Controller\n\t551b  T540-SO-CR Unified Wire Storage Controller\n\t5580  T540-5080 Unified Wire Storage Controller\n\t5581  T540-5081 Unified Wire Storage Controller\n\t5582  T504-5082 Unified Wire Storage Controller\n\t5583  T540-5083 Unified Wire Storage Controller\n\t5584  T540-5084 Unified Wire Storage Controller\n\t5585  T580-5085 Unified Wire Storage Controller\n\t5586  T580-5086 Unified Wire Storage Controller\n\t5587  T580-5087 Unified Wire Storage Controller\n\t5588  T570-5088 Unified Wire Storage Controller\n\t5589  T520-5089 Unified Wire Storage Controller\n\t5590  T540-5090 Unified Wire Storage Controller\n\t5591  T522-5091 Unified Wire Storage Controller\n\t5592  T520-5092 Unified Wire Storage Controller\n\t5593  T580-5093 Unified Wire Storage Controller\n\t5594  T540-5094 Unified Wire Storage Controller\n\t5595  T540-5095 Unified Wire Storage Controller\n\t5596  T580-5096 Unified Wire Storage Controller\n\t5597  T520-5097 Unified Wire Storage Controller\n\t5598  T580-5098 Unified Wire Storage Controller\n\t5599  T580-5099 Unified Wire Storage Controller\n\t559a  T520-509A Unified Wire Storage Controller\n\t559b  T540-509B Unified Wire Storage Controller\n\t559c  T520-509C Unified Wire Storage Controller\n\t559d  T540-509D Unified Wire Storage Controller\n\t559e  T520-509E Unified Wire Storage Controller\n\t559f  T540-509F Unified Wire Storage Controller\n\t55a0  T540-50A0 Unified Wire Storage Controller\n\t55a1  T540-50A1 Unified Wire Storage Controller\n\t55a2  T580-50A2 Unified Wire Storage Controller\n\t55a3  T580-50A3 Unified Wire Storage Controller\n\t55a4  T540-50A4 Unified Wire Storage Controller\n\t55a5  T522-50A5 Unified Wire Storage Controller\n\t55a6  T522-50A6 Unified Wire Storage Controller\n\t55a7  T580-50A7 Unified Wire Storage Controller\n\t55a8  T580-50A8 Unified Wire Storage Controller\n\t55a9  T580-50A9 Unified Wire Storage Controller\n\t55aa  T580-50AA Unified Wire Storage Controller\n\t55ab  T520-50AB Unified Wire Storage Controller\n\t55ac  T540-50AC Unified Wire Storage Controller\n\t55ad  T520-50AD Unified Wire Storage Controller\n\t55ae  T540-50AE Unified Wire Storage Controller\n\t55af  T580-50AF Unified Wire Storage Controller\n\t55b0  T520-50B0 Unified Wire Storage Controller\n\t5601  T520-CR Unified Wire Storage Controller\n\t5602  T522-CR Unified Wire Storage Controller\n\t5603  T540-CR Unified Wire Storage Controller\n\t5604  T520-BCH Unified Wire Storage Controller\n\t5605  T540-BCH Unified Wire Storage Controller\n\t5606  T540-CH Unified Wire Storage Controller\n\t5607  T520-SO Unified Wire Storage Controller\n\t5608  T520-CX Unified Wire Storage Controller\n\t5609  T520-BT Unified Wire Storage Controller\n\t560a  T504-BT Unified Wire Storage Controller\n\t560b  B520-SR Unified Wire Storage Controller\n\t560c  B504-BT Unified Wire Storage Controller\n\t560d  T580-CR Unified Wire Storage Controller\n\t560e  T540-LP-CR Unified Wire Storage Controller\n\t560f  T540 [Amsterdam] Unified Wire Storage Controller\n\t5610  T580-LP-CR Unified Wire Storage Controller\n\t5611  T520-LL-CR Unified Wire Storage Controller\n\t5612  T560-CR Unified Wire Storage Controller\n\t5613  T580-CHR Unified Wire Storage Controller\n\t5614  T580-SO-CR Unified Wire Storage Controller\n\t5615  T502-BT Unified Wire Storage Controller\n\t5616  T580-OCP-SO Unified Wire Storage Controller\n\t5617  T520-OCP-SO Unified Wire Storage Controller\n\t5618  T540-BT Unified Wire Storage Controller\n\t5619  T540-LP-BT Unified Wire Storage Controller\n\t561a  T540-SO-BT Unified Wire Storage Controller\n\t561b  T540-SO-CR Unified Wire Storage Controller\n\t5680  T540-5080 Unified Wire Storage Controller\n\t5681  T540-5081 Unified Wire Storage Controller\n\t5682  T504-5082 Unified Wire Storage Controller\n\t5683  T540-5083 Unified Wire Storage Controller\n\t5684  T540-5084 Unified Wire Storage Controller\n\t5685  T580-5085 Unified Wire Storage Controller\n\t5686  T580-5086 Unified Wire Storage Controller\n\t5687  T580-5087 Unified Wire Storage Controller\n\t5688  T570-5088 Unified Wire Storage Controller\n\t5689  T520-5089 Unified Wire Storage Controller\n\t5690  T540-5090 Unified Wire Storage Controller\n\t5691  T522-5091 Unified Wire Storage Controller\n\t5692  T520-5092 Unified Wire Storage Controller\n\t5693  T580-5093 Unified Wire Storage Controller\n\t5694  T540-5094 Unified Wire Storage Controller\n\t5695  T540-5095 Unified Wire Storage Controller\n\t5696  T580-5096 Unified Wire Storage Controller\n\t5697  T520-5097 Unified Wire Storage Controller\n\t5698  T580-5098 Unified Wire Storage Controller\n\t5699  T580-5099 Unified Wire Storage Controller\n\t569a  T520-509A Unified Wire Storage Controller\n\t569b  T540-509B Unified Wire Storage Controller\n\t569c  T520-509C Unified Wire Storage Controller\n\t569d  T540-509D Unified Wire Storage Controller\n\t569e  T520-509E Unified Wire Storage Controller\n\t569f  T540-509F Unified Wire Storage Controller\n\t56a0  T540-50A0 Unified Wire Storage Controller\n\t56a1  T540-50A1 Unified Wire Storage Controller\n\t56a2  T580-50A2 Unified Wire Storage Controller\n\t56a3  T580-50A3 Unified Wire Storage Controller\n\t56a4  T540-50A4 Unified Wire Storage Controller\n\t56a5  T522-50A5 Unified Wire Storage Controller\n\t56a6  T522-50A6 Unified Wire Storage Controller\n\t56a7  T580-50A7 Unified Wire Storage Controller\n\t56a8  T580-50A8 Unified Wire Storage Controller\n\t56a9  T580-50A9 Unified Wire Storage Controller\n\t56aa  T580-50AA Unified Wire Storage Controller\n\t56ab  T520-50AB Unified Wire Storage Controller\n\t56ac  T540-50AC Unified Wire Storage Controller\n\t56ad  T520-50AD Unified Wire Storage Controller\n\t56ae  T540-50AE Unified Wire Storage Controller\n\t56af  T580-50AF Unified Wire Storage Controller\n\t56b0  T520-50B0 Unified Wire Storage Controller\n\t5701  T520-CR Unified Wire Ethernet Controller\n\t5702  T522-CR Unified Wire Ethernet Controller\n\t5703  T540-CR Unified Wire Ethernet Controller\n\t5704  T520-BCH Unified Wire Ethernet Controller\n\t5705  T540-BCH Unified Wire Ethernet Controller\n\t5706  T540-CH Unified Wire Ethernet Controller\n\t5707  T520-SO Unified Wire Ethernet Controller\n\t5708  T520-CX Unified Wire Ethernet Controller\n\t5709  T520-BT Unified Wire Ethernet Controller\n\t570a  T504-BT Unified Wire Ethernet Controller\n\t570b  B520-SR Unified Wire Ethernet Controller\n\t570c  B504-BT Unified Wire Ethernet Controller\n\t570d  T580-CR Unified Wire Ethernet Controller\n\t570e  T540-LP-CR Unified Wire Ethernet Controller\n\t570f  T540 [Amsterdam] Unified Wire Ethernet Controller\n\t5710  T580-LP-CR Unified Wire Ethernet Controller\n\t5711  T520-LL-CR Unified Wire Ethernet Controller\n\t5712  T560-CR Unified Wire Ethernet Controller\n\t5713  T580-CR Unified Wire Ethernet Controller\n\t5714  T580-SO-CR Unified Wire Ethernet Controller\n\t5715  T502-BT Unified Wire Ethernet Controller\n\t5780  T540-5080 Unified Wire Ethernet Controller\n\t5781  T540-5081 Unified Wire Ethernet Controller\n\t5782  T504-5082 Unified Wire Ethernet Controller\n\t5783  T540-5083 Unified Wire Ethernet Controller\n\t5784  T580-5084 Unified Wire Ethernet Controller\n\t5785  T580-5085 Unified Wire Ethernet Controller\n\t5786  T580-5086 Unified Wire Ethernet Controller\n\t5787  T580-5087 Unified Wire Ethernet Controller\n\t5788  T570-5088 Unified Wire Ethernet Controller\n\t5789  T520-5089 Unified Wire Ethernet Controller\n\t5790  T540-5090 Unified Wire Ethernet Controller\n\t5791  T522-5091 Unified Wire Ethernet Controller\n\t5792  T520-5092 Unified Wire Ethernet Controller\n\t5793  T580-5093 Unified Wire Ethernet Controller\n\t5794  T540-5094 Unified Wire Ethernet Controller\n\t5795  T540-5095 Unified Wire Ethernet Controller\n\t5796  T580-5096 Unified Wire Ethernet Controller\n\t5797  T520-5097 Unified Wire Ethernet Controller\n\t5801  T520-CR Unified Wire Ethernet Controller [VF]\n\t5802  T522-CR Unified Wire Ethernet Controller [VF]\n\t5803  T540-CR Unified Wire Ethernet Controller [VF]\n\t5804  T520-BCH Unified Wire Ethernet Controller [VF]\n\t5805  T540-BCH Unified Wire Ethernet Controller [VF]\n\t5806  T540-CH Unified Wire Ethernet Controller [VF]\n\t5807  T520-SO Unified Wire Ethernet Controller [VF]\n\t5808  T520-CX Unified Wire Ethernet Controller [VF]\n\t5809  T520-BT Unified Wire Ethernet Controller [VF]\n\t580a  T504-BT Unified Wire Ethernet Controller [VF]\n\t580b  B520-SR Unified Wire Ethernet Controller [VF]\n\t580c  B504-BT Unified Wire Ethernet Controller [VF]\n\t580d  T580-CR Unified Wire Ethernet Controller [VF]\n\t580e  T540-LP-CR Unified Wire Ethernet Controller [VF]\n\t580f  T540 [Amsterdam] Unified Wire Ethernet Controller [VF]\n\t5810  T580-LP-CR Unified Wire Ethernet Controller [VF]\n\t5811  T520-LL-CR Unified Wire Ethernet Controller [VF]\n\t5812  T560-CR Unified Wire Ethernet Controller [VF]\n\t5813  T580-CHR Unified Wire Ethernet Controller [VF]\n\t5814  T580-SO-CR Unified Wire Ethernet Controller [VF]\n\t5815  T502-BT Unified Wire Ethernet Controller [VF]\n\t5816  T580-OCP-SO Unified Wire Ethernet Controller [VF]\n\t5817  T520-OCP-SO Unified Wire Ethernet Controller [VF]\n\t5818  T540-BT Unified Wire Ethernet Controller [VF]\n\t5819  T540-LP-BT Unified Wire Ethernet Controller [VF]\n\t581a  T540-SO-BT Unified Wire Ethernet Controller [VF]\n\t581b  T540-SO-CR Unified Wire Ethernet Controller [VF]\n\t5880  T540-5080 Unified Wire Ethernet Controller [VF]\n\t5881  T540-5081 Unified Wire Ethernet Controller [VF]\n\t5882  T504-5082 Unified Wire Ethernet Controller [VF]\n\t5883  T540-5083 Unified Wire Ethernet Controller [VF]\n\t5884  T540-5084 Unified Wire Ethernet Controller [VF]\n\t5885  T580-5085 Unified Wire Ethernet Controller [VF]\n\t5886  T580-5086 Unified Wire Ethernet Controller [VF]\n\t5887  T580-5087 Unified Wire Ethernet Controller [VF]\n\t5888  T570-5088 Unified Wire Ethernet Controller [VF]\n\t5889  T520-5089 Unified Wire Ethernet Controller [VF]\n\t5890  T540-5090 Unified Wire Ethernet Controller [VF]\n\t5891  T522-5091 Unified Wire Ethernet Controller [VF]\n\t5892  T520-5092 Unified Wire Ethernet Controller [VF]\n\t5893  T580-5093 Unified Wire Ethernet Controller [VF]\n\t5894  T540-5094 Unified Wire Ethernet Controller [VF]\n\t5895  T540-5095 Unified Wire Ethernet Controller [VF]\n\t5896  T580-5096 Unified Wire Ethernet Controller [VF]\n\t5897  T520-5097 Unified Wire Ethernet Controller [VF]\n\t5898  T580-5098 Unified Wire Ethernet Controller [VF]\n\t5899  T580-5099 Unified Wire Ethernet Controller [VF]\n\t589a  T520-509A Unified Wire Ethernet Controller [VF]\n\t589b  T540-509B Unified Wire Ethernet Controller [VF]\n\t589c  T520-509C Unified Wire Ethernet Controller [VF]\n\t589d  T540-509D Unified Wire Ethernet Controller [VF]\n\t589e  T520-509E Unified Wire Ethernet Controller [VF]\n\t589f  T540-509F Unified Wire Ethernet Controller [VF]\n\t58a0  T540-50A0 Unified Wire Ethernet Controller [VF]\n\t58a1  T540-50A1 Unified Wire Ethernet Controller [VF]\n\t58a2  T580-50A2 Unified Wire Ethernet Controller [VF]\n\t58a3  T580-50A3 Unified Wire Ethernet Controller [VF]\n\t58a4  T540-50A4 Unified Wire Ethernet Controller [VF]\n\t58a5  T522-50A5 Unified Wire Ethernet Controller [VF]\n\t58a6  T522-50A6 Unified Wire Ethernet Controller [VF]\n\t58a7  T580-50A7 Unified Wire Ethernet Controller [VF]\n\t58a8  T580-50A8 Unified Wire Ethernet Controller [VF]\n\t58a9  T580-50A9 Unified Wire Ethernet Controller [VF]\n\t58aa  T580-50AA Unified Wire Ethernet Controller [VF]\n\t58ab  T520-50AB Unified Wire Ethernet Controller [VF]\n\t58ac  T540-50AC Unified Wire Ethernet Controller [VF]\n\t58ad  T520-50AD Unified Wire Ethernet Controller [VF]\n\t58ae  T540-50AE Unified Wire Ethernet Controller [VF]\n\t58af  T580-50AF Unified Wire Ethernet Controller [VF]\n\t58b0  T520-50B0 Unified Wire Ethernet Controller [VF]\n\t6001  T6225-CR Unified Wire Ethernet Controller\n\t6002  T6225-SO-CR Unified Wire Ethernet Controller\n\t6003  T6425-CR Unified Wire Ethernet Controller\n\t6004  T6425-SO-CR Unified Wire Ethernet Controller\n\t6005  T6225-OCP-SO Unified Wire Ethernet Controller\n\t6006  T62100-OCP-SO Unified Wire Ethernet Controller\n\t6007  T62100-LP-CR Unified Wire Ethernet Controller\n\t6008  T62100-SO-CR Unified Wire Ethernet Controller\n\t6009  T6210-BT Unified Wire Ethernet Controller\n\t600d  T62100-CR Unified Wire Ethernet Controller\n\t6011  T6225-LL-CR Unified Wire Ethernet Controller\n\t6014  T61100-OCP-SO Unified Wire Ethernet Controller\n\t6015  T6201-BT Unified Wire Ethernet Controller\n\t6080  T6225-6080 Unified Wire Ethernet Controller\n\t6081  T62100-6081 Unified Wire Ethernet Controller\n\t6082  T6225-6082 Unified Wire Ethernet Controller\n\t6083  T62100-6083 Unified Wire Ethernet Controller\n\t6084  T64100-6084 Unified Wire Ethernet Controller\n\t6085  T6240-6085 Unified Wire Ethernet Controller\n\t6086  T6225-6086 Unified Wire Ethernet Controller\n\t6087  T6225-6087 Unified Wire Ethernet Controller\n\t6088  T62100-6088 Unified Wire Ethernet Controller\n\t6089  T62100-6089 Unified Wire Ethernet Controller\n\t608a  T62100-608a Unified Wire Ethernet Controller\n\t6401  T6225-CR Unified Wire Ethernet Controller\n\t6402  T6225-SO-CR Unified Wire Ethernet Controller\n\t6403  T6425-CR Unified Wire Ethernet Controller\n\t6404  T6425-SO-CR Unified Wire Ethernet Controller\n\t6405  T6225-OCP-SO Unified Wire Ethernet Controller\n\t6406  T62100-OCP-SO Unified Wire Ethernet Controller\n\t6407  T62100-LP-CR Unified Wire Ethernet Controller\n\t6408  T62100-SO-CR Unified Wire Ethernet Controller\n\t6409  T6210-BT Unified Wire Ethernet Controller\n\t640d  T62100-CR Unified Wire Ethernet Controller\n\t6411  T6225-LL-CR Unified Wire Ethernet Controller\n\t6414  T61100-OCP-SO Unified Wire Ethernet Controller\n\t6415  T6201-BT Unified Wire Ethernet Controller\n\t6480  T6225-6080 Unified Wire Ethernet Controller\n\t6481  T62100-6081 Unified Wire Ethernet Controller\n\t6482  T6225-6082 Unified Wire Ethernet Controller\n\t6483  T62100-6083 Unified Wire Ethernet Controller\n\t6484  T64100-6084 Unified Wire Ethernet Controller\n\t6485  T6240-6085 Unified Wire Ethernet Controller\n\t6486  T6225-6086 Unified Wire Ethernet Controller\n\t6487  T6225-6087 Unified Wire Ethernet Controller\n\t6488  T62100-6088 Unified Wire Ethernet Controller\n\t6489  T62100-6089 Unified Wire Ethernet Controller\n\t648a  T62100-608a Unified Wire Ethernet Controller\n\t6501  T6225-CR Unified Wire Storage Controller\n\t6502  T6225-SO-CR Unified Wire Storage Controller\n\t6503  T6425-CR Unified Wire Storage Controller\n\t6504  T6425-SO-CR Unified Wire Storage Controller\n\t6505  T6225-OCP-SO Unified Wire Storage Controller\n\t6506  T62100-OCP-SO Unified Wire Storage Controller\n\t6507  T62100-LP-CR Unified Wire Storage Controller\n\t6508  T62100-SO-CR Unified Wire Storage Controller\n\t6509  T6210-BT Unified Wire Storage Controller\n\t650d  T62100-CR Unified Wire Storage Controller\n\t6511  T6225-LL-CR Unified Wire Storage Controller\n\t6514  T61100-OCP-SO Unified Wire Storage Controller\n\t6515  T6201-BT Unified Wire Storage Controller\n\t6580  T6225-6080 Unified Wire Storage Controller\n\t6581  T62100-6081 Unified Wire Storage Controller\n\t6582  T6225-6082 Unified Wire Storage Controller\n\t6583  T62100-6083 Unified Wire Storage Controller\n\t6584  T64100-6084 Unified Wire Storage Controller\n\t6585  T6240-6085 Unified Wire Storage Controller\n\t6586  T6225-6086 Unified Wire Storage Controller\n\t6587  T6225-6087 Unified Wire Storage Controller\n\t6588  T62100-6088 Unified Wire Storage Controller\n\t6589  T62100-6089 Unified Wire Storage Controller\n\t658a  T62100-608a Unified Wire Storage Controller\n\t6601  T6225-CR Unified Wire Storage Controller\n\t6602  T6225-SO-CR Unified Wire Storage Controller\n\t6603  T6425-CR Unified Wire Storage Controller\n\t6604  T6425-SO-CR Unified Wire Storage Controller\n\t6605  T6225-OCP-SO Unified Wire Storage Controller\n\t6606  T62100-OCP-SO Unified Wire Storage Controller\n\t6607  T62100-LP-CR Unified Wire Storage Controller\n\t6608  T62100-SO-CR Unified Wire Storage Controller\n\t6609  T6210-BT Unified Wire Storage Controller\n\t660d  T62100-CR Unified Wire Storage Controller\n\t6611  T6225-LL-CR Unified Wire Storage Controller\n\t6614  T61100-OCP-SO Unified Wire Storage Controller\n\t6615  T6201-BT Unified Wire Storage Controller\n\t6680  T6225-6080 Unified Wire Storage Controller\n\t6681  T62100-6081 Unified Wire Storage Controller\n\t6682  T6225-6082 Unified Wire Storage Controller\n\t6683  T62100-6083 Unified Wire Storage Controller\n\t6684  T64100-6084 Unified Wire Storage Controller\n\t6685  T6240-6085 Unified Wire Storage Controller\n\t6686  T6225-6086 Unified Wire Storage Controller\n\t6687  T6225-6087 Unified Wire Storage Controller\n\t6688  T62100-6088 Unified Wire Storage Controller\n\t6689  T62100-6089 Unified Wire Storage Controller\n\t668a  T62100-608a Unified Wire Storage Controller\n\t6801  T6225-CR Unified Wire Ethernet Controller [VF]\n\t6802  T6225-SO-CR Unified Wire Ethernet Controller [VF]\n\t6803  T6425-CR Unified Wire Ethernet Controller [VF]\n\t6804  T6425-SO-CR Unified Wire Ethernet Controller [VF]\n\t6805  T6225-OCP-SO Unified Wire Ethernet Controller [VF]\n\t6806  T62100-OCP-SO Unified Wire Ethernet Controller [VF]\n\t6807  T62100-LP-CR Unified Wire Ethernet Controller [VF]\n\t6808  T62100-SO-CR Unified Wire Ethernet Controller [VF]\n\t6809  T6210-BT Unified Wire Ethernet Controller [VF]\n\t680d  T62100-CR Unified Wire Ethernet Controller [VF]\n\t6811  T6225-LL-CR Unified Wire Ethernet Controller [VF]\n\t6814  T61100-OCP-SO Unified Wire Ethernet Controller [VF]\n\t6815  T6201-BT Unified Wire Ethernet Controller [VF]\n\t6880  T6225-6080 Unified Wire Ethernet Controller [VF]\n\t6881  T62100-6081 Unified Wire Ethernet Controller [VF]\n\t6882  T6225-6082 Unified Wire Ethernet Controller [VF]\n\t6883  T62100-6083 Unified Wire Ethernet Controller [VF]\n\t6884  T64100-6084 Unified Wire Ethernet Controller [VF]\n\t6885  T6240-6085 Unified Wire Ethernet Controller [VF]\n\t6886  T6225-6086 Unified Wire Ethernet Controller [VF]\n\t6887  T6225-6087 Unified Wire Ethernet Controller [VF]\n\t6888  T62100-6088 Unified Wire Ethernet Controller [VF]\n\t6889  T62100-6089 Unified Wire Ethernet Controller [VF]\n\t688a  T62100-608a Unified Wire Ethernet Controller [VF]\n\ta000  PE10K Unified Wire Ethernet Controller\n1426  Storage Technology Corp.\n1427  Better On-Line Solutions\n1428  Edec Co Ltd\n1429  Unex Technology Corp.\n142a  Kingmax Technology Inc\n142b  Radiolan\n142c  Minton Optic Industry Co Ltd\n142d  Pix stream Inc\n142e  Vitec Multimedia\n\t4020  VM2-2 [Video Maker 2] MPEG1/2 Encoder\n\t4337  VM2-2-C7 [Video Maker 2 rev. C7] MPEG1/2 Encoder\n142f  Radicom Research Inc\n1430  ITT Aerospace/Communications Division\n1431  Gilat Satellite Networks\n1432  Edimax Computer Co.\n\t9130  RTL81xx Fast Ethernet\n1433  Eltec Elektronik GmbH\n# Nee Real Time Devices US Inc.\n1435  RTD Embedded Technologies, Inc.\n\t4520  PCI4520\n\t6020  SPM6020\n\t6030  SPM6030\n\t6420  SPM186420\n\t6430  SPM176430\n\t6431  SPM176431\n\t7520  DM7520\n\t7540  SDM7540\n\t7820  DM7820\n1436  CIS Technology Inc\n1437  Nissin Inc Co\n1438  Atmel-dream\n1439  Outsource Engineering & Mfg. Inc\n143a  Stargate Solutions Inc\n143b  Canon Research Center, America\n143c  Amlogic Inc\n143d  Tamarack Microelectronics Inc\n143e  Jones Futurex Inc\n143f  Lightwell Co Ltd - Zax Division\n1440  ALGOL Corp.\n1441  AGIE Ltd\n1442  Phoenix Contact GmbH & Co.\n1443  Unibrain S.A.\n1444  TRW\n1445  Logical DO Ltd\n1446  Graphin Co Ltd\n1447  AIM GmBH\n1448  Alesis Studio Electronics\n1449  TUT Systems Inc\n144a  Adlink Technology\n\t6208  PCI-6208V\n\t7250  PCI-7250\n\t7296  PCI-7296\n\t7432  PCI-7432\n\t7433  PCI-7433\n\t7434  PCI-7434\n\t7841  PCI-7841\n\t8133  PCI-8133\n\t8164  PCI-8164\n\t8554  PCI-8554\n\t9111  PCI-9111\n\t9113  PCI-9113\n\t9114  PCI-9114\n# 2-16 MB SRAM, 4x UART, I2C, misc I/O\n\ta001  ADi-BSEC\n# nee Loronix Information Systems Inc.\n144b  Verint Systems Inc.\n144c  Catalina Research Inc\n144d  Samsung Electronics Co Ltd\n\t1600  Apple PCIe SSD\n\ta800  XP941 PCIe SSD\n\ta802  NVMe SSD Controller SM951/PM951\n\ta804  NVMe SSD Controller SM961/PM961\n\ta808  NVMe SSD Controller SM981/PM981/PM983\n\t\t1d49 403b  Thinksystem U.2 PM983 NVMe SSD\n\ta820  NVMe SSD Controller 171X\n\t\t1028 1f95  Express Flash NVMe XS1715 SSD 400GB\n\t\t1028 1f96  Express Flash NVMe XS1715 SSD 800GB\n\t\t1028 1f97  Express Flash NVMe XS1715 SSD 1600GB\n\t\t1028 1fa4  Express Flash NVMe SM1715 3.2TB SFF\n\t\t1028 1fa6  Express Flash NVMe SM1715 3.2TB AIC\n\t\t1028 1fba  Express Flash NVMe SM1715 800GB SFF\n\t\t1028 1fbb  Express Flash NVMe SM1715 1.6TB SFF\n\t\t1028 1fbc  Express Flash NVMe SM1715 1.6TB AIC\n\ta821  NVMe SSD Controller 172X\n\t\t1028 1fb7  Express Flash NVMe PM1725 3.2TB SFF\n\t\t1028 1fb8  Express Flash NVMe PM1725 3.2TB AIC\n\t\t1028 1fb9  Express Flash NVMe PM1725 6.4TB AIC\n\t\t1028 1fc1  Express Flash NVMe PM1725 800GB SFF\n\t\t1028 1fc2  Express Flash NVMe PM1725 1.6TB SFF\n\t\t1028 1fc4  Express Flash NVMe PM1725 1.6TB AIC\n\ta822  NVMe SSD Controller 172Xa/172Xb\n\t\t1014 0621  PCIe3 1.6TB NVMe Flash Adapter II x8\n\t\t1014 0622  PCIe3 3.2TB NVMe Flash Adapter II x8\n\t\t1014 0629  PCIe3 6.4TB NVMe Flash Adapter II x8\n\t\t1014 064a  PCIe3 1.6TB NVMe Flash Adapter III x8\n\t\t1014 064b  PCIe3 3.2TB NVMe Flash Adapter III x8\n\t\t1014 064c  PCIe3 6.4TB NVMe Flash Adapter III x8\n\t\t1028 1fd9  Express Flash PM1725a 800GB SFF\n\t\t1028 1fda  Express Flash PM1725a 1.6TB SFF\n\t\t1028 1fdb  Express Flash PM1725a 3.2TB SFF\n\t\t1028 1fdc  Express Flash PM1725a 6.4TB SFF\n\t\t1028 1fdd  Express Flash PM1725a 1.6TB AIC\n\t\t1028 1fde  Express Flash PM1725a 3.2TB AIC\n\t\t1028 1fdf  Express Flash PM1725a 6.4TB AIC\n\t\t1028 1ff3  Express Flash PM1725b 1.6TB SFF\n\t\t1028 1ff4  Express Flash PM1725b 3.2TB SFF\n\t\t1028 1ff5  Express Flash PM1725b 6.4TB SFF\n\t\t1028 1ff6  Express Flash PM1725b 12.8TB SFF\n\t\t1028 1ff7  Express Flash PM1725b 1.6TB AIC\n\t\t1028 1ff8  Express Flash PM1725b 3.2TB AIC\n\t\t1028 1ff9  Express Flash PM1725b 6.4TB AIC\n\t\t1028 1ffa  Express Flash PM1725b 12.8TB AIC\n144e  OLITEC\n144f  Askey Computer Corp.\n1450  Octave Communications Ind.\n1451  SP3D Chip Design GmBH\n1453  MYCOM Inc\n1454  Altiga Networks\n1455  Logic Plus Plus Inc\n1456  Advanced Hardware Architectures\n1457  Nuera Communications Inc\n1458  Gigabyte Technology Co., Ltd\n1459  DOOIN Electronics\n145a  Escalate Networks Inc\n145b  PRAIM SRL\n145c  Cryptek\n145d  Gallant Computer Inc\n145e  Aashima Technology B.V.\n145f  Baldor Electric Company\n\t0001  NextMove PCI\n1460  DYNARC INC\n1461  Avermedia Technologies Inc\n\ta3ce  M179\n\ta3cf  M179\n\ta836  M115 DVB-T, PAL/SECAM/NTSC Tuner\n\te836  M115S Hybrid Analog/DVB PAL/SECAM/NTSC Tuner\n\tf436  AVerTV Hybrid+FM\n1462  Micro-Star International Co., Ltd. [MSI]\n\taaf0  Radeon RX 580 Gaming X 8G\n1463  Fast Corporation\n1464  Interactive Circuits & Systems Ltd\n1465  GN NETTEST Telecom DIV.\n1466  Designpro Inc.\n1467  DIGICOM SPA\n1468  AMBIT Microsystem Corp.\n1469  Cleveland Motion Controls\n# formerly IFR.\n146a  Aeroflex\n# 1.5 GHz to 3.0 GHz x 1Hz\n\t3010  3010 RF Synthesizer\n\t3a11  3011A PXI RF Synthesizer\n146b  Parascan Technologies Ltd\n146c  Ruby Tech Corp.\n\t1430  FE-1430TX Fast Ethernet PCI Adapter\n146d  Tachyon, INC.\n146e  Williams Electronics Games, Inc.\n146f  Multi Dimensional Consulting Inc\n1470  Bay Networks\n1471  Integrated Telecom Express Inc\n1472  DAIKIN Industries, Ltd\n1473  ZAPEX Technologies Inc\n1474  Doug Carson & Associates\n1475  PICAZO Communications\n1476  MORTARA Instrument Inc\n1477  Net Insight\n1478  DIATREND Corporation\n1479  TORAY Industries Inc\n147a  FORMOSA Industrial Computing\n147b  ABIT Computer Corp.\n\t1084  IP35 [Dark Raider]\n147c  AWARE, Inc.\n147d  Interworks Computer Products\n147e  Matsushita Graphic Communication Systems, Inc.\n147f  NIHON UNISYS, Ltd.\n1480  SCII Telecom\n1481  BIOPAC Systems Inc\n1482  ISYTEC - Integrierte Systemtechnik GmBH\n\t0001  PCI-16 Host Interface for ITC-16\n1483  LABWAY Corporation\n1484  Logic Corporation\n1485  ERMA - Electronic GmBH\n1486  L3 Communications Telemetry & Instrumentation\n1487  MARQUETTE Medical Systems\n1489  KYE Systems Corporation\n148a  OPTO\n148b  INNOMEDIALOGIC Inc.\n148c  Tul Corporation / PowerColor\n148d  DIGICOM Systems, Inc.\n\t1003  HCF 56k Data/Fax Modem\n148e  OSI Plus Corporation\n148f  Plant Equipment, Inc.\n1490  Stone Microsystems PTY Ltd.\n1491  ZEAL Corporation\n1492  Time Logic Corporation\n1493  MAKER Communications\n1494  WINTOP Technology, Inc.\n1495  TOKAI Communications Industry Co. Ltd\n1496  JOYTECH Computer Co., Ltd.\n1497  SMA Regelsysteme GmBH\n\t1497  SMA Technologie AG\n1498  TEWS Technologies GmbH\n\t0330  TPMC816 2 Channel CAN bus controller.\n\t035d  TPMC861 4-Channel Isolated Serial Interface RS422/RS485\n\t0385  TPMC901 Extended CAN bus with 2/4/6 CAN controller\n\t21cc  TCP460 CompactPCI 16 Channel Serial Interface RS232/RS422\n\t21cd  TCP461 CompactPCI 8 Channel Serial Interface RS232/RS422\n\t3064  TPCI100 (2 Slot IndustryPack PCI Carrier)\n\t30c8  TPCI200 4 Slot IndustryPack PCI Carrier\n\t70c8  TPCE200 4 Slot IndustryPack PCIe Carrier\n\t9177  TXMC375 8 channel RS232/RS422/RS485 programmable serial interface\n1499  EMTEC CO., Ltd\n149a  ANDOR Technology Ltd\n149b  SEIKO Instruments Inc\n149c  OVISLINK Corp.\n149d  NEWTEK Inc\n\t0001  Video Toaster for PC\n149e  Mapletree Networks Inc.\n149f  LECTRON Co Ltd\n14a0  SOFTING GmBH\n14a1  Systembase Co Ltd\n14a2  Millennium Engineering Inc\n14a3  Maverick Networks\n14a4  Lite-On Technology Corporation\n\t22f1  M8Pe Series NVMe SSD\n# Wrong vendor ID used\n\t4318  Broadcom BCM4318 [AirForce One 54g] 802.11g WLAN Controller\n14a5  XIONICS Document Technologies Inc\n14a6  INOVA Computers GmBH & Co KG\n14a7  MYTHOS Systems Inc\n14a8  FEATRON Technologies Corporation\n14a9  HIVERTEC Inc\n14aa  Advanced MOS Technology Inc\n14ab  Mentor Graphics Corp.\n14ac  Novaweb Technologies Inc\n14ad  Time Space Radio AB\n14ae  CTI, Inc\n14af  Guillemot Corporation\n\t7102  3D Prophet II MX\n14b0  BST Communication Technology Ltd\n14b1  Nextcom K.K.\n14b2  ENNOVATE Networks Inc\n14b3  XPEED Inc\n\t0000  DSL NIC\n14b4  PHILIPS Business Electronics B.V.\n14b5  Creamware GmBH\n\t0200  Scope\n\t0300  Pulsar\n\t0400  PulsarSRB\n\t0600  Pulsar2\n\t0800  DSP-Board\n\t0900  DSP-Board\n\t0a00  DSP-Board\n\t0b00  DSP-Board\n14b6  Quantum Data Corp.\n14b7  PROXIM Inc\n\t0001  Symphony 4110\n14b8  Techsoft Technology Co Ltd\n14b9  Cisco Aironet Wireless Communications\n\t0001  PC4800\n\t0340  PC4800\n\t0350  350 series 802.11b Wireless LAN Adapter\n\t4500  PC4500\n\t4800  Cisco Aironet 340 802.11b Wireless LAN Adapter/Aironet PC4800\n\ta504  Cisco Aironet Wireless 802.11b\n\ta505  Cisco Aironet CB20a 802.11a Wireless LAN Adapter\n\ta506  Cisco Aironet Mini PCI b/g\n14ba  INTERNIX Inc.\n# ARCNET interface card based on SMSC COM20022 chip and manufactured for SMSC Japan\n\t0600  ARC-PCI/22\n14bb  SEMTECH Corporation\n14bc  Globespan Semiconductor Inc.\n\td002  Pulsar [PCI ADSL Card]\n\td00f  Pulsar [PCI ADSL Card]\n14bd  CARDIO Control N.V.\n14be  L3 Communications\n14bf  SPIDER Communications Inc.\n14c0  COMPAL Electronics Inc\n\t1201  X550 10Gb 2P RJ45 OCP Mezz\n# now owned by CSP, Inc.\n14c1  MYRICOM Inc.\n\t0008  Myri-10G Dual-Protocol NIC\n\t\t14c1 0008  10G-PCIE-8A\n\t\t14c1 0009  10G-PCIE-8A (MSI-X firmware)\n\t\t14c1 000a  10G-PCIE-8B\n\t8043  Myrinet 2000 Scalable Cluster Interconnect\n\t\t103c 1240  Myrinet M2L-PCI64/2-3.0 LANai 7.4 (HP OEM)\n14c2  DTK Computer\n14c3  MEDIATEK Corp.\n\t7630  MT7630e 802.11bgn Wireless Network Adapter\n# MT7612E too?\n\t7662  MT7662E 802.11ac PCI Express Wireless Network Adapter\n14c4  IWASAKI Information Systems Co Ltd\n14c5  Automation Products AB\n14c6  Data Race Inc\n14c7  Modular Technology Holdings Ltd\n14c8  Turbocomm Tech. Inc.\n14c9  ODIN Telesystems Inc\n14ca  PE Logic Corp.\n14cb  Billionton Systems Inc\n14cc  NAKAYO Telecommunications Inc\n14cd  Universal Global Scientific Industrial Co.,Ltd\n\t0001  USI-1514-1GbaseT [OCP1]\n\t0002  USI-4227-SFP [OCP2]\n\t0003  USI-X557-10GbaseT [OCP3]\n14ce  Whistle Communications\n14cf  TEK Microsystems Inc.\n14d0  Ericsson Axe R & D\n14d1  Computer Hi-Tech Co Ltd\n14d2  Titan Electronics Inc\n\t8001  VScom 010L 1 port parallel adaptor\n\t8002  VScom 020L 2 port parallel adaptor\n\t8010  VScom 100L 1 port serial adaptor\n\t8011  VScom 110L 1 port serial and 1 port parallel adaptor\n\t8020  VScom 200L 1 or 2 port serial adaptor\n\t8021  VScom 210L 2 port serial and 1 port parallel adaptor\n\t8028  VScom 200I/200I-SI 2-port serial adapter\n\t8040  VScom 400L 4 port serial adaptor\n\t8043  VScom 430L 4-port serial and 3-port parallel adapter\n\t8048  VScom 400I 4-port serial adapter\n\t8080  VScom 800L 8 port serial adaptor\n\t8088  VScom 800I 8-port serial adapter\n\ta000  VScom 010H 1 port parallel adaptor\n\ta001  VScom 100H 1 port serial adaptor\n\ta003  VScom 400H 4 port serial adaptor\n\ta004  VScom 400HF1 4 port serial adaptor\n\ta005  VScom 200H 2 port serial adaptor\n\ta007  VScom PCI800EH (PCIe) 8-port serial adapter Port 1-4\n\ta008  VScom PCI800EH (PCIe) 8-port serial adapter Port 5-8\n\ta009  VScom PCI400EH (PCIe) 4-port serial adapter\n\te001  VScom 010HV2 1 port parallel adaptor\n\te010  VScom 100HV2 1 port serial adaptor\n\te020  VScom 200HV2 2 port serial adaptor\n14d3  CIRTECH (UK) Ltd\n\t0002  DTL-T14000 Rev. 1 [PS2 TOOL CD/DVD Emulator]\n\t0003  DTL-T14000 Rev. 2 [PS2 TOOL CD/DVD Emulator]\n\t0004  DTL-T14000 Rev. 3 [PS2 TOOL CD/DVD Emulator]\n14d4  Panacom Technology Corp\n14d5  Nitsuko Corporation\n14d6  Accusys Inc\n\t6101  ACS-61xxx, PCIe to SAS/SATA RAID HBA\n\t6201  ACS-62xxx, External PCIe to SAS/SATA RAID controller\n14d7  Hirakawa Hewtech Corp\n14d8  HOPF Elektronik GmBH\n# Formerly SiPackets, Inc., formerly API NetWorks, Inc., formerly Alpha Processor, Inc.\n14d9  Alliance Semiconductor Corporation\n\t0010  AP1011/SP1011 HyperTransport-PCI Bridge [Sturgeon]\n\t9000  AS90L10204/10208 HyperTransport to PCI-X Bridge\n14da  National Aerospace Laboratories\n14db  AFAVLAB Technology Inc\n\t2120  TK9902\n\t2182  AFAVLAB Technology Inc. 8-port serial card\n14dc  Amplicon Liveline Ltd\n\t0000  PCI230\n\t0001  PCI242\n\t0002  PCI244\n\t0003  PCI247\n\t0004  PCI248\n\t0005  PCI249\n\t0006  PCI260\n\t0007  PCI224\n\t0008  PCI234\n\t0009  PCI236\n\t000a  PCI272\n\t000b  PCI215\n14dd  Boulder Design Labs Inc\n14de  Applied Integration Corporation\n14df  ASIC Communications Corp\n14e1  INVERTEX\n14e2  INFOLIBRIA\n14e3  AMTELCO\n14e4  Broadcom Inc. and subsidiaries\n\t0576  BCM43224 802.11a/b/g/n\n\t0800  Sentry5 Chipcommon I/O Controller\n\t0804  Sentry5 PCI Bridge\n\t0805  Sentry5 MIPS32 CPU\n\t0806  Sentry5 Ethernet Controller\n\t080b  Sentry5 Crypto Accelerator\n\t080f  Sentry5 DDR/SDR RAM Controller\n\t0811  Sentry5 External Interface Core\n\t0816  BCM3302 Sentry5 MIPS32 CPU\n\t1570  720p FaceTime HD Camera\n\t1600  NetXtreme BCM5752 Gigabit Ethernet PCI Express\n\t\t1028 01c1  Precision 490\n\t\t1028 01c2  Latitude D620\n\t\t103c 3015  PCIe LAN on Motherboard\n\t\t107b 5048  E4500 Onboard\n\t\t1259 2705  AT-2711FX\n\t1601  NetXtreme BCM5752M Gigabit Ethernet PCI Express\n\t1604  BCM5745X NetXtreme-E Ethernet Partition\n\t1605  BCM5745X NetXtreme-E RDMA Partition\n\t1606  BCM5745X NetXtreme-E RDMA Virtual Function\n\t1609  BCM5745X NetXtreme-E Ethernet Virtual Function\n\t1612  BCM70012 Video Decoder [Crystal HD]\n\t1614  BCM57454 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet\n\t1615  BCM70015 Video Decoder [Crystal HD]\n\t1639  NetXtreme II BCM5709 Gigabit Ethernet\n\t\t1028 0235  PowerEdge R710 BCM5709 Gigabit Ethernet\n\t\t1028 0236  PowerEdge R610 BCM5709 Gigabit Ethernet\n\t\t1028 0237  PowerEdge T610 BCM5709 Gigabit Ethernet\n\t\t103c 7055  NC382i Integrated Multi-port PCI Express Gigabit Server Adapter\n\t\t103c 7059  NC382T PCIe Dual Port Multifunction Gigabit Server Adapter\n\t\t10a9 8027  Quad port Gigabit Ethernet Controller\n\t163a  NetXtreme II BCM5709S Gigabit Ethernet\n\t\t1028 027b  PowerEdge M805 Broadcom NetXtreme II BCM5709S\n\t\t1028 029c  PowerEdge M710 BCM5709S Gigabit Ethernet\n\t\t103c 171d  NC382m Dual Port 1GbE Multifunction BL-c Adapter\n\t\t103c 7056  NC382i Integrated Quad Port PCI Express Gigabit Server Adapter\n\t\t1259 2984  AT-2973SX\n\t163b  NetXtreme II BCM5716 Gigabit Ethernet\n\t\t1028 028c  PowerEdge R410 BCM5716 Gigabit Ethernet\n\t\t1028 028d  PowerEdge T410 BCM5716 Gigabit Ethernet\n\t\t1028 02f1  PowerEdge R510 BCM5716 Gigabit Ethernet\n\t163c  NetXtreme II BCM5716S Gigabit Ethernet\n\t163d  NetXtreme II BCM57811 10-Gigabit Ethernet\n\t\t1043 858a  PEB-10G/57811-1S\n\t163e  NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function\n\t163f  NetXtreme II BCM57811 10-Gigabit Ethernet Virtual Function\n\t1641  NetXtreme BCM57787 Gigabit Ethernet PCIe\n\t1642  NetXtreme BCM57764 Gigabit Ethernet PCIe\n\t1643  NetXtreme BCM5725 Gigabit Ethernet PCIe\n\t1644  NetXtreme BCM5700 Gigabit Ethernet\n\t\t1014 0277  Broadcom Vigil B5700 1000Base-T\n\t\t1028 00d1  Broadcom BCM5700\n\t\t1028 0106  Broadcom BCM5700\n\t\t1028 0109  Broadcom BCM5700 1000Base-T\n\t\t1028 010a  Broadcom BCM5700 1000BaseTX\n\t\t10b7 1000  3C996-T 1000Base-T\n\t\t10b7 1001  3C996B-T 1000Base-T\n\t\t10b7 1002  3C996C-T 1000Base-T\n\t\t10b7 1003  3C997-T 1000Base-T Dual Port\n\t\t10b7 1004  3C996-SX 1000Base-SX\n\t\t10b7 1005  3C997-SX 1000Base-SX Dual Port\n\t\t10b7 1008  3C942 Gigabit LOM (31X31)\n\t\t14e4 0002  NetXtreme 1000Base-SX\n\t\t14e4 0003  NetXtreme 1000Base-SX\n\t\t14e4 0004  NetXtreme 1000Base-T\n\t\t14e4 1028  NetXtreme 1000BaseTX\n\t\t14e4 1644  BCM5700 1000Base-T\n\t1645  NetXtreme BCM5701 Gigabit Ethernet\n\t\t0e11 007c  NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T)\n\t\t0e11 007d  NC6770 Gigabit Server Adapter (PCI-X, 1000-SX)\n\t\t0e11 0085  NC7780 Gigabit Server Adapter (embedded, WOL)\n\t\t0e11 0099  NC7780 Gigabit Server Adapter (embedded, WOL)\n\t\t0e11 009a  NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T)\n\t\t0e11 00c1  NC6770 Gigabit Server Adapter (PCI-X, 1000-SX)\n\t\t1028 0121  Broadcom BCM5701 1000Base-T\n\t\t103c 128a  BCM5701 1000Base-T (HP, OEM 3COM)\n\t\t103c 128b  1000Base-SX (PCI) [A7073A]\n\t\t103c 12a4  Core Lan 1000Base-T\n\t\t103c 12c1  IOX Core Lan 1000Base-T [A7109AX]\n\t\t103c 1300  Core LAN/SCSI Combo [A6794A]\n\t\t10a9 8010  IO9/IO10 Gigabit Ethernet (Copper)\n\t\t10a9 8011  Gigabit Ethernet (Copper)\n\t\t10a9 8012  Gigabit Ethernet (Fiber)\n\t\t10b7 1004  3C996-SX 1000Base-SX\n\t\t10b7 1006  3C996B-T 1000Base-T\n\t\t10b7 1007  3C1000-T 1000Base-T\n\t\t10b7 1008  3C940-BR01 1000Base-T\n\t\t14e4 0001  BCM5701 1000Base-T\n\t\t14e4 0005  BCM5701 1000Base-T\n\t\t14e4 0006  BCM5701 1000Base-T\n\t\t14e4 0007  BCM5701 1000Base-SX\n\t\t14e4 0008  BCM5701 1000Base-T\n\t\t14e4 1645  NetXtreme BCM5701 Gigabit Ethernet\n\t\t14e4 8008  BCM5701 1000Base-T\n\t1646  NetXtreme BCM5702 Gigabit Ethernet\n\t\t0e11 00bb  NC7760 1000BaseTX\n\t\t1028 0126  Broadcom BCM5702 1000BaseTX\n\t\t14e4 8009  BCM5702 1000BaseTX\n\t1647  NetXtreme BCM5703 Gigabit Ethernet\n\t\t0e11 0099  NC7780 1000BaseTX\n\t\t0e11 009a  NC7770 1000BaseTX\n\t\t10a9 8010  IO9 Gigabit Ethernet (Copper)\n\t\t14e4 0009  BCM5703 1000BaseTX\n\t\t14e4 000a  BCM5703 1000BaseSX\n\t\t14e4 000b  BCM5703 1000BaseTX\n\t\t14e4 8009  BCM5703 1000BaseTX\n\t\t14e4 800a  BCM5703 1000BaseTX\n\t1648  NetXtreme BCM5704 Gigabit Ethernet\n\t\t0e11 00cf  NC7772 Gigabit Server Adapter (PCI-X, 10,100,1000-T)\n\t\t0e11 00d0  NC7782 Gigabit Server Adapter (PCI-X, 10,100,1000-T)\n\t\t0e11 00d1  NC7783 Gigabit Server Adapter (PCI-X, 10,100,1000-T)\n\t\t1028 014a  PowerEdge 1750\n\t\t1028 0170  PowerEdge 6850 Broadcom NetXtreme BCM5704\n\t\t103c 310f  NC7782 Gigabit Server Adapter (PCI-X, 10,100,1000-T)\n\t\t10a9 8013  Dual Port Gigabit Ethernet (PCI-X,Copper)\n\t\t10a9 8018  Dual Port Gigabit Ethernet (A330)\n\t\t10a9 801a  Dual Port Gigabit Ethernet (IA-blade)\n\t\t10a9 801b  Quad Port Gigabit Ethernet (PCI-E,Copper)\n\t\t10b7 2000  3C998-T Dual Port 10/100/1000 PCI-X\n\t\t10b7 3000  3C999-T Quad Port 10/100/1000 PCI-X\n\t\t1166 1648  NetXtreme CIOB-E 1000Base-T\n\t\t1734 100b  PRIMERGY RX/TX series onboard LAN\n\t1649  NetXtreme BCM5704S_2 Gigabit Ethernet\n\t164a  NetXtreme II BCM5706 Gigabit Ethernet\n\t\t103c 1709  NC371i Integrated PCI-X Multifunction Gigabit Server Adapter\n\t\t103c 3070  NC380T PCI Express Dual Port Multifunction Gigabit Server Adapter\n\t\t103c 3101  NC370T MultifuNCtion Gigabit Server Adapter\n\t\t103c 3106  NC370i Multifunction Gigabit Server Adapter\n\t164c  NetXtreme II BCM5708 Gigabit Ethernet\n\t\t1028 01f0  PowerEdge R900 Broadcom NetXtreme II BCM5708\n\t\t1028 0205  PowerEdge 2970 Broadcom NetXtreme II BCM5708\n\t\t1028 020b  PowerEdge T605 Broadcom NetXtreme II BCM5708\n\t\t1028 0221  PowerEdge R805 Broadcom NetXtreme II BCM5708\n\t\t1028 0223  PowerEdge R905 Broadcom NetXtreme II BCM5708\n\t\t1028 1f12  PowerEdge R805/R905 Broadcom NetXtreme II BCM5708\n\t\t103c 7037  NC373T PCI Express Multifunction Gigabit Server Adapter\n\t\t103c 7038  NC373i Integrated Multifunction Gigabit Server Adapter\n\t\t103c 7045  NC374m PCI Express Dual Port Multifunction Gigabit Server Adapter\n\t164d  NetXtreme BCM5702FE Gigabit Ethernet\n\t164e  NetXtreme II BCM57710 10-Gigabit PCIe [Everest]\n\t\t103c 171c  NC532m Dual Port 10GbE Multifunction BL-C Adapter\n\t\t103c 7058  NC532i Dual Port 10GbE Multifunction BL-C Adapter\n\t164f  NetXtreme II BCM57711 10-Gigabit PCIe\n\t1650  NetXtreme II BCM57711E 10-Gigabit PCIe\n\t\t103c 171c  NC532m Dual Port 10GbE Multifunction BL-C Adapter\n\t\t103c 7058  NC532i Dual Port 10GbE Multifunction BL-C Adapter\n\t1653  NetXtreme BCM5705 Gigabit Ethernet\n\t\t0e11 00e3  NC7761 Gigabit Server Adapter\n\t\t1734 1073  Primergy Econel 200 D2020 mainboard\n\t1654  NetXtreme BCM5705_2 Gigabit Ethernet\n\t\t0e11 00e3  NC7761 Gigabit Server Adapter\n\t\t103c 3100  NC1020 ProLiant Gigabit Server Adapter 32 PCI\n\t\t103c 3226  NC150T 4-port Gigabit Combo Switch & Adapter\n\t1655  NetXtreme BCM5717 Gigabit Ethernet PCIe\n\t1656  NetXtreme BCM5718 Gigabit Ethernet PCIe\n\t1657  NetXtreme BCM5719 Gigabit Ethernet PCIe\n\t\t1014 0420  FC 5260/5899 4-port 1 GbE Adapter for Power\n\t\t103c 169d  Ethernet 1Gb 4-port 331FLR Adapter\n\t\t103c 22be  Ethernet 1Gb 4-port 331i Adapter\n\t\t103c 3383  Ethernet 1Gb 4-port 331T Adapter\n\t\t14e4 1904  4-port 1Gb Ethernet Adapter\n\t1659  NetXtreme BCM5721 Gigabit Ethernet PCI Express\n\t\t1014 02c6  eServer xSeries server mainboard\n\t\t1028 01e6  PowerEdge 860\n\t\t1028 023c  PowerEdge R200 Broadcom NetXtreme BCM5721\n\t\t103c 170b  NC320m PCI Express Dual Port Gigabit Server Adapter\n\t\t103c 7031  NC320T PCIe Gigabit Server Adapter\n\t\t103c 7032  NC320i PCIe Gigabit Server Adapter\n\t\t1734 1061  PRIMERGY RX/TX S2 series onboard LAN\n\t165a  NetXtreme BCM5722 Gigabit Ethernet PCI Express\n# Dual NIC server\n\t\t1014 0378  System x3350 (Machine type 4192)\n\t\t1028 020f  PowerEdge R300 Broadcom NetXtreme 5722\n\t\t1028 0210  PowerEdge T300 Broadcom NetXtreme 5722\n\t\t1028 0225  PowerEdge T105 Broadcom NetXtreme 5722\n\t\t103c 7051  NC105i PCIe Gigabit Server Adapter\n\t\t103c 7052  NC105T PCIe Gigabit Server Adapter\n\t165b  NetXtreme BCM5723 Gigabit Ethernet PCIe\n\t\t103c 705d  NC107i Integrated PCI Express Gigabit Server Adapter\n\t165c  NetXtreme BCM5724 Gigabit Ethernet PCIe\n\t165d  NetXtreme BCM5705M Gigabit Ethernet\n\t\t1028 865d  Latitude D400\n\t\t14e4 165d  Dell Latitude D600\n\t165e  NetXtreme BCM5705M_2 Gigabit Ethernet\n\t\t103c 088c  NC8000 laptop\n\t\t103c 0890  NC6000 laptop\n\t\t103c 099c  NX6110/NC6120\n\t\t10cf 1279  LifeBook E8010D\n\t165f  NetXtreme BCM5720 2-port Gigabit Ethernet PCIe\n\t\t1028 04f7  PowerEdge R320 server\n\t\t1028 08fd  PowerEdge R6515/R7515 LOM\n\t\t1028 08ff  PowerEdge Rx5xx LOM Board\n\t\t1028 0900  PowerEdge C6525 LOM\n\t\t103c 1786  NC332T Adapter\n\t\t103c 193d  NC332i Adapter\n\t\t103c 2133  NC332i Adapter\n\t\t103c 22e8  NC332i Adapter\n\t\t103c 22eb  NC332i Adapter\n\t1662  NetXtreme II BCM57712 10 Gigabit Ethernet\n\t1663  NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function\n\t1665  NetXtreme BCM5717 Gigabit Ethernet PCIe\n\t1668  NetXtreme BCM5714 Gigabit Ethernet\n\t\t103c 7039  NC324i PCIe Dual Port Gigabit Server Adapter\n\t1669  NetXtreme 5714S Gigabit Ethernet\n\t166a  NetXtreme BCM5780 Gigabit Ethernet\n\t\t103c 7035  NC325i Integrated Dual port PCIe Express Gigabit Server Adapter\n\t166b  NetXtreme BCM5780S Gigabit Ethernet\n\t166e  570x 10/100 Integrated Controller\n\t166f  NetXtreme II BCM57712 10 Gigabit Ethernet Virtual Function\n\t1672  NetXtreme BCM5754M Gigabit Ethernet PCI Express\n\t1673  NetXtreme BCM5755M Gigabit Ethernet PCI Express\n\t1674  NetXtreme BCM5756ME Gigabit Ethernet PCI Express\n\t1677  NetXtreme BCM5751 Gigabit Ethernet PCI Express\n\t\t1028 0176  Dimension XPS Gen 4\n\t\t1028 0177  Dimension 8400\n\t\t1028 0179  Optiplex GX280\n\t\t1028 0182  Latitude D610\n\t\t1028 0187  Precision M70\n\t\t1028 01a3  Latitude X1\n\t\t1028 01a8  Precision 380\n\t\t1028 01ad  OptiPlex GX620\n\t\t103c 3006  DC7100 SFF(DX878AV)\n\t\t1462 028c  915P/G Neo2\n\t\t1734 105d  Scenic W620\n\t1678  NetXtreme BCM5715 Gigabit Ethernet\n\t\t103c 703e  NC326i PCIe Dual Port Gigabit Server Adapter\n\t1679  NetXtreme BCM5715S Gigabit Ethernet\n\t\t103c 1707  NC326m PCIe Dual Port Adapter\n\t\t103c 170c  NC325m PCIe Quad Port Adapter\n\t\t103c 703c  NC326i PCIe Dual Port Gigabit Server Adapter\n\t167a  NetXtreme BCM5754 Gigabit Ethernet PCI Express\n\t\t1028 01da  OptiPlex 745\n\t\t1028 01de  Precision 390\n\t\t1028 01df  PowerEdge SC440\n\t\t1028 0214  Precision T3400\n\t\t1028 021e  Precision T5400\n\t167b  NetXtreme BCM5755 Gigabit Ethernet PCI Express\n\t\t103c 280a  DC5750 Microtower\n\t167d  NetXtreme BCM5751M Gigabit Ethernet PCI Express\n\t\t1014 0577  ThinkPad X41 / Z60t\n\t\t103c 0934  nx8220\n\t\t103c 0940  Compaq nw8240 Mobile Workstation\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t17aa 2081  ThinkPad R60e\n\t167e  NetXtreme BCM5751F Fast Ethernet PCI Express\n\t167f  NetLink BCM5787F Fast Ethernet PCI Express\n\t1680  NetXtreme BCM5761e Gigabit Ethernet PCIe\n\t1681  NetXtreme BCM5761 Gigabit Ethernet PCIe\n\t1682  NetXtreme BCM57762 Gigabit Ethernet PCIe\n\t\t106b 00f6  Thunderbolt to Gigabit Ethernet Adapter\n\t1683  NetXtreme BCM57767 Gigabit Ethernet PCIe\n\t1684  NetXtreme BCM5764M Gigabit Ethernet PCIe\n\t1685  NetXtreme II BCM57500S Gigabit Ethernet\n\t1686  NetXtreme BCM57766 Gigabit Ethernet PCIe\n\t1687  NetXtreme BCM5762 Gigabit Ethernet PCIe\n\t1688  NetXtreme BCM5761 10/100/1000BASE-T Ethernet\n\t\t1259 2708  AT-2712 FX\n# The Broadcom 57800 device has two 1Gig ports and two 10Gig ports. The subsystem information can be used to differentiate.\n\t168a  NetXtreme II BCM57800 1/10 Gigabit Ethernet\n\t\t1028 1f5c  BCM57800 10-Gigabit Ethernet\n\t\t1028 1f5d  BCM57800 10-Gigabit Ethernet\n\t\t1028 1f67  BCM57800 1-Gigabit Ethernet\n\t\t1028 1f68  BCM57800 1-Gigabit Ethernet\n\t168d  NetXtreme II BCM57840 10/20 Gigabit Ethernet\n\t168e  NetXtreme II BCM57810 10 Gigabit Ethernet\n\t\t1014 0492  PCIe2 2-port 10 GbE BaseT RJ45 Adapter (FC EN0W; CCIN 2CC4)\n\t\t103c 1798  Flex-10 10Gb 2-port 530FLB Adapter [Meru]\n\t\t103c 17a5  Flex-10 10Gb 2-port 530M Adapter\n\t\t103c 18d3  Ethernet 10Gb 2-port 530T Adapter\n\t\t103c 1930  FlexFabric 10Gb 2-port 534FLR-SFP+ Adapter\n\t\t103c 1931  StoreFabric CN1100R Dual Port Converged Network Adapter\n\t\t103c 1932  FlexFabric 10Gb 2-port 534FLB Adapter\n\t\t103c 1933  FlexFabric 10Gb 2-port 534M Adapter\n\t\t103c 193a  FlexFabric 10Gb 2-port 533FLR-T Adapter\n\t\t103c 3382  Ethernet 10Gb 2-port 530FLR-SFP+ Adapter\n\t\t103c 339d  Ethernet 10Gb 2-port 530SFP+ Adapter\n\t\t193d 1003  530F-B\n\t\t193d 1006  530F-L\n\t1690  NetXtreme BCM57760 Gigabit Ethernet PCIe\n\t1691  NetLink BCM57788 Gigabit Ethernet PCIe\n\t\t1028 04aa  XPS 8300\n\t1692  NetLink BCM57780 Gigabit Ethernet PCIe\n\t\t1025 033d  Aspire 7740G\n\t1693  NetLink BCM5787M Gigabit Ethernet PCI Express\n\t\t1025 0121  Aspire 5920G\n\t\t103c 30c0  6710b\n\t\t17aa 20d5  ThinkPad R61\n\t1694  NetLink BCM57790 Gigabit Ethernet PCIe\n\t1696  NetXtreme BCM5782 Gigabit Ethernet\n\t\t103c 12bc  d530 CMT (DG746A)\n\t\t14e4 000d  NetXtreme BCM5782 1000Base-T\n\t1698  NetLink BCM5784M Gigabit Ethernet PCIe\n\t1699  NetLink BCM5785 Gigabit Ethernet\n\t169a  NetLink BCM5786 Gigabit Ethernet PCI Express\n\t169b  NetLink BCM5787 Gigabit Ethernet PCI Express\n\t169c  NetXtreme BCM5788 Gigabit Ethernet\n\t\t103c 308b  MX6125\n\t\t103c 30a1  NC2400\n\t\t144d c018  X20\n\t\t1462 590c  KT6 Delta-FIS2R (MS-6590)\n\t169d  NetLink BCM5789 Gigabit Ethernet PCI Express\n\t16a0  NetLink BCM5785 Fast Ethernet\n\t16a1  BCM57840 NetXtreme II 10 Gigabit Ethernet\n\t\t1043 866e  PEB-10G/57840-2T 10GBase-T Network Adapter\n\t16a2  BCM57840 NetXtreme II 10/20-Gigabit Ethernet\n\t\t103c 1916  FlexFabric 20Gb 2-port 630FLB Adapter\n\t\t103c 1917  FlexFabric 20Gb 2-port 630M Adapter\n\t\t103c 2231  3820C 10/20Gb Converged Network Adapter\n\t\t103c 22fa  FlexFabric 10Gb 2-port 536FLB Adapter\n\t16a3  NetXtreme BCM57786 Gigabit Ethernet PCIe\n\t16a4  BCM57840 NetXtreme II Ethernet Multi Function\n\t\t103c 1916  NPAR 20Gb 2-port 630FLB Adapter\n\t\t103c 1917  NPAR 20Gb 2-port 630M Adapter\n\t\t103c 2231  3820C 10/20Gb Converged Network Adapter (NPAR 1.5)\n\t\t103c 22fa  FlexFabric 10Gb 2-port 536FLB Adapter (NPAR 1.5)\n# The Broadcom 57800 device has two 1Gig ports and two 10Gig ports. The subsystem information can be used to differentiate.\n\t16a5  NetXtreme II BCM57800 1/10 Gigabit Ethernet Multi Function\n\t\t1028 1f5c  NetXtreme II BCM57800 10-Gigabit Ethernet Multi Function\n\t\t1028 1f5d  NetXtreme II BCM57800 10-Gigabit Ethernet Multi Function\n\t\t1028 1f67  NetXtreme II BCM57800 1-Gigabit Ethernet Multi Function\n\t\t1028 1f68  NetXtreme II BCM57800 1-Gigabit Ethernet Multi Function\n\t16a6  NetXtreme BCM5702X Gigabit Ethernet\n\t\t0e11 00bb  NC7760 Gigabit Server Adapter (PCI-X, 10/100/1000-T)\n\t\t1028 0126  BCM5702 1000Base-T\n\t\t14e4 000c  BCM5702 1000Base-T\n\t\t14e4 8009  BCM5702 1000Base-T\n\t16a7  NetXtreme BCM5703X Gigabit Ethernet\n\t\t0e11 00ca  NC7771 Gigabit Server Adapter (PCI-X, 10,100,1000-T)\n\t\t0e11 00cb  NC7781 Gigabit Server Adapter (PCI-X, 10,100,1000-T)\n\t\t1014 026f  eServer xSeries server mainboard\n\t\t14e4 0009  NetXtreme BCM5703 1000Base-T\n\t\t14e4 000a  NetXtreme BCM5703 1000Base-SX\n\t\t14e4 000b  NetXtreme BCM5703 1000Base-T\n\t\t14e4 800a  NetXtreme BCM5703 1000Base-T\n\t16a8  NetXtreme BCM5704S Gigabit Ethernet\n\t\t103c 132b  PCI-X 1000Mbps Dual-port Built-in\n\t\t10a9 8014  Dual Port Gigabit Ethernet (PCI-X,Fiber)\n\t\t10a9 801c  Quad Port Gigabit Ethernet (PCI-E,Fiber)\n\t\t10b7 2001  3C998-SX Dual Port 1000-SX PCI-X\n# The Broadcom 57800 device has two 1Gig ports and two 10Gig ports. The subsystem information can be used to differentiate.\n\t16a9  NetXtreme II BCM57800 1/10 Gigabit Ethernet Virtual Function\n\t\t1028 1f5c  NetXtreme II BCM57800 10-Gigabit Ethernet Virtual Function\n\t\t1028 1f5d  NetXtreme II BCM57800 10-Gigabit Ethernet Virtual Function\n\t\t1028 1f67  NetXtreme II BCM57800 1-Gigabit Ethernet Virtual Function\n\t\t1028 1f68  NetXtreme II BCM57800 1-Gigabit Ethernet Virtual Function\n\t16aa  NetXtreme II BCM5706S Gigabit Ethernet\n\t\t103c 3102  NC370F MultifuNCtion Gigabit Server Adapter\n\t\t103c 310c  NC370i Multifunction Gigabit Server Adapter\n\t16ab  NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function\n\t16ac  NetXtreme II BCM5708S Gigabit Ethernet\n\t\t1014 0304  NetXtreme II BCM5708S Gigabit Ethernet\n\t\t1028 01bb  PowerEdge 1955 Broadcom NetXtreme II BCM5708S\n\t\t1028 020c  PowerEdge M605 Broadcom NetXtreme II BCM5708S\n\t\t103c 1706  NC373m Multifunction Gigabit Server Adapter\n\t\t103c 7038  NC373i PCI Express Multifunction Gigabit Server Adapter\n\t\t103c 703b  NC373i Integrated Multifunction Gigabit Server Adapter\n\t\t103c 703d  NC373F PCI Express Multifunction Gigabit Server Adapter\n\t16ad  NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function\n\t\t103c 1916  FlexFabric 20Gb 2-port 630FLB Adapter\n\t\t103c 1917  FlexFabric 20Gb 2-port 630M Adapter\n\t\t103c 2231  3820C 10/20Gb Converged Network Adapter (SR-IOV VF)\n\t\t103c 22fa  FlexFabric 10Gb 2-port 536FLB Adapter (SR-IOV VF)\n\t16ae  NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function\n\t\t103c 1798  NPAR 10Gb 2-port 530FLB Adapter\n\t\t103c 17a5  NPAR 10Gb 2-port 530M Adapter\n\t\t103c 18d3  NPAR 10Gb 2-port 530T Adapter\n\t\t103c 1930  NPAR 10Gb 2-port 534FLR-SFP+ Adapter\n\t\t103c 1931  NPAR CN1100R Dual Port Converged Network Adapter\n\t\t103c 1932  NPAR 10Gb 2-port 534FLB Adapter\n\t\t103c 1933  NPAR 10Gb 2-port 534M Adapter\n\t\t103c 193a  NPAR 10Gb 2-port 533FLR-T Adapter\n\t\t103c 3382  NPAR 10Gb 2-port 530FLR-SFP+ Adapter\n\t\t103c 339d  NPAR 10Gb 2-port 530SFP+ Adapter\n\t16af  NetXtreme II BCM57810 10 Gigabit Ethernet Virtual Function\n\t\t103c 1798  Flex-10 10Gb 2-port 530FLB Adapter\n\t\t103c 17a5  Flex-10 10Gb 2-port 530M Adapter\n\t\t103c 18d3  Ethernet 10Gb 2-port 530T Adapter\n\t\t103c 1930  FlexFabric 10Gb 2-port 534FLR-SFP+ Adapter\n\t\t103c 1931  StoreFabric CN1100R Dual Port Converged Network Adapter\n\t\t103c 1932  FlexFabric 10Gb 2-port 534FLB Adapter\n\t\t103c 1933  FlexFabric 10Gb 2-port 534M Adapter\n\t\t103c 193a  FlexFabric 10Gb 2-port 533FLR-T Adapter\n\t\t103c 3382  Ethernet 10Gb 2-port 530FLR-SFP+ Adapter\n\t\t103c 339d  Ethernet 10Gb 2-port 530SFP+ Adapter\n\t16b0  NetXtreme BCM57761 Gigabit Ethernet PCIe\n\t16b1  NetLink BCM57781 Gigabit Ethernet PCIe\n\t\t1849 96b1  Z77 Extreme4 motherboard\n\t16b2  NetLink BCM57791 Gigabit Ethernet PCIe\n\t16b3  NetXtreme BCM57786 Gigabit Ethernet PCIe\n\t16b4  NetXtreme BCM57765 Gigabit Ethernet PCIe\n\t16b5  NetLink BCM57785 Gigabit Ethernet PCIe\n\t16b6  NetLink BCM57795 Gigabit Ethernet PCIe\n\t16b7  NetXtreme BCM57782 Gigabit Ethernet PCIe\n\t16bc  BCM57765/57785 SDXC/MMC Card Reader\n\t16be  BCM57765/57785 MS Card Reader\n\t16bf  BCM57765/57785 xD-Picture Card Reader\n\t16c1  NetXtreme-E RDMA Virtual Function\n\t16c6  NetXtreme BCM5702A3 Gigabit Ethernet\n\t\t10b7 1100  3C1000B-T 10/100/1000 PCI\n\t\t14e4 000c  BCM5702 1000Base-T\n\t\t14e4 8009  BCM5702 1000Base-T\n\t16c7  NetXtreme BCM5703 Gigabit Ethernet\n\t\t0e11 00ca  NC7771 Gigabit Server Adapter (PCI-X, 10,100,1000-T)\n\t\t0e11 00cb  NC7781 Gigabit Server Adapter (PCI-X, 10,100,1000-T)\n\t\t103c 12c3  Combo FC/GigE-SX [A9782A]\n\t\t103c 12ca  Combo FC/GigE-T [A9784A]\n\t\t103c 1321  Core I/O LAN/SCSI Combo [AB314A]\n\t\t14e4 0009  NetXtreme BCM5703 1000Base-T\n\t\t14e4 000a  NetXtreme BCM5703 1000Base-SX\n\t16c8  BCM57301 NetXtreme-C 10Gb Ethernet Controller\n\t16c9  BCM57302 NetXtreme-C 10Gb/25Gb Ethernet Controller\n\t16ca  BCM57304 NetXtreme-C 10Gb/25Gb/40Gb/50Gb Ethernet Controller\n\t16cb  NetXtreme-C Ethernet Virtual Function\n\t16cc  BCM57417 NetXtreme-E Ethernet Partition\n\t16ce  BCM57311 NetXtreme-C 10Gb RDMA Ethernet Controller\n\t16cf  BCM57312 NetXtreme-C 10Gb/25Gb RDMA Ethernet Controller\n\t16d0  BCM57402 NetXtreme-E 10Gb Ethernet Controller\n\t16d1  BCM57404 NetXtreme-E 10Gb/25Gb Ethernet Controller\n\t16d2  BCM57406 NetXtreme-E 10GBASE-T Ethernet Controller\n\t16d3  NetXtreme-E Ethernet Virtual Function\n\t16d4  BCM57402 NetXtreme-E Ethernet Partition\n\t16d5  BCM57407 NetXtreme-E 10GBase-T Ethernet Controller\n\t16d6  BCM57412 NetXtreme-E 10Gb RDMA Ethernet Controller\n\t\t14e4 4120  NetXtreme E-Series Advanced Dual-port 10Gb SFP+ Ethernet Network Daughter Card\n\t\t152d 8b20  BCM57412 NetXtreme-E 10Gb RDMA Ethernet Controller\n\t\t152d 8b22  BCM57412 NetXtreme-E 25Gb RDMA Ethernet Controller\n\t16d7  BCM57414 NetXtreme-E 10Gb/25Gb RDMA Ethernet Controller\n\t\t14e4 1202  BCM957412M4122C OCP 1x25G Type1 wRoCE\n\t\t14e4 1402  BCM957414A4142CC 10Gb/25Gb Ethernet PCIe\n\t\t14e4 1404  BCM957414M4142C OCP 2x25G Type1 wRoCE\n\t\t14e4 4140  NetXtreme E-Series Advanced Dual-port 25Gb SFP28 Network Daughter Card\n\t\t1590 020e  Ethernet 25Gb 2-port 631SFP28 Adapter\n\t\t1590 0211  Ethernet 25Gb 2-port 631FLR-SFP28 Adapter\n\t16d8  BCM57416 NetXtreme-E Dual-Media 10G RDMA Ethernet Controller\n\t\t1028 1feb  NetXtreme-E 10Gb SFP+ Adapter\n\t\t14e4 4163  BCM957416M4163C OCP 2x10GBT Type1 wRoCE\n\t\t1590 020c  Ethernet 10Gb 2-port 535T Adapter\n\t\t1590 0212  Ethernet 10Gb 2-port 535FLR-T Adapter\n\t16d9  BCM57417 NetXtreme-E 10GBASE-T RDMA Ethernet Controller\n\t\t108e 4866  Dual Port 10GBase-T Ethernet Controller\n\t16dc  NetXtreme-E Ethernet Virtual Function\n\t16dd  NetLink BCM5781 Gigabit Ethernet PCI Express\n\t16de  BCM57412 NetXtreme-E Ethernet Partition\n\t16df  BCM57314 NetXtreme-C 10Gb/25Gb/40Gb/50Gb RDMA Ethernet Controller\n\t16e1  NetXtreme-C Ethernet Virtual Function\n\t16e2  BCM57417 NetXtreme-E 10Gb/25Gb RDMA Ethernet Controller\n\t\t108e 4866  Dual Port 10Gb/25Gb SFP28 Ethernet Controller\n\t16e3  BCM57416 NetXtreme-E 10Gb RDMA Ethernet Controller\n\t16e5  NetXtreme-C RDMA Virtual Function\n\t16e7  BCM57404 NetXtreme-E Ethernet Partition\n\t16e8  BCM57406 NetXtreme-E Ethernet Partition\n\t16e9  BCM57407 NetXtreme-E 25Gb Ethernet Controller\n\t16ec  BCM57414 NetXtreme-E Ethernet Partition\n\t16ed  BCM57414 NetXtreme-E RDMA Partition\n\t16ee  BCM57416 NetXtreme-E Ethernet Partition\n\t16ef  BCM57416 NetXtreme-E RDMA Partition\n\t16f1  BCM57452 NetXtreme-E 10Gb/25Gb/40Gb/50Gb Ethernet\n\t16f3  NetXtreme BCM5727 Gigabit Ethernet PCIe\n\t16f7  NetXtreme BCM5753 Gigabit Ethernet PCI Express\n\t16fd  NetXtreme BCM5753M Gigabit Ethernet PCI Express\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a3  Compaq nw8440\n\t16fe  NetXtreme BCM5753F Fast Ethernet PCI Express\n\t170c  BCM4401-B0 100Base-TX\n\t\t1028 0188  Inspiron 6000 laptop\n\t\t1028 018d  Inspiron 700m/710m\n\t\t1028 0196  Inspiron 5160\n\t\t1028 01af  Inspiron 6400\n\t\t1028 01cd  Inspiron 9400 Laptop\n\t\t1028 01d7  XPS M1210\n\t\t1028 01d8  Inspiron E1405\n\t\t103c 099c  NX6110/NC6120\n\t\t103c 30a2  NX7300 laptop\n\t\t14e4 170c  HP Compaq 6720t Mobile Thin Client\n\t170d  NetXtreme BCM5901 100Base-TX\n\t\t1014 0545  ThinkPad R40e\n\t170e  NetXtreme BCM5901 100Base-TX\n\t1712  NetLink BCM5906 Fast Ethernet PCI Express\n\t1713  NetLink BCM5906M Fast Ethernet PCI Express\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 0209  XPS M1330\n\t\t103c 30c0  Compaq 6710b\n\t\t17aa 3a23  IdeaPad S10e\n\t1750  BCM57508 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet\n\t1751  BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet\n\t1752  BCM57502 NetXtreme-E 10Gb/25Gb/40Gb/50Gb Ethernet\n\t1806  BCM5750X NetXtreme-E Ethernet Virtual Function\n\t1807  BCM5750X NetXtreme-E RDMA Virtual Function\n\t3352  BCM3352\n\t3360  BCM3360\n\t4210  BCM4210 iLine10 HomePNA 2.0\n\t4211  BCM4211 iLine10 HomePNA 2.0 + V.90 56k modem\n\t4212  BCM4212 v.90 56k modem\n\t4220  802-11b/g Wireless PCI controller, packaged as a Linksys WPC54G ver 1.2 PCMCIA card\n\t4222  NetXtreme BCM5753M Gigabit Ethernet PCI Express\n\t4301  BCM4301 802.11b Wireless LAN Controller\n\t\t1028 0407  TrueMobile 1180 Onboard WLAN\n\t\t1043 0120  WL-103b Wireless LAN PC Card\n\t\t16a5 1602  B-300 802.11b Wireless CardBus Adapter\n\t\t1737 4301  WMP11 v2.7 802.11b Wireless-B PCI Adapter\n\t4305  BCM4307 V.90 56k Modem\n\t4306  BCM4306 802.11bg Wireless LAN controller\n\t4307  BCM4306 802.11bg Wireless LAN Controller\n\t4310  BCM4310 Chipcommon I/OController\n\t4311  BCM4311 802.11b/g WLAN\n\t\t1028 0007  Wireless 1390 WLAN Mini-Card\n\t\t1028 0008  Wireless 1390 WLAN ExpressCard\n\t\t103c 1363  BCM4311 802.11b/g Wireless LAN Controller\n\t\t103c 1364  BCM4311 802.11b/g Wireless LAN Controller\n\t\t103c 1365  BCM4311 802.11b/g Wireless LAN Controller\n\t\t103c 1374  BCM4311 802.11b/g Wireless LAN Controller\n\t\t103c 1375  BCM4311 802.11b/g Wireless LAN Controller\n\t\t103c 1376  BCM4311 802.11b/g Wireless LAN Controller\n\t\t103c 1377  BCM4311 802.11b/g Wireless LAN Controller\n\t\t103c 137f  BCM4322 802.11a/b/g/n Wireless LAN Controller\n\t\t103c 1380  BCM4322 802.11a/b/g/n Wireless LAN Controller\n\t\t14e4 4311  BCM94311MCG\n\t4312  BCM4311 802.11a/b/g\n\t\t1028 0007  Wireless 1490 Dual Band WLAN Mini-Card\n\t\t1028 0008  Wireless 1490 Dual Band WLAN ExpressCard\n\t\t103c 135a  Broadcom 802.11a/b/g WLAN\n\t\t103c 135f  Broadcom 802.11a/b/g WLAN\n\t\t103c 1360  Broadcom 802.11a/b/g WLAN\n\t\t103c 1361  Broadcom 802.11a/b/g WLAN\n\t\t103c 1362  Broadcom 802.11a/b/g WLAN\n\t\t103c 1370  Broadcom 802.11a/b/g WLAN\n\t\t103c 1371  Broadcom 802.11a/b/g WLAN\n\t\t103c 1372  Broadcom 802.11a/b/g WLAN\n\t\t103c 1373  Broadcom 802.11a/b/g WLAN\n\t\t103c 30b5  Presario V3242AU\n\t\t106b 0089  AirPort Extreme\n\t\t1371 103c  Broadcom 802.11 Multiband-netwerkadapter(6715s)\n\t4313  BCM4311 802.11a\n\t4315  BCM4312 802.11b/g LP-PHY\n\t\t1028 000b  Wireless 1395 WLAN Mini-Card\n\t\t1028 000c  Wireless 1397 WLAN Mini-Card\n\t\t103c 137c  BCM4312 802.11b/g Wireless LAN Controller\n\t\t103c 137d  BCM4312 802.11b/g Wireless LAN Controller\n\t\t103c 1507  U98Z049.00 Wireless Mini PCIe Card\n\t\t105b e003  T77H030.00 Wireless Mini PCIe Card\n\t\t105b e01b  T77H106.00 Wireless Half-size Mini PCIe Card\n\t4318  BCM4318 [AirForce One 54g] 802.11g Wireless LAN Controller\n\t\t1028 0005  Wireless 1370 WLAN Mini-PCI Card\n\t\t1028 0006  Wireless 1370 WLAN PC Card\n\t\t103c 1355  Broadcom 802.11b/g WLAN\n\t\t103c 1356  Broadcom 802.11b/g WLAN\n\t\t103c 1357  Broadcom 802.11b/g WLAN\n\t\t1043 100f  WL-138G v2 / WL-138gE / WL-100gE\n\t\t1043 120f  A6U notebook embedded card\n\t\t1154 0355  Buffalo WLI2-PCI-G54S High Speed Mode Wireless Adapter\n\t\t1468 0311  Aspire 3022WLMi, 5024WLMi, 5020\n\t\t1468 0312  TravelMate 2410\n\t\t14e4 0449  Gateway 7510GX\n\t\t16ec 0119  U.S.Robotics Wireless MAXg PC Card\n\t\t1737 0042  WMP54GS v1.1 802.11g Wireless-G PCI Adapter with SpeedBooster\n\t\t1737 0048  WPC54G v3 802.11g Wireless-G Notebook Adapter\n\t\t1737 0049  WPC54GS v2 802.11g Wireless-G Notebook Adapter with SpeedBooster\n\t\t1799 7000  F5D7000 v4000 Wireless G Desktop Card\n\t\t1799 7001  F5D7001 v2000 Wireless G Plus Desktop Card\n\t\t1799 7010  F5D7010 v4000 Wireless G Notebook Card\n\t\t1799 7011  F5D7011 v2000 High-Speed Mode Wireless G Notebook Card\n\t4319  BCM4318 [AirForce 54g] 802.11a/b/g PCI Express Transceiver\n\t\t1028 0005  Wireless 1470 Dual Band WLAN Mini-PCI Card\n\t\t1028 0006  Wireless 1470 Dual Band WLAN PC Card\n\t\t103c 1358  Broadcom 802.11a/b/g WLAN\n\t\t103c 1359  Broadcom 802.11a/b/g WLAN\n\t\t103c 135a  Broadcom 802.11a/b/g WLAN\n\t4320  BCM4306 802.11b/g Wireless LAN Controller\n\t\t1028 0001  TrueMobile 1300 WLAN Mini-PCI Card\n\t\t1028 0002  TrueMobile 1300 WLAN PC Card\n\t\t1028 0003  Wireless 1350 WLAN Mini-PCI Card\n\t\t1028 0004  Wireless 1350 WLAN PC Card\n\t\t103c 12f4  Broadcom 802.11b/g WLAN\n\t\t103c 12f8  Broadcom 802.11b/g WLAN\n\t\t103c 12fa  Broadcom 802.11b/g WLAN\n\t\t103c 12fb  Broadcom 802.11b/g WLAN\n\t\t1043 100f  WL-100G\n\t\t1057 7025  WN825G\n\t\t106b 004e  AirPort Extreme\n\t\t1154 0330  Buffalo WLI2-PCI-G54S High Speed Mode Wireless Desktop Adapter\n\t\t144f 7050  eMachines M6805 802.11g Built-in Wireless\n\t\t144f 7051  Sonnet Aria Extreme PCI\n\t\t1737 0013  WMP54G v1 802.11g PCI Adapter\n\t\t1737 0014  WMP54G v2 802.11g PCI Adapter\n\t\t1737 0015  WMP54GS v1.0 802.11g Wireless-G PCI Adapter with SpeedBooster\n\t\t1737 4320  WPC54G v1 / WPC54GS v1 802.11g Wireless-G Notebook Adapter\n\t\t1799 7000  F5D7000 v1000 Wireless G Desktop Card\n\t\t1799 7001  F5D7001 v1000 Wireless G Plus Desktop Card\n\t\t1799 7010  F5D7010 v1000 Wireless G Notebook Card\n\t\t1799 7011  F5D7011 v1000 High-Speed Mode Wireless G Notebook Card\n\t\t185f 1220  TravelMate 290E WLAN Mini-PCI Card\n\t4321  BCM4321 802.11a Wireless Network Controller\n\t4322  BCM4322 802.11bgn Wireless Network Controller\n\t4324  BCM4309 802.11abg Wireless Network Controller\n\t\t1028 0001  Truemobile 1400\n\t\t1028 0002  TrueMobile 1400 Dual Band WLAN PC Card\n\t\t1028 0003  Truemobile 1450 MiniPCI\n\t\t1028 0004  Wireless 1450 Dual Band WLAN PC Card\n\t\t103c 12f9  Broadcom 802.11a/b/g WLAN\n\t\t103c 12fc  Broadcom 802.11a/b/g WLAN\n\t4325  BCM4306 802.11bg Wireless Network Controller\n\t\t1414 0003  Wireless Notebook Adapter MN-720\n\t\t1414 0004  Wireless PCI Adapter MN-730\n\t4326  BCM4307 Chipcommon I/O Controller?\n\t4328  BCM4321 802.11a/b/g/n\n\t\t1028 0009  Wireless 1500 Draft 802.11n WLAN Mini-Card\n\t\t1028 000a  Wireless 1500 Draft 802.11n WLAN Mini-card\n\t\t103c 1366  BCM4321 802.11a/b/g/n Wireless LAN Controller\n\t\t103c 1367  BCM4321 802.11a/b/g/n Wireless LAN Controller\n\t\t103c 1368  BCM4321 802.11a/b/g/n Wireless LAN Controller\n\t\t103c 1369  BCM4321 802.11a/b/g/n Wireless LAN Controller\n\t\t106b 0087  AirPort Extreme\n\t\t106b 0088  AirPort Extreme\n\t\t106b 008b  AirPort Extreme\n\t\t106b 008c  AirPort Extreme\n\t\t106b 0090  AirPort Extreme\n\t\t14e4 4328  BCM4328 802.11a/b/g/n\n\t\t1737 0066  WPC600N v1 802.11a/b/g/n Wireless-N CardBus Adapter\n\t\t1737 0068  WEC600N v1 802.11a/b/g/n Wireless-N ExpressCard\n\t4329  BCM4321 802.11b/g/n\n\t\t1385 7b00  WN511B RangeMax NEXT Wireless Notebook Adapter\n\t\t1385 7d00  WN311B RangeMax Next 270 Mbps Wireless PCI Adapter\n\t\t1737 0058  WPC300N v1 Wireless-N Notebook Adapter\n\t432a  BCM4321 802.11an Wireless Network Controller\n\t432b  BCM4322 802.11a/b/g/n Wireless LAN Controller\n\t\t1028 000d  Wireless 1510 Wireless-N WLAN Mini-Card\n\t\t106b 008d  AirPort Extreme\n\t\t106b 008e  AirPort Extreme\n\t432c  BCM4322 802.11b/g/n\n\t\t1799 d311  Dynex DX-NNBX 802.11n WLAN Cardbus Card\n\t432d  BCM4322 802.11an Wireless Network Controller\n\t4331  BCM4331 802.11a/b/g/n\n\t\t106b 00d6  AirPort Extreme\n\t\t106b 00e4  AirPort Extreme\n\t\t106b 00ef  AirPort Extreme\n\t\t106b 00f4  AirPort Extreme\n\t\t106b 00f5  AirPort Extreme\n\t\t106b 010e  AirPort Extreme\n\t\t106b 010f  AirPort Extreme\n\t4333  Serial (EDGE/GPRS modem part of Option GT Combo Edge)\n\t4344  EDGE/GPRS data and 802.11b/g combo cardbus [GC89]\n\t4350  BCM43222 Wireless Network Adapter\n\t4351  BCM43222 802.11abgn Wireless Network Adapter\n\t4353  BCM43224 802.11a/b/g/n\n\t\t1028 000e  Wireless 1520 Half-size Mini PCIe Card\n\t\t103c 1509  WMIB-275N Half-size Mini PCIe Card\n\t\t106b 0093  AirPort Extreme\n\t\t106b 00d1  AirPort Extreme\n\t\t106b 00e9  AirPort Extreme\n\t\t14e4 04d8  Pegatron UPWL6024\n\t4357  BCM43225 802.11b/g/n\n\t\t105b e021  T77H103.00 Wireless Half-size Mini PCIe Card\n\t4358  BCM43227 802.11b/g/n\n\t4359  BCM43228 802.11a/b/g/n\n\t\t1028 0011  Wireless 1530 Half-size Mini PCIe Card\n\t\t103c 182c  BCM943228HM4L 802.11a/b/g/n 2x2 Wi-Fi Adapter\n\t4360  BCM4360 802.11ac Wireless Network Adapter\n\t4365  BCM43142 802.11b/g/n\n\t\t1028 0016  Wireless 1704 802.11n + BT 4.0\n\t43a0  BCM4360 802.11ac Wireless Network Adapter\n\t43a1  BCM4360 802.11ac Wireless Network Adapter\n\t43a2  BCM4360 802.11ac Wireless Network Adapter\n\t43a3  BCM4350 802.11ac Wireless Network Adapter\n\t43a9  BCM43217 802.11b/g/n\n\t43aa  BCM43131 802.11b/g/n\n\t43ae  BCM43162 802.11ac Wireless Network Adapter\n\t43b1  BCM4352 802.11ac Wireless Network Adapter\n\t43ba  BCM43602 802.11ac Wireless LAN SoC\n\t43bb  BCM43602 802.11ac Wireless LAN SoC\n\t43bc  BCM43602 802.11ac Wireless LAN SoC\n\t43d3  BCM43567 802.11ac Wireless Network Adapter\n\t43d9  BCM43570 802.11ac Wireless Network Adapter\n\t43dc  BCM4355 802.11ac Wireless LAN SoC\n\t43df  BCM4354 802.11ac Wireless LAN SoC\n\t43e9  BCM4358 802.11ac Wireless LAN SoC\n\t43ec  BCM4356 802.11ac Wireless Network Adapter\n\t4401  BCM4401 100Base-T\n\t\t1025 0035  TravelMate 660\n\t\t1025 0064  Extensa 3000 series laptop\n\t\t1028 8127  Dimension 2400\n\t\t103c 08b0  tc1100 tablet\n\t\t1043 80a8  A7V8X motherboard\n\t4402  BCM4402 Integrated 10/100BaseT\n\t4403  BCM4402 V.90 56k Modem\n\t4410  BCM4413 iLine32 HomePNA 2.0\n\t4411  BCM4413 V.90 56k modem\n\t4412  BCM4412 10/100BaseT\n\t4430  BCM44xx CardBus iLine32 HomePNA 2.0\n\t4432  BCM4432 CardBus 10/100BaseT\n\t4464  BCM4364 802.11ac Wireless Network Adapter\n# brcmfmac reports it as BCM4377/4 but macOS drivers call it BCM4377b\n\t4488  BCM4377b Wireless Network Adapter\n\t4610  BCM4610 Sentry5 PCI to SB Bridge\n\t4611  BCM4610 Sentry5 iLine32 HomePNA 1.0\n\t4612  BCM4610 Sentry5 V.90 56k Modem\n\t4613  BCM4610 Sentry5 Ethernet Controller\n\t4614  BCM4610 Sentry5 External Interface\n\t4615  BCM4610 Sentry5 USB Controller\n\t4704  BCM4704 PCI to SB Bridge\n\t4705  BCM4704 Sentry5 802.11b Wireless LAN Controller\n\t4706  BCM4704 Sentry5 Ethernet Controller\n\t4707  BCM4704 Sentry5 USB Controller\n\t4708  BCM4704 Crypto Accelerator\n\t4710  BCM4710 Sentry5 PCI to SB Bridge\n\t4711  BCM47xx Sentry5 iLine32 HomePNA 2.0\n\t4712  BCM47xx V.92 56k modem\n\t4713  Sentry5 Ethernet Controller\n\t4714  BCM47xx Sentry5 External Interface\n\t4715  BCM47xx Sentry5 USB / Ethernet Controller\n\t4716  BCM47xx Sentry5 USB Host Controller\n\t4717  BCM47xx Sentry5 USB Device Controller\n\t4718  Sentry5 Crypto Accelerator\n\t4719  BCM47xx/53xx RoboSwitch Core\n\t4720  BCM4712 MIPS CPU\n\t4727  BCM4313 802.11bgn Wireless Network Adapter\n\t\t1028 0010  Inspiron M5010 / XPS 8300\n\t5365  BCM5365P Sentry5 Host Bridge\n\t5600  BCM5600 StrataSwitch 24+2 Ethernet Switch Controller\n\t5605  BCM5605 StrataSwitch 24+2 Ethernet Switch Controller\n\t5615  BCM5615 StrataSwitch 24+2 Ethernet Switch Controller\n\t5625  BCM5625 StrataSwitch 24+2 Ethernet Switch Controller\n\t5645  BCM5645 StrataSwitch 24+2 Ethernet Switch Controller\n\t5670  BCM5670 8-Port 10GE Ethernet Switch Fabric\n\t5680  BCM5680 G-Switch 8 Port Gigabit Ethernet Switch Controller\n\t5690  BCM5690 12-port Multi-Layer Gigabit Ethernet Switch\n\t5691  BCM5691 GE/10GE 8+2 Gigabit Ethernet Switch Controller\n\t5692  BCM5692 12-port Multi-Layer Gigabit Ethernet Switch\n\t5695  BCM5695 12-port + HiGig Multi-Layer Gigabit Ethernet Switch\n\t5698  BCM5698 12-port Multi-Layer Gigabit Ethernet Switch\n\t5820  BCM5820 Crypto Accelerator\n\t5821  BCM5821 Crypto Accelerator\n\t5822  BCM5822 Crypto Accelerator\n\t5823  BCM5823 Crypto Accelerator\n\t5824  BCM5824 Crypto Accelerator\n\t5840  BCM5840 Crypto Accelerator\n\t5841  BCM5841 Crypto Accelerator\n\t5850  BCM5850 Crypto Accelerator\n\t5e87  Valkyrie offload engine\n\t5e88  Viper Offload Engine\n\t8602  BCM7400/BCM7405 Serial ATA Controller\n\t9026  CN99xx [ThunderX2] Integrated USB 3.0 xHCI Host Controller\n\t9027  CN99xx [ThunderX2] Integrated AHCI/SATA 3 Host Controller\n\ta8d8  BCM43224/5 Wireless Network Adapter\n\taa52  BCM43602 802.11ac Wireless LAN SoC\n\tb302  BCM56302 StrataXGS 24x1GE 2x10GE Switch Controller\n\tb334  BCM56334 StrataXGS 24x1GE 4x10GE Switch Controller\n\tb370  BCM56370 Switch ASIC\n\tb371  BCM56371 Switch ASIC\n\tb372  BCM56372 Switch ASIC\n\tb375  BCM56375 Switch ASIC\n\tb376  BCM56376 Switch ASIC\n\tb377  BCM56377 Switch ASIC\n\tb379  Broadcom BCM56379 Switch ASIC\n\tb470  BCM56470 SWITCH ASIC\n\tb471  BCM56471 SWITCH ASIC\n\tb472  BCM56472 SWITCH ASIC\n\tb800  BCM56800 StrataXGS 10GE Switch Controller\n\tb842  BCM56842 Trident 10GE Switch Controller\n# Trident2\n\tb850  Broadcom BCM56850 Switch ASIC\n\tb880  BCM56880 Switch ASIC\n# Tomahawk\n\tb960  Broadcom BCM56960 Switch ASIC\n# Tomahawk4\n\tb990  BCM56990 Switch ASIC\n\td802  BCM58802 Stingray 50Gb Ethernet SoC\n\t\t14e4 8021  Stingray Dual-Port 25Gb Ethernet PCIe SmartNIC w16GB DRAM (Part No BCM958802A8046C)\n\t\t14e4 8023  PS410T-H04 NetXtreme-S 4x10G 10GBaseT PCIe SmartNIC\n\t\t14e4 8024  Stingray Dual-Port 25Gb Ethernet PCIe SmartNIC w4GB DRAM (Part No BCM958802A8044C)\n\t\t14e4 8028  Stingray Dual-Port 25Gb Ethernet PCIe SmartNIC w8GB DRAM (Part No BCM958802A8048C)\n\t\t1bb0 0021  HPE SimpliVity Accelerator\n\td804  BCM58804 Stingray 100Gb Ethernet SoC\n14e5  Pixelfusion Ltd\n14e6  SHINING Technology Inc\n14e7  3CX\n14e8  RAYCER Inc\n14e9  GARNETS System CO Ltd\n14ea  Planex Communications, Inc\n\tab06  FNW-3603-TX CardBus Fast Ethernet\n\tab07  RTL81xx RealTek Ethernet\n\tab08  FNW-3602-TX CardBus Fast Ethernet\n14eb  SEIKO EPSON Corp\n# nee ACQIRIS\n14ec  Agilent Technologies\n\t0000  Aciris Digitizer (malformed ID)\n14ed  DATAKINETICS Ltd\n14ee  MASPRO KENKOH Corp\n14ef  CARRY Computer ENG. CO Ltd\n14f0  CANON RESEACH CENTRE FRANCE\n14f1  Conexant Systems, Inc.\n\t1002  HCF 56k Modem\n\t1003  HCF 56k Modem\n\t1004  HCF 56k Modem\n\t1005  HCF 56k Modem\n\t1006  HCF 56k Modem\n\t1022  HCF 56k Modem\n\t1023  HCF 56k Modem\n\t1024  HCF 56k Modem\n\t1025  HCF 56k Modem\n\t1026  HCF 56k Modem\n\t1032  HCF 56k Modem\n\t1033  HCF 56k Data/Fax Modem\n\t\t1033 8077  NEC\n\t\t122d 4027  Dell Zeus - MDP3880-W(B) Data Fax Modem\n\t\t122d 4030  Dell Mercury - MDP3880-U(B) Data Fax Modem\n\t\t122d 4034  Dell Thor - MDP3880-W(U) Data Fax Modem\n\t\t13e0 020d  Dell Copper\n\t\t13e0 020e  Dell Silver\n\t\t13e0 0261  IBM\n\t\t13e0 0290  Compaq Goldwing\n\t\t13e0 02a0  IBM\n\t\t13e0 02b0  IBM\n\t\t13e0 02c0  Compaq Scooter\n\t\t13e0 02d0  IBM\n\t\t144f 1500  IBM P85-DF (1)\n\t\t144f 1501  IBM P85-DF (2)\n\t\t144f 150a  IBM P85-DF (3)\n\t\t144f 150b  IBM P85-DF Low Profile (1)\n\t\t144f 1510  IBM P85-DF Low Profile (2)\n\t1034  HCF 56k Data/Fax/Voice Modem\n\t1035  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem\n\t\t10cf 1098  Fujitsu P85-DFSV\n\t1036  HCF 56k Data/Fax/Voice/Spkp Modem\n\t\t104d 8067  HCF 56k Modem\n\t\t122d 4029  MDP3880SP-W\n\t\t122d 4031  MDP3880SP-U\n\t\t13e0 0209  Dell Titanium\n\t\t13e0 020a  Dell Graphite\n\t\t13e0 0260  Gateway Red Owl\n\t\t13e0 0270  Gateway White Horse\n\t1052  HCF 56k Data/Fax Modem (Worldwide)\n\t1053  HCF 56k Data/Fax Modem (Worldwide)\n\t1054  HCF 56k Data/Fax/Voice Modem (Worldwide)\n\t1055  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem (Worldwide)\n\t1056  HCF 56k Data/Fax/Voice/Spkp Modem (Worldwide)\n\t\t122d 4035  MDP3900V-W\n\t1057  HCF 56k Data/Fax/Voice/Spkp Modem (Worldwide)\n\t1059  HCF 56k Data/Fax/Voice Modem (Worldwide)\n\t1063  HCF 56k Data/Fax Modem\n\t1064  HCF 56k Data/Fax/Voice Modem\n\t1065  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem\n\t1066  HCF 56k Data/Fax/Voice/Spkp Modem\n\t\t122d 4033  Dell Athena - MDP3900V-U\n\t1085  HCF V90 56k Data/Fax/Voice/Spkp PCI Modem\n\t10b6  CX06834-11 HCF V.92 56k Data/Fax/Voice/Spkp Modem\n\t1433  HCF 56k Data/Fax Modem\n\t1434  HCF 56k Data/Fax/Voice Modem\n\t1435  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem\n\t1436  HCF 56k Data/Fax Modem\n\t1453  HCF 56k Data/Fax Modem\n\t\t13e0 0240  IBM\n\t\t13e0 0250  IBM\n\t\t144f 1502  IBM P95-DF (1)\n\t\t144f 1503  IBM P95-DF (2)\n\t1454  HCF 56k Data/Fax/Voice Modem\n\t1455  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem\n\t1456  HCF 56k Data/Fax/Voice/Spkp Modem\n\t\t122d 4035  Dell Europa - MDP3900V-W\n\t\t122d 4302  Dell MP3930V-W(C) MiniPCI\n\t1610  ADSL AccessRunner PCI Arbitration Device\n\t1611  AccessRunner PCI ADSL Interface Device\n\t1620  AccessRunner V2 PCI ADSL Arbitration Device\n\t1621  AccessRunner V2 PCI ADSL Interface Device\n\t1622  AccessRunner V2 PCI ADSL Yukon WAN Adapter\n\t1803  HCF 56k Modem\n\t\t0e11 0023  623-LAN Grizzly\n\t\t0e11 0043  623-LAN Yogi\n\t1811  MiniPCI Network Adapter\n\t1815  HCF 56k Modem\n\t\t0e11 0022  Grizzly\n\t\t0e11 0042  Yogi\n# Integrated in CX86111/CX86113 processors\n\t1830  CX861xx Integrated Host Bridge\n\t2003  HSF 56k Data/Fax Modem\n\t2004  HSF 56k Data/Fax/Voice Modem\n\t2005  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem\n\t2006  HSF 56k Data/Fax/Voice/Spkp Modem\n\t2013  HSF 56k Data/Fax Modem\n\t\t0e11 b195  Bear\n\t\t0e11 b196  Seminole 1\n\t\t0e11 b1be  Seminole 2\n\t\t1025 8013  Acer\n\t\t1033 809d  NEC\n\t\t1033 80bc  NEC\n\t\t155d 6793  HP\n\t\t155d 8850  E Machines\n\t2014  HSF 56k Data/Fax/Voice Modem\n\t2015  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem\n\t2016  HSF 56k Data/Fax/Voice/Spkp Modem\n\t2043  HSF 56k Data/Fax Modem (WorldW SmartDAA)\n\t2044  HSF 56k Data/Fax/Voice Modem (WorldW SmartDAA)\n\t2045  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem (WorldW SmartDAA)\n\t\t14f1 2045  Generic SoftK56\n\t2046  HSF 56k Data/Fax/Voice/Spkp Modem (WorldW SmartDAA)\n\t2063  HSF 56k Data/Fax Modem (SmartDAA)\n\t2064  HSF 56k Data/Fax/Voice Modem (SmartDAA)\n\t2065  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem (SmartDAA)\n\t2066  HSF 56k Data/Fax/Voice/Spkp Modem (SmartDAA)\n\t2093  HSF 56k Modem\n\t\t155d 2f07  Legend\n\t2143  HSF 56k Data/Fax/Cell Modem (Mob WorldW SmartDAA)\n\t2144  HSF 56k Data/Fax/Voice/Cell Modem (Mob WorldW SmartDAA)\n\t2145  HSF 56k Data/Fax/Voice/Spkp (w/HS)/Cell Modem (Mob WorldW SmartDAA)\n\t2146  HSF 56k Data/Fax/Voice/Spkp/Cell Modem (Mob WorldW SmartDAA)\n\t2163  HSF 56k Data/Fax/Cell Modem (Mob SmartDAA)\n\t2164  HSF 56k Data/Fax/Voice/Cell Modem (Mob SmartDAA)\n\t2165  HSF 56k Data/Fax/Voice/Spkp (w/HS)/Cell Modem (Mob SmartDAA)\n\t2166  HSF 56k Data/Fax/Voice/Spkp/Cell Modem (Mob SmartDAA)\n\t2343  HSF 56k Data/Fax CardBus Modem (Mob WorldW SmartDAA)\n\t2344  HSF 56k Data/Fax/Voice CardBus Modem (Mob WorldW SmartDAA)\n\t2345  HSF 56k Data/Fax/Voice/Spkp (w/HS) CardBus Modem (Mob WorldW SmartDAA)\n\t2346  HSF 56k Data/Fax/Voice/Spkp CardBus Modem (Mob WorldW SmartDAA)\n\t2363  HSF 56k Data/Fax CardBus Modem (Mob SmartDAA)\n\t2364  HSF 56k Data/Fax/Voice CardBus Modem (Mob SmartDAA)\n\t2365  HSF 56k Data/Fax/Voice/Spkp (w/HS) CardBus Modem (Mob SmartDAA)\n\t2366  HSF 56k Data/Fax/Voice/Spkp CardBus Modem (Mob SmartDAA)\n\t2443  HSF 56k Data/Fax Modem (Mob WorldW SmartDAA)\n\t\t104d 8075  Modem\n\t\t104d 8083  Modem\n\t\t104d 8097  Modem\n\t2444  HSF 56k Data/Fax/Voice Modem (Mob WorldW SmartDAA)\n\t2445  HSF 56k Data/Fax/Voice/Spkp (w/HS) Modem (Mob WorldW SmartDAA)\n\t2446  HSF 56k Data/Fax/Voice/Spkp Modem (Mob WorldW SmartDAA)\n\t2463  HSF 56k Data/Fax Modem (Mob SmartDAA)\n\t2464  HSF 56k Data/Fax/Voice Modem (Mob SmartDAA)\n\t2465  HSF 56k Data/Fax/Voice/Spkp (w/HS) Modem (Mob SmartDAA)\n\t2466  HSF 56k Data/Fax/Voice/Spkp Modem (Mob SmartDAA)\n\t2702  HSFi modem RD01-D270\n\t\t1028 8d88  SmartHSFi V92 56K PCI Modem\n\t2f00  HSF 56k HSFi Modem\n\t\t13e0 8d84  IBM HSFi V.90\n\t\t13e0 8d85  Compaq Stinger\n\t\t14f1 2004  Dynalink 56PMi\n\t2f02  HSF 56k HSFi Data/Fax\n\t2f11  HSF 56k HSFi Modem\n\t2f20  HSF 56k Data/Fax Modem\n\t\t14f1 200c  Soft Data Fax Modem with SmartCP\n\t\t14f1 200f  Dimension 3000\n\t2f30  SoftV92 SpeakerPhone SoftRing Modem with SmartSP\n\t\t14f1 2014  Devolo MikroLink 56K Modem PCI\n\t2f50  Conexant SoftK56 Data/Fax Modem\n\t5b7a  CX23418 Single-Chip MPEG-2 Encoder with Integrated Analog Video/Broadcast Audio Decoder\n\t\t0070 7444  WinTV HVR-1600\n\t\t107d 6f34  WinFast DVR3100 H\n\t\t5854 3343  GoTView PCI DVD3 Hybrid\n\t8200  CX25850\n\t8234  RS8234 ATM SAR Controller [ServiceSAR Plus]\n\t8800  CX23880/1/2/3 PCI Video and Audio Decoder\n\t\t0070 2801  Hauppauge WinTV 28xxx (Roslyn) models\n\t\t0070 3400  WinTV 34604\n\t\t0070 3401  Hauppauge WinTV 34xxx models\n\t\t0070 6902  WinTV HVR-4000-HD\n\t\t0070 7801  WinTV HVR-1800 MCE\n\t\t0070 9001  Nova-T DVB-T\n\t\t0070 9200  Nova-SE2 DVB-S\n\t\t0070 9202  Nova-S-Plus DVB-S\n\t\t0070 9402  WinTV-HVR1100 DVB-T/Hybrid\n\t\t0070 9600  WinTV 88x Video\n\t\t0070 9802  WinTV-HVR1100 DVB-T/Hybrid (Low Profile)\n\t\t1002 00f8  ATI TV Wonder Pro\n\t\t1002 00f9  ATI TV Wonder\n\t\t1002 a101  HDTV Wonder\n\t\t1043 4823  PVR-416\n\t\t107d 6611  Winfast TV 2000XP Expert\n\t\t107d 6613  Leadtek Winfast 2000XP Expert\n\t\t107d 6620  Leadtek Winfast DV2000\n\t\t107d 663c  Leadtek PVR 2000\n\t\t107d 665f  WinFast DTV1000-T\n\t\t10fc d003  IODATA GV-VCP3/PCI\n\t\t10fc d035  IODATA GV/BCTV7E\n\t\t1421 0334  Instant TV DVB-T PCI\n\t\t1461 000a  AVerTV 303 (M126)\n\t\t1461 000b  AverTV Studio 303 (M126)\n\t\t1461 8011  UltraTV Media Center PCI 550\n\t\t1462 8606  MSI TV-@nywhere Master\n\t\t14c7 0107  GDI Black Gold\n\t\t14f1 0187  Conexant DVB-T reference design\n\t\t14f1 0342  Digital-Logic MICROSPACE Entertainment Center (MEC)\n\t\t153b 1166  Cinergy 1400 DVB-T\n\t\t1540 2580  Provideo PV259\n\t\t1554 4811  PixelView\n\t\t1554 4813  Club 3D  ZAP1000 MCE Edition\n\t\t17de 08a1  KWorld/VStream XPert DVB-T with cx22702\n\t\t17de 08a6  KWorld/VStream XPert DVB-T\n\t\t17de 08b2  KWorld DVB-S 100\n\t\t17de a8a6  digitalnow DNTV Live! DVB-T\n\t\t1822 0025  digitalnow DNTV Live! DVB-T Pro\n\t\t185b e000  VideoMate X500\n\t\t18ac d500  FusionHDTV 5 Gold\n\t\t18ac d810  FusionHDTV 3 Gold-Q\n\t\t18ac d820  FusionHDTV 3 Gold-T\n\t\t18ac db00  FusionHDTV DVB-T1\n\t\t18ac db11  FusionHDTV DVB-T Plus\n\t\t18ac db50  FusionHDTV DVB-T Dual Digital\n\t\t5654 2388  GoTView PCI Hybrid TV Tuner Card\n\t\t7063 3000  pcHDTV HD3000 HDTV\n\t\t7063 5500  pcHDTV HD-5500\n\t8801  CX23880/1/2/3 PCI Video and Audio Decoder [Audio Port]\n\t\t0070 2801  Hauppauge WinTV 28xxx (Roslyn) models\n\t\t185b e000  VideoMate X500\n\t\t5654 2388  GoTView PCI Hybrid Audio AVStream Device\n\t\t7063 5500  pcHDTV HD-5500\n\t8802  CX23880/1/2/3 PCI Video and Audio Decoder [MPEG Port]\n\t\t0070 2801  Hauppauge WinTV 28xxx (Roslyn) models\n\t\t0070 6902  WinTV HVR-4000-HD\n\t\t0070 9002  Nova-T DVB-T Model 909\n\t\t0070 9402  WinTV-HVR1100 DVB-T/Hybrid\n\t\t0070 9600  WinTV 88x MPEG Encoder\n\t\t1043 4823  PVR-416\n\t\t107d 663c  Leadtek PVR 2000\n\t\t107d 665f  WinFast DTV1000-T\n\t\t14f1 0187  Conexant DVB-T reference design\n\t\t17de 08a1  XPert DVB-T PCI BDA DVBT 23880 Transport Stream Capture\n\t\t17de 08a6  KWorld/VStream XPert DVB-T\n\t\t18ac d500  DViCO FusionHDTV5 Gold\n\t\t18ac d810  DViCO FusionHDTV3 Gold-Q\n\t\t18ac d820  DViCO FusionHDTV3 Gold-T\n\t\t18ac db00  DVICO FusionHDTV DVB-T1\n\t\t18ac db10  DVICO FusionHDTV DVB-T Plus\n\t\t5654 2388  GoTView PCI Hybrid TS Capture Device\n\t\t7063 3000  pcHDTV HD3000 HDTV\n\t\t7063 5500  pcHDTV HD-5500\n\t8804  CX23880/1/2/3 PCI Video and Audio Decoder [IR Port]\n\t\t0070 6902  WinTV HVR-4000-HD\n\t\t0070 9002  Nova-T DVB-T Model 909\n\t\t0070 9402  WinTV-HVR1100 DVB-T/Hybrid\n\t\t7063 5500  pcHDTV HD-5500\n\t8811  CX23880/1/2/3 PCI Video and Audio Decoder [Audio Port]\n\t\t0070 3400  WinTV 34604\n\t\t0070 3401  Hauppauge WinTV 34xxx models\n\t\t0070 6902  WinTV HVR-4000-HD\n\t\t0070 9402  WinTV-HVR1100 DVB-T/Hybrid\n\t\t0070 9600  WinTV 88x Audio\n\t\t1462 8606  MSI TV-@nywhere Master\n\t\t18ac d500  DViCO FusionHDTV5 Gold\n\t\t18ac d810  DViCO FusionHDTV3 Gold-Q\n\t\t18ac d820  DViCO FusionHDTV3 Gold-T\n\t\t18ac db00  DVICO FusionHDTV DVB-T1\n\t\t5654 2388  GoTView PCI Hybrid Audio Capture Device\n\t8852  CX23885 PCI Video and Audio Decoder\n\t\t0070 8010  WinTV HVR-1400 ExpressCard\n\t\t0070 f038  WinTV HVR-5525\n\t\t107d 6f22  WinFast PxTV1200\n\t\t12ab d585  PE988J Hybrid ATSC/QAM PCI-E AVS Video Capture (SoftEncoder)\n\t\t13c2 3013  TT-budget CT2-4500 CI\n\t\t1461 c039  AVerTV Hybrid Express (A577)\n\t\t153b 117e  Cinergy T PCIe Dual\n\t\t18ac db78  FusionHDTV DVB-T Dual Express\n\t\t4254 0950  S950\n\t\t4254 0952  S952\n\t\t4254 0982  T982\n\t\t4254 9580  T9580\n\t\t4254 980c  T980C\n\t8880  CX23887/8 PCIe Broadcast Audio and Video Decoder with 3D Comb\n\t\t0070 2259  WinTV HVR-1250\n\t\t0070 6a18  WinTV-quadHD\n\t\t0070 c108  WinTV-HVR-4400-HD model 1278\n\t\t1461 3100  CE310B SD PCIe Video Capture Card\n\t\t5654 2389  GoTView X5 DVD Hybrid PCI-E\n\t\t5654 2390  GoTView X5 3D HYBRID PCI-E\n14f2  MOBILITY Electronics\n\t0120  EV1000 bridge\n\t0121  EV1000 Parallel port\n\t0122  EV1000 Serial port\n\t0123  EV1000 Keyboard controller\n\t0124  EV1000 Mouse controller\n14f3  BroadLogic\n\t2030  2030 DVB-S Satellite Receiver\n\t2035  2035 DVB-S Satellite Receiver\n\t2050  2050 DVB-T Terrestrial (Cable) Receiver\n\t2060  2060 ATSC Terrestrial (Cable) Receiver\n14f4  TOKYO Electronic Industry CO Ltd\n14f5  SOPAC Ltd\n14f6  COYOTE Technologies LLC\n14f7  WOLF Technology Inc\n14f8  AUDIOCODES Inc\n\t2077  TP-240 dual span E1 VoIP PCI card\n14f9  AG COMMUNICATIONS\n14fa  WANDEL & GOLTERMANN\n14fb  TRANSAS MARINE (UK) Ltd\n14fc  Quadrics Ltd\n\t0000  QsNet Elan3 Network Adapter\n\t0001  QsNetII Elan4 Network Adapter\n\t0002  QsNetIII Elan5 Network Adapter\n14fd  JAPAN Computer Industry Inc\n14fe  ARCHTEK TELECOM Corp\n14ff  TWINHEAD INTERNATIONAL Corp\n1500  DELTA Electronics, Inc\n\t1360  RTL81xx RealTek Ethernet\n1501  BANKSOFT CANADA Ltd\n1502  MITSUBISHI ELECTRIC LOGISTICS SUPPORT Co Ltd\n1503  KAWASAKI LSI USA Inc\n1504  KAISER Electronics\n1505  ITA INGENIEURBURO FUR TESTAUFGABEN GmbH\n1506  CHAMELEON Systems Inc\n# Should be HTEC Ltd, but there are no known HTEC chips and 1507 is already used by mistake by Motorola (see vendor ID 1057).\n1507  Motorola ?? / HTEC\n\t0001  MPC105 [Eagle]\n\t0002  MPC106 [Grackle]\n\t0003  MPC8240 [Kahlua]\n\t0100  MC145575 [HFC-PCI]\n\t0431  KTI829c 100VG\n\t4801  Raven\n\t4802  Falcon\n\t4803  Hawk\n\t4806  CPX8216\n1508  HONDA CONNECTORS/MHOTRONICS Inc\n1509  FIRST INTERNATIONAL Computer Inc\n150a  FORVUS RESEARCH Inc\n150b  YAMASHITA Systems Corp\n150c  KYOPAL CO Ltd\n150d  WARPSPPED Inc\n150e  C-PORT Corp\n150f  INTEC GmbH\n1510  BEHAVIOR TECH Computer Corp\n1511  CENTILLIUM Technology Corp\n1512  ROSUN Technologies Inc\n1513  Raychem\n1514  TFL LAN Inc\n1515  Advent design\n1516  MYSON Technology Inc\n\t0800  MTD-8xx 100/10M Ethernet PCI Adapter\n\t0803  SURECOM EP-320X-S 100/10M Ethernet PCI Adapter\n\t\t1320 10bd  SURECOM EP-320X-S 100/10M Ethernet PCI Adapter\n\t0891  MTD-8xx 100/10M Ethernet PCI Adapter\n1517  ECHOTEK Corp\n# old ID, now 1059\n1518  Kontron\n1519  TELEFON AKTIEBOLAGET LM Ericsson\n151a  Globetek\n\t1002  PCI-1002\n\t1004  PCI-1004\n\t1008  PCI-1008\n151b  COMBOX Ltd\n151c  DIGITAL AUDIO LABS Inc\n\t0003  Prodif T 2496\n\t4000  Prodif 88\n151d  Fujitsu Computer Products Of America\n151e  MATRIX Corp\n151f  TOPIC SEMICONDUCTOR Corp\n\t0000  TP560 Data/Fax/Voice 56k modem\n1520  CHAPLET System Inc\n1521  BELL Corp\n1522  MainPine Ltd\n\t0100  PCI <-> IOBus Bridge\n\t\t1522 0200  RockForceDUO 2 Port V.92/V.44 Data/Fax/Voice Modem\n\t\t1522 0300  RockForceQUATRO 4 Port V.92/V.44 Data/Fax/Voice Modem\n\t\t1522 0400  RockForceDUO+ 2 Port V.92/V.44 Data/Fax/Voice Modem\n\t\t1522 0500  RockForceQUATRO+ 4 Port V.92/V.44 Data/Fax/Voice Modem\n\t\t1522 0600  RockForce+ 2 Port V.90 Data/Fax/Voice Modem\n\t\t1522 0700  RockForce+ 4 Port V.90 Data/Fax/Voice Modem\n\t\t1522 0800  RockForceOCTO+ 8 Port V.92/V.44 Data/Fax/Voice Modem\n\t\t1522 0c00  RockForceDUO+ 2 Port V.92/V.44 Data, V.34 Super-G3 Fax, Voice Modem\n\t\t1522 0d00  RockForceQUATRO+ 4 Port V.92/V.44 Data, V.34 Super-G3 Fax, Voice Modem\n\t\t1522 1d00  RockForceOCTO+ 8 Port V.92/V.44 Data, V.34 Super-G3 Fax, Voice Modem\n\t\t1522 2000  RockForceD1 1 Port V.90 Data Modem\n\t\t1522 2100  RockForceF1 1 Port V.34 Super-G3 Fax Modem\n\t\t1522 2200  RockForceD2 2 Port V.90 Data Modem\n\t\t1522 2300  RockForceF2 2 Port V.34 Super-G3 Fax Modem\n\t\t1522 2400  RockForceD4 4 Port V.90 Data Modem\n\t\t1522 2500  RockForceF4 4 Port V.34 Super-G3 Fax Modem\n\t\t1522 2600  RockForceD8 8 Port V.90 Data Modem\n\t\t1522 2700  RockForceF8 8 Port V.34 Super-G3 Fax Modem\n\t\t1522 3000  IQ Express D1 - 1 Port V.92 Data Modem\n\t\t1522 3100  IQ Express F1 - 1 Port V.34 Super-G3 Fax Modem\n\t\t1522 3200  IQ Express D2 - 2 Port V.92 Data Modem\n\t\t1522 3300  IQ Express F2 - 2 Port V.34 Super-G3 Fax Modem\n\t\t1522 3400  IQ Express D4 - 4 Port V.92 Data Modem\n\t\t1522 3500  IQ Express F4 - 4 Port V.34 Super-G3 Fax Modem\n\t\t1522 3c00  IQ Express D8 - 8 Port V.92 Data Modem\n\t\t1522 3d00  IQ Express F8 - 8 Port V.34 Super-G3 Fax Modem\n\t4000  PCI Express UART\n\t\t1522 4001  IQ Express 1-port V.34 Super-G3 Fax\n\t\t1522 4002  IQ Express 2-port V.34 Super-G3 Fax\n\t\t1522 4004  IQ Express 4-port V.34 Super-G3 Fax\n\t\t1522 4008  IQ Express 8-port V.34 Super-G3 Fax\n\t\t1522 4100  IQ Express SideBand\n1523  MUSIC Semiconductors\n1524  ENE Technology Inc\n\t0510  CB710 Memory Card Reader Controller\n\t\t103c 006a  NX9500\n\t0520  FLASH memory: ENE Technology Inc:\n\t0530  ENE PCI Memory Stick Card Reader Controller\n\t0550  ENE PCI Secure Digital Card Reader Controller\n\t0551  SD/MMC Card Reader Controller\n\t0610  PCI Smart Card Reader Controller\n\t0720  Memory Stick Card Reader Controller\n\t0730  ENE PCI Memory Stick Card Reader Controller\n\t0750  ENE PCI SmartMedia / xD Card Reader Controller\n\t0751  ENE PCI Secure Digital / MMC Card Reader Controller\n\t1211  CB1211 Cardbus Controller\n\t1225  CB1225 Cardbus Controller\n\t1410  CB1410 Cardbus Controller\n\t\t1025 003c  CL50 motherboard\n\t\t1025 005a  TravelMate 290\n\t\t103c 30d5  530 Laptop\n\t1411  CB-710/2/4 Cardbus Controller\n\t\t103c 006a  NX9500\n\t1412  CB-712/4 Cardbus Controller\n\t1420  CB1420 Cardbus Controller\n\t1421  CB-720/2/4 Cardbus Controller\n\t1422  CB-722/4 Cardbus Controller\n1525  IMPACT Technologies\n1526  ISS, Inc\n1527  SOLECTRON\n1528  ACKSYS\n1529  AMERICAN MICROSystems Inc\n152a  QUICKTURN DESIGN Systems\n152b  FLYTECH Technology CO Ltd\n152c  MACRAIGOR Systems LLC\n152d  QUANTA Computer Inc\n152e  MELEC Inc\n152f  PHILIPS - CRYPTO\n1530  ACQIS Technology Inc\n1531  CHRYON Corp\n1532  ECHELON Corp\n\t0020  LonWorks PCLTA-20 PCI LonTalk Adapter\n1533  BALTIMORE\n1534  ROAD Corp\n1535  EVERGREEN Technologies Inc\n1536  ACTIS Computer\n1537  DATALEX COMMUNCATIONS\n1538  ARALION Inc\n\t0303  ARS106S Ultra ATA 133/100/66 Host Controller\n1539  ATELIER INFORMATIQUES et ELECTRONIQUE ETUDES S.A.\n153a  ONO SOKKI\n153b  TERRATEC Electronic GmbH\n\t1144  Aureon 5.1\n# Terratec seems to use several IDs for the same card.\n\t1147  Aureon 5.1 Sky\n\t1158  Philips Semiconductors SAA7134 (rev 01) [Terratec Cinergy 600 TV]\n153c  ANTAL Electronic\n153d  FILANET Corp\n153e  TECHWELL Inc\n153f  MIPS Technologies, Inc.\n\t0001  SOC-it 101 System Controller\n1540  PROVIDEO MULTIMEDIA Co Ltd\n1541  MACHONE Communications\n# nee VIVID Technology Inc.\n1542  Concurrent Real-Time\n\t9260  RCIM-II Real-Time Clock & Interrupt Module\n\t9271  RCIM-III Real-Time Clock & Interrupt Module (PCIe)\n\t9272  Pulse Width Modulator Card\n\t9277  5 Volt Delta Sigma Converter Card\n\t9278  10 Volt Delta Sigma Converter Card\n\t9287  Analog Output Card\n\t9290  FPGA Card\n\t9300  Universal Exhaust Gas Oxygen Sensor Simulator\n\t9310  Digital Programmable Resistor\n\t9350  Analog Input Card\n1543  SILICON Laboratories\n\t3052  Intel 537 [Winmodem]\n\t4c22  Si3036 MC'97 DAA\n1544  DCM DATA Systems\n1545  VISIONTEK\n1546  IOI Technology Corp\n1547  MITUTOYO Corp\n1548  JET PROPULSION Laboratory\n1549  INTERCONNECT Systems Solutions\n154a  MAX Technologies Inc\n154b  COMPUTEX Co Ltd\n154c  VISUAL Technology Inc\n154d  PAN INTERNATIONAL Industrial Corp\n154e  SERVOTEST Ltd\n154f  STRATABEAM Technology\n1550  OPEN NETWORK Co Ltd\n1551  SMART Electronic DEVELOPMENT GmBH\n1552  RACAL AIRTECH Ltd\n1553  CHICONY Electronics Co Ltd\n1554  PROLINK Microsystems Corp\n1555  GESYTEC GmBH\n1556  PLDA\n\t1100  PCI Express Core Reference Design\n\t110f  PCI Express Core Reference Design Virtual Function\n\t1110  XpressRich Reference Design\n\t1113  XpressSwitch\n\tbe00  PCI Express Bridge\n1557  MEDIASTAR Co Ltd\n1558  CLEVO/KAPOK Computer\n1559  SI LOGIC Ltd\n155a  INNOMEDIA Inc\n155b  PROTAC INTERNATIONAL Corp\n155c  Cemax-Icon Inc\n155d  Mac System Co Ltd\n155e  LP Elektronik GmbH\n155f  Perle Systems Ltd\n1560  Terayon Communications Systems\n1561  Viewgraphics Inc\n1562  Symbol Technologies\n1563  A-Trend Technology Co Ltd\n1564  Yamakatsu Electronics Industry Co Ltd\n1565  Biostar Microtech Int'l Corp\n1566  Ardent Technologies Inc\n1567  Jungsoft\n1568  DDK Electronics Inc\n1569  Palit Microsystems Inc.\n156a  Avtec Systems\n156b  2wire Inc\n156c  Vidac Electronics GmbH\n156d  Alpha-Top Corp\n156e  Alfa Inc\n156f  M-Systems Flash Disk Pioneers Ltd\n1570  Lecroy Corp\n1571  Contemporary Controls\n\ta001  CCSI PCI20-485 ARCnet\n\ta002  CCSI PCI20-485D ARCnet\n\ta003  CCSI PCI20-485X ARCnet\n\ta004  CCSI PCI20-CXB ARCnet\n\ta005  CCSI PCI20-CXS ARCnet\n\ta006  CCSI PCI20-FOG-SMA ARCnet\n\ta007  CCSI PCI20-FOG-ST ARCnet\n\ta008  CCSI PCI20-TB5 ARCnet\n\ta009  CCSI PCI20-5-485 5Mbit ARCnet\n\ta00a  CCSI PCI20-5-485D 5Mbit ARCnet\n\ta00b  CCSI PCI20-5-485X 5Mbit ARCnet\n\ta00c  CCSI PCI20-5-FOG-ST 5Mbit ARCnet\n\ta00d  CCSI PCI20-5-FOG-SMA 5Mbit ARCnet\n\ta201  CCSI PCI22-485 10Mbit ARCnet\n\ta202  CCSI PCI22-485D 10Mbit ARCnet\n\ta203  CCSI PCI22-485X 10Mbit ARCnet\n\ta204  CCSI PCI22-CHB 10Mbit ARCnet\n\ta205  CCSI PCI22-FOG_ST 10Mbit ARCnet\n\ta206  CCSI PCI22-THB 10Mbit ARCnet\n1572  Otis Elevator Company\n1573  Lattice - Vantis\n1574  Fairchild Semiconductor\n1575  Voltaire Advanced Data Security Ltd\n1576  Viewcast COM\n1578  HITT\n\t4d34  VPMK4 [Video Processor Mk IV]\n\t5615  VPMK3 [Video Processor Mk III]\n1579  Dual Technology Corp\n157a  Japan Elecronics Ind Inc\n157b  Star Multimedia Corp\n157c  Eurosoft (UK)\n\t8001  Fix2000 PCI Y2K Compliance Card\n157d  Gemflex Networks\n157e  Transition Networks\n157f  PX Instruments Technology Ltd\n1580  Primex Aerospace Co\n1581  SEH Computertechnik GmbH\n1582  Cytec Corp\n1583  Inet Technologies Inc\n1584  Uniwill Computer Corp\n1585  Logitron\n1586  Lancast Inc\n1587  Konica Corp\n1588  Solidum Systems Corp\n1589  Atlantek Microsystems Pty Ltd\n\t0008  Leutron Vision PicPortExpress CL\n\t0009  Leutron Vision PicPortExpress CL Stereo\n158a  Digalog Systems Inc\n158b  Allied Data Technologies\n158c  Hitachi Semiconductor & Devices Sales Co Ltd\n158d  Point Multimedia Systems\n158e  Lara Technology Inc\n158f  Ditect Coop\n# formerly 3PAR Inc.\n1590  Hewlett Packard Enterprise\n\t0001  Eagle Cluster Manager\n\t0002  Osprey Cluster Manager\n\t0003  Harrier Cluster Manager\n\ta01d  FC044X Fibre Channel HBA\n1591  ARN\n1592  Syba Tech Ltd\n\t0781  Multi-IO Card\n\t0782  Parallel Port Card 2xEPP\n\t0783  Multi-IO Card\n\t0785  Multi-IO Card\n\t0786  Multi-IO Card\n\t0787  Multi-IO Card\n\t0788  Multi-IO Card\n\t078a  Multi-IO Card\n1593  Bops Inc\n1594  Netgame Ltd\n1595  Diva Systems Corp\n1596  Folsom Research Inc\n1597  Memec Design Services\n1598  Granite Microsystems\n1599  Delta Electronics Inc\n159a  General Instrument\n159b  Faraday Technology Corp\n\t4321  StorLink SL3516 (Gemini) Host Bridge\n159c  Stratus Computer Systems\n159d  Ningbo Harrison Electronics Co Ltd\n159e  A-Max Technology Co Ltd\n159f  Galea Network Security\n15a0  Compumaster SRL\n15a1  Geocast Network Systems\n15a2  Catalyst Enterprises Inc\n\t0001  TA700 PCI Bus Analyzer/Exerciser\n15a3  Italtel\n15a4  X-Net OY\n15a5  Toyota Macs Inc\n15a6  Sunlight Ultrasound Technologies Ltd\n15a7  SSE Telecom Inc\n15a8  Shanghai Communications Technologies Center\n15aa  Moreton Bay\n15ab  Bluesteel Networks Inc\n15ac  North Atlantic Instruments\n\t6893  3U OpenVPX Multi-function I/O Board [Model 68C3]\n15ad  VMware\n\t0405  SVGA II Adapter\n\t0710  SVGA Adapter\n\t0720  VMXNET Ethernet Controller\n\t0740  Virtual Machine Communication Interface\n\t0770  USB2 EHCI Controller\n\t0774  USB1.1 UHCI Controller\n\t0778  USB3 xHCI 0.96 Controller\n\t0779  USB3 xHCI 1.0 Controller\n\t0790  PCI bridge\n\t07a0  PCI Express Root Port\n\t07b0  VMXNET3 Ethernet Controller\n\t07c0  PVSCSI SCSI Controller\n\t07e0  SATA AHCI controller\n\t0801  Virtual Machine Interface\n\t\t15ad 0800  Hypervisor ROM Interface\n\t0820  Paravirtual RDMA controller\n\t1977  HD Audio Controller\n15ae  Amersham Pharmacia Biotech\n15b0  Zoltrix International Ltd\n15b1  Source Technology Inc\n15b2  Mosaid Technologies Inc\n15b3  Mellanox Technologies\n\t0191  MT25408 [ConnectX IB Flash Recovery]\n\t01f6  MT27500 Family [ConnectX-3 Flash Recovery]\n\t01f8  MT27520 Family [ConnectX-3 Pro Flash Recovery]\n\t01ff  MT27600 Family [Connect-IB Flash Recovery]\n\t0209  MT27700 Family [ConnectX-4 Flash Recovery]\n\t020b  MT27710 Family [ConnectX-4 Lx Flash Recovery]\n\t020d  MT28800 Family [ConnectX-5 Flash Recovery]\n\t020f  MT28908A0 Family [ConnectX-6 Flash Recovery]\n\t0210  MT28908A0 Family [ConnectX-6 Secure Flash Recovery]\n\t0211  MT416842 Family [BlueField SoC Flash Recovery]\n\t0212  MT2892 Family [ConnectX-6 Dx Flash Recovery]\n\t0213  MT2892 Family [ConnectX-6 Dx Secure Flash Recovery]\n\t0214  MT42822 Family [BlueField-2 SoC Flash Recovery]\n\t0215  MT42822 Family [BlueField-2 Secure Flash Recovery]\n\t0216  MT2894 Family [ConnectX-6 Lx Flash Recovery]\n\t0217  MT2894 Family [ConnectX-6 Lx Secure Flash Recovery]\n\t024e  MT53100 [Spectrum-2, Flash recovery mode]\n\t024f  MT53100 [Spectrum-2, Secure Flash recovery mode]\n\t0250  Spectrum-3, Flash recovery mode\n\t0251  Spectrum-3, Secure Flash recovery mode\n\t0252  Amos chiplet\n\t0254  Spectrum-4, Flash recovery mode\n\t0255  Spectrum-4, Secure Flash recovery mode\n\t0256  Ofek chiplet\n\t0257  Quantum-2 in Flash Recovery Mode\n\t0262  MT27710 [ConnectX-4 Lx Programmable] EN\n\t0263  MT27710 [ConnectX-4 Lx Programmable Virtual Function] EN\n\t0264  Innova-2 Flex Burn image\n\t0281  NPS-600 Flash Recovery\n\t1002  MT25400 Family [ConnectX-2 Virtual Function]\n\t1003  MT27500 Family [ConnectX-3]\n\t\t1014 04b5  PCIe3 40GbE RoCE Converged Host Bus Adapter for Power\n\t\t103c 1777  InfiniBand FDR/EN 10/40Gb Dual Port 544FLR-QSFP Adapter (Rev Cx)\n\t\t103c 17c9  Infiniband QDR/Ethernet 10Gb 2-port 544i Adapter\n\t\t103c 18ce  InfiniBand QDR/EN 10Gb Dual Port 544M Adapter\n\t\t103c 18cf  InfiniBand FDR/EN 10/40Gb Dual Port 544M Adapter\n\t\t103c 18d6  InfiniBand FDR/EN 10/40Gb Dual Port 544QSFP Adapter\n\t\t15b3 0025  ConnectX-3 IB QDR Dual Port Mezzanine Card\n\t\t15b3 0026  ConnectX-3 IB FDR Dual Port Mezzanine Card\n\t\t15b3 0028  ConnectX-3 VPI Dual QSFP+ Port QDR Infiniband 40Gb/s or 10Gb Ethernet\n\t\t15b3 0059  ConnectX-3 VPI IB FDR/40 GbE Single Port QSFP+ Mezzanine Card\n\t\t15b3 0064  ConnectX-3 EN 10/40 GbE Single Port QSFP+ Adapter (MCX313A-BCBT)\n\t\t15b3 0065  ConnectX-3 VPI IB FDR/40 GbE Dual Port QSFP+ Adapter\n\t\t15b3 0066  ConnectX-3 IB FDR10 Dual Port Mezzanine Card\n\t\t15b3 0067  ConnectX-3 VPI IB FDR/40 GbE Single Port QSFP+ Adapter\n\t\t15b3 0071  ConnectX-3 VPI IB FDR/40 GbE Dual Port QSFP+ Mezzanine Card\n# SVID = 15B3 SSID = 0078\n\t\t15b3 0078  ConnectX-3 10 GbE Dual Port KR Mezzanine Card\n\t\t15b3 0079  ConnectX-3 40 GbE Dual Port QSFP+ Adapter\n# SVID = 15B3 SSID = 0080\n\t\t15b3 0080  ConnectX-3 10 GbE Dual Port SFP+ Adapter\n\t1004  MT27500/MT27520 Family [ConnectX-3/ConnectX-3 Pro Virtual Function]\n\t1005  MT27510 Family\n\t1006  MT27511 Family\n\t1007  MT27520 Family [ConnectX-3 Pro]\n\t\t1014 04eb  2-Port 10GbE NIC and RoCE SR PCIe3\n\t\t103c 22f3  InfiniBand FDR/Ethernet 10Gb/40Gb 2-port 544+QSFP Adapter\n\t\t103c 22f4  InfiniBand FDR/Ethernet 10Gb/40Gb 2-port 544+FLR-QSFP Adapter\n\t\t103c 801f  Ethernet 10G 2-port 546SFP+ Adapter\n\t\t117c 0090  FastFrame NQ41\n\t\t117c 0091  FastFrame NQ42\n\t\t117c 0092  FastFrame NQ11\n\t\t117c 0093  FastFrame NQ12\n\t\t15b3 0006  Mellanox Technologies ConnectX-3 Pro Stand-up dual-port 40GbE MCX314A-BCCT\n\t\t15b3 0078  ConnectX-3 Pro 10 GbE Dual Port KR Mezzanine Card\n\t\t15b3 0079  ConnectX-3 Pro 40 GbE Dual Port QSFP+ Adapter\n\t\t15b3 0080  ConnectX-3 Pro 10 GbE Dual Port SFP+ Adapter\n\t\t193d 1002  520F-B\n\t1009  MT27530 Family\n\t100a  MT27531 Family\n\t100b  MT27540 Family\n\t100c  MT27541 Family\n\t100d  MT27550 Family\n\t100e  MT27551 Family\n\t100f  MT27560 Family\n\t1010  MT27561 Family\n\t1011  MT27600 [Connect-IB]\n\t1012  MT27600 Family [Connect-IB Virtual Function]\n\t1013  MT27700 Family [ConnectX-4]\n\t\t1014 04f7  PCIe3 2-port 100 GbE (NIC and RoCE) QSFP28 Adapter for Power\n\t\t15b3 0003  Mellanox Technologies ConnectX-4 Stand-up single-port 40GbE MCX413A-BCAT\n\t\t15b3 0005  Mellanox Technologies ConnectX-4 Stand-up single-port 40GbE MCX415A-BCAT\n\t\t15b3 0006  MCX416A-BCAT, ConnectX-4 EN, 40/56GbE 2P, PCIe3.0 x16\n\t\t15b3 0007  ConnectX-4 EN network interface card, 40/56GbE dual-port QSFP28, PCIe3.0 x16, tall bracket\n\t\t15b3 0008  ConnectX-4 Stand-up dual-port 100GbE MCX416A-CCAT\n\t\t15b3 0033  ConnectX-4 VPI IB EDR/100 GbE Single Port QSFP28 Adapter\n\t\t15b3 0034  ConnectX-4 VPI IB EDR/100 GbE Dual Port QSFP28 Adapter\n\t\t15b3 0050  ConnectX-4 100 GbE Dual Port QSFP28 Adapter\n\t1014  MT27700 Family [ConnectX-4 Virtual Function]\n\t1015  MT27710 Family [ConnectX-4 Lx]\n\t\t15b3 0001  ConnectX-4 Lx EN network interface card, 25GbE single-port SFP28, PCIe3.0 x8, tall bracket, ROHS R6\n\t\t15b3 0003  Stand-up ConnectX-4 Lx EN, 25GbE dual-port SFP28, PCIe3.0 x8, MCX4121A-ACAT\n\t\t15b3 0004  ConnectX-4 Lx Stand-up dual-port 10GbE MCX4121A-XCAT\n\t\t15b3 0005  Mellanox Technologies ConnectX-4 Lx Stand-up single-port 40GbE MCX4131A-BCAT\n\t\t15b3 0020  MCX4411A-ACQN, ConnectX-4 Lx EN OCP, 1x25Gb\n\t\t15b3 0021  MCX4421A-ACQN ConnectX-4 Lx EN OCP,2x25G\n\t\t15b3 0025  ConnectX-4 Lx 25 GbE Dual Port SFP28 rNDC\n\t\t193d 100a  620F-B\n\t1016  MT27710 Family [ConnectX-4 Lx Virtual Function]\n\t1017  MT27800 Family [ConnectX-5]\n\t\t15b3 0006  ConnectX®-5 EN network interface card, 100GbE single-port QSFP28, PCIe3.0 x16, tall bracket; MCX515A-CCAT\n\t\t15b3 0020  ConnectX®-5 EN network interface card, 10/25GbE dual-port SFP28, PCIe3.0 x8, tall bracket ; MCX512A-ACAT\n\t\t15b3 0068  ConnectX®-5 EN network interface card for OCP2.0, Type 1, with host management, 25GbE dual-port SFP28, PCIe3.0 x8, no bracket Halogen free ; MCX542B-ACAN\n\t1018  MT27800 Family [ConnectX-5 Virtual Function]\n\t1019  MT28800 Family [ConnectX-5 Ex]\n\t\t15b3 0008  ConnectX-5 Ex EN network interface card, 100GbE dual-port QSFP28, PCIe4.0 x16, tall bracket; MCX516A-CDAT\n\t101a  MT28800 Family [ConnectX-5 Ex Virtual Function]\n\t101b  MT28908 Family [ConnectX-6]\n\t101c  MT28908 Family [ConnectX-6 Virtual Function]\n\t101d  MT2892 Family [ConnectX-6 Dx]\n\t101e  ConnectX Family mlx5Gen Virtual Function\n\t101f  MT2894 Family [ConnectX-6 Lx]\n\t1020  MT28860\n\t1021  MT28861\n\t1974  MT28800 Family [ConnectX-5 PCIe Bridge]\n\t1975  MT416842 Family [BlueField SoC PCIe Bridge]\n\t1976  MT28908 Family [ConnectX-6 PCIe Bridge]\n\t1977  MT2892 Family [ConnectX-6 Dx PCIe Bridge]\n\t1978  MT42822 Family [BlueField-2 SoC PCIe Bridge]\n\t4117  MT27712A0-FDCF-AE\n\t\t1bd4 0039  SN10XMP2P25\n\t\t1bd4 004d  SN10XMP2P25,YZPC-01191-101\n\t5274  MT21108 InfiniBridge\n\t5a44  MT23108 InfiniHost\n\t5a45  MT23108 [Infinihost HCA Flash Recovery]\n\t5a46  MT23108 PCI Bridge\n\t5e8c  MT24204 [InfiniHost III Lx HCA]\n\t5e8d  MT25204 [InfiniHost III Lx HCA Flash Recovery]\n\t6001  NVMe SNAP Controller\n\t6274  MT25204 [InfiniHost III Lx HCA]\n\t6278  MT25208 InfiniHost III Ex (Tavor compatibility mode)\n\t6279  MT25208 [InfiniHost III Ex HCA Flash Recovery]\n\t6282  MT25208 [InfiniHost III Ex]\n\t6340  MT25408A0-FCC-SI ConnectX, Dual Port 10Gb/s InfiniBand / 10GigE Adapter IC with PCIe 2.0 x8 2.5GT/s Interface\n\t634a  MT25408A0-FCC-DI ConnectX, Dual Port 20Gb/s InfiniBand / 10GigE Adapter IC with PCIe 2.0 x8 2.5GT/s Interface\n\t\t1014 1014  4X InfiniBand DDR Expansion Card (CFFh) for IBM BladeCenter\n\t6368  MT25448 [ConnectX EN 10GigE, PCIe 2.0 2.5GT/s]\n\t6372  MT25458 ConnectX EN 10GBASE-T PCIe 2.5 GT/s\n\t6732  MT25408A0-FCC-GI ConnectX, Dual Port 20Gb/s InfiniBand / 10GigE Adapter IC with PCIe 2.0 x8 5.0GT/s Interface\n\t673c  MT25408A0-FCC-QI ConnectX, Dual Port 40Gb/s InfiniBand / 10GigE Adapter IC with PCIe 2.0 x8 5.0GT/s Interface\n\t\t1014 0415  PCIe2 2-port 4X InfiniBand QDR Adapter for Power\n\t\t1014 0487  GX++ 1-port 4X IB QDR Adapter for Power 795\n\t\t103c 1782  4X QDR InfiniBand Mezzanine HCA for c-Class BladeSystem\n\t\t15b3 0021  HP InfiniBand 4X QDR CX-2 PCI-e G2 Dual Port HCA\n\t6746  MT26438 [ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE Virtualization+]\n\t\t103c 1781  NC543i 1-port 4x QDR IB/Flex-10 10Gb Adapter\n\t\t103c 3349  NC543i 2-port 4xQDR IB/10Gb Adapter\n\t6750  MT26448 [ConnectX EN 10GigE, PCIe 2.0 5GT/s]\n\t\t1014 0416  PCIe2 2-Port 10GbE RoCE SFP+ Adapter\n\t\t1014 0461  PCIe2 2-Port 10GbE RoCE SR Adapter\n\t\t15b3 0018  HP 10 GbE PCI-e G2 Dual-Port NIC (rev C1)\n# FC EC26\n\t\t15b3 6572  IBM Flex System EN4132 2-port 10Gb RoCE Adapter\n\t675a  MT26458 ConnectX EN 10GBASE-T PCIe Gen2 5.0 GT/s\n\t6764  MT26468 [ConnectX EN 10GigE, PCIe 2.0 5GT/s Virtualization+]\n\t\t103c 3313  NC542m Dual Port Flex-10 10GbE BLc Adapter\n\t676e  MT26478 [ConnectX EN 40GigE, PCIe 2.0 5GT/s]\n\t6778  MT26488 [ConnectX VPI PCIe 2.0 5GT/s - IB DDR / 10GigE Virtualization+]\n\t7101  NPS-400 configuration and management interface\n\t7102  NPS-400 network interface PF\n\t7103  NPS-400 network interface VF\n\t7121  NPS-600 configuration and management interface\n\t7122  NPS-600 network interface PF\n\t7123  NPS-600 network interface VF\n\t8200  Innova-2 Flex Shell Logic\n\ta2d0  MT416842 BlueField SoC Crypto enabled\n\ta2d1  MT416842 BlueField SoC Crypto disabled\n\ta2d2  MT416842 BlueField integrated ConnectX-5 network controller\n\ta2d3  MT416842 BlueField multicore SoC family VF\n\ta2d4  MT42822 BlueField-2 SoC Crypto enabled\n\ta2d5  MT42822 BlueField-2 SoC Crypto disabled\n\ta2d6  MT42822 BlueField-2 integrated ConnectX-6 Dx network controller\n\tc2d2  MT416842 BlueField SoC management interfac\n\tc2d3  MT42822 BlueField-2 SoC Management Interface\n# SwitchX-2, 40GbE switch\n\tc738  MT51136\n\tc739  MT51136 GW\n\tc838  MT52236\n\tc839  MT52236 router\n\tcaf1  ConnectX-4 CAPI Function\n# Spectrum, 100GbE Switch\n\tcb84  MT52100\n\tcf08  Switch-IB2\n\tcf6c  MT53100 [Spectrum-2]\n\tcf70  Spectrum-3\n\tcf80  Spectrum-4\n\td2f0  Quantum HDR (200Gbps) switch\n\td2f2  Quantum-2 NDR (400Gbps) switch\n15b4  CCI/TRIAD\n15b5  Cimetrics Inc\n15b6  Texas Memory Systems Inc\n\t0001  XP15 DSP Accelerator\n\t0002  XP30 DSP Accelerator\n\t0003  XP00 Data Acquisition Device\n\t0004  XP35 DSP Accelerator\n\t0007  XP100 DSP Accelerator [XP100-T0]\n\t0008  XP100 DSP Accelerator [XP100-T1]\n\t0009  XP100 DSP Accelerator [XP100-E0]\n\t000a  XP100 DSP Accelerator [XP100-E1]\n\t000e  XP100 DSP Accelerator [XP100-0]\n\t000f  XP100 DSP Accelerator [XP100-1]\n\t0010  XP100 DSP Accelerator [XP100-P0]\n\t0011  XP100 DSP Accelerator [XP100-P1]\n\t0012  XP100 DSP Accelerator [XP100-P2]\n\t0013  XP100 DSP Accelerator [XP100-P3]\n\t0014  RamSan Flash SSD\n\t0015  ZBox\n15b7  Sandisk Corp\n\t2001  Skyhawk Series NVME SSD\n\t5001  WD Black NVMe SSD\n\t5002  WD Black 2018/PC SN720 NVMe SSD\n\t5003  WD Black 2018/PC SN520 NVMe SSD\n15b8  ADDI-DATA GmbH\n\t1001  APCI1516 SP controller (16 digi outputs)\n\t1003  APCI1032 SP controller (32 digi inputs w/ opto coupler)\n\t1004  APCI2032 SP controller (32 digi outputs)\n\t1005  APCI2200 SP controller (8/16 digi outputs (relay))\n\t1006  APCI1564 SP controller (32 digi ins, 32 digi outs)\n\t100a  APCI1696 SP controller (96 TTL I/Os)\n\t3001  APCI3501 SP controller (analog output board)\n\t300f  APCI3600 Noise and vibration measurement board\n\t7001  APCI7420 2-port Serial Controller\n\t7002  APCI7300 Serial Controller\n15b9  Maestro Digital Communications\n15ba  Impacct Technology Corp\n15bb  Portwell Inc\n15bc  Agilent Technologies\n\t0100  HPFC-5600 Tachyon DX2+ FC\n\t0103  QX4 PCI Express quad 4-gigabit Fibre Channel controller\n\t0105  Celerity FC-44XS/FC-42XS/FC-41XS/FC-44ES/FC-42ES/FC-41ES\n\t\t117c 0022  Celerity FC-42XS Fibre Channel Adapter\n\t\t117c 0025  Celerity FC-44ES Fibre Channel Adapter\n\t\t117c 0026  Celerity FC-42ES Fibre Channel Adapter\n\t1100  E8001-66442 PCI Express CIC\n\t2922  64 Bit, 133MHz PCI-X Exerciser & Protocol Checker\n\t2928  64 Bit, 66MHz PCI Exerciser & Analyzer\n\t2929  64 Bit, 133MHz PCI-X Analyzer & Exerciser\n15bd  DFI Inc\n15be  Sola Electronics\n15bf  High Tech Computer Corp (HTC)\n15c0  BVM Ltd\n15c1  Quantel\n15c2  Newer Technology Inc\n15c3  Taiwan Mycomp Co Ltd\n15c4  EVSX Inc\n15c5  Procomp Informatics Ltd\n\t8010  1394b - 1394 Firewire 3-Port Host Adapter Card\n15c6  Technical University of Budapest\n15c7  Tateyama System Laboratory Co Ltd\n\t0349  Tateyama C-PCI PLC/NC card Rev.01A\n15c8  Penta Media Co Ltd\n15c9  Serome Technology Inc\n15ca  Bitboys OY\n15cb  AG Electronics Ltd\n15cc  Hotrail Inc\n15cd  Dreamtech Co Ltd\n15ce  Genrad Inc\n15cf  Hilscher GmbH\n\t0000  CIFX 50E-DP(M/S)\n15d1  Infineon Technologies AG\n15d2  FIC (First International Computer Inc)\n15d3  NDS Technologies Israel Ltd\n15d4  Iwill Corp\n15d5  Tatung Co\n15d6  Entridia Corp\n15d7  Rockwell-Collins Inc\n15d8  Cybernetics Technology Co Ltd\n15d9  Super Micro Computer Inc\n15da  Cyberfirm Inc\n15db  Applied Computing Systems Inc\n15dc  Litronic Inc\n\t0001  Argus 300 PCI Cryptography Module\n15dd  Sigmatel Inc\n15de  Malleable Technologies Inc\n15df  Infinilink Corp\n15e0  Cacheflow Inc\n15e1  Voice Technologies Group Inc\n15e2  Quicknet Technologies Inc\n\t0500  PhoneJack-PCI\n15e3  Networth Technologies Inc\n15e4  VSN Systemen BV\n15e5  Valley technologies Inc\n15e6  Agere Inc\n15e7  Get Engineering Corp\n15e8  National Datacomm Corp\n\t0130  Wireless PCI Card\n\t0131  NCP130A2 Wireless NIC\n15e9  Pacific Digital Corp\n\t1841  ADMA-100 DiscStaQ ATA Controller\n15ea  Tokyo Denshi Sekei K.K.\n15eb  DResearch Digital Media Systems GmbH\n15ec  Beckhoff GmbH\n\t3101  FC3101 Profibus DP 1 Channel PCI\n\t5102  FC5102\n15ed  Macrolink Inc\n15ee  In Win Development Inc\n15ef  Intelligent Paradigm Inc\n15f0  B-Tree Systems Inc\n15f1  Times N Systems Inc\n15f2  Diagnostic Instruments Inc\n15f3  Digitmedia Corp\n15f4  Valuesoft\n15f5  Power Micro Research\n15f6  Extreme Packet Device Inc\n15f7  Banctec\n15f8  Koga Electronics Co\n15f9  Zenith Electronics Corp\n15fa  J.P. Axzam Corp\n15fb  Zilog Inc\n15fc  Techsan Electronics Co Ltd\n15fd  N-CUBED.NET\n15fe  Kinpo Electronics Inc\n15ff  Fastpoint Technologies Inc\n1600  Northrop Grumman - Canada Ltd\n1601  Tenta Technology\n1602  Prosys-tec Inc\n1603  Nokia Wireless Communications\n1604  Central System Research Co Ltd\n1605  Pairgain Technologies\n1606  Europop AG\n1607  Lava Semiconductor Manufacturing Inc\n1608  Automated Wagering International\n1609  Scimetric Instruments Inc\n1612  Telesynergy Research Inc.\n1618  Stone Ridge Technology\n\t0001  RDX 11\n\t0002  HFT-01\n\t0400  FarSync T2P (2 port X.21/V.35/V.24)\n\t0440  FarSync T4P (4 port X.21/V.35/V.24)\n\t0610  FarSync T1U (1 port X.21/V.35/V.24)\n\t0620  FarSync T2U (2 port X.21/V.35/V.24)\n\t0640  FarSync T4U (4 port X.21/V.35/V.24)\n\t1610  FarSync TE1 (T1,E1)\n\t2610  FarSync DSL-S1 (SHDSL)\n\t3640  FarSync T4E (4-port X.21/V.35/V.24)\n\t4620  FarSync T2Ue PCI Express (2-port X.21/V.35/V.24)\n\t4640  FarSync T4Ue PCI Express (4-port X.21/V.35/V.24)\n1619  FarSite Communications Ltd\n\t0400  FarSync T2P (2 port X.21/V.35/V.24)\n\t0440  FarSync T4P (4 port X.21/V.35/V.24)\n\t0610  FarSync T1U (1 port X.21/V.35/V.24)\n\t0620  FarSync T2U (2 port X.21/V.35/V.24)\n\t0640  FarSync T4U (4 port X.21/V.35/V.24)\n\t1610  FarSync TE1 (T1,E1)\n\t1612  FarSync TE1 PCI Express (T1,E1)\n\t2610  FarSync DSL-S1 (SHDSL)\n\t3640  FarSync T4E (4-port X.21/V.35/V.24)\n\t4620  FarSync T2Ue PCI Express (2-port X.21/V.35/V.24)\n\t4640  FarSync T4Ue PCI Express (4-port X.21/V.35/V.24)\n\t5621  FarSync T2Ee PCI Express (2 port X.21/V.35/V.24)\n\t5641  FarSync T4Ee PCI Express (4 port X.21/V.35/V.24)\n\t6620  FarSync T2U-PMC PCI Express (2 port X.21/V.35/V.24)\n161f  Rioworks\n1621  Lynx Studio Technology, Inc.\n\t0020  LynxTWO-A\n\t0021  LynxTWO-B\n\t0022  LynxTWO-C\n\t0023  Lynx L22\n\t0024  Lynx AES16\n\t0025  Lynx AES16-SRC\n\t0028  Lynx AES16e\n1626  TDK Semiconductor Corp.\n\t8410  RTL81xx Fast Ethernet\n1629  Kongsberg Spacetec AS\n\t1003  Format synchronizer v3.0\n\t1006  Format synchronizer, model 10500\n\t1007  Format synchronizer, model 21000\n\t2002  Fast Universal Data Output\n\t3100  IO31000 Frame Synchronizer and I/O\n\t3200  IO32000 Frame Synchronizer and I/O\n\t4002  High Rate Demodulator\n\t5001  High Rate FEC\n\t6001  High Rate Demodulator and FEC\n1631  Packard Bell B.V.\n1638  Standard Microsystems Corp [SMC]\n\t1100  SMC2602W EZConnect / Addtron AWA-100 / Eumitcom PCI WL11000\n163c  Smart Link Ltd.\n\t3052  SmartLink SmartPCI562 56K Modem\n\t5449  SmartPCI561 Modem\n1641  MKNet Corp.\n1642  Bitland(ShenZhen) Information Technology Co., Ltd.\n# nee Brocade Communications Systems, Inc.\n1657  Cavium QLogic\n\t0013  425/825/42B/82B 4Gbps/8Gbps PCIe dual port FC HBA\n\t\t103c 1742  82B 8Gbps dual port FC HBA\n\t\t103c 1744  42B 4Gbps dual port FC HBA\n\t\t1657 0014  425/825 4Gbps/8Gbps PCIe dual port FC HBA\n\t0014  1010/1020/1007/1741 10Gbps CNA\n\t\t1657 0014  1010/1020/1007/1741 10Gbps CNA - FCOE\n\t\t1657 0015  1010/1020/1007/1741 10Gbps CNA - LL\n\t0017  415/815/41B/81B 4Gbps/8Gbps PCIe single port FC HBA\n\t\t103c 1741  41B 4Gbps single port FC HBA\n\t\t103c 1743  81B 8Gbps single port FC HBA\n\t\t1657 0014  415/815 4Gbps/8Gbps single port PCIe FC HBA\n\t0021  804 8Gbps FC HBA for HP Bladesystem c-class\n\t0022  BR-1860 Fabric Adapter\n\t\t1657 0022  10Gbps CNA - FCOE\n\t\t1657 0023  10Gbps CNA - LL\n\t\t1657 0024  16Gbps FC HBA\n# Mezz card for IBM\n\t0023  1867/1869 16Gbps FC HBA\n# Same Device_ID used for 410 (1port) and 420 (2 port) HBAs.\n\t0646  400 4Gbps PCIe FC HBA\n165a  Epix Inc\n\tc100  PIXCI(R) CL1 Camera Link Video Capture Board [custom QL5232]\n\td200  PIXCI(R) D2X Digital Video Capture Board [custom QL5232]\n\td300  PIXCI(R) D3X Digital Video Capture Board [custom QL5232]\n\teb01  PIXCI(R) EB1 PCI Camera Link Video Capture Board\n# Gidel Reconfigurable Computing\n165c  Gidel Ltd.\n\t5361  PROCStarII60-1\n\t5362  PROCStarII60-2\n\t5364  PROCStarII60-4\n\t5435  ProcSparkII\n\t5661  ProcE60\n\t56e1  ProcE180\n\t5911  ProcStarIII110-1\n\t5912  ProcStarIII110-2\n\t5913  ProcStarIII110-3\n\t5914  ProcStarIII110-4\n\t5921  ProcStarIII150-1\n\t5922  ProcStarIII150-2\n\t5923  ProcStarIII150-3\n\t5924  ProcStarIII150-4\n\t5931  ProcStarIII260-1\n\t5932  ProcStarIII260-2\n\t5933  ProcStarIII260-3\n\t5934  ProcStarIII260-4\n\t5941  ProcStarIII340-1\n\t5942  ProcStarIII340-2\n\t5943  ProcStarIII340-3\n\t5944  ProcStarIII340-4\n\t5a01  ProceIII80\n\t5a11  ProceIII110\n\t5a21  ProceIII150\n\t5a31  ProceIII260\n\t5a41  ProceIII340\n\t5b51  ProceIV360\n\t5b61  ProceIV530\n\t5b71  ProceIV820\n\t5c01  ProcStarIV80-1\n\t5c02  ProcStarIV80-2\n\t5c03  ProcStarIV80-3\n\t5c04  ProcStarIV80-4\n\t5c11  ProcStarIV110-1\n\t5c12  ProcStarIV110-2\n\t5c13  ProcStarIV110-3\n\t5c14  ProcStarIV110-4\n\t5c51  ProcStarIV360-1\n\t5c52  ProcStarIV360-2\n\t5c53  ProcStarIV360-3\n\t5c54  ProcStarIV360-4\n\t5c61  ProcStarIV530-1\n\t5c62  ProcStarIV530-2\n\t5c63  ProcStarIV530-3\n\t5c64  ProcStarIV530-4\n\t5c71  ProcStarIV820-1\n\t5c72  ProcStarIV820-2\n\t5c73  ProcStarIV820-3\n\t5c74  ProcStarIV820-4\n\t5d01  Proc10480\n\t5d11  Proc104110\n\t5f01  ProceV_A3\n\t5f11  ProceV_A7\n\t5f21  ProceV_AB\n\t5f31  ProceV_D5\n\t5f41  ProceV_D8\n\t6732  Proc6M\n\t6832  Proc12M\n\t7101  Proc10a_27\n\t7111  Proc10a_48\n\t7121  Proc10a_66\n\t7141  Proc10a_115\n\t7181  Proc10a_27S\n\t7191  Proc10a_48S\n\t71a1  Proc10a_66S\n\t71b1  Proc10A\n\t72b1  HawkEye\n\t73b1  Proc10s\n165d  Hsing Tech. Enterprise Co., Ltd.\n165f  Linux Media Labs, LLC\n\t1020  LMLM4 MPEG-4 encoder\n1661  Worldspace Corp.\n1668  Actiontec Electronics Inc\n\t0100  Mini-PCI bridge\n# Formerly SiByte, Inc.\n166d  Broadcom Corporation\n\t0001  SiByte BCM1125/1125H/1250 System-on-a-Chip PCI\n\t0002  SiByte BCM1125H/1250 System-on-a-Chip HyperTransport\n\t0012  SiByte BCM1280/BCM1480 System-on-a-Chip PCI-X\n\t0014  Sibyte BCM1280/BCM1480 System-on-a-Chip HyperTransport\n1677  Bernecker + Rainer\n\t104e  5LS172.6 B&R Dual CAN Interface Card\n\t12d7  5LS172.61 B&R Dual CAN Interface Card\n\t20ad  5ACPCI.MFIO-K01 Profibus DP / K-Feldbus / COM\n1678  NetEffect\n\t0100  NE020 10Gb Accelerated Ethernet Adapter (iWARP RNIC)\n1679  Tokyo Electron Device Ltd.\n\t3000  SD Standard host controller [Ellen]\n167b  ZyDAS Technology Corp.\n\t2102  ZyDAS ZD1202\n\t\t187e 3406  ZyAIR B-122 CardBus 11Mbs Wireless LAN Card\n\t\t187e 3407  ZyAIR B-320 802.11b Wireless PCI Adapter\n\t2116  ZD1212B Wireless Adapter\n167d  Samsung Electro-Mechanics Co., Ltd.\n\ta000  MagicLAN SWL-2210P 802.11b [Intersil ISL3874]\n167e  ONNTO Corp.\n1681  Hercules\n1682  XFX Pine Group Inc.\n\tc580  Radeon RX 580\n1688  CastleNet Technology Inc.\n\t1170  WLAN 802.11b card\n# nee Atheros Communications, Inc.\n168c  Qualcomm Atheros\n\t0007  AR5210 Wireless Network Adapter [AR5000 802.11a]\n\t\t1737 0007  WPC54A Wireless PC Card\n\t\t1b47 0100  Harmony 8450CN Wireless CardBus Module\n\t\t1b47 0110  Skyline 4030 / Harmony 8450 802.11a Wireless CardBus Adapter\n\t\t8086 2501  PRO/Wireless 5000 LAN PCI Adapter Module\n\t0011  AR5211 Wireless Network Adapter [AR5001A 802.11a]\n\t0012  AR5211 Wireless Network Adapter [AR5001X 802.11ab]\n\t\t1186 3a03  AirPro DWL-A650 Wireless Cardbus Adapter (rev.B)\n\t\t1186 3a04  AirPro DWL-AB650 Multimode Wireless Cardbus Adapter\n\t\t1186 3a05  AirPro DWL-AB520 Multimode Wireless PCI Adapter\n\t\t126c 8031  2201 Mobile Adapter\n\t\t1385 4400  WAB501 802.11ab Wireless CardBus Card\n\t\t1b47 aa00  8460 802.11ab Wireless CardBus Adapter\n\t0013  AR5212/5213/2414 Wireless Network Adapter\n\t\t0308 3402  AG-100 802.11ag Wireless Cardbus Adapter\n\t\t0308 3405  G-102 v2 802.11g Wireless Cardbus Adapter\n\t\t0308 3408  G-170S 802.11g Wireless CardBus Adapter\n\t\t0e11 00e5  NC6000/NC8000 laptop\n\t\t10b7 6002  3CRWE154A72 802.11abg Cardbus Adapter\n\t\t1113 d301  Philips CPWNA100 Wireless CardBus adapter\n\t\t1113 ee23  SMCWPCIT-G 108Mbps Wireless PCI adapter\n\t\t1154 033b  Buffalo WLI-CB-AMG54\n\t\t1154 034e  Buffalo WLI-CB-AG108HP 802.11abg Cardbus Adapter\n\t\t1186 3202  DWL-G650 (Rev B3,B5) Wireless cardbus adapter\n\t\t1186 3203  AirPlus DWL-G520 Wireless PCI Adapter (rev. A)\n\t\t1186 3a07  AirXpert DWL-AG650 Wireless Cardbus Adapter\n\t\t1186 3a08  AirXpert DWL-AG520 Wireless PCI Adapter\n\t\t1186 3a12  D-Link AirPlus DWL-G650 Wireless Cardbus Adapter(rev.C)\n\t\t1186 3a13  AirPlus DWL-G520 Wireless PCI Adapter (rev. B)\n\t\t1186 3a14  AirPremier AG DWL-AG530 Wireless PCI Adapter (rev.A)\n\t\t1186 3a17  D-Link AirPremier DWL-G680 Wireless Cardbus Adapter\n\t\t1186 3a18  D-Link AirPremier DWL-G550 Wireless PCI Adapter\n\t\t1186 3a1a  WNA-2330 802.11bg Wireless CardBus Adapter\n\t\t1186 3a63  D-Link AirPremier DWL-AG660 Wireless Cardbus Adapter\n\t\t1186 3a93  Conceptronic C54I Wireless 801.11g PCI card\n\t\t1186 3a94  Conceptronic C54C 802.11g Wireless Cardbus Adapter\n\t\t1186 3ab0  Allnet ALL0281 Wireless PCI Card\n\t\t1385 4600  WAG511 802.11a/b/g Dual Band Wireless PC Card\n\t\t1385 4610  WAG511 802.11a/b/g Dual Band Wireless PC Card\n\t\t1385 4900  WG311v1 802.11g Wireless PCI Adapter\n\t\t1385 4a00  WAG311 802.11a/g Wireless PCI Adapter\n\t\t1385 4b00  WG511T 108 Mbps Wireless PC Card (rev.A/B)\n\t\t1385 4d00  WG311T 108 Mbps Wireless PCI Adapter (rev.A2)\n\t\t1385 4f00  WG511U Double 108 Mbps Wireless PC Card\n\t\t1385 5a00  WG311T (rev.A3 v1h3/v1h4) 108 Mbps Wireless PCI Adapter [AR2412]\n\t\t1385 5b00  WG511T 108 Mbps Wireless PC Card (rev.C)\n\t\t1385 5d00  WPN511 RangeMax Wireless PC Card\n\t\t1458 e911  GN-WIAG02\n\t\t1468 0403  U10H014 802.11g Cardbus Adapter\n\t\t1468 0408  ThinkPad 11b/g Wireless LAN Mini PCI Adapter\n\t\t14b7 0a10  8480-WD 802.11abg Cardbus Adapter\n\t\t14b7 0a60  8482-WD ORiNOCO 11a/b/g Wireless PCI Adapter\n\t\t14b7 aa30  8800-FC 802.11bg Cardbus Adapter\n\t\t14b7 aa40  8470-WD 802.11bg Cardbus Adapter\n\t\t14b9 cb21  CB21 802.11a/b/g Cardbus Adapter\n\t\t1668 1026  IBM HighRate 11 a/b/g Wireless CardBus Adapter\n\t\t168c 0013  AirPlus XtremeG DWL-G650 Wireless PCMCIA Adapter\n\t\t168c 1025  DWL-G650B2 Wireless CardBus Adapter\n\t\t168c 1027  Engenius NL-3054CB ARIES b/g CardBus Adapter\n\t\t168c 1042  Ubiquiti Networks SuperRange a/b/g Cardbus Adapter\n\t\t168c 1051  EZ Connect g 802.11g 108Mbps Wireless PCI Adapter\n\t\t168c 2026  Netgate 5354MP ARIES a(108Mb turbo)/b/g MiniPCI Adapter\n\t\t168c 2027  D-Link AirPlus DWL-G520 Wireless PCI Adapter (rev. A)\n\t\t168c 2041  Engenius 5354MP Plus ARIES2 b/g MiniPCI Adapter\n\t\t168c 2042  Engenius 5354MP Plus ARIES2 a/b/g MiniPCI Adapter\n\t\t168c 2051  TRENDnet TEW-443PI Wireless PCI Adapter\n\t\t16a5 160a  BWP712 802.11bg Wireless CardBus Adapter\n\t\t16ab 7302  Trust Speedshare Turbo Pro Wireless PCI Adapter\n\t\t1737 0017  WPC55AG\n\t\t1737 0026  WMP55AG v1.1\n\t\t1737 0035  WPC55AG v1.2 802.11abg Cardbus Adapter\n\t\t1737 0036  WMP55AG v1.2 802.11abg PCI Adapter\n\t\t1799 3000  F6D3000 Dual-Band Wireless A+G Desktop Card\n\t\t1799 3010  F6D3010 Dual-Band Wireless A+G Notebook Card\n\t\t17cf 0042  Z-COMAX Highpower XG-622H (400mw) 802.11b/g mini-PCI Adapter\n\t\t185f 1012  CM9 Wireless a/b/g MiniPCI Adapter\n\t\t185f 2012  Wistron NeWeb WLAN a+b+g model CB9\n\t\ta727 6801  3CRXJK10075 OfficeConnect Wireless 108Mbps 11g XJACK PC Card\n\t001a  AR2413/AR2414 Wireless Network Adapter [AR5005G(S) 802.11bg]\n\t\t1052 168c  Sweex Wireless Lan PC Card 54Mbps\n\t\t1113 ee20  SMC Wireless CardBus Adapter 802.11g (SMCWCB-G EU)\n\t\t1113 ee24  SMC Wireless PCI Card WPCI-G\n\t\t1186 3a15  AirPlus G DWL-G630 Wireless Cardbus Adapter (rev.D1)\n\t\t1186 3a16  AirPlus G DWL-G510 Wireless PCI Adapter(rev.B)\n\t\t1186 3a1c  WNA-1330 Notebook Adapter\n\t\t1186 3a1d  WDA-1320 Desktop Adapter\n\t\t1186 3a23  AirPlus G DWL-G520+A Wireless PCI Adapter\n\t\t1186 3a24  AirPlus G DWL-G650+A Wireless Cardbus Adapter\n\t\t1186 3b08  AirPlus G DWL-G630 Wireless Cardbus Adapter (rev.C1)\n\t\t168c 001a  Belkin FD7000\n\t\t168c 1052  TP-Link TL-WN510G Wireless CardBus Adapter\n\t\t168c 2052  Compex Wireless 802.11 b/g  MiniPCI Adapter, Rev A1 [WLM54G]\n\t\t16ec 0122  Wireless PCI Adapter Model 5418\n\t\t1737 0053  WPC54G v7 802.11g Wireless-G Notebook Adapter\n\t\t1799 700c  F5D7000 v5000 Wireless G Desktop Card\n\t\t1799 701d  F5D7010 v5000 Wireless G Notebook Card\n\t\t17f9 0008  DX-WGNBC 802.11bg Wireless CardBus Adapter\n\t\t17f9 0018  DX-WGDTC 802.11bg Wireless PCI Adapter\n\t001b  AR5413/AR5414 Wireless Network Adapter [AR5006X(S) 802.11abg]\n# Atheros AR5414 32-bit mini-PCI type IIIB\n\t\t0777 1107  UB5 802.11a Wireless Mini PCI Adapter\n\t\t0777 3002  XR2 802.11g Wireless Mini PCI Adapter\n\t\t0777 3005  XR5 802.11a Wireless Mini PCI Adapter\n\t\t0777 3009  XR9 900MHz Wireless Mini PCI Adapter\n\t\t1154 034e  WLI-CB-AG108HP 802.11abg Wireless CardBus Adapter\n\t\t1186 3a19  D-Link AirPremier AG DWL-AG660 Wireless Cardbus Adapter\n\t\t1186 3a22  AirPremier AG DWL-AG530 Wireless PCI Adapter (rev.B)\n\t\t11ad 5001  WN5301A 802.11bg Wireless PCI Adapter\n\t\t1458 e901  GN-WI01HT Wireless a/b/g MiniPCI Adapter\n\t\t168c 001b  Wireless LAN PCI LiteOn\n\t\t168c 1062  IPN-W100CB 802.11abg Wireless CardBus Adapter\n\t\t168c 2062  EnGenius EMP-8602 (400mw) or Compex WLM54AG (SuperAG)\n\t\t168c 2063  EnGenius EMP-8602 (400mw) or Compex WLM54AG\n\t\t17f9 000b  WL-711A 802.11abg Wireless CardBus Adapter\n\t\t17f9 000c  WPIA-112AG 802.11abg Wireless PCI Adapter\n\t\t17f9 000d  PC-686X 802.11abg Wireless Mini PCI Adapter\n\t\t185f 1600  DCMA-82 High Power WLAN 802.11a/b/g mini-PCI Module (Super A/G, eXtended Range, 400mW)\n\t\t1948 3aba  RBTBJ-AW 802.11abg Wireless Cardbus Adapter\n\t\ta727 6804  Wireless 11a/b/g PC Card with XJACK(r) Antenna\n\t001c  AR242x / AR542x Wireless Network Adapter (PCI-Express)\n\t\t0777 3006  SRX 802.11abg Wireless ExpressCard Adapter\n\t\t103c 137a  AR5BXB63 (Foxconn) 802.11bg Mini PCIe NIC\n\t\t106b 0086  AirPort Extreme\n\t\t144f 7106  WLL3140 (Toshiba PA3501U-1MPC) 802.11bg Wireless Mini PCIe Card\n\t\t144f 7128  WLL3141 (Toshiba PA3613U-1MPC) 802.11bg Wireless Mini PCIe Card\n\t\t1468 0428  AR5BXB63 802.11bg NIC\n\t\t1468 042a  AR5007EG 802.11bg NIC\n\t\t147b 1033  AirPace Wi-Fi\n\t\t168c 001c  AR242x 802.11abg NIC (PCI Express)\n\t\t168c 3061  AR5006EGS 802.11bg NIC (2.4GHz, PCI Express)\n\t\t168c 3062  AR5006EXS 802.11abg NIC (2.4/5.0GHz, PCI Express)\n\t\t168c 3063  AR5006EX 802.11abg NIC (2.4/5.0GHz, PCI Express)\n\t\t168c 3065  AR5006EG 802.11bg NIC (2.4GHz, PCI Express)\n\t\t168c 3067  AR242x 802.11abg Wireless PCI Express Adapter (rev 01)\n\t\t1a3b 1026  AW-GE780 802.11bg Wireless Mini PCIe Card\n\t001d  AR2417 Wireless Network Adapter [AR5007G 802.11bg]\n\t\t1799 720b  F5D7000 v8000 Wireless G Desktop Card\n\t\t1799 721b  F5D7010 v8000 Wireless G Notebook Card\n# the name AR5005VL is used for some AR5513 based designs\n\t0020  AR5513 802.11abg Wireless NIC\n\t\t0308 3407  M-102 802.11g Wireless Cardbus Adapter\n\t\t1186 3a67  DWL-G650M Super G MIMO Wireless Notebook Adapter\n\t\t1186 3a68  DWL-G520M Wireless 108G MIMO Desktop Adapter\n\t\t187e 340e  M-302 802.11g Wireless PCI Adapter\n\t\t1976 2003  TEW-601PC 802.11g Wireless CardBus Adapter\n\t0023  AR5416 Wireless Network Adapter [AR5008 802.11(a)bgn]\n\t\t0308 340b  NWD-170N 802.11bgn Wireless CardBus Adapter\n\t\t1154 0365  Buffalo WLP-CB-AG300 802.11abgn Cardbus Adapter\n\t\t1154 0367  WLI-CB-AG301N 802.11abgn Wireless CardBus Adapter\n\t\t1186 3a6a  DWA-642 802.11n RangeBooster N CardBus Adapter\n\t\t1186 3a6b  DWA-547 802.11n RangeBooster N 650 DeskTop Adapter\n\t\t1186 3a6d  DWA-552 802.11n Xtreme N Desktop Adapter (rev A1)\n\t\t1186 3a76  DWA-645 802.11n RangeBooster N 650 Notebook Adapter (rev A1)\n\t\t1737 0059  WPC300N v2 Wireless-N Notebook Adapter\n\t\t1737 0069  WPC100 v1 802.11n RangePlus Wireless Notebook Adapter\n\t\t1737 0072  WMP110 v1 802.11n RangePlus Wireless PCI Adapter\n\t\t1799 8011  F5D8011 v1 802.11n N1 Wireless Notebook Card\n\t\t187e 3411  NWD-370N 802.11n Wireless PCI Adapter\n\t\t1976 2008  TEW-621PC 802.11bgn Wireless CardBus Adapter\n\t0024  AR5418 Wireless Network Adapter [AR5008E 802.11(a)bgn] (PCI-Express)\n\t\t106b 0087  AirPort Extreme\n\t\t1186 3a70  DWA-556 Xtreme N PCI Express Desktop Adapter\n\t0027  AR9160 Wireless Network Adapter [AR9001 802.11(a)bgn]\n\t\t0777 4082  SR71-A 802.11abgn Wireless Mini PCI Adapter\n\t0029  AR922X Wireless Network Adapter\n\t\t0777 4005  SR71-15 802.11an Mini PCI Adapter\n\t\t1186 3a7a  DWA-552 802.11n Xtreme N Desktop Adapter (rev A2)\n\t\t1186 3a7d  DWA-552 802.11n Xtreme N Desktop Adapter (rev A3)\n\t\t168c 0029  AR922X Wireless Network Adapter\n\t\t168c 2096  Compex WLM200NX / Wistron DNMA-92\n\t002a  AR928X Wireless Network Adapter (PCI-Express)\n\t\t0777 4f05  SR71-X 802.11abgn Wireless ExpressCard Adapter [AR9280]\n\t\t103c 3041  AR5BHB92-H 802.11abgn Wireless Half-size Mini PCIe Card [AR9280]\n\t\t103c 3042  AzureWave AW-NE773 802.11abgn Wireless Half-size Mini PCIe Card [AR9280]\n\t\t105b e006  T77H053.00 802.11bgn Wireless Mini PCIe Card [AR9281]\n\t\t105b e01f  T77H047.31 802.11bgn Wireless Half-size Mini PCIe Card [AR9283]\n\t\t106b 008f  AirPort Extreme\n\t\t11ad 6600  WN6600A 802.11bgn Wireless Mini PCIe Card [AR9281]\n\t\t144f 7141  WLL6080 802.11bgn Wireless Mini PCIe Card [AR9281]\n\t\t168c 0203  DW1525 802.11abgn WLAN PCIe Card [AR9280]\n\t\t1a32 0303  EM303 802.11bgn Wireless Mini PCIe Card [AR9281]\n\t\t1a32 0306  EM306 802.11bgn Wireless Half-size Mini PCIe Card [AR9283]\n\t\t1a3b 1067  AW-NE771 802.11bgn Wireless Mini PCIe Card [AR9281]\n\t\t1a3b 1071  AW-NE772 802.11abgn Wireless Mini PCIe Card [AR9280]\n\t\t1a3b 1081  AW-NE773 802.11abgn Wireless Half-size Mini PCIe Card [AR9280]\n\t002b  AR9285 Wireless Network Adapter (PCI-Express)\n\t\t1028 0204  Wireless 1502 802.11bgn Half-size Mini PCIe Card\n\t\t1028 0205  Wireless 1702 802.11bgn Half-size Mini PCIe Card [AR9002WB-1NGCD]\n\t\t103c 303f  U98Z062.10 802.11bgn Wireless Half-size Mini PCIe Card\n\t\t103c 3040  U98Z062.12 802.11bgn Wireless Half-size Mini PCIe Card\n\t\t105b e017  T77H126.00 802.11bgn Wireless Half-size Mini PCIe Card\n\t\t105b e023  T77H121.04 802.11bgn Wireless Half-size Mini PCIe Card\n\t\t105b e025  T77H121.05 802.11bgn Wireless Half-size Mini PCIe Card\n\t\t1113 e811  WN7811A (Toshiba PA3722U-1MPC) 802.11bgn Wireless Half-size Mini PCIe Card\n\t\t185f 30af  DNXA-95 802.11bgn Wireless Half-size Mini PCIe Card\n\t\t1931 0023  Option GTM67x PCIe WiFi Adapter\n\t\t1a3b 1089  AW-NE785 / AW-NE785H 802.11bgn Wireless Full or Half-size Mini PCIe Card\n\t\t1a3b 2c37  AW-NB037H 802.11bgn Wireless Half-size Mini PCIe Card [AR9002WB-1NGCD]\n\t\t1b9a 0401  XW204E 802.11bgn Wireless Half-size Mini PCIe Card\n\t\t1b9a 0c03  WB214E 802.11bgn Wireless Half-size Mini PCIe Card [AR9002WB-1NGCD]\n\t002c  AR2427 802.11bg Wireless Network Adapter (PCI-Express)\n\t002d  AR9227 Wireless Network Adapter\n\t002e  AR9287 Wireless Network Adapter (PCI-Express)\n\t\t105b e034  T77H167.00\n\t0030  AR93xx Wireless Network Adapter\n\t\t103c 1627  AR9380/HB112 802.11abgn 3×3 Wi-Fi Adapter\n\t\t106b 009a  AirPort Extreme\n\t\t1186 3a7e  DWA-566 Wireless N 300 Dual Band PCIe Desktop Adapter\n\t\t1a56 2000  Killer Wireless-N 1102 Half-size Mini PCIe Card [AR9382]\n\t\t1a56 2001  Killer Wireless-N 1103 Half-size Mini PCIe Card [AR9380]\n\t0032  AR9485 Wireless Network Adapter\n\t\t1028 0208  Wireless 1506 WLAN Half Mini-Card\n\t\t103c 1838  AR9485/HB125 802.11bgn 1×1 Wi-Fi Adapter\n\t\t105b e044  Unex DHXA-225\n\t\t144d 410e  AR9485WB-EG 802.11b/g/n mini-PCIe card on a series 3 laptop\n\t\t1a3b 1186  AW-NE186H\n\t0033  AR958x 802.11abgn Wireless Network Adapter\n\t\t168c a120  AR9582 802.11a/n WLAN Mini-PCIe Adapter\n\t0034  AR9462 Wireless Network Adapter\n\t\t1028 020b  Wireless 1601 802.11abgn Adapter\n\t\t1028 0300  Wireless 1802 802.11abgn Adapter\n\t\t1a56 2003  Killer Wireless-N 1202 Half-size Mini PCIe Card\n\t0036  QCA9565 / AR9565 Wireless Network Adapter\n\t0037  AR9485 Wireless Network Adapter\n# Also used as Gigabyte GC-WB150 on a PCIe-to-mini-PCIe converter\n\t\t1a3b 2100  AW-NB100H 802.11n Wireless Mini PCIe Card\n\t003c  QCA986x/988x 802.11ac Wireless Network Adapter\n\t003e  QCA6174 802.11ac Wireless Network Adapter\n\t\t1a56 143a  Killer 1435 Wireless-AC\n\t\t1a56 1525  Killer N1525 Wireless-AC\n\t0040  QCA9980/9990 802.11ac Wireless Network Adapter\n\t0041  QCA6164 802.11ac Wireless Network Adapter\n\t0042  QCA9377 802.11ac Wireless Network Adapter\n\t0046  QCA9984 802.11ac Wave 2 Wireless Network Adapter\n\t0050  QCA9887 802.11ac Wireless Network Adapter\n\t0207  AR5210 Wireless Network Adapter [AR5000 802.11a]\n\t1014  AR5212 802.11abg NIC\n\t\t1014 058a  ThinkPad 11a/b/g Wireless LAN Mini Express Adapter (AR5BXB6)\n\t9013  AR5002X Wireless Network Adapter\n\tff19  AR5006X Wireless Network Adapter\n\tff1b  AR2425 Wireless Network Adapter [AR5007EG 802.11bg]\n\tff1c  AR5008 Wireless Network Adapter\n\tff1d  AR922x Wireless Network Adapter\n# Found in \"AVM Fritz!Box FON WLAN 7270v3\"\n\t\t168c ee1c  AR9220-AC1A [AVM Fritz!Box FON WLAN 7270 v3]\n1695  EPoX Computer Co., Ltd.\n169c  Netcell Corporation\n\t0044  Revolution Storage Processing Card\n# The right ID is 196d, but they got it nibble-swapped in 2202.\n169d  Club-3D VB (Wrong ID)\n16a5  Tekram Technology Co.,Ltd.\n16ab  Global Sun Technology Inc\n\t1100  GL24110P\n\t1101  PLX9052 PCMCIA-to-PCI Wireless LAN\n\t1102  PCMCIA-to-PCI Wireless Network Bridge\n\t8501  WL-8305 Wireless LAN PCI Adapter\n16ae  SafeNet Inc\n\t0001  SafeXcel 1140\n\t000a  SafeXcel 1841\n\t1141  SafeXcel 1141\n# misused vendor ID 0001\n\t\t0001 0001  SafeXcel 1141 v. 1.1\n\t1841  SafeXcel 1842\n16af  SparkLAN Communications, Inc.\n16b4  Aspex Semiconductor Ltd\n16b8  Sonnet Technologies, Inc.\n16be  Creatix Polymedia GmbH\n16c3  Synopsys, Inc.\n\tabcd  DWC_usb3 / PCIe bridge\n\tabce  DWC_usb3\n\tabcf  DWC_usb31\n\tedda  EPMockUp\n16c6  Micrel-Kendin\n\t8695  Centaur KS8695 ARM processor\n\t8842  KSZ8842-PMQL 2-Port Ethernet Switch\n16c8  Octasic Inc.\n16c9  EONIC B.V. The Netherlands\n16ca  CENATEK Inc\n\t0001  Rocket Drive DL\n# nee Innocore Gaming Ltd., nee Densitron Gaming Ltd., a division of Densitron Technologies\n16cd  Advantech Co. Ltd\n\t0101  DirectPCI SRAM for DPX-11x series\n\t0102  DirectPCI SRAM for DPX-S/C/E-series\n\t0103  DirectPCI ROM for DPX-11x series\n\t0104  DirectPCI ROM for DPX-S/C/E-series\n\t0105  DirectPCI I/O for DPX-114/DPX-115\n\t0106  DirectPCI I/O for DPX-116\n\t0107  DirectPCI I/O for DPX-116U\n\t0108  DirectPCI I/O for DPX-117\n\t0109  DirectPCI I/O for DPX-112\n\t010a  DirectPCI I/O for DPX-C/E-series\n\t010b  DirectPCI I/O for DPX-S series\n16ce  Roland Corp.\n16d5  Acromag, Inc.\n\t0504  PMC-DX504 Reconfigurable FPGA with LVDS I/O\n\t0520  PMC520 Serial Communication, 232 Octal\n\t0521  PMC521 Serial Communication, 422/485 Octal\n\t1020  PMC-AX1020 Reconfigurable FPGA with A/D & D/A\n\t1065  PMC-AX1065 Reconfigurable FPGA with A/D & D/A\n\t2004  PMC-DX2004 Reconfigurable FPGA with LVDS I/O\n\t2020  PMC-AX2020 Reconfigurable FPGA with A/D & D/A\n\t2065  PMC-AX2065 Reconfigurable FPGA with A/D & D/A\n\t3020  PMC-AX3020 Reconfigurable FPGA with A/D & D/A\n\t3065  PMC-AX3065 Reconfigurable FPGA with A/D & D/A\n\t4243  PMC424, APC424, AcPC424 Digital I/O and Counter Timer Module\n\t4248  PMC464, APC464, AcPC464 Digital I/O and Counter Timer Module\n\t424b  PMC-DX2002 Reconfigurable FPGA with Differential I/O\n\t4253  PMC-DX503 Reconfigurable FPGA with TTL and Differential I/O\n\t4312  PMC-CX1002 Reconfigurable Conduction-Cooled FPGA Virtex-II with Differential I/O\n\t4313  PMC-CX1003 Reconfigurable Conduction-Cooled FPGA Virtex-II with CMOS and Differential I/O\n\t4322  PMC-CX2002 Reconfigurable Conduction-Cooled FPGA Virtex-II with Differential I/O\n\t4323  PMC-CX2003 Reconfigurable Conduction-Cooled FPGA Virtex-II with CMOS and Differential I/O\n\t4350  PMC-DX501 Reconfigurable Digital I/O Module\n\t4353  PMC-DX2003 Reconfigurable FPGA with TTL and Differential I/O\n\t4357  PMC-DX502 Reconfigurable Differential I/O Module\n\t4457  PMC730, APC730, AcPC730 Multifunction Module\n\t4471  XMC730 Multi-function I/O module with front I/O\n\t4473  XMC730CC Multi-function I/O module with rear I/O Conduction-cooled\n\t464d  PMC408 32-Channel Digital Input/Output Module\n\t4850  PMC220-16 12-Bit Analog Output Module\n\t4a42  PMC483, APC483, AcPC483 Counter Timer Module\n\t4a50  PMC484, APC484, AcPC484 Counter Timer Module\n\t4a56  PMC230 16-Bit Analog Output Module\n\t4b47  PMC330, APC330, AcPC330 Analog Input Module, 16-bit A/D\n\t4c40  PMC-LX40 Reconfigurable Virtex-4 FPGA with plug-in I/O\n\t4c60  PMC-LX60 Reconfigurable Virtex-4 FPGA with plug-in I/O\n\t4d4d  PMC341, APC341, AcPC341 Analog Input Module, Simultaneous Sample & Hold\n\t4d4e  PMC482, APC482, AcPC482 Counter Timer Board\n\t524d  PMC-DX2001 Reconfigurable FPGA with TTL I/O\n\t5335  PMC-SX35 Reconfigurable Virtex-4 FPGA with plug-in I/O\n\t5456  PMC470 48-Channel Digital Input/Output Module\n\t5601  PMC-VLX85 Reconfigurable Virtex-5 FPGA with plug-in I/O\n\t5602  PMC-VLX110 Reconfigurable Virtex-5 FPGA with plug-in I/O\n\t5603  PMC-VSX95 Reconfigurable Virtex-5 FPGA with plug-in I/O\n\t5604  PMC-VLX155 Reconfigurable Virtex-5 FPGA with plug-in I/O\n\t5605  PMC-VFX70 Reconfigurable Virtex-5 FPGA with plug-in I/O\n\t5606  PMC-VLX155-1M Reconfigurable Virtex-5 FPGA with plug-in I/O\n\t5701  PMC-SLX150: Reconfigurable Spartan-6 FPGA with plug-in I/O\n\t5702  PMC-SLX150-1M: Reconfigurable Spartan-6 FPGA with plug-in I/O\n\t5801  XMC-VLX85 Reconfigurable Virtex-5 FPGA with plug-in I/O\n\t5802  XMC-VLX110 Reconfigurable Virtex-5 FPGA with plug-in I/O\n\t5803  XMC-VSX95 Reconfigurable Virtex-5 FPGA with plug-in I/O\n\t5804  XMC-VLX155 Reconfigurable Virtex-5 FPGA with plug-in I/O\n\t5807  XMC-SLX150: Reconfigurable Spartan-6 FPGA with plug-in I/O\n\t5808  XMC-SLX150-1M: Reconfigurable Spartan-6 FPGA with plug-in I/O\n\t5901  APCe8650 PCI Express IndustryPack Carrier Card\n\t6301  XMC Module with user-configurable Virtex-6 FPGA, 240k logic cells, SFP front I/O\n\t6302  XMC Module with user-configurable Virtex-6 FPGA, 365k logic cells, SFP front I/O\n\t6303  XMC Module with user-configurable Virtex-6 FPGA, 240k logic cells, no front I/O\n\t6304  XMC Module with user-configurable Virtex-6 FPGA, 365k logic cells, no front I/O\n\t7000  XMC-7K325F: User-configurable Kintex-7 FPGA, 325k logic cells plus SFP front I/O\n\t7001  XMC-7K410F: User-configurable Kintex-7 FPGA, 410k logic cells plus SFP front I/O\n\t7002  XMC-7K325AX: User-Configurable Kintex-7 FPGA, 325k logic cells with AXM Plug-In I/O\n\t7003  XMC-7K410AX: User-Configurable Kintex-7 FPGA, 410k logic cells with AXM Plug-In I/O\n\t7004  XMC-7K325CC: User-Configurable Kintex-7 FPGA, 325k logic cells, conduction-cooled\n\t7005  XMC-7K410CC: User-Configurable Kintex-7 FPGA, 410k logic cells, conduction-cooled\n\t7006  XMC-7A200: User-Configurable Artix-7 FPGA, 200k logic cells with Plug-In I/O\n\t7007  XMC-7A200CC: User-Configurable Conduction-Cooled Artix-7 FPGA, with 200k logic cells\n\t7011  AP440-1: 32-Channel Isolated Digital Input Module\n\t7012  AP440-2: 32-Channel Isolated Digital Input Module\n\t7013  AP440-3: 32-Channel Isolated Digital Input Module\n\t7014  AP445: 32-Channel Isolated Digital Output Module\n\t7015  AP471 48-Channel TTL Level Digital Input/Output Module\n\t7016  AP470 48-Channel TTL Level Digital Input/Output Module\n\t7017  AP323 16-bit, 20 or 40 Channel Analog Input Module\n\t7018  AP408: 32-Channel Digital I/O Module\n\t7019  AP341 14-bit, 16-Channel Simultaneous Conversion Analog Input Module\n\t701a  AP220-16 12-Bit, 16-Channel Analog Output Module\n\t701b  AP231-16 16-Bit, 16-Channel Analog Output Module\n\t701c  AP225 12-Bit, 16-Channel Analog Output Module with Waveform Memory\n\t701d  AP235 16-Bit, 16-Channel Analog Output Module with Waveform Memory\n\t7021  APA7-201 Reconfigurable Artix-7 FPGA module 48 TTL channels\n\t7022  APA7-202 Reconfigurable Artix-7 FPGA module 24 RS485 channels\n\t7023  APA7-203 Reconfigurable Artix-7 FPGA module 24 TTL & 12 RS485 channels\n\t7024  APA7-204 Reconfigurable Artix-7 FPGA module 24 LVDS channels\n\t7027  AP418 16-Channel High Voltage Digital Input/Output Module\n\t7029  AP342 14-bit, 12-Channel Isolated Simultaneous Conversion Analog Input Module\n\t702a  AP226 12-Bit, 8-Channel Isolated Analog Output Module\n\t702b  AP236 16-Bit, 8-Channel Isolated Analog Output Module\n\t7031  AP441-1: 32-Channel Isolated Digital Input Module\n\t7032  AP441-2: 32-Channel Isolated Digital Input Module\n\t7033  AP441-3: 32-Channel Isolated Digital Input Module\n\t7042  AP482 Counter Timer Module with TTL Level Input/Output\n\t7043  AP483 Counter Timer Module with TTL Level and RS422 Input/Output\n\t7044  AP484 Counter Timer Module with RS422 Input/Output\n\t7051  APA7-501 Reconfigurable Artix-7 52,160 Cell FPGA module 48 TTL channels\n\t7052  APA7-502 Reconfigurable Artix-7 52,160 Cell FPGA module 24 RS485 channels\n\t7053  APA7-503 Reconfigurable Artix-7 52,160 Cell FPGA module 24 TTL & 12 RS485 channels\n\t7054  APA7-504 Reconfigurable Artix-7 52,160 Cell FPGA module 24 LVDS channels\n16da  Advantech Co., Ltd.\n\t0011  INES GPIB-PCI\n16df  PIKA Technologies Inc.\n16e2  Geotest-MTS\n16e3  European Space Agency\n\t1e0f  LEON2FT Processor\n16e5  Intellon Corp.\n\t6000  INT6000 Ethernet-to-Powerline Bridge [HomePlug AV]\n\t6300  INT6300 Ethernet-to-Powerline Bridge [HomePlug AV]\n16ec  U.S. Robotics\n\t00ed  USR997900\n\t0116  USR997902 10/100/1000 Mbps PCI Network Card\n\t2f00  USR5660A (USR265660A, USR5660A-BP) 56K PCI Faxmodem\n\t3685  Wireless Access PCI Adapter Model 022415\n\t4320  USR997904 10/100/1000 64-bit NIC (Marvell Yukon)\n\tab06  USR997901A 10/100 Cardbus NIC\n16ed  Sycron N. V.\n\t1001  UMIO communication card\n16f2  ETAS GmbH\n\t0200  I/O board\n\t\t16f2 0010  ES53xx I/O board\n16f3  Jetway Information Co., Ltd.\n16f4  Vweb Corp\n\t8000  VW2010\n16f6  VideoTele.com, Inc.\n1702  Internet Machines Corporation (IMC)\n1705  Digital First, Inc.\n170b  NetOctave\n\t0100  NSP2000-SSL crypto accelerator\n170c  YottaYotta Inc.\n1719  EZChip Technologies\n\t1000  NPA Access Network Processor Family\n# Seems to be a 2nd ID for Vitesse Semiconductor\n1725  Vitesse Semiconductor\n\t7174  VSC7174 PCI/PCI-X Serial ATA Host Bus Controller\n172a  Accelerated Encryption\n\t13c8  AEP SureWare Runner 1000V3\n# nee Fujitsu Siemens Computers GmbH\n1734  Fujitsu Technology Solutions\n1735  Aten International Co. Ltd.\n1737  Linksys\n\t0029  WPG54G ver. 4 PCI Card\n\t1032  Gigabit Network Adapter\n\t\t1737 0015  EG1032 v2 Instant Gigabit Network Adapter\n\t\t1737 0024  EG1032 v3 Instant Gigabit Network Adapter\n\t1064  Gigabit Network Adapter\n\t\t1737 0016  EG1064 v2 Instant Gigabit Network Adapter\n\tab08  21x4x DEC-Tulip compatible 10/100 Ethernet\n\tab09  21x4x DEC-Tulip compatible 10/100 Ethernet\n173b  Altima (nee Broadcom)\n\t03e8  AC1000 Gigabit Ethernet\n\t03e9  AC1001 Gigabit Ethernet\n\t03ea  AC9100 Gigabit Ethernet\n\t\t173b 0001  AC1002\n\t03eb  AC1003 Gigabit Ethernet\n1743  Peppercon AG\n\t8139  ROL/F-100 Fast Ethernet Adapter with ROL\n1745  ViXS Systems, Inc.\n\t2020  XCode II Series\n\t2100  XCode 2100 Series\n1749  RLX Technologies\n174b  PC Partner Limited / Sapphire Technology\n174d  WellX Telecom SA\n175c  AudioScience Inc\n175e  Sanera Systems, Inc.\n1760  TEDIA spol. s r. o.\n\t0101  PCD-7004 Digital Bi-Directional Ports PCI Card\n\t0102  PCD-7104 Digital Input & Output PCI Card\n\t0121  PCT-7303A PC card with IRC counters\n\t0122  PCT-7408A PC card with counters and timers\n\t0123  PCT-7424 PCI card with standard counters\n\t0214  PCT-7424C (F0) PC card with standard counters\n\t0215  PCT-7424C (F1) PC card with standard counters\n\t0216  PCT-7424E (F0) PC card with standard counters\n\t0217  PCT-7424E (F1) PC card with standard counters\n\t0303  PCD-7006C Digital Input & Output PCI Card\n\tff00  CTU CAN FD PCIe Card\n1761  Pickering Interfaces Ltd\n1771  InnoVISION Multimedia Ltd.\n1775  General Electric\n177d  Cavium, Inc.\n\t0001  Nitrox XL N1\n\t0003  Nitrox XL N1 Lite\n\t0004  Octeon (and older) FIPS\n\t0005  Octeon CN38XX Network Processor Pass 3.x\n\t0006  RoHS\n\t0010  Nitrox XL NPX\n\t0020  Octeon CN31XX Network Processor\n\t0030  Octeon CN30XX Network Processor\n\t0040  Octeon CN58XX Network Processor\n\t0050  Octeon CN57XX Network Processor (CN54XX/CN55XX/CN56XX)\n\t0070  Octeon CN50XX Network Processor\n\t0080  Octeon CN52XX Network Processor\n\t0090  Octeon II CN63XX Network Processor\n\t0091  Octeon II CN68XX Network Processor\n\t0092  Octeon II CN65XX Network Processor\n\t0093  Octeon II CN61XX Network Processor\n\t0094  Octeon Fusion CNF71XX Cell processor\n\t0095  Octeon III CN78XX Network Processor\n\t0096  Octeon III CN70XX Network Processor\n\t9700  Octeon III CN73XX Network Processor\n\t9702  CN23XX [LiquidIO II] Intelligent Adapter\n\t\t177d 0003  CN2350 [LiquidIO II] 2-port 10GbE Intelligent adapter\n# This was changed during the production phase to 10GbE adapter.\n\t\t177d 0004  CN2350 [LiquidIO II] 2-port 10GbE Intelligent adapter\n\t\t177d 0005  CN2360 [LiquidIO II] 2-port 10GbE Intelligent adapter\n\t\t177d 0006  CN2360 [LiquidIO II] 2-port 25GbE Intelligent adapter\n\t\t177d 0007  CN2350 [LiquidIO II] 2-port 25GbE Intelligent adapter\n\t\t177d 0008  CN2350 [LiquidIO II] 2-port 10GbE SFP+ Intelligent adapter\n\t\t177d 0009  CN2360 [LiquidIO II] 2-port 10GbE SFP+ Intelligent adapter\n\t\t177d 000a  CN2350 [LiquidIO II] 2-port 10GBASE-T Intelligent adapter\n\t\t177d 000b  CN2360 [LiquidIO II] 2-port 10GBASE-T Intelligent adapter\n\t9703  CN23XX [LiquidIO II] NVMe Controller\n\t9712  CN23XX [LiquidIO II] SRIOV Virtual Function\n\t\t177d 0003  CN2350 [LiquidIO II] 2-port 10GbE SRIOV Virtual Function\n\t\t177d 0004  CN2350 [LiquidIO II] 2-port 10GbE SRIOV Virtual Function\n\t\t177d 0005  CN2360 [LiquidIO II] 2-port 10GbE SRIOV Virtual Function\n\t\t177d 0006  CN2360 [LiquidIO II] 2-port 25GbE SRIOV Virtual Function\n\t\t177d 0007  CN2350 [LiquidIO II] 2-port 25GbE SRIOV Virtual Function\n\t9713  CN23XX [LiquidIO II] NVMe SRIOV Virtual Function\n\t9800  Octeon Fusion CNF75XX Processor\n\ta001  ThunderX MRML(Master RML Bridge to RSL devices)\n\ta002  THUNDERX PCC Bridge\n\t\t177d a102  CN88XX PCC Bridge\n\ta008  THUNDERX SMMU\n\t\t177d a108  CN88XX SMMU\n\ta009  THUNDERX Generic Interrupt Controller\n\ta00a  THUNDERX GPIO Controller\n\ta00b  THUNDERX MPI / SPI Controller\n\ta00c  THUNDERX MIO-PTP Controller\n\ta00d  THUNDERX MIX Network Controller\n\ta00e  THUNDERX Reset Controller\n\ta00f  THUNDERX UART Controller\n\ta010  THUNDERX eMMC/SD Controller\n\ta011  THUNDERX MIO-BOOT Controller\n\ta012  THUNDERX TWSI / I2C Controller\n\ta013  THUNDERX CCPI (Multi-node connect)\n\ta014  THUNDERX Voltage Regulator Module\n\ta015  THUNDERX PCIe Switch Logic Interface\n\ta016  THUNDERX Key Memory\n\ta017  THUNDERX GTI (Global System Timers)\n\ta018  THUNDERX Random Number Generator\n\ta019  THUNDERX DFA\n\ta01a  THUNDERX Zip Coprocessor\n\ta01b  THUNDERX xHCI USB Controller\n\ta01c  THUNDERX AHCI SATA Controller\n\t\t177d a11c  CN88XX AHCI SATA Controller\n\ta01d  THUNDERX RAID Coprocessor\n\ta01e  THUNDERX Network Interface Controller\n\ta01f  THUNDERX Traffic Network Switch\n\ta020  THUNDERX PEM (PCI Express Interface)\n\ta021  THUNDERX L2C (Level-2 Cache Controller)\n\ta022  THUNDERX LMC (DRAM Controller)\n\ta023  THUNDERX OCLA (On-Chip Logic Analyzer)\n\ta024  THUNDERX OSM\n\ta025  THUNDERX GSER (General Serializer/Deserializer)\n\ta026  THUNDERX BGX (Common Ethernet Interface)\n\ta027  THUNDERX IOBN\n\ta029  THUNDERX NCSI (Network Controller Sideband Interface)\n\ta02a  ThunderX SGPIO (Serial GPIO controller for SATA disk lights)\n\ta02b  THUNDERX SMI / MDIO Controller\n\ta02c  THUNDERX DAP (Debug Access Port)\n\ta02d  THUNDERX PCIERC (PCIe Root Complex)\n\ta02e  ThunderX L2C-TAD (Level 2 cache tag and data)\n\ta02f  THUNDERX L2C-CBC\n\ta030  THUNDERX L2C-MCI\n\ta031  THUNDERX MIO-FUS (Fuse Access Controller)\n\ta032  THUNDERX FUSF (Fuse Controller)\n\ta033  THUNDERX Random Number Generator virtual function\n\ta034  THUNDERX Network Interface Controller virtual function\n\ta035  THUNDERX Parallel Bus\n\ta036  ThunderX RAD (RAID acceleration engine) virtual function\n\ta037  THUNDERX ZIP virtual function\n\ta040  THUNDERX CPT Cryptographic Accelerator\n\ta100  THUNDERX CN88XX 48 core SoC\n\ta200  OCTEON TX CN81XX/CN80XX\n\ta300  OCTEON TX CN83XX\n\taf00  CN99xx [ThunderX2] Integrated PCI Host bridge\n\taf84  CN99xx [ThunderX2] Integrated PCI Express RP Bridge\n1787  Hightech Information System Ltd.\n1789  Ennyah Technologies Corp.\n# also used by Struck Innovative Systeme for joint developments\n1796  Research Centre Juelich\n\t0001  SIS1100 [Gigabit link]\n\t0002  HOTlink\n\t0003  Counter Timer\n\t0004  CAMAC Controller\n\t0005  PROFIBUS\n\t0006  AMCC HOTlink\n\t0007  LVD Cable Bus\n\t0008  100MHz, 64bit Sequence Generator based on VirtexII\n\t0009  double 14bit-ADC\n\t000a  SIS1100 with N110 TDC\n\t000b  double 14bit-ADC with memory\n\t000d  Synchronisation Slave\n\t000e  SIS1100-eCMC\n\t000f  TDC (GPX)\n\t0010  PCIe Counter Timer\n\t0011  SIS1100-e single link\n\t0012  SIS1100-e quad link\n\t0013  4x2.5GHz SFP to 4 lane PCIe bridge\n\t0014  SIS1100 with GPX piggy back\n\t0015  SIS8100 [Gigabit link, MicroTCA]\n\t0016  SIS1100e with 4 lanes\n\t0017  Quad 14bit, 50MHz ADC with 2.5GHz SFP\n\t0018  SIS8300 4-lane PCI Express, Micro TCA for Physics ADC\n\t0019  SIS SIS8300-Lx MTCA.4 Digitizer\n\t001a  100MHz, 64bit Sequence Generator based on VirtexII\n\t001c  Quad 16bit, 150MHz ADC with 2.5GHz SFP\n\t0030  100MHz, 64bit Sequence Generator based on Spartan6\n\t0031  200MHz 64bit Sequence Generator based on Spartan7\n# nee Techwell, Inc.\n1797  Intersil Techwell\n\t5864  TW5864 multimedia video controller\n\t6801  TW6802 multimedia video card\n\t6802  TW6802 multimedia other device\n\t6810  TW6816 multimedia video controller\n\t6811  TW6816 multimedia video controller\n\t6812  TW6816 multimedia video controller\n\t6813  TW6816 multimedia video controller\n# port 5 of 8\n\t6814  TW6816 multimedia video controller\n# port 6 of 8\n\t6815  TW6816 multimedia video controller\n# port 7 of 8\n\t6816  TW6816 multimedia video controller\n# channel 8 of 8\n\t6817  TW6816 multimedia video controller\n# Example MuniPCI-E card: http://www.commell.com.tw/product/surveillance/MPX-6864.htm\n\t6864  TW6864 multimedia video controller\n1799  Belkin\n\t6001  F5D6001 Wireless PCI Card [Realtek RTL8180]\n\t6020  F5D6020 v3000 Wireless PCMCIA Card [Realtek RTL8180]\n\t6060  F5D6060 Wireless PDA Card\n\t700f  F5D7000 v7000 Wireless G Desktop Card [Realtek RTL8185]\n\t701f  F5D7010 v7000 Wireless G Notebook Card [Realtek RTL8185]\n179a  id Quantique\n\t0001  Quantis PCI 16Mbps\n179c  Data Patterns\n\t0557  DP-PCI-557 [PCI 1553B]\n\t0566  DP-PCI-566 [Intelligent PCI 1553B]\n\t1152  DP-cPCI-1152 (8-channel Isolated ADC Module)\n\t5031  DP-CPCI-5031-Synchro Module\n# cPCI Carrier for Mezzanine Modules\n\t5112  DP-cPCI-5112 [MM-Carrier]\n\t5121  DP-CPCI-5121-IP Carrier\n\t5211  DP-CPCI-5211-IP Carrier\n\t5679  AGE Display Module\n17a0  Genesys Logic, Inc\n\t7163  GL9701 PCIe to PCI Bridge\n\t8083  GL880 USB 1.1 UHCI controller\n\t8084  GL880 USB 2.0 EHCI controller\n\t9750  GL9750 SD Host Controller\n17aa  Lenovo\n\t402b  Intel 82599ES 10Gb 2-port Server Adapter X520-2\n17ab  Phillips Components\n17af  Hightech Information System Ltd.\n17b3  Hawking Technologies\n\tab08  PN672TX 10/100 Ethernet\n17b4  Indra Networks, Inc.\n\t0011  WebEnhance 100 GZIP Compression Card\n\t0012  WebEnhance 200 GZIP Compression Card\n\t0015  WebEnhance 300 GZIP Compression Card\n\t0016  StorCompress 300 GZIP Compression Card\n\t0017  StorSecure 300 GZIP Compression and AES Encryption Card\n17c0  Wistron Corp.\n17c2  Newisys, Inc.\n# nee Airgo Networks, Inc.\n17cb  Qualcomm\n\t0001  AGN100 802.11 a/b/g True MIMO Wireless Card\n\t\t1385 5c00  WGM511 Pre-N 802.11g Wireless CardBus Adapter\n\t\t1737 0045  WMP54GX v1 802.11g Wireless-G PCI Adapter with SRX\n\t0002  AGN300 802.11 a/b/g True MIMO Wireless Card\n\t\t1385 6d00  WPNT511 RangeMax 240 Mbps Wireless CardBus Adapter\n\t\t1737 0054  WPC54GX4 v1 802.11g Wireless-G Notebook Adapter with SRX400\n\t0400  Datacenter Technologies QDF2432 PCI Express Root Port\n\t0401  Datacenter Technologies QDF2400 PCI Express Root Port\n17cc  NetChip Technology, Inc\n\t2280  USB 2.0\n17cd  Cadence Design Systems, Inc.\n17cf  Z-Com, Inc.\n17d3  Areca Technology Corp.\n\t1110  ARC-1110 4-Port PCI-X to SATA RAID Controller\n\t1120  ARC-1120 8-Port PCI-X to SATA RAID Controller\n\t1130  ARC-1130 12-Port PCI-X to SATA RAID Controller\n\t1160  ARC-1160 16-Port PCI-X to SATA RAID Controller\n\t1170  ARC-1170 24-Port PCI-X to SATA RAID Controller\n\t1201  ARC-1200 2-Port PCI-Express to SATA II RAID Controller\n\t1203  ARC-1203 2/4/8 Port PCIe 2.0 to SATA 6Gb RAID Controller\n\t1210  ARC-1210 4-Port PCI-Express to SATA RAID Controller\n\t1214  ARC-12x4 PCIe 2.0 to SAS/SATA 6Gb RAID Controller\n\t\t17d3 1214  ARC-1214 4-Port PCIe 2.0 to SAS/SATA 6Gb RAID Controller\n\t\t17d3 1224  ARC-1224 8-Port PCIe 2.0 to SAS/SATA 6Gb RAID Controller\n\t\t17d3 1264  ARC-1264 12/16 Port PCIe 2.0 to SATA 6Gb RAID Controller\n\t\t17d3 1284  ARC-1284 24 Port PCIe 2.0 to SATA 6Gb RAID Controller\n\t1220  ARC-1220 8-Port PCI-Express to SATA RAID Controller\n\t1222  ARC-1222 8-Port PCI-Express to SAS/SATA II RAID Controller\n\t1230  ARC-1230 12-Port PCI-Express to SATA RAID Controller\n\t1260  ARC-1260 16-Port PCI-Express to SATA RAID Controller\n\t1280  ARC-1280/1280ML 24-Port PCI-Express to SATA II RAID Controller\n\t\t17d3 1221  ARC-1221 8-Port PCI-Express to SATA RAID Controller\n\t1300  ARC-1300ix-16 16-Port PCI-Express to SAS Non-RAID Host Adapter\n\t1320  ARC-1320 8/16 Port PCIe 2.0 to SAS/SATA 6Gb Non-RAID Host Adapter\n\t1330  ARC-1330 16 Port PCIe 3.0 to SAS/SATA 12Gb Non-RAID Host Adapter\n\t1680  ARC-1680 series PCIe to SAS/SATA 3Gb RAID Controller\n\t\t17d3 1212  ARC-1212 4-Port PCIe to SAS/SATA II RAID Controller\n\t\t17d3 1222  ARC-1222 8-Port PCIe to SAS/SATA 3Gb RAID Controller\n\t\t17d3 1680  ARC-1680 8/12/16/24 Port PCIe to SAS/SATA 3Gb RAID Controller\n\t1880  ARC-188x series PCIe 2.0/3.0 to SAS/SATA 6/12Gb RAID Controller\n\t\t17d3 1213  ARC-1213 4-Port PCIe 2.0 to SAS/SATA 6Gb RAID Controller\n\t\t17d3 1215  ARC-1215 4-Port PCIe 3.0 to SAS/SATA 6Gb RAID Controller\n\t\t17d3 1216  ARC-1216 4-Port PCIe 3.0 to SAS/SATA 12Gb RAID Controller\n\t\t17d3 1223  ARC-1223 8-Port PCIe 2.0 to SAS/SATA 6Gb RAID Controller\n\t\t17d3 1225  ARC-1225 8-Port PCIe 3.0 to SAS/SATA 6Gb RAID Controller\n\t\t17d3 1226  ARC-1226 8-Port PCIe 3.0 to SAS/SATA 12Gb RAID Controller\n\t\t17d3 1880  ARC-1880 8/12/16/24 Port PCIe 2.0 to SAS/SATA 6Gb RAID Controller\n\t\t17d3 1882  ARC-1882 8/12/16/24 Port PCIe 3.0 to SAS/SATA 6Gb RAID Controller\n\t\t17d3 1883  ARC-1883 8/12/16/24 Port PCIe 3.0 to SAS/SATA 12Gb RAID Controller\n\t1884  ARC-1884 series PCIe 3.0 to SAS/SATA 12/6Gb RAID Controller\n\t188a  ARC-1886 series PCIe 4.0 to NVMe/SAS/SATA 16/12/6Gb RAID Controller\n# nee Neterion Inc., previously S2io Inc.\n17d5  Exar Corp.\n\t5731  Xframe 10-Gigabit Ethernet PCI-X\n\t5732  Xframe II 10-Gigabit Ethernet PCI-X 2.0\n\t5831  Xframe 10-Gigabit Ethernet PCI-X\n\t\t103c 12d5  PCI-X 133MHz 10GbE SR Fiber\n\t\t10a9 8020  Single Port 10-Gigabit Ethernet (PCI-X, Fiber)\n\t\t10a9 8024  Single Port 10-Gigabit Ethernet (PCI-X, Fiber)\n\t5832  Xframe II 10-Gigabit Ethernet PCI-X 2.0\n\t\t103c 1337  PCI-X 266MHz 10GigE SR [AD385A]\n\t\t10a9 8021  Single Port 10-Gigabit Ethernet II (PCI-X, Fiber)\n\t\t17d5 6020  Xframe II SR\n\t\t17d5 6021  Xframe II SR, Low Profile\n\t\t17d5 6022  Xframe E SR\n\t\t17d5 6420  Xframe II LR\n\t\t17d5 6421  Xframe II LR, Low Profile\n\t\t17d5 6422  Xframe E LR\n\t\t17d5 6c20  Xframe II CX4\n\t\t17d5 6c21  Xframe II CX4, Low Profile\n\t\t17d5 6c22  Xframe E CX4\n\t5833  X3100 Series 10 Gigabit Ethernet PCIe\n\t\t17d5 6030  X3110 Single Port SR\n\t\t17d5 6031  X3120 Dual Port SR\n\t\t17d5 6430  X3110 Single Port LR\n\t\t17d5 6431  X3120 Dual Port LR\n\t\t17d5 7030  X3110 Single Port LRM\n\t\t17d5 7031  X3120 Dual Port LRM\n\t\t17d5 7430  X3110 Single Port 10GBase-T\n\t\t17d5 7431  X3120 Dual Port 10GBase-T\n\t\t17d5 7830  X3110 Single Port 10GBase-CR\n\t\t17d5 7831  X3120 Dual Port 10GBase-CR\n17db  Cray Inc\n\t0101  XT Series [Seastar] 3D Toroidal Router\n17de  KWorld Computer Co. Ltd.\n17df  Dini Group\n\t1864  Virtex4 PCI Board w/ QL5064 Bridge [DN7000K10PCI/DN8000K10PCI/DN8000K10PSX/NOTUS]\n\t1865  Virtex4 ASIC Emulator [DN8000K10PCIe]\n\t1866  Virtex4 ASIC Emulator Cable Connection [DN8000K10PCI]\n\t1867  Virtex4 ASIC Emulator Cable Connection [DN8000K10PCIe]\n\t1868  Virtex4 ASIC Emulator [DN8000K10PCIe-8]\n\t1900  Virtex5 PCIe ASIC Emulator [DN9000K10PCIe8T/DN9002K10PCIe8T/DN9200K10PCIe8T/DN7006K10PCIe8T/DN7406K10PCIe8T]\n\t1901  Virtex5 PCIe ASIC Emulator Large BARs [DN9000K10PCIe8T/DN9002K10PCIe8T/DN9200K10PCIe8T/DN7006K10PCIe8T/DN7406K10PCIe8T]\n\t1902  Virtex5 PCIe ASIC Emulator Low Power [Interceptor]\n\t1903  Spartan6 PCIe FPGA Accelerator Board [DNBFCS12PCIe]\n\t1904  Virtex6 PCIe ASIC Emulation Board [DNDUALV6_PCIe4]\n\t1905  Virtex6 PCIe ASIC Emulation Board [DNV6F6PCIe]\n\t1906  Virtex6 PCIe ASIC Emulation Board [DN2076K10]\n\t1907  Virtex6 PCIe ASIC Emulation Board [DNV6F2PCIe]\n\t1908  Virtex6 PCIe ASIC Emulation Board Large BARs[DNV6F2PCIe]\n\t1909  Kintex7 PCIe FPGA Accelerator Board [DNK7F5PCIe]\n\t190a  Virtex7 PCIe ASIC Emulation Board [DNV7F1A]\n\t190b  Stratix5 PCIe ASIC Emulation Board [DNS5GXF2]\n\t190c  Virtex7 PCIe ASIC Emulation Board [DNV7F2A]\n\t190d  Virtex7 PCIe ASIC Emulation Board [DNV7F4A]\n\t190e  Virtex7 PCIe ASIC Emulation Board [DNV7F2B]\n\t190f  KintexUS PCIe MainRef Design [DNPCIE_40G_KU_LL]\n\t1910  VirtexUS ASIC Emulation Board [DNVUF4A]\n\t1911  VirtexUS PCIe ASIC Emulation Board [DNVU_F2PCIe]\n\t1912  KintexUS PCIe MainRef Design [DNPCIe_40G_KU_LL_QSFP]\n\t1913  VirtexUS ASIC Emulation Board [DNVUF1A]\n\t1914  VirtexUS ASIC Emulation Board [DNVUF2A]\n\t1915  Arria10 PCIe MainRef Design [DNPCIe_80G_A10_LL]\n\t1916  VirtexUS PCIe Accelerator Board [DNVUF2_HPC_PCIe]\n\t1917  UltrascalePlus PCIe Accelerator Board [DNPCIe_400G_VU_LL]\n\t1918  VirtexUS+ ASIC Emulation Board [DNVUPF4A]\n\t1919  UltrascalePlus PCIe Accelerator Board [DNPCIe_400G_VUP_HBM_LL]\n\t1a00  Virtex6 PCIe DMA Netlist Design\n\t1a01  Virtex6 PCIe Darklite Design [DNPCIe_HXT_10G_LL]\n\t1a02  Virtex7 PCIe DMA Netlist Design\n\t1a03  Kintex7 PCIe Darklite Design [DNPCIe_K7_10G_LL]\n\t1a05  Stratix5 PCIe Darklite Design [DNS5GX_F2]\n\t1a06  VirtexUS PCIe DMA Netlist Design\n\t1a07  KintexUS PCIe Darklite Design [DNPCIe_40G_KU_LL]\n\t1a08  KintexUS PCIe Darklite Design [DNPCIe_40G_KU_LL_QSFP]\n\t1a09  Arria10 PCIe Darklite Design [DNPCIe_80G_A10_LL]\n\t1a0a  VirtexUS PCIe Darklite Design [DNVUF2_HPC_PCIe]\n\t1a0b  UltrascalePlus PCIe Darklite Design [DNPCIe_400G_VU_LL]\n\t1a0c  KintexUS PCIe DRAM Packet Capture Design [DNPCIe_40G_KU_LL]\n\t1a0d  KintexUS PCIe DRAM Packet Capture Design [DNPCIe_40G_KU_LL_2QSFP]\n\t1a0e  UltrascalePlus PCIe Darklite Design [DNPCIe_400G_VUP_HBM_LL]\n17e4  Sectra AB\n\t0001  KK671 Cardbus encryption board\n\t0002  KK672 Cardbus encryption board\n# nee Entropic Communications Inc.\n17e6  MaxLinear\n\t0010  EN2010 [c.Link] MoCA Network Controller (Coax, PCI interface)\n\t0011  EN2010 [c.Link] MoCA Network Controller (Coax, MPEG interface)\n\t0021  EN2210 [c.Link] MoCA Network Controller (Coax)\n\t0025  EN2510 [c.Link] MoCA Network Controller (Coax, PCIe interface)\n\t0027  EN2710 [c.Link] MoCA 2.0 Network Controller (Coax, PCIe interface)\n\t3700  MoCA 2.0 Network Controller (Coax, PCIe interface)\n\t3710  MoCA 2.5 Network Controller (Coax, PCIe interface)\n17ee  Connect Components Ltd\n17f2  Albatron Corp.\n17f3  RDC Semiconductor, Inc.\n\t1010  R1010 IDE Controller\n\t1011  R1011 IDE Controller\n\t1012  R1012 IDE Controller\n\t1031  PCI/PCI-X to PCI-E Bridge\n\t2012  M2012/R3308 VGA-compatible graphics adapter\n\t6020  R6020 North Bridge\n\t6021  R6021 Host Bridge\n\t6030  R6030 ISA Bridge\n\t6031  R6031 ISA Bridge\n\t6040  R6040 MAC Controller\n\t6060  R6060 USB 1.1 Controller\n\t6061  R6061 USB 2.0 Controller\n17f7  Topdek Semiconductor Inc.\n17f9  Gemtek Technology Co., Ltd\n17fc  IOGEAR, Inc.\n17fe  InProComm Inc.\n\t2120  IPN 2120 802.11b\n\t\t1737 0020  WMP11 v4 802.11b Wireless-B PCI Adapter\n\t2220  IPN 2220 802.11g\n\t\t1468 0305  T60N871 802.11g Mini PCI Wireless Adapter\n\t\t1737 0029  WPC54G v4 802.11g Wireless-G Notebook Adapter\n17ff  Benq Corporation\n1800  Qualcore Logic Inc.\n\t1100  Nanospeed Trading Gateway\n1803  ProdaSafe GmbH\n1804  Ralink corp. (wrong ID)\n\t3060  RT3060 Wireless 802.11n 1T/1R\n1805  Euresys S.A.\n1809  Lumanate, Inc.\n180c  IEI Integration Corp\n1813  Ambient Technologies Inc\n\t4000  HaM controllerless modem\n\t\t16be 0001  V9x HAM Data Fax Modem\n\t4100  HaM plus Data Fax Modem\n\t\t16be 0002  V9x HAM 1394\n1814  Ralink corp.\n\t0101  Wireless PCI Adapter RT2400 / RT2460\n\t\t1043 0127  WiFi-b add-on Card\n\t\t1371 0010  Minitar MNW2BPCI Wireless PCI Card\n\t\t1462 6828  PC11B2 (MS-6828) Wireless 11b PCI Card\n\t0200  RT2500 802.11g PCI [PC54G2]\n\t0201  RT2500 Wireless 802.11bg\n\t\t1043 130f  WL-130g\n\t\t1186 3c00  DWL-G650X Wireless 11g CardBus Adapter\n\t\t1371 001e  CWC-854 Wireless-G CardBus Adapter\n\t\t1371 001f  CWM-854 Wireless-G Mini PCI Adapter\n\t\t1371 0020  CWP-854 Wireless-G PCI Adapter\n\t\t1458 e381  GN-WMKG 802.11b/g Wireless CardBus Adapter\n\t\t1458 e931  GN-WIKG 802.11b/g mini-PCI Adapter\n\t\t1462 6833  Unknown 802.11g mini-PCI Adapter\n\t\t1462 6835  Wireless 11G CardBus CB54G2\n\t\t1737 0032  WMP54G v4.0 PCI Adapter\n\t\t1799 700a  F5D7000 v2000/v3000 Wireless G Desktop Card\n\t\t1799 701a  F5D7010 v2000/v3000 Wireless G Notebook Card\n\t\t1814 2560  RT2500 Wireless 802.11bg\n\t\t182d 9073  WL-115 Wireless Network PCI Adapter\n\t\t185f 22a0  CN-WF513 Wireless Cardbus Adapter\n\t\t18eb 5312  WL531P IEEE 802.11g PCI Card-EU\n\t\t1948 3c00  C54RC v1 Wireless 11g CardBus Adapter\n\t\t1948 3c01  C54Ri v1 Wireless 11g PCI Adapter\n\t0300  Wireless Adapter Canyon CN-WF511\n\t0301  RT2561/RT61 802.11g PCI\n\t\t1186 3c08  AirPlus G DWL-G630 Wireless Cardbus Adapter (rev.E1)\n\t\t1186 3c09  DWL-G510 Rev C\n\t\t13d1 abe3  miniPCI Pluscom 802.11 a/b/g\n\t\t1458 e933  GN-WI01GS\n\t\t1458 e934  GN-WP01GS\n\t\t1462 b833  MP54G5 (MS-6833B)\n\t\t1737 0055  WMP54G v4.1\n\t\t1799 700e  F5D7000 v6000 Wireless G Desktop Card\n\t\t1799 701e  F5D7010 v6000 Wireless G Notebook Card\n\t\t17f9 0012  AWLC3026T 802.11g Wireless CardBus Adapter\n\t\t1814 2561  EW-7108PCg/EW-7128g\n\t0302  RT2561/RT61 rev B 802.11g\n\t\t1186 3a71  DWA-510 Wireless G Desktop Adapter\n\t\t1186 3c08  AirPlus G DWL-G630 Wireless Cardbus Adapter (rev.E2)\n\t\t1186 3c09  AirPlus G DWL-G510 Wireless Network Adapter (Rev.C)\n\t\t1462 b834  PC54G3 Wireless 11g PCI Card\n\t\t1948 3c23  C54RC v2 Wireless 11g CardBus Adapter\n\t\t1948 3c24  C54Ri v2 Wireless 11g PCI Adapter\n\t0401  RT2600 802.11 MIMO\n\t\t1737 0052  WPC54GR v1 802.11g Wireless-G Notebook Adapter with RangeBooster\n\t\t17f9 0011  WPCR-137G 802.11bg Wireless CardBus Adapter\n\t\t17f9 0016  WPIR-119GH 802.11bg Wireless Desktop Adapter\n\t0601  RT2800 802.11n PCI\n\t\t1799 801c  F5D8011 v3 802.11n N1 Wireless Notebook Card\n\t\t187e 3412  NWD-310N 802.11n Wireless PCI Adapter\n\t0681  RT2890 Wireless 802.11n PCIe\n\t\t1458 e939  GN-WS30N-RH 802.11bgn Mini PCIe Card\n\t0701  RT2760 Wireless 802.11n 1T/2R\n\t\t1737 0074  WMP110 v2 802.11n RangePlus Wireless PCI Adapter\n\t0781  RT2790 Wireless 802.11n 1T/2R PCIe\n\t\t1814 2790  RT2790 Wireless 802.11n 1T/2R PCIe\n\t3060  RT3060 Wireless 802.11n 1T/1R\n\t\t1186 3c04  DWA-525 Wireless N 150 Desktop Adapter (rev.A1)\n\t3062  RT3062 Wireless 802.11n 2T/2R\n\t3090  RT3090 Wireless 802.11n 1T/1R PCIe\n\t\t13bd 1057  GN-WS32L-RH Half-size Mini PCIe Card\n\t3091  RT3091 Wireless 802.11n 1T/2R PCIe\n\t3092  RT3092 Wireless 802.11n 2T/2R PCIe\n\t3290  RT3290 Wireless 802.11n 1T/1R PCIe\n\t\t103c 18ec  Ralink RT3290LE 802.11bgn 1x1 Wi-Fi and Bluetooth 4.0 Combo Adapter\n\t3298  RT3290 Bluetooth\n\t\t103c 18ec  Ralink RT3290LE 802.11bgn 1x1 Wi-Fi and Bluetooth 4.0 Combo Adapter\n\t3592  RT3592 Wireless 802.11abgn 2T/2R PCIe\n\t359f  RT3592 PCIe Wireless Network Adapter\n\t5360  RT5360 Wireless 802.11n 1T/1R\n\t\t1186 3c05  DWA-525 Wireless N 150 Desktop Adapter (rev.A2)\n\t\t20f4 703a  TEW-703PI N150 Wireless PCI Adapter\n\t5362  RT5362 PCI 802.11n Wireless Network Adapter\n\t5390  RT5390 Wireless 802.11n 1T/1R PCIe\n\t\t103c 1636  U98Z077.00 Half-size Mini PCIe Card\n\t5392  RT5392 PCIe Wireless Network Adapter\n\t539b  RT5390R 802.11bgn PCIe Wireless Network Adapter\n\t539f  RT5390 [802.11 b/g/n 1T1R G-band PCI Express Single Chip]\n\t\t103c 1637  Pavilion DM1Z-3000 PCIe wireless card\n\t5592  RT5592 PCIe Wireless Network Adapter\n\te932  RT2560F 802.11 b/g PCI\n1815  Devolo AG\n1820  InfiniCon Systems Inc.\n1822  Twinhan Technology Co. Ltd\n\t4e35  Mantis DTV PCI Bridge Controller [Ver 1.0]\n182d  SiteCom Europe BV\n# HFC-based ISDN card\n\t3069  ISDN PCI DC-105V2\n\t9790  WL-121 Wireless Network Adapter 100g+ [Ver.3]\n182e  Raza Microelectronics, Inc.\n\t0008  XLR516 Processor\n# Strange vendor ID used by BCM5785 when in RAID mode\n182f  Broadcom\n# HT1000 uses 3 IDs 1166:024a (Native SATA Mode), 1166:024b (PATA/IDE Mode), 182f:000b (RAID Mode) depends on SATA BIOS setting\n\t000b  BCM5785 [HT1000] SATA (RAID Mode)\n1830  Credence Systems Corporation\n\t8000  CPIn\n\t8001  CPId\n\t8002  CPIx\n\t8003  CPIq\n183b  MikroM GmbH\n\t08a7  MVC100 DVI\n\t08a8  MVC101 SDI\n\t08a9  MVC102 DVI+Audio\n\t08b0  MVC200-DC\n1846  Alcatel-Lucent\n1849  ASRock Incorporation\n184a  Thales Computers\n\t1100  MAX II cPLD\n1850  Advantest Corporation\n\t0048  EK220-66401 Computer Interface Card\n1851  Microtune, Inc.\n1852  Anritsu Corp.\n1853  SMSC Automotive Infotainment System Group\n1854  LG Electronics, Inc.\n185b  Compro Technology, Inc.\n\t1489  VideoMate Vista T100\n185f  Wistron NeWeb Corp.\n1864  SilverBack\n\t2110  ISNAP 2110\n1867  Topspin Communications\n\t5a44  MT23108 InfiniHost HCA\n\t5a45  MT23108 InfiniHost HCA flash recovery\n\t5a46  MT23108 InfiniHost HCA bridge\n\t6278  MT25208 InfiniHost III Ex (Tavor compatibility mode)\n\t6282  MT25208 InfiniHost III Ex\n186c  Humusoft, s.r.o.\n\t0612  AD612 Data Acquisition Device\n\t0614  MF614 Multifunction I/O Card\n\t0622  AD622 Data Acquisition Device\n\t0624  MF624 Multifunction I/O PCI Card\n\t0625  MF625 3-phase Motor Driver\n\t0634  MF634 Multifunction I/O PCIe Card\n\t0644  MF644 Multifunction I/O Thb Card\n186f  WiNRADiO Communications\n1876  L-3 Communications\n\ta101  VigraWATCH PCI\n\ta102  VigraWATCH PMC\n\ta103  Vigra I/O\n187e  ZyXEL Communications Corporation\n\t3403  ZyAir G-110 802.11g\n\t340e  M-302 802.11g XtremeMIMO\n1885  Avvida Systems Inc.\n1888  Varisys Ltd\n\t0301  VMFX1 FPGA PMC module\n\t0601  VSM2 dual PMC carrier\n\t0710  VS14x series PowerPC PCI board\n\t0720  VS24x series PowerPC PCI board\n188a  Ample Communications, Inc\n1890  Egenera, Inc.\n1894  KNC One\n1896  B&B Electronics Manufacturing Company, Inc.\n\t4202  MIport 3PCIU2 2-port Serial\n\t4204  MIport 3PCIU4 4-port Serial\n\t4208  MIport 3PCIU8 8-port Serial\n\t4211  MIport 3PCIOU1 1-port Isolated Serial\n\t4212  MIport 3PCIOU2 2-port Isolated Serial\n\t4214  MIport 3PCIOU4 4-port Isolated Serial\n\tbb10  3PCI2 2-Port Serial\n\tbb11  3PCIO1 1-Port Isolated Serial\n1897  AMtek\n18a1  Astute Networks Inc.\n18a2  Stretch Inc.\n\t0002  VRC6016 16-Channel PCIe DVR Card\n18a3  AT&T\n18ac  DViCO Corporation\n\td500  FusionHDTV 5\n\td800  FusionHDTV 3 Gold\n\td810  FusionHDTV 3 Gold-Q\n\td820  FusionHDTV 3 Gold-T\n\tdb30  FusionHDTV DVB-T Pro\n\tdb40  FusionHDTV DVB-T Hybrid\n\tdb78  FusionHDTV DVB-T Dual Express\n18b8  Ammasso\n\tb001  AMSO 1100 iWARP/RDMA Gigabit Ethernet Coprocessor\n# formally Info-Tek Corp.\n18bc  GeCube Technologies, Inc.\n18c3  Micronas Semiconductor Holding AG\n\t0720  nGene PCI-Express Multimedia Controller\n\t\t1461 032e  Hybrid M779 PCI-E\n# Nee Octigabay System\n18c8  Cray Inc\n18c9  ARVOO Engineering BV\n18ca  XGI Technology Inc. (eXtreme Graphics Innovation)\n\t0020  Z7/Z9 (XG20 core)\n\t0021  Z9s/Z9m (XG21 core)\n\t0027  Z11/Z11M\n\t0040  Volari V3XT/V5/V8\n\t0047  Volari 8300 (chip: XP10, codename: XG47)\n# should be 182d\n18d2  Sitecom Europe BV (Wrong ID)\n# Sitecom HFC-S based ISDN controller card DC-105v2\n\t3069  DC-105v2 ISDN controller\n18d4  Celestica\n18d8  Dialogue Technology Corp.\n18dd  Artimi Inc\n\t4c6f  Artimi RTMI-100 UWB adapter\n18df  LeWiz Communications\n18e6  MPL AG\n\t0001  OSCI [Octal Serial Communication Interface]\n18eb  Advance Multimedia Internet Technology, Inc.\n18ec  Cesnet, z.s.p.o.\n\t6d05  ML555\n\t\t18ec 0100  NIC (ethernet interfaces)\n\t\t18ec 0200  NIC (szedata2) 4x1G\n\t\t18ec 0201  NIC (szedata2) 2x10G\n\t\t18ec 0300  NIFIC (szedata2) 4x1G\n\t\t18ec 0302  NIFIC (szedata2) 2x10G\n\t\t18ec 4200  Flexible FlowMon (szedata2) 1x10G\n\t\t18ec ff00  Testing design\n\t\t18ec ff01  Boot design\n\tc006  COMBO6\n\t\t18ec d001  COMBO-4MTX\n\t\t18ec d002  COMBO-4SFP\n\t\t18ec d003  COMBO-4SFPRO\n\t\t18ec d004  COMBO-2XFP\n\tc032  COMBO-LXT110\n\t\t18ec 0100  NIC (ethernet interfaces)\n\t\t18ec 0200  NIC (szedata2) 4x1G\n\t\t18ec 0201  NIC (szedata2) 2x10G\n\t\t18ec 0300  NIFIC (szedata2) 4x1G\n\t\t18ec 0302  NIFIC (szedata2) 2x10G\n\t\t18ec 4200  Flexible FlowMon (szedata2) 1x10G\n\t\t18ec ff00  Testing design\n\t\t18ec ff01  Boot design\n\tc045  COMBO6E\n\tc050  COMBO-PTM\n\tc058  COMBO6X\n\t\t18ec d001  COMBO-4MTX\n\t\t18ec d002  COMBO-4SFP\n\t\t18ec d003  COMBO-4SFPRO\n\t\t18ec d004  COMBO-2XFP\n\tc132  COMBO-LXT155\n\t\t18ec 0100  NIC (ethernet interfaces)\n\t\t18ec 0200  NIC (szedata2) 4x1G\n\t\t18ec 0201  NIC (szedata2) 2x10G\n\t\t18ec 0300  NIFIC (szedata2) 4x1G\n\t\t18ec 0302  NIFIC (szedata2) 2x10G\n\t\t18ec 4200  Flexible FlowMon (szedata2) 1x10G\n\t\t18ec ff00  Testing design\n\t\t18ec ff01  Boot design\n\tc232  COMBO-FXT100\n\t\t18ec 0100  NIC (ethernet interfaces)\n\t\t18ec 0200  NIC (szedata2) 4x1G\n\t\t18ec 0201  NIC (szedata2) 2x10G\n\t\t18ec 0300  NIFIC (szedata2) 4x1G\n\t\t18ec 0302  NIFIC (szedata2) 2x10G\n\t\t18ec 4200  Flexible FlowMon (szedata2) 1x10G\n\t\t18ec ff00  Testing design\n\t\t18ec ff01  Boot design\n18ee  Chenming Mold Ind. Corp.\n18f1  Spectrum GmbH\n18f4  Napatech A/S\n\t0031  NT20X Network Adapter\n\t0051  NT20X Capture Card\n\t0061  NT20E Capture Card\n\t0064  NT20E Inline Card\n\t0071  NT4E Capture Card\n\t0074  NT4E Inline Card\n\t0081  NT4E 4-port Expansion Card\n\t0091  NT20X Capture Card [New Rev]\n\t00a1  NT4E-STD Capture Card\n\t00a4  NT4E-STD Inline Card\n# 8 x 1 Gbps / 10 Gbps PCIe Optical Bypass Adapter\n\t00b1  NTBPE Optical Bypass Adapter\n\t00c5  NT20E2 Network Adapter 2x10Gb\n\t00d5  NT40E2-4 Network Adapter 4x10Gb\n\t00e5  NT40E2-1 Network Adapter 1x40Gb\n# 4-Port Adapter for 1 GbE In-Line Bypass Applications\n\t00f5  NT4E2-4T-BP Network Adapter 4x1Gb with Electrical Bypass\n\t0105  NT4E2-4-PTP Network Adapter 4x1Gb\n\t0115  NT20E2-PTP Network Adapter 2x10Gb\n\t0125  NT4E2-4-PTP Network Adapter 4x1Gb\n\t0135  NT20E2-PTP Network Adapter 2x10Gb\n\t0145  NT40E3-4-PTP Network Adapter 4x10Gb\n\t0155  NT100E3-1-PTP Network Adapter 1x100Gb\n\t0165  NT80E3-2-PTP Network Adapter 2x40Gb\n\t0175  NT20E3-2-PTP Network Adapter 2x10Gb\n\t0185  NT40A01 Network Adapter\n\t01a5  NT200A01 Network Adapter\n\t01c5  NT200A02 Network Adapter\n18f6  NextIO\n\t1000  [Nexsis] Switch Virtual P2P PCIe Bridge\n\t1001  [Texsis] Switch Virtual P2P PCIe Bridge\n\t1050  [Nexsis] Switch Virtual P2P PCI Bridge\n\t1051  [Texsis] Switch Virtual P2P PCI Bridge\n\t2000  [Nexsis] Switch Integrated Mgmt. Endpoint\n\t2001  [Texsis] Switch Integrated Mgmt. Endpoint\n18f7  Commtech, Inc.\n\t0001  ESCC-PCI-335 Serial PCI Adapter [Fastcom]\n\t0002  422/4-PCI-335 Serial PCI Adapter [Fastcom]\n\t0003  232/4-1M-PCI Serial PCI Adapter [Fastcom]\n\t0004  422/2-PCI-335 Serial PCI Adapter [Fastcom]\n\t0005  IGESCC-PCI-ISO/1 Serial PCI Adapter [Fastcom]\n\t000a  232/4-PCI-335 Serial PCI Adapter [Fastcom]\n\t000b  232/8-PCI-335 Serial PCI Adapter [Fastcom]\n\t000f  FSCC Serial PCI Adapter [Fastcom]\n\t0010  GSCC Serial PCI Adapter [Fastcom]\n\t0011  QSSB Serial PCI Adapter [Fastcom]\n\t0014  SuperFSCC Serial PCI Adapter [Fastcom]\n\t0015  SuperFSCC-104-LVDS Serial PC/104+ Adapter [Fastcom]\n\t0016  FSCC-232 RS-232 Serial PCI Adapter [Fastcom]\n# Software UARTs\n\t0017  SuperFSCC-104 Serial PC/104+ Adapter [Fastcom]\n# Software UARTs\n\t0018  SuperFSCC/4 Serial PCI Adapter [Fastcom]\n# Software UARTs\n\t0019  SuperFSCC Serial PCI Adapter [Fastcom]\n\t001a  SuperFSCC-LVDS Serial PCI Adapter [Fastcom]\n# Software UARTs\n\t001b  FSCC/4 Serial PCI Adapter [Fastcom]\n# RS-644 Only\n\t001c  SuperFSCC/4-LVDS Serial PCI Adapter [Fastcom]\n# Software UARTs\n\t001d  FSCC Serial PCI Adapter [Fastcom]\n\t001e  SuperFSCC/4 Serial PCIe Adapter [Fastcom]\n\t001f  SuperFSCC/4 Serial cPCI Adapter [Fastcom]\n\t0020  422/4-PCIe Serial PCIe Adapter [Fastcom]\n\t0021  422/8-PCIe Serial PCIe Adapter [Fastcom]\n# RS-644 Only\n\t0022  SuperFSCC/4-LVDS Serial PCIe Adapter [Fastcom]\n# Software UARTs\n\t0023  SuperFSCC/4 Serial cPCI Adapter [Fastcom]\n# RS-644 Only, Software UARTs\n\t0025  SuperFSCC/4-LVDS Serial PCI Adapter [Fastcom]\n# RS-644 Only, Software UARTs\n\t0026  SuperFSCC-LVDS Serial PCI Adapter [Fastcom]\n# Software UARTs\n\t0027  FSCC/4 Serial PCIe Adapter [Fastcom]\n18fb  Resilience Corporation\n1904  Hangzhou Silan Microelectronics Co., Ltd.\n\t2031  SC92031 PCI Fast Ethernet Adapter\n\t8139  RTL8139D [Realtek] PCI 10/100BaseTX ethernet adaptor\n1905  Micronas USA, Inc.\n1912  Renesas Technology Corp.\n\t0002  SH7780 PCI Controller (PCIC)\n\t0011  SH7757 PCIe End-Point [PBI]\n\t0012  SH7757 PCIe-PCI Bridge [PPB]\n\t0013  SH7757 PCIe Switch [PS]\n\t0014  uPD720201 USB 3.0 Host Controller\n\t0015  uPD720202 USB 3.0 Host Controller\n\t001a  SH7758 PCIe-PCI Bridge [PPB]\n\t001b  SH7758 PCIe End-Point [PBI]\n\t001d  SH7758 PCIe Switch [PS]\n1919  Soltek Computer Inc.\n1923  Sangoma Technologies Corp.\n\t0040  A200/Remora FXO/FXS Analog AFT card\n\t0100  A104d QUAD T1/E1 AFT card\n\t0300  A101 single-port T1/E1\n\t0400  A104u Quad T1/E1 AFT\n1924  Solarflare Communications\n\t0703  SFC4000 rev A net [Solarstorm]\n\t\t10b8 0102  SMC10GPCIe-10BT (A2) [TigerCard]\n\t\t10b8 0103  SMC10GPCIe-10BT (A3) [TigerCard]\n\t\t10b8 0201  SMC10GPCIe-XFP (A1) [TigerCard]\n\t\t1924 0101  SFE4001-A1\n\t\t1924 0102  SFE4001-A2\n\t\t1924 0103  SFE4001-A3\n\t\t1924 0201  SFE4002-A1\n\t\t1924 0301  SFE4003-A1\n\t\t1924 0302  SFE4003-A2\n\t\t1924 0303  SFE4003-A3\n\t\t1924 0304  SFE4003-A4\n\t\t1924 0500  SFE4005-A0\n\t0710  SFC4000 rev B [Solarstorm]\n\t\t10b8 0103  SMC10GPCIe-10BT (A3) [TigerCard]\n\t\t10b8 0201  SMC10GPCIe-XFP (A1) [TigerCard]\n\t\t1924 0102  SFE4001-A2\n\t\t1924 0103  SFE4001-A3\n\t\t1924 0201  SFE4002-A1\n\t\t1924 0302  SFE4003-A2\n\t\t1924 0303  SFE4003-A3\n\t\t1924 0304  SFE4003-A4\n\t\t1924 0500  SFE4005-A0\n\t\t1924 5102  SFN4111T-A2\n\t\t1924 5103  SFN4111T-R3\n\t\t1924 5104  SFN4111T-R4\n\t\t1924 5105  SFN4111T-R5\n\t\t1924 5201  SFN4112F-R1\n\t\t1924 5202  SFN4112F-R2\n\t0803  SFC9020 10G Ethernet Controller\n\t\t1014 0478  2-port 10GbE Low-Latency (R7)\n\t\t1014 0479  2-port 10GbE OpenOnload (R7)\n\t\t1014 04a7  Solarflare 10Gb Low-latency Dual-port HBA (R7)\n\t\t1014 04a8  Solarflare 10Gb Dual-port HBA (R7)\n\t\t103c 2132  Ethernet 10Gb 2-port 570FLR-SFP+ Adapter (R1)\n\t\t103c 2136  Ethernet 10Gb 2-port 570SFP+ Adapter (R7)\n\t\t1924 1201  SFA6902F-R1 SFP+ AOE Adapter\n\t\t1924 6200  SFN5122F-R0 SFP+ Server Adapter\n\t\t1924 6201  SFN5122F-R1 SFP+ Server Adapter\n\t\t1924 6202  SFN5122F-R2 SFP+ Server Adapter\n\t\t1924 6204  SFN5122F-R4 SFP+ Server Adapter\n\t\t1924 6205  SFN5122F-R5 SFP+ Server Adapter\n\t\t1924 6206  SFN5122F-R6 SFP+ Server Adapter\n\t\t1924 6207  SFN5122F-R7 SFP+ Server Adapter\n\t\t1924 6210  SFN5322F-R0 SFP+ Precision Time Synchronization Server Adapter\n\t\t1924 6211  SFN5322F-R1 SFP+ Precision Time Synchronization Server Adapter\n\t\t1924 6217  SFN5322F-R7 SFP+ Precision Time Synchronization Server Adapter\n\t\t1924 6227  SFN6122F-R7 SFP+ Server Adapter\n\t\t1924 6237  SFN6322F-R7 SFP+ Precision Time Synchronization Server Adapter\n\t\t1924 6501  SFN5802K-R1 Mezzanine Adapter\n\t\t1924 6511  SFN5814H-R1 Mezzanine Adapter\n\t\t1924 6521  SFN5812H-R1 Mezzanine Adapter\n\t\t1924 6562  SFN6832F-R2 SFP+ Mezzanine Adapter\n\t\t1924 6a05  SFN5112F-R5 SFP+ Server Adapter\n\t\t1924 6a06  SFN5112F-R6 SFP+ Server Adapter\n\t\t1924 7206  SFN5162F-R6 SFP+ Server Adapter\n\t\t1924 7207  SFN5162F-R7 SFP+ Server Adapter\n\t\t1924 7a06  SFN5152F-R6 SFP+ Server Adapter\n\t\t1924 7a07  SFN5152F-R7 SFP+ Server Adapter\n\t0813  SFL9021 10GBASE-T Ethernet Controller\n\t\t1924 6100  SFN5121T-R0 10GBASE-T Server Adapter\n\t\t1924 6102  SFN5121T-R2 10GBASE-T Server Adapter\n\t\t1924 6103  SFN5121T-R3 10GBASE-T Server Adapter\n\t\t1924 6104  SFN5121T-R4 10GBASE-T Server Adapter\n\t\t1924 6902  SFN5111T-R2 10GBASE-T Server Adapter\n\t\t1924 6904  SFN5111T-R4 10GBASE-T Server Adapter\n\t\t1924 7104  SFN5161T-R4 10GBASE-T Server Adapter\n\t\t1924 7904  SFN5151T-R4 10GBASE-T Server Adapter\n\t0903  SFC9120 10G Ethernet Controller\n\t\t1014 04cc  SFN7122F-R2 2x10GbE SFP+ Flareon Ultra\n\t\t1924 8002  SFN7122F-R1 SFP+ Server Adapter\n\t\t1924 8003  SFN7x41Q-R1 Flareon Ultra 7000 Series 10/40G Adapter\n\t\t1924 8006  SFN7022F-R1 SFP+ Server Adapter\n\t\t1924 8007  SFN7322F-R2 Precision Time SFP+ Server Adapter\n\t\t1924 8009  SFN7x22F-R2 Flareon Ultra 7000 Series 10G Adapter\n\t\t1924 800a  SFN7x02F-R2 Flareon 7000 Series 10G Adapter\n\t\t1924 800c  SFN7x22F-R3 Flareon Ultra 7000 Series 10G Adapter\n\t\t1924 800d  SFN7x02F-R3 Flareon 7000 Series 10G Adapter\n\t\t1924 8010  SFA7942Q-R1 QSFP+ AOE Adapter\n\t\t1924 8015  SFA7942Q-A5-0-R1 QSFP+ AOE Adapter\n\t0923  SFC9140 10/40G Ethernet Controller\n\t\t1924 800b  SFN7x42Q-R1 Flareon Ultra 7000 Series 10/40G Adapter\n\t\t1924 800e  SFN7x42Q-R2 Flareon Ultra 7000 Series 10/40G Adapter\n\t\t1924 800f  SFN7xx4F-R1 Flareon Ultra 7000 Series 10G Adapter\n\t0a03  SFC9220 10/40G Ethernet Controller\n\t\t1924 8011  SFN8022-R1 8000 Series 10G Adapter\n\t\t1924 8012  SFN8522-R1 8000 Series 10G Adapter\n\t\t1924 8013  SFN8042-R1 8000 Series 10/40G Adapter\n\t\t1924 8014  SFN8542-R1 8000 Series 10/40G Adapter\n\t\t1924 8016  SFN8022-R2 8000 Series 10G Adapter\n\t\t1924 8017  SFN8522-R2 8000 Series 10G Adapter\n\t\t1924 8018  SFN8042-R2 8000 Series 10/40G Adapter\n\t\t1924 8019  SFN8542-R2 8000 Series 10/40G Adapter\n\t\t1924 801a  SFN8722-R1 8000 Series OCP 10G Adapter\n\t\t1924 801b  SFN8522-R3 8000 Series 10G Adapter\n\t\t1924 801c  SFN8042-R3 8000 Series 10/40G Adapter\n\t\t1924 8021  SFN8041-R1 8000 Series 10/40G Adapter\n\t0b03  XtremeScale SFC9250 10/25/40/50/100G Ethernet Controller\n\t\t1924 801d  x2522-R1 2000 Series 10/25G Adapter\n\t\t1924 801e  x2542-R1 2000 Series 40/100G Adapter\n\t\t1924 8022  XtremeScale X2522 10G Network Adapter\n\t\t1924 8024  XtremeScale X2562 OCP 3.0 Dual Port SFP28\n\t\t1924 8027  XtremeScale X2541 PCIe Single Port QSFP28\n\t\t1924 8028  XtremeScale X2522-25G Network Adapter\n\t\t1924 802a  XtremeScale X2542 PCIe Dual Port QSFP28\n\t\t1924 802b  XtremeScale X2552 OCP 2.0 Dual Port SFP28\n\t\t1924 802c  XtremeScale X2522-25G PCIe Dual Port SFP28\n\t\t1924 802d  XtremeScale X2562 OCP 3.0 Dual Port SFP28\n\t1803  SFC9020 10G Ethernet Controller (Virtual Function)\n\t1813  SFL9021 10GBASE-T Ethernet Controller (Virtual Function)\n\t1903  SFC9120 10G Ethernet Controller (Virtual Function)\n\t1923  SFC9140 10/40G Ethernet Controller (Virtual Function)\n\t1a03  SFC9220 10/40G Ethernet Controller (Virtual Function)\n\t1b03  XtremeScale SFC9250 10/25/40/50/100G Ethernet Controller (Virtual Function)\n\t6703  SFC4000 rev A iSCSI/Onload [Solarstorm]\n\t\t10b8 0102  SMC10GPCIe-10BT (A2) [TigerCard]\n\t\t10b8 0103  SMC10GPCIe-10BT (A3) [TigerCard]\n\t\t10b8 0201  SMC10GPCIe-XFP (A1) [TigerCard]\n\t\t1924 0101  SFE4001-A1\n\t\t1924 0102  SFE4001-A2\n\t\t1924 0103  SFE4001-A3\n\t\t1924 0201  SFE4002-A1\n\t\t1924 0301  SFE4003-A1\n\t\t1924 0302  SFE4003-A2\n\t\t1924 0303  SFE4003-A3\n\t\t1924 0304  SFE4003-A4\n\t\t1924 0500  SFE4005-A0\n\tc101  EF1-21022T [EtherFabric]\n192a  BiTMICRO Networks Inc.\n\t0008  RAMPART\n192e  TransDimension\n1931  Option N.V.\n\t000c  Qualcomm MSM6275 UMTS chip\n1932  DiBcom\n193c  MAXIM Integrated Products\n193d  Hangzhou H3C Technologies Co., Ltd.\n193f  AHA Products Group\n\t0001  AHA36x-PCIX\n\t0360  AHA360-PCIe\n\t0363  AHA363-PCIe\n\t0364  AHA364-PCIe\n\t0367  AHA367-PCIe\n\t0370  AHA370-PCIe\n\t0604  AHA604\n\t0605  AHA605\n\t3641  AHA3641\n\t3642  AHA3642\n\t6101  AHA6101\n\t6102  AHA6102\n1942  ClearSpeed Technology plc\n\te511  Advance X620 accelerator card\n\te521  Advance e620 accelerator card\n1947  C-guys, Inc.\n\t4743  CG200 Dual SD/SDIO Host controller device\n1948  Alpha Networks Inc.\n194a  DapTechnology B.V.\n\t1111  FireSpy3850\n\t1112  FireSpy450b\n\t1113  FireSpy450bT\n\t1114  FireSpy850\n\t1115  FireSpy850bT\n\t1200  FireTrac 3460bT\n\t1201  FireTrac 3460bT (fallback firmware)\n\t1202  FireTrac 3460bT\n\t1203  FireTrac 3460bT (fallback firmware)\n# nee Curtis, Inc.\n1954  One Stop Systems, Inc.\n1957  Freescale Semiconductor Inc\n\t0012  MPC8548E\n\t0013  MPC8548\n\t0014  MPC8543E\n\t0015  MPC8543\n\t0018  MPC8547E\n\t0019  MPC8545E\n\t001a  MPC8545\n\t0020  MPC8568E\n\t0021  MPC8568\n\t0022  MPC8567E\n\t0023  MPC8567\n\t0030  MPC8533E\n\t0031  MPC8533\n\t0032  MPC8544E\n\t0033  MPC8544\n\t0040  MPC8572E\n\t0041  MPC8572\n\t0050  MPC8536E\n\t0051  MPC8536\n\t0052  MPC8535E\n\t0053  MPC8535\n\t0060  MPC8569\n\t0061  MPC8569E\n\t0070  P2020E\n\t0071  P2020\n\t0078  P2010E\n\t0079  P2010\n\t0080  MPC8349E\n\t0081  MPC8349\n\t0082  MPC8347E TBGA\n\t0083  MPC8347 TBGA\n\t0084  MPC8347E PBGA\n\t\t110a 4074  SIMATIC NET CP 1628\n\t0085  MPC8347 PBGA\n\t\t110a 4046  SIMATIC NET CP 1623\n\t0086  MPC8343E\n\t0087  MPC8343\n\t00b4  MPC8315E\n\t00b6  MPC8314E\n\t\t1a56 1101  Killer Xeno Pro Gigabit Ethernet Controller\n\t00c2  MPC8379E\n\t00c3  MPC8379\n\t00c4  MPC8378E\n\t00c5  MPC8378\n\t00c6  MPC8377E\n\t00c7  MPC8377\n\t0100  P1020E\n\t0101  P1020\n\t0102  P1021E\n\t0103  P1021\n\t0108  P1011E\n\t0109  P1011\n\t010a  P1012E\n\t010b  P1012\n\t0110  P1022E\n\t0111  P1022\n\t\t1c7f 5200  EB5200\n\t0118  P1013E\n\t0119  P1013\n\t0128  P1010\n\t0400  P4080E\n\t0401  P4080\n\t0408  P4040E\n\t0409  P4040\n\t041f  P3041\n\t0440  T4240 with security\n\t0441  T4240 without security\n\t0446  T4160 with security\n\t0447  T4160 without security\n\t0830  T2080 with security\n\t0831  T2080 without security\n\t0838  T2081 with security\n\t0839  T2081 without security\n\t580c  MPC5121e\n\t7010  MPC8641 PCI Host Bridge\n\t7011  MPC8641D PCI Host Bridge\n\t7018  MPC8610\n\tc006  MPC8308\n\t\t1a56 1201  Killer E2100 Gigabit Ethernet Controller\n# PCIe interface for emulator\n\tfc02  RedStone\n# CFI device over PCIe\n\tfc03  CFI\n1958  Faster Technology, LLC.\n1959  PA Semi, Inc\n\ta000  PA6T Core\n\ta001  PWRficient Host Bridge\n\ta002  PWRficient PCI-Express Port\n\ta003  PWRficient SMBus Controller\n\ta004  PWRficient 16550 UART\n\ta005  PWRficient Gigabit Ethernet\n\ta006  PWRficient 10-Gigabit Ethernet\n\ta007  PWRficient DMA Controller\n\ta008  PWRficient LPC/Localbus Interface\n\ta009  PWRficient L2 Cache\n\ta00a  PWRficient DDR2 Memory Controller\n\ta00b  PWRficient SERDES\n\ta00c  PWRficient System/Debug Controller\n\ta00d  PWRficient PCI-Express Internal Endpoint\n1966  Orad Hi-Tec Systems\n\t1975  DVG64 family\n\t1977  DVG128 family\n# nee Atheros Communications, Inc. nee Attansic Technology Corp.\n1969  Qualcomm Atheros\n\t1026  AR8121/AR8113/AR8114 Gigabit or Fast Ethernet\n\t\t1043 8304  P5KPL-CM Motherboard\n\t1048  Attansic L1 Gigabit Ethernet\n\t\t1043 8226  P5KPL-VM Motherboard\n\t1062  AR8132 Fast Ethernet\n\t1063  AR8131 Gigabit Ethernet\n\t\t1458 e000  GA-G31M-ES2L Motherboard\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t1066  Attansic L2c Gigabit Ethernet\n\t1067  Attansic L1c Gigabit Ethernet\n\t1073  AR8151 v1.0 Gigabit Ethernet\n\t1083  AR8151 v2.0 Gigabit Ethernet\n\t1090  AR8162 Fast Ethernet\n\t\t1043 108d  VivoBook X202E, X202EV\n\t1091  AR8161 Gigabit Ethernet\n\t\t1043 1477  N56VZ\n\t10a0  QCA8172 Fast Ethernet\n\t10a1  QCA8171 Gigabit Ethernet\n\t2048  Attansic L2 Fast Ethernet\n\t2060  AR8152 v1.1 Fast Ethernet\n\t2062  AR8152 v2.0 Fast Ethernet\n\t\t1043 8468  Eee PC 1015PX\n# E2200, E2201, E2205\n\te091  Killer E220x Gigabit Ethernet Controller\n\te0a1  Killer E2400 Gigabit Ethernet Controller\n\te0b1  Killer E2500 Gigabit Ethernet Controller\n196a  Sensory Networks Inc.\n\t0101  NodalCore C-1000 Content Classification Accelerator\n\t0102  NodalCore C-2000 Content Classification Accelerator\n\t0105  NodalCore C-3000 Content Classification Accelerator\n196d  Club-3D BV\n196e  PNY\n1971  AGEIA Technologies, Inc.\n\t1011  Physics Processing Unit [PhysX]\n\t\t1043 0001  PhysX P1\n# nee Eberspaecher Electronics\n1974  Star Electronics GmbH & Co. KG\n\t0009  FlexCard PMC-II\n\t0011  FlexCard PMC-II Ethernet\n1976  TRENDnet\n1977  Parsec\n197b  JMicron Technology Corp.\n\t0250  JMC250 PCI Express Gigabit Ethernet Controller\n\t0260  JMC260 PCI Express Fast Ethernet Controller\n\t0368  JMB368 IDE controller\n\t2360  JMB360 AHCI Controller\n\t2361  JMB361 AHCI/IDE\n\t\t1462 7235  P965 Neo MS-7235 mainboard\n\t2362  JMB362 SATA Controller\n\t\t1043 8460  P8P67 Deluxe Motherboard\n\t2363  JMB363 SATA/IDE Controller\n\t\t1043 81e4  P5B [JMB363]\n\t\t1458 b000  Motherboard\n\t\t1849 2363  Motherboard (one of many)\n\t2364  JMB364 AHCI Controller\n\t2365  JMB365 AHCI/IDE\n\t2366  JMB366 AHCI/IDE\n\t2368  JMB368 IDE controller\n\t2369  JMB369 Serial ATA Controller\n\t2380  IEEE 1394 Host Controller\n\t2381  Standard SD Host Controller\n\t2382  SD/MMC Host Controller\n\t2383  MS Host Controller\n\t2384  xD Host Controller\n\t2386  Standard SD Host Controller\n\t2387  SD/MMC Host Controller\n\t2388  MS Host Controller\n\t2389  xD Host Controller\n\t2391  Standard SD Host Controller\n\t2392  SD/MMC Host Controller\n\t2393  MS Host Controller\n\t2394  xD Host Controller\n1982  Distant Early Warning Communications Inc\n\t1600  OX16C954 HOST-A\n\t16ff  OX16C954 HOST-B\n1987  Phison Electronics Corporation\n\t5007  E7 NVMe Controller\n\t5012  E12 NVMe Controller\n1989  Montilio Inc.\n\t0001  RapidFile Bridge\n\t8001  RapidFile\n198a  Nallatech Ltd.\n1993  Innominate Security Technologies AG\n1999  A-Logics\n\ta900  AM-7209 Video Processor\n199a  Pulse-LINK, Inc.\n199d  Xsigo Systems\n\t8209  Virtual NIC Device\n\t890a  Virtual HBA Device\n199f  Auvitek\n\t8501  AU85X1 PCI REV1.1\n\t8521  AU8521 TV card\n# nee ServerEngines Corp.\n19a2  Emulex Corporation\n\t0120  x1 PCIe Gen2 Bridge[Pilot4]\n\t0200  BladeEngine 10Gb PCI-E iSCSI adapter\n\t0201  BladeEngine 10Gb PCIe Network Adapter\n\t0211  BladeEngine2 10Gb Gen2 PCIe Network Adapter\n\t0212  BladeEngine2 10Gb Gen2 PCIe iSCSI Adapter\n\t0221  BladeEngine3 10Gb Gen2 PCIe Network Adapter\n\t0222  BladeEngine3 10Gb Gen2 PCIe iSCSI Adapter\n\t0700  OneConnect OCe10100/OCe10102 Series 10 GbE\n\t\t103c 1747  NC550SFP DualPort 10GbE Server Adapter\n\t\t103c 1749  NC550SFP Dual Port Server Adapter\n\t\t103c 174a  NC551m Dual Port FlexFabric 10Gb Adapter\n\t\t103c 174b  StorageWorks NC550 DualPort Converged Network Adapter\n\t\t103c 3314  NC551i Dual Port FlexFabric 10Gb Adapter\n\t0702  OneConnect 10Gb iSCSI Initiator\n\t0704  OneConnect OCe10100/OCe10102 Series 10 GbE CNA\n\t\t10df e602  OneConnect OCe10100 10Gb CNA\n\t\t10df e630  OneConnect OCe10102-FM-E / OCe10102-FX-E for EMC VNX Symmetrix\n\t0710  OneConnect 10Gb NIC (be3)\n# FC 5287 / FC 5284; CCIN 5287\n\t\t1014 03d0  PCIe2 2-port 10GbE SR Adapter for POWER\n# FC 5288 / FC 5286; CCIN 5288\n\t\t1014 03d1  PCIe2 2-port 10GbE SFP+ Copper Adapter for POWER\n\t\t1014 0409  Integrated Multifunction Card with Dual 10GbE SR Optical + Dual 1GbE for Power 750/760\n\t\t1014 040a  Integrated Multifunction Card with Dual 10GbE SR Copper + Dual 1GbE for Power 750/760\n\t\t103c 3315  NC553i 10Gb 2-port FlexFabric Converged Network Adapter\n\t\t103c 3340  NC552SFP 2-port 10Gb Server Adapter\n\t\t103c 3341  NC552m 10Gb 2-port FlexFabric Converged Network Adapter\n\t\t103c 3345  NC553m 10Gb 2-port FlexFabric Converged Network Adapter\n\t\t103c 337b  NC554FLB 10Gb 2-port FlexFabric Converged Network Adapter\n\t\t10df e733  Flex System EN4054 4-port 10Gb Ethernet Mezzanine Adapter\n\t0712  OneConnect 10Gb iSCSI Initiator (be3)\n\t0714  OneConnect 10Gb FCoE Initiator (be3)\n\t\t103c 3315  NC553i 10Gb 2-port FlexFabric Converged Network Adapter\n\t\t103c 337b  NC554FLB 10Gb 2-port FlexFabric Converged Network Adapter\n\t0800  ServerView iRMC HTI\n19a8  DAQDATA GmbH\n19ac  Kasten Chase Applied Research\n\t0001  ACA2400 Crypto Accelerator\n19ae  Progeny Systems Corporation\n\t0520  4135 HFT Interface Controller\n\t0521  Decimator\n19ba  ZyXEL Communications Corp.\n\t2330  ZyWALL Turbo Card\n19c1  Exegy Inc.\n# nee NextNet Wireless\n19d1  Motorola Expedience\n19d4  Quixant Limited\n19da  ZOTAC International (MCO) Ltd.\n19de  Pico Computing\n19e2  Vector Informatik GmbH\n19e3  DDRdrive LLC\n\t5801  DDRdrive X1\n\t5808  DDRdrive X8\n\tdd52  DDRdrive X1-30\n19e5  Huawei Technologies Co., Ltd.\n# subvendor\n\t0123  ES3000 V3 NVMe PCIe SSD\n\t\t19e5 3022  NVMe SSD ES3600P V3 800GB 2.5\" U.2\n\t\t19e5 3023  NVMe SSD ES3600P V3 1200GB 2.5\" U.2\n\t\t19e5 3024  NVMe SSD ES3600P V3 1600GB 2.5\" U.2\n\t\t19e5 3025  NVMe SSD ES3600P V3 2000GB 2.5\" U.2\n\t\t19e5 3026  NVMe SSD ES3600P V3 3200GB 2.5\" U.2\n\t\t19e5 3033  NVMe SSD ES3600C V3 1200GB HHHL AIC\n\t\t19e5 3034  NVMe SSD ES3600C V3 1600GB HHHL AIC\n\t\t19e5 3036  NVMe SSD ES3600C V3 3200GB HHHL AIC\n\t0200  Hi1822 Family (2*100GE)\n\t0202  Hi1822 Family (2*32G FC)\n\t0203  Hi1822 Family (2*16G FC)\n\t0205  Hi1822 Family (2*100GE)\n\t0206  Hi1822 Family (2*25GE)\n\t0210  Hi1822 Family (4*25GE)\n\t0211  Hi1822 Family (4*25GE)\n\t0212  Hi1822 Family (2*8G FC)\n\t1710  iBMA Virtual Network Adapter\n\t1711  Hi1710 [iBMC Intelligent Management system chip w/VGA support]\n\t1822  Hi1822 Family (4*25GE)\n\t371e  Hi1822 Family Virtual Bridge\n\t375e  Hi1822 Family Virtual Function\n\t379e  Hi1822 Family Virtual Function\n\ta120  HiSilicon PCIe Root Port with Gen4\n\ta121  HiSilicon PCI-PCI Bridge\n\ta122  HiSilicon Embedded DMA Engine\n\ta124  HiSilicon Internal SDI Function Engine\n\ta125  HiSilicon SDI Network Controller\n\ta126  HiSilicon SDI NVMe Storage Controller\n\ta127  HiSilicon SDI Accelerator\n\ta12a  HiSilicon Add-on PCI-PCI Bridge\n\ta220  HNS GE Network Controller\n\ta221  HNS GE/10GE/25GE Network Controller\n\ta222  HNS GE/10GE/25GE RDMA Network Controller\n\ta224  HNS GE/10GE/25GE/50GE RDMA Network Controller\n\ta226  HNS GE/10GE/25GE/50GE/100GE RDMA Network Controller\n\ta22a  HiSilicon Network For SDI\n\ta22e  HNS Network Controller (Virtual Function)\n\ta22f  HNS RDMA Network Controller (Virtual Function)\n\ta230  HiSilicon SAS 3.0 HBA\n\ta235  HiSilicon AHCI HBA\n\ta238  HiSilicon USB 3.0 Host Controller\n\ta239  HiSilicon USB 2.0 2-port Host Controller\n\ta23a  HiSilicon USB 2.0 Host Controller\n\ta23b  HiSilicon USB 1.1 Host Controller\n\ta250  HiSilicon ZIP Engine\n\ta251  HiSilicon ZIP Engine(Virtual Function)\n\ta255  HiSilicon SEC Engine\n\ta256  HiSilicon SEC Engine(Virtual Function)\n\ta258  HiSilicon HPRE Engine\n\ta259  HiSilicon HPRE Engine(Virtual Function)\n\ta25a  HiSilicon RDE Engine\n\ta25b  HiSilicon RDE Engine(Virtual Function)\n19e7  NET (Network Equipment Technologies)\n\t1001  STIX DSP Card\n\t1002  STIX - 1 Port T1/E1 Card\n\t1003  STIX - 2 Port T1/E1 Card\n\t1004  STIX - 4 Port T1/E1 Card\n\t1005  STIX - 4 Port FXS Card\n19ee  Netronome Systems, Inc.\n19f1  BFG Tech\n19ff  Eclipse Electronic Systems, Inc.\n1a03  ASPEED Technology, Inc.\n\t1150  AST1150 PCI-to-PCI Bridge\n\t2000  ASPEED Graphics Family\n\t\t15d9 0832  X10SRL-F\n1a05  deltaww\n1a07  Kvaser AB\n\t0006  CAN interface PC104+ HS/HS\n\t0007  CAN interface PCIcanx II HS or HS/HS\n\t0008  CAN interface PCIEcan HS or HS/HS\n\t0009  CAN interface PCI104 HS/HS\n1a08  Sierra semiconductor\n\t0000  SC15064\n1a0e  DekTec Digital Video B.V.\n\t083f  DTA-2111 VHF/UHF Modulator\n1a17  Force10 Networks, Inc.\n\t8002  PB-10GE-2P 10GbE Security Card\n1a1d  GFaI e.V.\n\t1a17  Meta Networks MTP-1G IDPS NIC\n1a1e  3Leaf Systems, Inc.\n1a22  Ambric Inc.\n1a29  Fortinet, Inc.\n\t4338  CP8 Content Processor ASIC\n\t4e36  NP6 Network Processor\n\t4e37  NP7 Network Processor\n1a2b  Ascom AG\n\t0000  GESP v1.2\n\t0001  GESP v1.3\n\t0002  ECOMP v1.3\n\t0005  ETP v1.4\n\t000a  ETP-104 v1.1\n\t000e  DSLP-104 v1.1\n# nee Metalink Ltd.\n1a30  Lantiq\n\t0680  MtW8171 [Hyperion II]\n\t0700  Wave300 PSB8224 [Hyperion III]\n\t0710  Wave300 PSB8231 [Hyperion III]\n1a32  Quanta Microsystems, Inc\n1a3b  AzureWave\n\t1112  AR9285 Wireless Network Adapter (PCI-Express)\n1a41  Tilera Corp.\n\t0001  TILE64 processor\n\t0002  TILEPro processor\n\t0200  TILE-Gx processor\n\t0201  TILE-Gx Processor Virtual Function\n\t2000  TILE-Gx PCI Express Root Port\n1a4a  SLAC National Accelerator Lab TID-AIR\n\t1000  MCOR Power Supply Controller\n\t1010  AMC EVR - Stockholm Timing Board\n\t1020  Cluster On Board (COB) Ethernet Switch\n\t2000  PGPCard - 4 Lane\n\t2001  PGPCard - 8 Lane Plus EVR\n\t2010  PCI-Express EVR\n# PC-260-101-03\n\t2020  PGP-GEN3 PCIe\n\t2030  AXI Stream DAQ PCIe card\n1a51  Hectronic AB\n1a55  Rohde & Schwarz DVS GmbH\n\t0010  SDStationOEM\n\t0011  SDStationOEM II\n\t0020  Centaurus\n\t0021  Centaurus II\n\t0022  Centaurus II LT\n\t0030  CLIPSTER-VPU 1.x (Hugo)\n\t0040  Hydra Cinema (JPEG)\n\t0050  CLIPSTER-VPU 2.x (DigiLab)\n\t0060  CLIPSTER-DCI 2.x (HydraX)\n\t0061  Atomix\n\t0062  Atomix LT\n\t0063  Atomix HDMI\n\t0064  Atomix STAN\n\t0065  Atomix HDMI STAN\n\t0070  RED Rocket\n\t0090  CinePlay\n1a56  Bigfoot Networks, Inc.\n1a57  Highly Reliable Systems\n1a58  Razer USA Ltd.\n1a5d  Celoxica\n1a5e  Aprius Inc.\n1a5f  System TALKS Inc.\n1a68  VirtenSys Limited\n1a71  XenSource, Inc.\n1a73  Violin Memory, Inc\n\t0001  Mozart [Memory Appliance 1010]\n1a76  Wavesat\n1a77  Lightfleet Corporation\n1a78  Virident Systems Inc.\n\t0031  FlashMAX Drive\n\t\t1a78 0034  FlashMAX PCIe SSD [rev 3]\n\t\t1a78 0037  FlashMAX PCIe SSD [rev 3D]\n\t\t1a78 0038  FlashMAX PCIe SSD [rev 4]\n\t\t1a78 0039  FlashMAX PCIe SSD [rev 4D]\n\t0040  FlashMAX II\n\t0041  FlashMAX II\n\t0042  FlashMAX II\n\t0050  FlashMAX III\n1a84  Commex Technologies\n\t0001  Vulcan SP HT6210 10-Gigabit Ethernet (rev 02)\n1a88  MEN Mikro Elektronik\n\t4d45  Multifunction IP core\n1a8a  StarBridge, Inc.\n1a8c  Verigy Pte. Ltd.\n\t1100  E8001-66443 PCI Express CIC\n1a8e  DRS Technologies\n\t2090  Model 2090 PCI Express\n1aa8  Ciprico, Inc.\n\t0009  RAIDCore Controller\n\t000a  RAIDCore Controller\n1aae  Global Velocity, Inc.\n1ab4  Distributed Management Task Force, Inc. (DMTF)\n1ab6  CalDigit, Inc.\n\t6201  RAID Card\n# Parallels VM virtual devices\n1ab8  Parallels, Inc.\n\t4000  Virtual Machine Communication Interface\n\t4005  Accelerated Virtual Video Adapter\n\t4006  Memory Ballooning Controller\n1ab9  Espia Srl\n1ac8  Aeroflex Gaisler\n1acc  Point of View BV\n1ad7  Spectracom Corporation\n\t8000  TSync-PCIe Time Code Processor\n\t9100  TPRO-PCI-66U Timecode Reader/Generator\n1ade  Spin Master Ltd.\n\t1501  Swipetech barcode scanner\n\t3038  PCIe Video Bridge\n\t\t13c2 3016  TT-budget S2-4200 Twin\n\t\t4254 0552  S952 v3\n1ae0  Google, Inc.\n\t0042  Compute Engine Virtual Ethernet [gVNIC]\n1ae3  SANBlaze Technology, Inc.\n1ae7  First Wise Media GmbH\n\t0520  HFC-S PCI A [X-TENSIONS XC-520]\n1ae8  Silicon Software GmbH\n\t0a40  microEnable IV-BASE x1\n\t0a41  microEnable IV-FULL x1\n\t0a44  microEnable IV-FULL x4\n\t0e44  microEnable IV-GigE x4\n1ae9  Wilocity Ltd.\n\t0101  Wil6200 PCI Express Upstream Port\n\t0200  Wil6200 PCI Express Port\n\t0201  Wil6200 Wireless PCI Express Port\n\t0301  Wil6200 802.11ad Wireless Network Adapter\n\t0302  Wil6200 802.11ad Wireless Network Adapter\n\t0310  Wil6200 802.11ad Wireless Network Adapter\n1aea  Alcor Micro\n\t6601  AU6601 PCI-E Flash card reader controller\n1aec  Wolfson Microelectronics\n# nee Fusion-io\n1aed  SanDisk\n\t1003  ioDimm3 (v1.2)\n\t1005  ioDimm3\n\t\t1014 03c3  High IOPS SSD PCIe Adapter\n\t\t103c 176f  1.28TB MLC PCIe ioDrive Duo\n\t\t103c 1770  5.2TB MLC PCIe ioDrive Octal\n\t\t103c 178b  160GB SLC PCIe ioDrive\n\t\t103c 178c  320GB MLC PCIe ioDrive\n\t\t103c 178d  320GB SLC PCIe ioDrive Duo\n\t\t103c 178e  640GB MLC PCIe ioDrive Duo\n\t1006  ioXtreme\n\t1007  ioXtreme Pro\n\t1008  ioXtreme-2\n\t2001  ioDrive2\n\t3001  ioMemory FHHL\n\t3002  ioMemory HHHL\n\t3003  ioMemory Mezzanine\n1aee  Caustic Graphics Inc.\n# nee Qumranet, Inc.\n1af4  Red Hat, Inc.\n\t1000  Virtio network device\n\t1001  Virtio block device\n\t1002  Virtio memory balloon\n\t1003  Virtio console\n\t1004  Virtio SCSI\n\t1005  Virtio RNG\n\t1009  Virtio filesystem\n# virtio 1.0\n\t1041  Virtio network device\n# virtio 1.0\n\t1042  Virtio block device\n# virtio 1.0\n\t1043  Virtio console\n# virtio 1.0\n\t1044  Virtio RNG\n# virtio 1.0\n\t1045  Virtio memory balloon\n# virtio 1.0\n\t1048  Virtio SCSI\n# virtio 1.0\n\t1049  Virtio filesystem\n# virtio 1.0\n\t1050  Virtio GPU\n# virtio 1.0\n\t1052  Virtio input\n\t1110  Inter-VM shared memory\n\t\t1af4 1100  QEMU Virtual Machine\n1af5  Netezza Corp.\n1afa  J & W Electronics Co., Ltd.\n1b03  Magnum Semiconductor, Inc,\n\t6100  DXT/DXTPro Multiformat Broadcast HD/SD Encoder/Decoder/Transcoder\n\t7000  D7 Multiformat Broadcast HD/SD Encoder/Decoder/Transcoder\n1b08  MSC Technologies GmbH\n1b0a  Pegatron\n1b13  Jaton Corp\n1b1a  K&F Computing Research Co.\n\t0e70  GRAPE\n1b21  ASMedia Technology Inc.\n\t0611  ASM1061 SATA IDE Controller\n\t0612  ASM1062 Serial ATA Controller\n\t\t1849 0612  Motherboard\n\t1042  ASM1042 SuperSpeed USB Host Controller\n\t\t1043 8488  P8B WS Motherboard\n\t\t1849 1042  Motherboard\n\t1080  ASM1083/1085 PCIe to PCI Bridge\n\t\t1849 1080  Motherboard\n\t1142  ASM1042A USB 3.0 Host Controller\n\t1184  ASM1184e PCIe Switch Port\n\t\t1849 1184  ASM1184e PCIe Switch\n\t1242  ASM1142 USB 3.1 Host Controller\n\t1343  ASM1143 USB 3.1 Host Controller\n\t2142  ASM2142 USB 3.1 Host Controller\n1b26  Netcope Technologies, a.s.\n\tc132  COMBO-LXT155\n\tc1c0  NFB-100G1-e0\n\tc1c1  NFB-100G1-e1\n\tc250  NFB-200G2-master\n\tc251  NFB-200G2-slave\n\tc2c0  NFB-100G2-e0\n\tc2c1  NFB-100G2-e1\n\tcb20  COMBO-20G\n\tcb40  COMBO-40G\n\tcb80  NFB-40G2\n1b2c  Opal-RT Technologies Inc.\n1b36  Red Hat, Inc.\n\t0001  QEMU PCI-PCI bridge\n\t0002  QEMU PCI 16550A Adapter\n\t\t1af4 1100  QEMU Virtual Machine\n\t0003  QEMU PCI Dual-port 16550A Adapter\n\t\t1af4 1100  QEMU Virtual Machine\n\t0004  QEMU PCI Quad-port 16550A Adapter\n\t\t1af4 1100  QEMU Virtual Machine\n\t0005  QEMU PCI Test Device\n\t\t1af4 1100  QEMU Virtual Machine\n\t0006  PCI Rocker Ethernet switch device\n\t0007  PCI SD Card Host Controller Interface\n\t0008  QEMU PCIe Host bridge\n\t0009  QEMU PCI Expander bridge\n\t000a  PCI-PCI bridge (multiseat)\n\t000b  QEMU PCIe Expander bridge\n\t000c  QEMU PCIe Root port\n\t000d  QEMU XHCI Host Controller\n\t0100  QXL paravirtual graphic card\n\t\t1af4 1100  QEMU Virtual Machine\n1b37  Signal Processing Devices Sweden AB\n\t0001  ADQ214\n\t0003  ADQ114\n\t0005  ADQ112\n\t000e  ADQ108\n\t000f  ADQDSP\n\t0014  ADQ412\n\t0015  ADQ212\n\t001b  SDR14\n\t001c  ADQ1600\n\t001e  ADQ208\n\t001f  DSU\n\t0020  ADQ14\n\t0023  ADQ7\n\t0026  ADQ8\n\t2014  TX320\n\t2019  S6000\n# now owned by HGST (a Western Digital subsidiary)\n1b39  sTec, Inc.\n\t0001  S1120 PCIe Accelerator SSD\n1b3a  Westar Display Technologies\n\t7589  HRED J2000 - JPEG 2000 Video Codec Device\n1b3e  Teradata Corp.\n\t1fa8  BYNET BIC2SE/X\n\t\t1b3e 00a3  BYNET BIC2SX\n\t\t1b3e 00c3  BYNET BIC2SE\n1b40  Schooner Information Technology, Inc.\n# also used by some PROXIM (14b7) devices erroneously\n1b47  Numascale AS\n\t0601  NumaChip N601\n\t0602  NumaChip N602\n1b4b  Marvell Technology Group Ltd.\n\t0640  88SE9128 SATA III 6Gb/s RAID Controller\n\t9120  88SE9120 SATA 6Gb/s Controller\n\t9123  88SE9123 PCIe SATA 6.0 Gb/s controller\n\t\tdc93 600e  DC-6xxe series SATA 6G controller\n\t9125  88SE9125 PCIe SATA 6.0 Gb/s controller\n\t9128  88SE9128 PCIe SATA 6 Gb/s RAID controller\n\t9130  88SE9128 PCIe SATA 6 Gb/s RAID controller with HyperDuo\n\t\t1043 8438  P8P67 Deluxe Motherboard\n\t9172  88SE9172 SATA 6Gb/s Controller\n\t9178  88SE9170 PCIe SATA 6Gb/s Controller\n\t917a  88SE9172 SATA III 6Gb/s RAID Controller\n\t9183  88SS9183 PCIe SSD Controller\n\t9192  88SE9172 SATA III 6Gb/s RAID Controller\n\t91a0  88SE912x SATA 6Gb/s Controller [IDE mode]\n\t91a4  88SE912x IDE Controller\n\t9220  88SE9220 PCIe 2.0 x2 2-port SATA 6 Gb/s RAID Controller\n\t9230  88SE9230 PCIe SATA 6Gb/s Controller\n\t\t1028 1fd6  BOSS-S1 Adapter\n\t\t1028 1fdf  BOSS-S1 Modular\n\t\t1028 1fe2  BOSS-S1 Adapter\n\t\t1028 2010  BOSS-S2 Adapter\n\t\t1d49 0300  ThinkSystem M.2 with Mirroring Enablement Kit\n\t9235  88SE9235 PCIe 2.0 x2 4-port SATA 6 Gb/s Controller\n\t9445  88SE9445 PCIe 2.0 x4 4-Port SAS/SATA 6 Gbps RAID Controller\n\t9480  88SE9480 SAS/SATA 6Gb/s RAID controller\n\t9485  88SE9485 SAS/SATA 6Gb/s controller\n1b55  NetUP Inc.\n\t18f6  Dual DVB Universal CI card\n\t18f7  Dual DVB Universal CI card rev 1.4\n\t2a2c  Dual DVB-S2-CI card\n\te2e4  Dual DVB-T/C-CI RF card\n# 2xHDMI and 2xHD-SDI inputs\n\te5f4  MPEG2 and H264 Encoder-Transcoder\n\tf1c4  Dual ASI-RX/TX-CI card\n1b66  DELTACAST\n\t0007  DELTA-3G-elp-d\n1b6f  Etron Technology, Inc.\n\t7023  EJ168 USB 3.0 Host Controller\n\t7052  EJ188/EJ198 USB 3.0 Host Controller\n1b73  Fresco Logic\n\t1000  FL1000G USB 3.0 Host Controller\n\t\t1d5c 1000  Anker USB 3.0 Express Card\n\t1009  FL1009 USB 3.0 Host Controller\n\t1100  FL1100 USB 3.0 Host Controller\n\t\t16b8 6e31  Allegro Pro USB 3.0 PCIe\n1b74  OpenVox Communication Co. Ltd.\n\t0115  D115P/D115E Single-port E1/T1 card\n\td130  D130P/D130E Single-port E1/T1 card (3rd GEN)\n\td210  D210P/D210E Dual-port E1/T1 card(2nd generation)\n\td230  D230 Dual-port E1/T1 card (2nd generation)\n\td410  D410/430 Quad-port E1/T1 card\n\td430  D410/430 Quad-port E1/T1 card\n1b79  Absolute Analysis\n1b85  OCZ Technology Group, Inc.\n\t1041  RevoDrive 3 X2 PCI-Express SSD 240 GB (Marvell Controller)\n\t6018  RD400/400A SSD\n\t8788  RevoDrive Hybrid\n1b94  Signatec / Dynamic Signals Corp\n\te400  PX14400 Dual Xilinx Virtex5 based Digitizer\n1b96  Western Digital\n1b9a  XAVi Technologies Corp.\n1baa  QNAP Systems, Inc.\n1bad  ReFLEX CES\n\tc001  XpressGXA10-LP1150\n\tc002  XpressGXA10-LP1151\n1bb0  SimpliVity Corporation\n\t0002  OmniCube Accelerator OA-3000\n\t0010  OmniCube Accelerator OA-3000-2\n1bb1  Seagate Technology PLC\n\t005d  Nytro PCIe Flash Storage\n\t\t1bb1 6501  Nytro XP6500-8A1536 1.5TB\n# 2TB Nytro PCIe controller\n\t\t1bb1 6502  Nytro XP6500-8A2048\n# 4TB Nytro PCIe controller\n\t\t1bb1 6503  Nytro XP6500-8A4096\n# 2GB DRAM variant of Nytro card\n\t\t1bb1 6511  Nytro XH6550-2GB DRAM\n# 8GB variant of Nytro PCIe controller\n\t\t1bb1 6512  Nytro XH6550-8GB DRAM\n# 1.5 TB Nytro PCIe controller\n\t\t1bb1 6521  Nytro XP6500-8A1536 1.5TB\n# 2TB Nytro PCIe controller\n\t\t1bb1 6522  Nytro XP6500-8A2048\n# 4TB Nytro PCIe controller\n\t\t1bb1 6523  Nytro XP6500-8A4096\n\t0100  Nytro Flash Storage\n\t\t1bb1 0101  Nytro XF1440\n\t\t1bb1 0103  Nytro 5000\n\t\t1bb1 0105  Nytro 5020\n\t\t1bb1 0106  Nytro 5020 TCG\n# Larkspur 2.5\"\n\t\t1bb1 0107  Nytro 5320\n# Larkspur 2.5\" TCG\n\t\t1bb1 0108  Nytro 5320 TCG\n\t\t1bb1 0121  Nytro XM1440\n\t\t1bb1 0123  Nytro 5000\n# Kiowa M.2\n\t\t1bb1 0125  Nytro 5020\n# Kiowa M.2 TCG\n\t\t1bb1 0126  Nytro 5020\n# Larkspur M.2 22110mm\n\t\t1bb1 0127  Nytro 5320 M.2\n# Larkspur M.2 22110mm TCG\n\t\t1bb1 0128  Nytro 5320 M.2 TCG\n# Larkspur M.2 2280mm\n\t\t1bb1 0131  Nytro 5320 M.2\n# Larkspur M.2 2280mm TCG\n\t\t1bb1 0132  Nytro 5320 M.2 TCG\n# Larkspur E1.S\n\t\t1bb1 0141  Nytro 5320 E1.S\n# Larkspur E1.S TCG\n\t\t1bb1 0142  Nytro 5320 E1.S TCG\n# Kersey 2.5\"\n\t\t1bb1 0151  Nytro 5520\n# Kersey 2.5\" TCG\n\t\t1bb1 0152  Nytro 5520 TCG\n\t\t1bb1 01a1  Nytro XP7102\n1bb3  Bluecherry\n\t4304  BC-04120A MPEG4 4 port video encoder / decoder\n\t4309  BC-08240A MPEG4 4 port video encoder / decoder\n\t4310  BC-16480A MPEG4 16 port video encoder / decoder\n\t4e04  BC-04120A 4 port MPEG4 video encoder / decoder\n\t4e09  BC-08240A 8 port MPEG4 video encoder / decoder\n\t4e10  BC-16480A 16 port MPEG4 video encoder / decoder\n\t5304  BC-H04120A 4 port H.264 video and audio encoder / decoder\n\t5308  BC-H08240A 8 port H.264 video and audio encoder / decoder\n\t5310  BC-H16480A 16 port H.264 video and audio encoder / decoder\n1bb5  Quantenna Communications, Inc.\n1bbf  Maxeler Technologies Ltd.\n\t0003  MAX3\n\t0004  MAX4\n1bcf  NEC Corporation\n\t001c  Vector Engine 1.0\n1bd0  Astronics Corporation\n\t1001  Mx5 PMC/XMC Databus Interface Card\n\t1002  PM1553-5 (PC/104+ MIL-STD-1553 Interface Card)\n\t1004  AB3000 Series Rugged Computer\n\t1005  PE1000 (Multi-Protocol PCIe/104 Interface Card)\n\t1101  OmniBus II PCIe Multi-Protocol Interface Card\n\t1102  OmniBusBox II Multi-Protocol Interface Core\n\t1103  OmniBus II cPCIe/PXIe Multi-Protocol Interface Card\n1bd4  Inspur Electronic Information Industry Co., Ltd.\n1bee  IXXAT Automation GmbH\n\t0003  CAN-IB200/PCIe\n1bef  Lantiq\n\t0011  MIPS SoC PCI Express Port\n1bf4  VTI Instruments Corporation\n\t0001  SentinelEX\n\t7011  RX0xxx\n1bfd  EeeTOP\n1c09  CSP, Inc.\n\t4254  10G-PCIE3-8D-2S\n\t4255  10G-PCIE3-8D-Q\n\t4256  10G-PCIE3-8D-2S\n\t4258  10G-PCIE3-8E-2S Network Adapter\n\t4260  10G-PCIE3-8E-4S Network Adapter\n\t4261  10G-PCIE3-8E-4S Network Adapter\n\t4262  10G-PCIE3-8E-4S Network Adapter\n\t4263  10G-PCIE3-8E-4S Network Adapter\n\t4264  10G-PCIE3-8E-2S Network Adapter\n\t4265  10G-PCIE3-8E-2S Network Adapter\n\t5000  25G-PCIE3-8A-2S Security Intelligent Adapter\n\t5001  25G-PCIE3-8B-2S Security Intelligent Adapter\n1c1c  Symphony\n\t0001  82C101\n1c1f  SoftLab-NSK\n1c28  Lite-On IT Corp. / Plextor\n\t0122  M6e PCI Express SSD [Marvell 88SS9183]\n# previously Fiberblaze\n1c2c  Silicom Denmark\n\t000a  Capture\n\t000f  SmartNIC\n\t00a0  FBC4G Capture 4x1Gb [Herculaneum]\n\t00a1  FBC4XG Capture 4x10Gb [Ancona]\n\t00a2  FBC8XG Capture 8x10Gb [Livorno]\n\t00a3  FBC2XG Capture 2x10Gb [Genoa]\n\t00a4  FBC4XGG3 Capture 4x10Gb [Livigno]\n\t00a5  FBC2XLG Capture 2x40Gb [Livorno]\n\t00a6  FBC1CG Capture 1x100Gb\n\t00a9  FBC2XGHH Capture 2x10Gb\n\t00ad  FBC2CGG3HL Capture 2x100Gb [Padua]\n\t00af  Capture slave device\n\t00e0  PacketMover 2x100Gb [Savona]\n\t00e1  PacketMover 2x100Gb [Tivoli]\n\t00e3  PacketMover 2x10Gb [Tivoli]\n\t00e5  PacketMover 2x10Gb [Corfu]\n\ta000  FBC2CGG3 Capture 2x40Gb [Mango_02]\n\ta001  FBC2CGG3 Capture 2x100Gb [Mango_02]\n\ta003  FBC2CGG3 Capture 16x10Gb [Mango]\n\ta007  FBC2CGG3 Capture 2x40Gb [Mango]\n\ta008  FBC2CGG3 Capture 2x25Gb [Mango]\n\ta009  FBC2CGG3 Capture 16x10Gb [Mango]\n\ta00a  FBC2CGG3 Capture 8x10Gb [Mango]\n\ta00e  FB2CG Capture 2x100Gb [Savona]\n\ta00f  FB2CG Capture 2x40Gb [Savona]\n\ta011  FB2CG Capture 2x25Gb [Savona]\n\ta012  FB2CG Capture 8x10Gb [Savona]\n# Used on V120 VME Crate Controller\n1c32  Highland Technology, Inc.\n1c33  Daktronics, Inc\n1c36  Annapurna Labs Ltd.\n\t0001  Gigabit Ethernet Adapter\n\t0002  SFP+ 10G Ethernet Adapter\n1c3b  Accensus, LLC\n\t0200  Telas2\n# http://www.accensusllc.com/accensustelas2.html\n\t0300  Telas 2.V\n1c44  Enmotus Inc\n\t8000  8000 Storage IO Controller\n# A Western Digital Subsidiary\n1c58  HGST, Inc.\n\t0003  Ultrastar SN100 Series NVMe SSD\n\t\t1014 04f5  PCIe3 1.6TB NVMe Flash Adapter\n\t\t1014 04f6  PCIe3 3.2TB NVMe Flash Adapter\n\t\t1c58 0003  Ultrastar SN100/SN150 NVMe SSD\n\t0023  Ultrastar SN200 Series NVMe SSD\n\t\t1c58 8823  Ultrastar Memory (ME200)\n1c5c  SK hynix\n\t1283  PC300 NVMe Solid State Drive 256GB\n\t1284  PC300 NVMe Solid State Drive 512GB\n\t1285  PC300 NVMe Solid State Drive 1TB\n\t1504  SC300 512GB M.2 2280 SATA Solid State Drive\n1c5f  Beijing Memblaze Technology Co. Ltd.\n\t0540  PBlaze4 NVMe SSD\n# http://www.nicevt.ru/ (in Russian)\n1c63  Science and Research Centre of Computer Technology (JSC \"NICEVT\")\n# http://www.radiotec.ru/catalog.php?cat=jr8&art=14109\n\t0008  K1927BB1Ya [EC8430] Angara Interconnection Network Adapter\n1c7e  TTTech Computertechnik AG\n\t0200  zFAS Debug Port\n1c7f  Elektrobit Austria GmbH\n\t5100  EB5100\n1c8a  TSF5 Corporation\n\t0001  Hunter PCI Express\n1c8c  Mobiveil, Inc.\n1cb0  Shannon Systems\n\td000  Venice NVMe SSD\n\t\t1cb0 2f10  Venice-E Series U.2 SSD\n\t\t1cb0 2f11  Venice Series U.2 SSD\n\t\t1cb0 2f12  Venice-X Series U.2 SSD\n\t\t1cb0 af10  Venice-E Series AIC SSD\n\t\t1cb0 af11  Venice Series AIC SSD\n\t\t1cb0 af12  Venice-X Series AIC SSD\n1cb1  Collion UG & Co.KG\n1cb5  Focusrite Audio Engineering Ltd\n\t0002  Clarett\n1cb8  Dawning Information Industry Co., Ltd.\n1cc1  ADATA Technology Co., Ltd.\n\t8201  XPG SX8200 Pro PCIe Gen3x4 M.2 2280 Solid State Drive\n1cc4  Union Memory (Shenzhen)\n\t17ab  NVMe 256G SSD device\n1cc5  Embedded Intelligence, Inc.\n\t0100  CAN-PCIe-02\n1cc7  Radian Memory Systems Inc.\n\t0200  RMS-200\n\t0250  RMS-250\n1ccf  Zoom Corporation\n\t0001  TAC-2 Thunderbolt Audio Converter\n1cd2  SesKion GmbH\n\t0301  Simulyzer-RT CompactPCI Serial DIO-1 card\n\t0302  Simulyzer-RT CompactPCI Serial PSI5-ECU-1 card\n\t0303  Simulyzer-RT CompactPCI Serial PSI5-SIM-1 card\n\t0304  Simulyzer-RT CompactPCI Serial PWR-ANA-1 card\n\t0305  Simulyzer-RT CompactPCI Serial CAN-1 card\n# supports 8x CAN (-FD) interfaces\n\t0306  Simulyzer-RT CompactPCI Serial CAN-2 card (CAN-FD)\n1cd7  Nanjing Magewell Electronics Co., Ltd.\n\t0010  Pro Capture Endpoint\n\t0014  PRO CAPTURE AIO 4K PLUS\n\t0017  PRO CAPTURE AIO 4K\n1cdd  secunet Security Networks AG\n1ce4  Exablaze\n\t0001  ExaNIC X4\n\t0002  ExaNIC X2\n\t0003  ExaNIC X10\n\t0004  ExaNIC X10-GM\n\t0005  ExaNIC X40\n\t0006  ExaNIC X10-HPT\n\t0007  ExaNIC X40\n\t0008  ExaNIC V5P\n\t0009  ExaNIC X25\n\t000a  ExaNIC X100\n\t000b  ExaNIC V9P\n\t0100  ExaDISK FX1\n1cf0  Akitio\n1cf7  Subspace Dynamics\n1d00  Pure Storage\n1d05  Tongfang Hongkong Limited\n1d0f  Amazon.com, Inc.\n\tcd01  NVMe SSD Controller\n\tec20  Elastic Network Adapter (ENA)\n\tefa0  Elastic Fabric Adapter (EFA)\n1d17  Zhaoxin\n\t070f  ZX-100 PCI Express Root Port\n\t0710  ZX-100/ZX-200 PCI Express Root Port\n\t0711  ZX-100/ZX-200 PCI Express Root Port\n\t0712  ZX-100/ZX-200 PCI Express Root Port\n\t0713  ZX-100/ZX-200 PCI Express Root Port\n\t0714  ZX-100/ZX-200 PCI Express Root Port\n\t0715  ZX-100/ZX-200 PCI Express Root Port\n\t0716  ZX-D PCI Express Root Port\n\t0717  ZX-D/ZX-E PCI Express Root Port\n\t0718  ZX-D/ZX-E PCI Express Root Port\n\t0719  ZX-D/ZX-E PCI Express Root Port\n\t071a  ZX-D/ZX-E PCI Express Root Port\n\t071b  ZX-D/ZX-E PCI Express Root Port\n\t071c  ZX-D/ZX-E PCI Express Root Port\n\t071d  ZX-D/ZX-E PCI Express Root Port\n\t071e  ZX-D/ZX-E PCI Express Root Port\n\t071f  ZX-200 Upstream Port of PCI Express Switch\n\t0720  ZX-200 PCIE RC6 controller\n\t0721  ZX-200 Downstream Port of PCI Express Switch\n\t0722  ZX-200 PCIE P2C bridge\n\t1000  ZX-D Standard Host Bridge\n\t1001  ZX-D/ZX-E Miscellaneous Bus\n\t1003  ZX-E Standard Host Bridge\n\t3001  ZX-100 Standard Host Bridge\n\t300a  ZX-100 Miscellaneous Bus\n\t3038  ZX-100/ZX-200/ZX-E Standard Universal PCI to USB Host Controller\n\t3104  ZX-100/ZX-200/ZX-E Standard Enhanced PCI to USB Host Controller\n\t31b0  ZX-100/ZX-D Standard Host Bridge\n\t31b1  ZX-100/ZX-D Standard Host Bridge\n\t31b2  ZX-100/ZX-D DRAM Controller\n\t31b3  ZX-100/ZX-D Power Management Controller\n\t31b4  ZX-100/ZX-D I/O APIC\n\t31b5  ZX-100/ZX-D Scratch Device\n\t31b7  ZX-100/ZX-D/ZX-E Standard Host Bridge\n\t31b8  ZX-100/ZX-D PCI to PCI Bridge\n\t3288  ZX-100/ZX-D/ZX-E High Definition Audio Controller\n\t345b  ZX-100/ZX-D/ZX-E Miscellaneous Bus\n\t3a02  ZX-100 C-320 GPU\n\t3a03  ZX-D C-860 GPU\n\t3a04  ZX-E C-960 GPU\n\t9002  ZX-100/ZX-200 EIDE Controller\n\t9003  ZX-100/ZX-E EIDE Controller\n\t9045  ZX-100/ZX-D/ZX-E RAID Accelerator 0\n\t9046  ZX-D/ZX-E RAID Accelerator 1\n\t9083  ZX-100/ZX-200/ZX-E StorX AHCI Controller\n\t9084  ZX-100 StorX AHCI Controller\n\t9100  ZX-200 Cross bus\n\t9101  ZX-200 Traffic Controller\n\t9141  ZX-100 High Definition Audio Controller\n\t9142  ZX-D High Definition Audio Controller\n\t9144  ZX-E High Definition Audio Controller\n\t9180  ZX-200 Networking Gigabit Ethernet Adapter\n\t9202  ZX-100 USB eXtensible Host Controller\n\t9203  ZX-200 USB eXtensible Host Controller\n\t9204  ZX-E USB eXtensible Host Controller\n\t9286  ZX-D eMMC Host Controller\n\t9300  ZX-D/ZX-E eSPI Host Controller\n\t95d0  ZX-100 Universal SD Host Controller\n\tf410  ZX-100/ZX-D/ZX-E PCI Com Port\n1d18  RME\n\t0001  Fireface UFX+\n1d1d  CNEX Labs\n\t1f1f  QEMU NVM Express LightNVM Controller\n\t2807  8800 series NVMe SSD\n# CEM Solutions Pvt. Ltd.\n1d21  Allo\n1d22  Baidu Technology\n\t1380  Cloud Storage Device\n1d26  Kalray Inc.\n\t0040  Turbocard2 Accelerator\n\t0080  Open Network Interface Card 80G\n\t00c0  Turbocard3 Accelerator\n\t0140  Open Network Interface Card 40G\n\te004  AB01/EMB01 Development Board\n1d37  NovaSparks\n\t0013  PM3\n\t0014  PM4\n\t0015  PM4edge\n\t0016  PM4edge User Device\n1d40  Techman Electronics (Changshu) Co., Ltd.\n1d44  DPT\n\ta400  PM2x24/PM3224\n1d49  Lenovo\n1d4c  Diamanti, Inc.\n1d5c  Fantasia Trading LLC\n1d61  Technobox, Inc.\n1d62  Nebbiolo Technologies\n1d65  Imagine Communications Corp.\n\t04de  Taurus/McKinley\n1d6a  Aquantia Corp.\n\t0001  AQC107 NBase-T/IEEE 802.3bz Ethernet Controller [AQtion]\n\t07b1  AQC107 NBase-T/IEEE 802.3bz Ethernet Controller [AQtion]\n\t08b1  AQC108 NBase-T/IEEE 802.3bz Ethernet Controller [AQtion]\n\t11b1  AQC111 NBase-T/IEEE 802.3bz Ethernet Controller [AQtion]\n\t12b1  AQC112 NBase-T/IEEE 802.3bz Ethernet Controller [AQtion]\n\t87b1  AQC107 NBase-T/IEEE 802.3bz Ethernet Controller [AQtion]\n\td107  AQC107 NBase-T/IEEE 802.3bz Ethernet Controller [AQtion]\n\t\t1043 8741  XG-C100C\n\td108  AQC108 NBase-T/IEEE 802.3bz Ethernet Controller [AQtion]\n1d6c  Atomic Rules LLC\n\t1001  A5PL-E1\n\t1002  A5PL-E7\n\t1003  S5PEDS-AB\n\t1004  KC705-K325\n\t1005  ZC706-Z045\n\t1006  KCU105-KU040\n\t1007  XUSP3S-VU095 [Jasper]\n\t1008  XUSPL4-VU065 [Mustang UltraScale]\n\t1009  XUSPL4-VU3P [Mustang UltraScale+]\n\t100a  A10PL4-A10GX115\n\t100b  K35-2SFP\n\t100c  K35-4SFP\n\t100d  AR-ARKA-FX0 [Arkville 32B DPDK Data Mover]\n\t\t1d6c 2001  DPDK-Aware Virtual Function [Arkville VF]\n\t100e  AR-ARKA-FX1 [Arkville 64B DPDK Data Mover]\n\t\t1d6c 2001  DPDK-Aware Virtual Function [Arkville VF]\n\t100f  AR-ARKA-FX1 [Arkville 64B DPDK Data Mover for Versal]\n\t1010  AR-ARKA-FX1 [Arkville 64B DPDK Data Mover for Agilex]\n\t1011  AR-MAN-U50 [Manitou Class Accelerator for U50]\n\t1012  AR-MAN-U200 [Manitou Class Accelerator for U200]\n\t1013  AR-MAN-U250 [Manitou Class Accelerator for U250]\n\t1014  AR-MAN-U280 [Manitou Class Accelerator for U280]\n\t4200  A5PL-E1-10GETI [10 GbE Ethernet Traffic Instrument]\n1d72  Xiaomi\n1d78  DERA\n1d7c  Aerotech, Inc.\n1d82  NETINT Technologies Inc.\n\t0101  Codensity D400 SSD\n\t0102  Codensity D408 PCIe Gen4 NVMe SSD\n\t0202  Codensity T408 Video Encoding-Decoding Accelerator\n1d87  Fuzhou Rockchip Electronics Co., Ltd\n\t0100  RK3399 PCI Express Root Port\n\t1808  RK1808 Neural Network Processor Card\n1d8f  Enyx\n1d93  YADRO (KNS Group)\n1d94  Chengdu Haiguang IC Design Co., Ltd.\n\t1450  Root Complex\n\t1451  I/O Memory Management Unit\n\t1452  PCIe Dummy Host Bridge\n\t1453  PCIE GPP Bridge\n\t1454  Internal PCIe GPP Bridge 0 to Bus B\n\t1455  PCIe Dummy Function\n\t1456  PSPCCP Command DMA Processor\n\t1458  10 Gb Ethernet Controller Port 0/Port1\n\t1459  10 Gb Ethernet Controller Port 2/Port3\n\t145a  PCIe Dummy Function\n\t145b  PCIE Non-Transparent Bridge\n\t145c  USB3 XHCI\n\t145d  Switch upstream in PCIe\n\t145e  Switch downstream in PCIe\n\t145f  USB 3.0 Host controller\n\t1460  Data Fabric: Device 18h; Function 0\n\t1461  Data Fabric: Device 18h; Function 1\n\t1462  Data Fabric: Device 18h; Function 2\n\t1463  Data Fabric: Device 18h; Function 3\n\t1464  Data Fabric: Device 18h; Function 4\n\t1465  Data Fabric: Device 18h; Function 5\n\t1466  Data Fabric: Device 18h; Function 6\n\t1467  Data Fabric: Device 18h; Function 7\n\t1468  NTBCCP\n\t7901  FCH SATA Controller [AHCI mode]\n\t7904  FCH SATA Controller [AHCI mode]\n\t7906  FCH SD Flash Controller\n\t790b  FCH SMBus Controller\n\t790e  FCH LPC Bridge\n1d95  Graphcore Ltd\n\t0001  Colossus GC2 [C2]\n\t0002  Colossus GC1 [S1]\n1d9b  Facebook, Inc.\n\t0010  Networking DOM Engine\n\t0011  IO Bridge\n1da1  Teko Telecom S.r.l.\n1da2  Sapphire Technology Limited\n1da3  Habana Labs Ltd.\n\t0001  HL-1000 AI Inference Accelerator [Goya]\n# PCIe accelerator card for Deep Learning training tasks\n\t1000  HL-2000 AI Training Accelerator [Gaudi]\n1dbb  NGD Systems, Inc.\n1dbf  Guizhou Huaxintong Semiconductor Technology Co., Ltd\n\t0401  StarDragon4800 PCI Express Root Port\n1dd8  Pensando Systems Inc\n\t1000  DSC Capri Upstream Port\n\t\t1dd8 4000  Naples 100Gb 2-port QSFP28 x16 8GB\n\t\t1dd8 4001  Naples 100Gb 2-port QSFP28 x16 4GB\n\t\t1dd8 4002  Naples 25Gb 2-port SFP28 x8 4GB\n\t1001  DSC Virtual Downstream Port\n\t\t1dd8 4000  Naples 100Gb 2-port QSFP28 x16 8GB\n\t\t1dd8 4001  Naples 100Gb 2-port QSFP28 x16 4GB\n\t\t1dd8 4002  Naples 25Gb 2-port SFP28 x8 4GB\n\t1002  DSC Ethernet Controller\n\t\t1dd8 4000  Naples 100Gb 2-port QSFP28 x16 8GB\n\t\t1dd8 4001  Naples 100Gb 2-port QSFP28 x16 4GB\n\t\t1dd8 4002  Naples 25Gb 2-port SFP28 x8 4GB\n\t1003  DSC Ethernet Controller VF\n\t\t1dd8 4000  Naples 100Gb 2-port QSFP28 x16 8GB\n\t\t1dd8 4001  Naples 100Gb 2-port QSFP28 x16 4GB\n\t\t1dd8 4002  Naples 25Gb 2-port SFP28 x8 4GB\n\t1004  DSC Management Controller\n\t\t1dd8 4000  Naples 100Gb 2-port QSFP28 x16 8GB\n\t\t1dd8 4001  Naples 100Gb 2-port QSFP28 x16 4GB\n\t\t1dd8 4002  Naples 25Gb 2-port SFP28 x8 4GB\n\t1007  DSC Storage Accelerator\n\t\t1dd8 4000  Naples 100Gb 2-port QSFP28 x16 8GB\n\t\t1dd8 4001  Naples 100Gb 2-port QSFP28 x16 4GB\n\t\t1dd8 4002  Naples 25Gb 2-port SFP28 x8 4GB\n1de0  Groq\n\t0000  Q100 Tensor Streaming Processor\n1de1  Tekram Technology Co.,Ltd.\n\t0391  TRM-S1040 [DC-315 / DC-395 series]\n\t2020  DC-390\n\t690c  690c\n\tdc29  DC290\n1de5  Eideticom, Inc\n\t1000  IO Memory Controller\n\t2000  NoLoad Hardware Development Kit\n1def  Ampere Computing, LLC\n\te005  eMAG PCI Express Root Port 0\n\te006  eMAG PCI Express Root Port 1\n\te007  eMAG PCI Express Root Port 2\n\te008  eMAG PCI Express Root Port 3\n\te009  eMAG PCI Express Root Port 4\n\te00a  eMAG PCI Express Root Port 5\n\te00b  eMAG PCI Express Root Port 6\n\te00c  eMAG PCI Express Root Port 7\n1df3  Ethernity Networks\n\t0201  ACE-NIC40 Programmable Network Accelerator\n\t\t1df3 0001  ENA1040\n\t\t1df3 0002  ENA1044\n\t\t1df3 0003  ENA1044S\n\t0202  ACE-NIC50 Programmable Network Accelerator\n\t\t1df3 0001  ENA2050F\n\t\t1df3 0002  ENA2050FS\n\t0203  ACE-NIC100 Programmable Network Accelerator\n\t\t1df3 0000  Maintenance Mode\n\t\t1df3 0001  ENA2080F\n\t\t1df3 0002  ENA2080FS\n\t\t1df3 0003  ENA2100F\n\t0204  ACE-NIC-NID Programmable Network Accelerator\n\t\t1df3 0001  ENA1020Z\n\t\t1df3 0002  ENA1020ZS\n1df7  opencpi.org\n\t0001  ml605\n\t0002  alst4\n\t0003  alst4x\n1dfc  JSC NT-COM\n\t1181  TDM 8 Port E1/T1/J1 Adapter\n1e17  Arnold & Richter Cine Technik GmbH & Co. Betriebs KG\n1e24  Squirrels Research Labs\n\t0101  Acorn CLE-101\n\t0215  Acorn CLE-215\n\t021f  Acorn CLE-215+\n\t1525  Xilinx BCU-1525\n# VU33P FPGA Accelerator\n\t1533  ForestKitten 33\n# JungleCat VU33P Module\n\t1633  JCM33\n# JungleCat VU35P Module\n\t1635  JCM35\n1e26  Fujitsu Client Computing Limited\n1e38  Thinci, Inc\n1e3d  Burlywood, Inc\n1e49  Yangtze Memory Technologies Co.,Ltd\n1e4c  GSI Technology\n# Associative Processing Unit chip\n\t0010  Gemini [ Lida ]\n\t\t1e4c 0120  SE120\n1e57  Beijing Panyi Technology Co., Ltd\n1e6b  Axiado Corp.\n1e89  ID Quantique SA\n\t0002  Quantis-PCIe-40M\n\t0003  Quantis-PCIe-240M\n# nee Tumsan Oy\n1fc0  Ascom (Finland) Oy\n\t0300  E2200 Dual E1/Rawpipe Card\n\t0301  C5400 SHDSL/E1 Card\n# nee PathScale, Inc\n1fc1  QLogic, Corp.\n\t000d  IBA6110 InfiniBand HCA\n\t0010  IBA6120 InfiniBand HCA\n1fc9  Tehuti Networks Ltd.\n\t3009  10-Giga TOE SmartNIC\n\t3010  10-Giga TOE SmartNIC\n\t\t0000 3002  10-Giga TOE Single Port XFP SmartNIC\n\t\t0000 3004  10-Giga TOE Single Port SFP+ SmartNIC\n\t\t0000 3008  10-Giga TOE Single Port CX4 SmartNIC\n\t3014  10-Giga TOE SmartNIC 2-Port\n\t\t0000 3003  10-Giga TOE Dual Port XFP Low Profile SmartNIC\n\t\t0000 3005  10-Giga TOE Dual Port SFP+ Low Profile SmartNIC\n\t\t0000 3014  10-Giga TOE Dual Port CX4 Low Profile SmartNIC\n\t3110  10-Giga TOE Single Port SmartNIC\n\t\t0000 3004  10-Giga TOE Single Port SFP+ SmartNIC\n\t3114  10-Giga TOE Dual Port Low Profile SmartNIC\n\t\t0000 3005  10-Giga TOE Dual Port SFP+ Low Profile SmartNIC\n\t\t0000 3011  10-Giga TOE Dual Port SFP+/CX4 Low Profile SmartNIC\n\t\t0000 3012  10-Giga TOE Dual Port CX4/SFP+ Low Profile SmartNIC\n\t\t0000 3014  10-Giga TOE Dual Port CX4 Low Profile SmartNIC\n\t3310  10-Giga TOE SFP+ Single Port SmartNIC\n\t\t0000 3004  10-Giga TOE Single Port SFP+ SmartNIC\n\t3314  10-Giga TOE Dual Port Low Profile SmartNIC\n\t\t0000 3005  10-Giga TOE Dual Port SFP+ Low Profile SmartNIC\n\t\t0000 3011  10-Giga TOE Dual Port SFP+/CX4 Low Profile SmartNIC\n\t\t0000 3012  10-Giga TOE Dual Port CX4/SFP+ Low Profile SmartNIC\n\t\t0000 3014  10-Giga TOE Dual Port CX4 Low Profile SmartNIC\n\t4010  TN4010 Clean SROM\n\t4020  TN9030 10GbE CX4 Ethernet Adapter\n\t\t180c 2040  Mustang-200 10GbE Ethernet Adapter\n\t4022  TN9310 10GbE SFP+ Ethernet Adapter\n\t\t1043 8709  XG-C100F 10GbE SFP+ Ethernet Adapter\n\t\t1186 4d00  DXE-810S 10GbE SFP+ Ethernet Adapter\n\t\t1432 8103  10 Gigabit Ethernet SFP+ PCI Express Adapter\n\t\t1fc9 3015  Ethernet Adapter\n\t4024  TN9210 10GBase-T Ethernet Adapter\n\t4025  TN9510 10GBase-T/NBASE-T Ethernet Adapter\n\t\t105a 7203  SANLink3 NBase-T1\n\t\t1186 2900  DXE-810T 10GBase-T Ethernet Adapter\n\t\t1432 8102  10 Gigabit Ethernet PCI Express Adapter\n\t\t1fc9 3015  Ethernet Adapter\n\t4026  TN9610 10GbE SFP+ Ethernet Adapter\n\t\t4c52 1000  LREC6860AF 10 Gigabit Ethernet Adapter\n\t4027  TN9710P 10GBase-T/NBASE-T Ethernet Adapter\n\t\t1154 0368  LGY-PCIE-MG\n\t\t1432 8104  10 Gigabit Ethernet PCI Express Adapter\n\t\t1546 4027  GE10-PCIE4XG202P 10Gbase-T/NBASE-T Ethernet Adapter\n\t\t1baa 3310  PCIe Expansion Card\n\t\t1fc9 3015  Ethernet Adapter\n\t\t4c52 1001  LREC6860BT 10 Gigabit Ethernet Adapter\n\t4527  TN9710Q 5GBase-T/NBASE-T Ethernet Adapter\n1fcc  StreamLabs\n\tf416  MS416\n\tfb01  MH4LM\n1fce  Cognio Inc.\n\t0001  Spectrum Analyzer PC Card (SAgE)\n1fd4  SUNIX Co., Ltd.\n\t0001  Matrix multiport serial adapter\n\t1999  Multiport serial controller\n2000  Smart Link Ltd.\n\t2800  SmartPCI2800 V.92 PCI Soft DFT\n2001  Temporal Research Ltd\n2003  Smart Link Ltd.\n\t8800  LM-I56N\n2004  Smart Link Ltd.\n2048  Beijing SpaceControl Technology Co.Ltd\n20f4  TRENDnet\n2116  ZyDAS Technology Corp.\n21c3  21st Century Computer Corp.\n22b8  Flex-Logix Technologies\n\t22a0  Flex Logix InferX X1 Inference Accelerator\n22db  Missing Link Electronics, Inc.\n2304  Colorgraphic Communications Corp.\n2348  Racore\n\t2010  8142 100VG/AnyLAN\n2646  Kingston Technology Company, Inc.\n270b  Xantel Corporation\n270f  Chaintech Computer Co. Ltd\n2711  AVID Technology Inc.\n2955  Connectix Virtual PC\n\t6e61  OHCI USB 1.1 controller\n2a15  3D Vision(???)\n2bd8  ROPEX Industrie-Elektronik GmbH\n3000  Hansol Electronics Inc.\n3112  Satelco Ingenieria S.A.\n3130  AUDIOTRAK\n3142  Post Impression Systems.\n31ab  Zonet\n\t1faa  ZEW1602 802.11b/g Wireless Adapter\n3388  Hint Corp\n\t0013  HiNT HC4 PCI to ISDN bridge, Multimedia audio controller\n\t0014  HiNT HC4 PCI to ISDN bridge, Network controller\n\t0020  HB6 Universal PCI-PCI bridge (transparent mode)\n\t0021  HB6 Universal PCI-PCI bridge (non-transparent mode)\n\t\t1775 c200  C2K CompactPCI interface bridge\n\t\t1775 ce90  CE9\n\t\t4c53 1050  CT7 mainboard\n\t\t4c53 1080  CT8 mainboard\n\t\t4c53 1090  Cx9 mainboard\n\t\t4c53 10a0  CA3/CR3 mainboard\n\t\t4c53 3010  PPCI mezzanine (32-bit PMC)\n\t\t4c53 3011  PPCI mezzanine (64-bit PMC)\n\t\t4c53 4000  PMCCARR1 carrier board\n\t0022  HiNT HB4 PCI-PCI Bridge (PCI6150)\n\t0026  HB2 PCI-PCI Bridge\n\t1014  AudioTrak Maya\n\t1018  Audiotrak INCA88\n\t1019  Miditrak 2120\n\t101a  E.Band [AudioTrak Inca88]\n\t101b  E.Band [AudioTrak Inca88]\n\t8011  VXPro II Chipset\n\t\t3388 8011  VXPro II Chipset CPU to PCI Bridge\n\t8012  VXPro II Chipset\n\t\t3388 8012  VXPro II Chipset PCI to ISA Bridge\n\t8013  VXPro II IDE\n\t\t3388 8013  VXPro II Chipset EIDE Controller\n\ta103  Blackmagic Design DeckLink HD Pro\n3411  Quantum Designs (H.K.) Inc\n3442  Bihl+Wiedemann GmbH\n\t1783  AS-i 3.0 cPCI Master\n\t1922  AS-i 3.0 PCI Master\n3475  Arastra Inc.\n3513  ARCOM Control Systems Ltd\n37d9  ITD Firm ltd.\n\t1138  SCHD-PH-8 Phase detector\n# 12-ch Relay Actuator Card\n\t1140  VR-12-PCI\n# multiport serial board\n\t1141  PCI-485(422)\n\t1142  PCI-CAN2\n3842  eVga.com. Corp.\n38ef  4Links\n3d3d  3DLabs\n\t0001  GLINT 300SX\n\t0002  GLINT 500TX\n\t\t0000 0000  GLoria L\n\t0003  GLINT Delta\n\t\t0000 0000  GLoria XL\n\t0004  Permedia\n\t0005  Permedia\n\t0006  GLINT MX\n\t\t0000 0000  GLoria XL\n\t\t1048 0a42  GLoria XXL\n\t0007  3D Extreme\n\t0008  GLINT Gamma G1\n\t\t1048 0a42  GLoria XXL\n\t0009  Permedia II 2D+3D\n\t\t1040 0011  AccelStar II\n\t\t1048 0a42  GLoria XXL\n\t\t13e9 1000  6221L-4U\n\t\t3d3d 0100  AccelStar II 3D Accelerator\n\t\t3d3d 0111  Permedia 3:16\n\t\t3d3d 0114  Santa Ana\n\t\t3d3d 0116  Oxygen GVX1\n\t\t3d3d 0119  Scirocco\n\t\t3d3d 0120  Santa Ana PCL\n\t\t3d3d 0125  Oxygen VX1\n\t\t3d3d 0127  Permedia3 Create!\n\t000a  GLINT R3\n\t\t3d3d 0121  Oxygen VX1\n\t000c  GLINT R3 [Oxygen VX1]\n\t\t3d3d 0144  Oxygen VX1-4X AGP [Permedia 4]\n\t000d  GLint R4 rev A\n\t000e  GLINT Gamma G2\n\t0011  GLint R4 rev B\n\t0012  GLint R5 rev A\n\t0013  GLint R5 rev B\n\t0020  VP10 visual processor\n\t0022  VP10 visual processor\n\t0024  VP9 visual processor\n\t002c  Wildcat Realizm 100/200\n\t0030  Wildcat Realizm 800\n\t0032  Wildcat Realizm 500\n\t0100  Permedia II 2D+3D\n\t07a1  Wildcat III 6210\n\t07a2  Sun XVR-500 Graphics Accelerator\n\t07a3  Wildcat IV 7210\n\t1004  Permedia\n\t3d04  Permedia\n\tffff  Glint VGA\n4005  Avance Logic Inc.\n\t0300  ALS300 PCI Audio Device\n\t0308  ALS300+ PCI Audio Device\n\t0309  PCI Input Controller\n\t1064  ALG-2064\n\t2064  ALG-2064i\n\t2128  ALG-2364A GUI Accelerator\n\t2301  ALG-2301\n\t2302  ALG-2302\n\t2303  AVG-2302 GUI Accelerator\n\t2364  ALG-2364A\n\t2464  ALG-2464\n\t2501  ALG-2564A/25128A\n\t4000  ALS4000 Audio Chipset\n\t\t4005 4000  ALS4000 Audio Chipset\n\t4710  ALC200/200P\n4033  Addtron Technology Co, Inc.\n\t1360  RTL8139 Ethernet\n4040  NetXen Incorporated\n\t0001  NXB-10GXSR 10-Gigabit Ethernet PCIe Adapter with SR-XFP optical interface\n\t\t103c 7047  NC510F PCIe 10-Gigabit Server Adapter\n\t0002  NXB-10GCX4 10-Gigabit Ethernet PCIe Adapter with CX4 copper interface\n\t\t103c 7048  NC510c PCIe 10-Gigabit Server Adapter\n\t0003  NXB-4GCU Quad Gigabit Ethernet PCIe Adapter with 1000-BASE-T interface\n\t0004  BladeCenter-H 10-Gigabit Ethernet High Speed Daughter Card\n\t0005  NetXen Dual Port 10GbE Multifunction Adapter for c-Class\n\t\t103c 170e  NC512m Dual Port 10GbE Multifunction BL-C Adapter\n\t0024  XG Mgmt\n\t0025  XG Mgmt\n\t0100  NX3031 Multifunction 1/10-Gigabit Server Adapter\n\t\t103c 171b  NC522m Dual Port 10GbE Multifunction BL-c Adapter\n\t\t103c 1740  NC375T PCI Express Quad Port Gigabit Server Adapter\n\t\t103c 3251  NC375i 1G w/NC524SFP 10G Module\n\t\t103c 705a  NC375i Integrated Quad Port Multifunction Gigabit Server Adapter\n\t\t103c 705b  NC522SFP Dual Port 10GbE Server Adapter\n\t\t152d 896b  TG20 Dual Port 10GbE Server/Storage Adapter\n\t\t4040 0124  NX3031 Quad Port Gigabit Server Adapter\n\t\t4040 0126  Dual Port SFP+ 10GbE Server Adapter\n4143  Digital Equipment Corp\n4144  Alpha Data\n\t0044  ADM-XRCIIPro\n4150  ONA Electroerosion\n\t0001  PCI32TLITE FILSTRUP1 PCI to VME Bridge Controller\n\t0006  PCI32TLITE UART 16550 Opencores\n\t0007  PCI32TLITE CAN Controller Opencores\n415a  Auzentech, Inc.\n416c  Aladdin Knowledge Systems\n\t0100  AladdinCARD\n\t0200  CPC\n4254  DVBSky\n4321  Tata Power Strategic Electronics Division\n4348  WCH.CN\n\t2273  CH351 PCI Dual Serial Port Controller\n\t3253  CH352 PCI Dual Serial Port Controller\n\t3453  CH353 PCI Quad Serial Port Controller\n\t5053  CH352 PCI Serial and Parallel Port Controller\n\t7053  CH353 PCI Dual Serial and Parallel Ports Controller\n\t7073  CH356 PCI Quad Serial and Parallel Ports Controller\n\t7173  CH355 PCI Quad Serial Port Controller\n434e  CAST Navigation LLC\n4444  Internext Compression Inc\n\t0016  iTVC16 (CX23416) Video Decoder\n\t\t0070 0003  WinTV PVR 250\n\t\t0070 0009  WinTV PVR 150\n\t\t0070 0801  WinTV PVR 150\n\t\t0070 0807  WinTV PVR 150\n\t\t0070 4001  WinTV PVR 250\n\t\t0070 4009  WinTV PVR 250\n\t\t0070 4801  WinTV PVR 250\n\t\t0070 4803  WinTV PVR 250\n\t\t0070 8003  WinTV PVR 150\n\t\t0070 8801  WinTV PVR 150\n\t\t0070 c801  WinTV PVR 150\n\t\t0070 e807  WinTV PVR 500 (1st unit)\n\t\t0070 e817  WinTV PVR 500 (2nd unit)\n\t\t0070 ff92  WiNTV PVR-550\n\t\t0270 0801  WinTV PVR 150\n\t\t104d 013d  ENX-26 TV Encoder\n\t\t10fc d038  GV-MVP/RX2W (1st unit)\n\t\t10fc d039  GV-MVP/RX2W (2nd unit)\n\t\t12ab fff3  MPG600\n\t\t12ab ffff  MPG600\n\t\t1461 c00a  M113 PCI Analog TV (PAL/SECAM, Philips FQ1216MK3 tuner)\n\t\t1461 c00b  M113 PCI Analog TV (PAL/SECAM+FM, Philips FM1216MK3 tuner)\n\t\t1461 c00c  M113 PCI Analog TV (NTSC, JAPAN version, Philips FI1286MK2 tuner)\n\t\t1461 c010  M113 PCI Analog TV (NTSC, Philips FI1236MK3 tuner)\n\t\t1461 c011  M113 PCI Analog TV (NTSC+FM, Philips FM1236MK3 tuner)\n\t\t1461 c018  M113 PCI Analog TV (NTSC, Philips FQ1236MK5 tuner)\n\t\t1461 c019  UltraTV 1500 MCE, a.k.a. M113 PCI Analog TV (NTSC+FM, Philips FQ1236MK5 tuner)\n\t\t1461 c01a  M113 PCI Analog TV (PAL/SECAM, Philips FQ1216MK5 tuner)\n\t\t1461 c01b  M113 PCI Analog TV (PAL/SECAM+FM, Philips FM1216MK5 tuner)\n\t\t1461 c030  M113 PCI Analog TV (NTSC-J, Partsnic tuner)\n\t\t1461 c031  M113 PCI Analog TV (NTSC-J+FM, Partsnic tuner)\n\t\t1461 c032  M113 PCI Analog TV (PAL/SECAM, Partsnic tuner)\n\t\t1461 c033  M113 PCI Analog TV (PAL/SECAM+FM, Partsnic tuner)\n\t\t1461 c034  M113 PCI Analog TV (NTSC, Partsnic tuner)\n\t\t1461 c035  M113 PCI Analog TV (NTSC+FM, Partsnic tuner)\n\t\t1461 c03f  C115 PCI video capture card (no tuner)\n\t\t1461 c136  M104 mini-PCI Analog TV\n\t\t1461 c20a  M755 AVerTV Video Capture (PAL/SECAM, Philips FQ1216MK3 tuner)\n\t\t1461 c218  M755 AVerTV Video Capture (NTSC, Philips FQ1236MK5 tuner)\n\t\t1461 c219  M755 AVerTV Video Capture (NTSC+FM, Philips FQ1236MK5 tuner)\n\t\t1461 c21a  M755 AVerTV Video Capture (PAL/SECAM, Philips FQ1216MK5 tuner)\n\t\t1461 c21b  M755 AVerTV Video Capture (PAL/SECAM+FM, Philips FM1216MK5 tuner)\n\t\t1461 c230  M755 AVerTV Video Capture (NTSC-J, Partsnic tuner)\n\t\t1461 c231  M755 AVerTV Video Capture (NTSC-J+FM, Partsnic tuner)\n\t\t1461 c232  M755 AVerTV Video Capture (PAL/SECAM, Partsnic tuner)\n\t\t1461 c233  M755 AVerTV Video Capture (PAL/SECAM+FM, Partsnic tuner)\n\t\t1461 c234  M755 AVerTV Video Capture (NTSC, Partsnic tuner)\n\t\t1461 c235  M755 AVerTV Video Capture (NTSC+FM, Partsnic tuner)\n\t\t1461 c337  E106 AVerMedia AVerTV Video Capture\n\t\t1461 c439  M116 AVerMedia AVerTV MCE 116 Plus (NTSC/PAL/SECAM+FM+REMOTE, Xceive 2028 tuner)\n\t\t1461 c5ff  C755 AVerTV Video Capture card (no tuner)\n\t\t1461 c6ff  C115 PCI video capture card (no tuner)\n\t\t1461 c739  M785 AVerMedia PCI Analog TV (NTSC/PAL/SECAM+FM, Xceive 2028 tuner)\n\t\t9005 0092  VideOh! AVC-2010\n\t\t9005 0093  VideOh! AVC-2410\n\t0803  iTVC15 (CX23415) Video Decoder\n\t\t0070 4000  WinTV PVR-350\n\t\t0070 4001  WinTV PVR-250\n\t\t0070 4800  WinTV PVR-350 (V1)\n\t\t12ab 0000  MPG160\n\t\t1461 a3ce  M179\n\t\t1461 a3cf  M179\n4468  Bridgeport machines\n4594  Cogetec Informatique Inc\n45fb  Baldor Electric Company\n4624  Budker Institute of Nuclear Physics\n\tadc1  ADC200ME High speed ADC\n\tde01  DL200ME High resolution delay line PCI based card\n\tde02  DL200ME Middle resolution delay line PCI based card\n# Can't find any information on this company\n4651  TXIC\n4680  Umax Computer Corp\n4843  Hercules Computer Technology Inc\n4916  RedCreek Communications Inc\n\t1960  RedCreek PCI adapter\n4943  Growth Networks\n494f  ACCES I/O Products, Inc.\n\t0508  PCI-IDO-16A FET Output Card\n\t0518  PCI-IDO-32A FET Output Card\n\t0520  PCI-IDO-48 FET Output Card\n\t0521  PCI-IDO-48A FET Output Card\n\t0703  PCIe-RO-4 Electromechanical Relay Output Card\n\t07d0  PCIe-IDO-24 FET Output Card\n\t0920  PCI-IDI-48 Isolated Digital Input Card\n\t0bd0  PCIe-IDI-24 Isolated Digital Input Card\n\t0c50  PCI-DIO-24H 1x 8255 Digital Input / Output Card\n\t0c51  PCI-DIO-24D 1x 8255 Digital Input / Output Card\n\t0c52  PCIe-DIO-24 1x 8255 Digital Input / Output Card\n\t0c53  PCIe-DIO-24H 8255 Digital Input / Output Card\n\t0c57  mPCIe-DIO-24 8255 Digital Input / Output Card\n\t0c60  PCI-DIO-48H 8255 Digital Input / Output Card\n\t0c61  PCIe-DIO-48 8255 Digital Input / Output Card\n\t0c62  P104-DIO-48 8255 Digital Input / Output Card\n\t0c68  PCI-DIO-72 8255 Digital Input / Output Card\n\t0c69  P104-DIO-96 8255 Digital Input / Output Card\n\t0c70  PCI-DIO-96 8255 Digital Input / Output Card\n\t0c78  PCI-DIO-120 8255 Digital Input / Output Card\n\t0dc8  PCI-IDIO-16 Isolated Digital Input / FET Output Card\n\t0e50  PCI-DIO-24S 8255 Digital Input / Output Card\n\t0e51  PCI-DIO-24H(C) 8255 Digital Input / Output Card\n\t0e52  PCI-DIO-24D(C) 8255 Digital Input / Output Card\n\t0e53  PCIe-DIO-24S 8255 Digital Input / Output Card\n\t0e54  PCIe-DIO-24HS 8255 Digital Input / Output Card\n\t0e55  PCIe-DIO-24DC 8255 Digital Input / Output Card\n\t0e56  PCIe-DIO-24DCS 8255 Digital Input / Output Card\n\t0e57  mPCIe-DIO-24S 8255 Digital Input / Output Card\n\t0e60  PCI-DIO-48S 2x 8255 Digital Input / Output Card\n\t0e61  PCIe-DIO-48S 2x 8255 Digital Input / Output Card\n\t0e62  P104-DIO-48S 2x 8255 Digital Input / Output Card\n\t0f00  PCI-IIRO-8 Isolated Digital / Relay Output Card\n\t0f01  LPCI-IIRO-8 Isolated Digital / Relay Output Card\n\t0f02  PCIe-IIRO-8 Isolated Digital / Relay Output Card\n\t0f08  PCI-IIRO-16 Isolated Digital / Relay Output Card\n\t0f09  PCIe-IIRO-16 Isolated Digital / Relay Output Card\n\t0fc0  PCIe-IDIO-12 Isolated Digital Input / FET Output Card\n\t0fc1  PCIe-IDI-12 Isolated Digital Input Card\n\t0fc2  PCIe-IDO-12 FET Output Card\n\t0fd0  PCIe-IDIO-24 Isolated Digital Input / FET Output Card\n\t1050  PCI-422/485-2 2x RS422/RS484 Card\n\t1051  PCIe-COM-2SRJ 2x RS422/RS484 Card w/RJ45 Connectors\n\t1052  104I-COM-2S 2x RS422/RS484 PCI/104 Board\n\t1053  mPCIe-COM-2S 2x RS422/RS484 PCI Express Mini Card\n\t1058  PCI-COM422/4 4x RS422 Card\n\t1059  PCI-COM485/4 4x RS485 Card\n\t105a  PCIe-COM422-4 4x RS422 Card\n\t105b  PCIe-COM485-4 4x RS485 Card\n\t105c  PCIe-COM-4SRJ 4x RS422/RS485 Card w/RJ45 Connectors\n\t105d  104I-COM-4S 4x RS422/RS484 PCI/104 Board\n\t105e  mPCIe-COM-4S 4x RS422/RS484 PCI Express Mini Card\n\t1068  PCI-COM422/8 8x RS422 Card\n\t1069  PCI-COM485/8 8x RS485 Card\n\t106a  PCIe-COM422-8 8x RS422 Card\n\t106b  PCIe-COM485-8 8x RS485 Card\n\t106c  104I-COM-8S 8x RS422/RS485 PCI/104 Board\n\t1088  PCI-COM232/1 1x RS232 Card\n\t1090  PCI-COM232/2 2x RS232 Card\n\t1091  PCIe-COM232-2RJ 2x RS232 Card w/RJ45 Connectors\n\t1093  mPCIe-COM232-2 2x RS232 PCI Express Mini Card\n\t1098  PCIe-COM232-4 4x RS232 Card\n\t1099  PCIe-COM232-4RJ 4x RS232 Card w/RJ45 Connectors\n\t109b  mPCIe-COM232-4 4x RS232 PCI Express Mini Card\n\t10a8  P104-COM232-8 8x RS232 PC-104+ Board\n\t10a9  PCIe-COM232-8 8x RS232 Card\n\t10c9  PCI-COM-1S 1x RS422/RS485 Card\n\t10d0  PCI-COM2S 2x RS422/RS485 Card\n\t10d1  PCIe-COM-2SMRJ 2x RS232/RS422/RS485 Card w/RJ45 Connectors\n\t10d2  104I-COM-2SM 2x RS232/RS422/RS485 PCI/104 Board\n\t10d3  mPCIe-COM-2SM 2x RS232/RS422/RS485 PCI Express Mini Card\n\t10d8  PCI-COM-4SM 4x RS232/RS422/RS485 Card\n\t10d9  PCIe-COM-4SM 4x RS232/RS422/RS485 Card\n\t10da  PCIe-COM-4SMRJ 4x RS232/RS422/RS485 Card w/RJ45 Connectors\n\t10db  104I-COM-4SM 4x RS232/RS422/RS485 PCI/104 Board\n\t10dc  mPCIe-COM-4SM 4x RS232/RS422/RS485 PCI Express Mini Card\n\t10e8  PCI-COM-8SM 8x RS232/RS422/RS485 Card\n\t10e9  PCIe-COM-8SM 8x RS232/RS422/RS485 Card\n\t10ea  104I-COM-8SM 8x RS232/RS422/RS485 PCI-104 Board\n\t1108  mPCIe-ICM485-1 1x Isolated RS485 PCI Express Mini Card\n\t1110  mPCIe-ICM422-2 2x Isolated RS422 PCI Express Mini Card\n\t1111  mPCIe-ICM485-2 2x Isolated RS485 PCI Express Mini Card\n\t1118  mPCIe-ICM422-4 4x Isolated RS422 PCI Express Mini Card\n\t1119  mPCIe-ICM485-4 4x Isolated RS485 PCI Express Mini Card\n\t1148  PCI-ICM-1S 1x Isolated RS422/RS485 Card\n\t1150  PCI-ICM-2S 2x Isolated RS422/RS485 Card\n\t1152  PCIe-ICM-2S 2x Isolated RS422/RS485 Card\n\t1158  PCI-ICM422/4 4x Isolated RS422 Card\n\t1159  PCI-ICM485/4 4x Isolated RS485 Card\n\t115a  PCIe-ICM-4S 4x Isolated RS422/RS485 Card\n\t1190  PCIe-ICM232-2 2x Isolated RS232 Card\n\t1191  mPCIe-ICM232-2 2x Isolated RS232 PCI Express Mini Card\n\t1198  PCIe-ICM232-4 4x Isolated RS232 Card\n\t1199  mPCIe-ICM232-4 4x Isolated RS422 PCI Express Mini Card\n\t11d0  PCIe-ICM-2SM 2x Isolated RS232/RS422/RS485 Card\n\t11d8  PCIe-ICM-4SM 4x Isolated RS232/RS422/RS485 Card\n\t1250  PCI-WDG-2S Watchdog and 2x Serial Card\n\t12d0  PCI-WDG-IMPAC\n\t2230  PCI-QUAD-8 8x Quadrature Input Card\n\t2231  PCI-QUAD-4 4x Quadrature Input Card\n\t22c0  PCI-WDG-CSM Watchdog Card\n\t25c0  P104-WDG-E Watchdog PC/104+ Board\n\t2c50  PCI-DIO-96CT 96x Digital Input / Output Card\n\t2c58  PCI-DIO-96C3 96x Digital Input / Output Card w/3x 8254 Counter Card\n\t2ee0  PCIe-DIO24S-CTR12 24x Digital Input / Output Card w/4x 8254 Counter Card\n\t2fc0  P104-WDG-CSM Watchdog PC/104+ Board\n\t2fc1  P104-WDG-CSMA Advanced Watchdog PC/104+ Board\n\t5ed0  PCI-DAC\n\t6c90  PCI-DA12-2 2x 12-bit Analog Output Card\n\t6c98  PCI-DA12-4 4x 12-bit Analog Output Card\n\t6ca0  PCI-DA12-6 6x 12-bit Analog Output Card\n\t6ca8  PCI-DA12-8 8x 12-bit Analog Output Card\n\t6ca9  PCI-DA12-8V\n\t6cb0  PCI-DA12-16 16x 12-bit Analog Output Card\n\t6cb1  PCI-DA12-16V\n\t8ef0  P104-FAS16-16\n\taca8  PCI-AI12-16 12-bit 100kHz Analog Input Card\n\taca9  PCI-AI12-16A 12-bit 100kHz Analog Input w/FIFO Card\n\teca8  PCI-AIO12-16 12-bit 100kHz Analog Input w/2x Analog Output and FIFO Card\n\tecaa  PCI-A12-16A 12-bit 100kHz Analog Input w/2x Analog Output and FIFO Card\n\tece8  LPCI-A16-16A 16-bit 500kHz Analog Input low-profile Card\n\tece9  LPCI-AIO16A 16-bit 500kHz Analog Input low-profile Card\n4978  Axil Computer Inc\n4a14  NetVin\n\t5000  NV5000SC\n\t\t4a14 5000  RT8029-Based Ethernet Adapter\n4b10  Buslogic Inc.\n4c48  LUNG HWA Electronics\n4c52  LR-Link\n4c53  SBS Technologies\n\t0000  PLUSTEST device\n\t\t4c53 3000  PLUSTEST card (PC104+)\n\t\t4c53 3001  PLUSTEST card (PMC)\n\t0001  PLUSTEST-MM device\n\t\t4c53 3002  PLUSTEST-MM card (PMC)\n4ca1  Seanix Technology Inc\n4d51  MediaQ Inc.\n\t0200  MQ-200\n4d54  Microtechnica Co Ltd\n4d56  MATRIX VISION GmbH\n\t0000  [mvHYPERION-CLe/CLb] CameraLink PCI Express x1 Frame Grabber\n\t0001  [mvHYPERION-CLf/CLm] CameraLink PCI Express x4 Frame Grabber\n\t0010  [mvHYPERION-16R16/-32R16] 16 Video Channel PCI Express x4 Frame Grabber\n\t0020  [mvHYPERION-HD-SDI] HD-SDI PCI Express x4 Frame Grabber\n\t0030  [mvHYPERION-HD-SDI-Merger] HD-SDI PCI Express x4 Frame Grabber\n4ddc  ILC Data Device Corp\n\t0100  DD-42924I5-300 (ARINC 429 Data Bus)\n\t0300  SB-3620 Motion Feedback Device\n\t0340  SB-3623 Motion Feedback Device\n\t0400  SB-3622 Motion Feedback Device\n\t0500  SB-3621 Motion Feedback Device\n\t0510  SB-3624 Motion Feedback Device\n\t0801  BU-65570I1 MIL-STD-1553 Test and Simulation\n\t0802  BU-65570I2 MIL-STD-1553 Test and Simulation\n\t0811  BU-65572I1 MIL-STD-1553 Test and Simulation\n\t0812  BU-65572I2 MIL-STD-1553 Test and Simulation\n\t0881  BU-65570T1 MIL-STD-1553 Test and Simulation\n\t0882  BU-65570T2 MIL-STD-1553 Test and Simulation\n\t0891  BU-65572T1 MIL-STD-1553 Test and Simulation\n\t0892  BU-65572T2 MIL-STD-1553 Test and Simulation\n\t0901  BU-65565C1 MIL-STD-1553 Data Bus\n\t0902  BU-65565C2 MIL-STD-1553 Data Bus\n\t0903  BU-65565C3 MIL-STD-1553 Data Bus\n\t0904  BU-65565C4 MIL-STD-1553 Data Bus\n\t0b01  BU-65569I1 MIL-STD-1553 Data Bus\n\t0b02  BU-65569I2 MIL-STD-1553 Data Bus\n\t0b03  BU-65569I3 MIL-STD-1553 Data Bus\n\t0b04  BU-65569I4 MIL-STD-1553 Data Bus\n\t0d01  SB-3641 Motion Feedback Device\n\t0d10  SB-365x Motion Feedback Device\n\t2f00  SB-3642 Motion Feedback Device\n\t3000  SB-3644 Motion Feedback Device\n5045  University of Toronto\n\t4243  BLASTbus PCI Interface Card v1\n5046  GemTek Technology Corporation\n\t1001  PCI Radio\n5053  Voyetra Technologies\n\t2010  Daytona Audio Adapter\n50b2  TerraTec Electronic GmbH\n5136  S S Technologies\n5143  Qualcomm Inc\n5145  Ensoniq (Old)\n\t3031  Concert AudioPCI\n5168  Animation Technologies Inc.\n\t0300  FlyDVB-S\n\t0301  FlyDVB-T\n5301  Alliance Semiconductor Corp.\n\t0001  ProMotion aT3D\n5333  S3 Graphics Ltd.\n\t0551  Plato/PX (system)\n\t5631  86c325 [ViRGE]\n\t8800  86c866 [Vision 866]\n\t8801  86c964 [Vision 964]\n\t8810  86c764_0 [Trio 32 vers 0]\n\t8811  86c764/765 [Trio32/64/64V+]\n\t8812  86cM65 [Aurora64V+]\n\t8813  86c764_3 [Trio 32/64 vers 3]\n\t8814  86c767 [Trio 64UV+]\n\t8815  86cM65 [Aurora 128]\n\t883d  86c988 [ViRGE/VX]\n\t8870  FireGL\n\t8880  86c868 [Vision 868 VRAM] vers 0\n\t8881  86c868 [Vision 868 VRAM] vers 1\n\t8882  86c868 [Vision 868 VRAM] vers 2\n\t8883  86c868 [Vision 868 VRAM] vers 3\n\t88b0  86c928 [Vision 928 VRAM] vers 0\n\t88b1  86c928 [Vision 928 VRAM] vers 1\n\t88b2  86c928 [Vision 928 VRAM] vers 2\n\t88b3  86c928 [Vision 928 VRAM] vers 3\n\t88c0  86c864 [Vision 864 DRAM] vers 0\n\t88c1  86c864 [Vision 864 DRAM] vers 1\n\t88c2  86c864 [Vision 864-P DRAM] vers 2\n\t88c3  86c864 [Vision 864-P DRAM] vers 3\n\t88d0  86c964 [Vision 964 VRAM] vers 0\n\t88d1  86c964 [Vision 964 VRAM] vers 1\n\t88d2  86c964 [Vision 964-P VRAM] vers 2\n\t88d3  86c964 [Vision 964-P VRAM] vers 3\n\t88f0  86c968 [Vision 968 VRAM] rev 0\n\t88f1  86c968 [Vision 968 VRAM] rev 1\n\t88f2  86c968 [Vision 968 VRAM] rev 2\n\t88f3  86c968 [Vision 968 VRAM] rev 3\n\t8900  86c755 [Trio 64V2/DX]\n\t\t5333 8900  86C775 Trio64V2/DX\n\t8901  86c775/86c785 [Trio 64V2/DX or /GX]\n\t\t5333 8901  86C775 Trio64V2/DX, 86C785 Trio64V2/GX\n\t8902  Plato/PX\n\t8903  Trio 3D business multimedia\n\t8904  86c365, 86c366 [Trio 3D]\n\t\t1014 00db  Integrated Trio3D\n\t\t4843 314a  Terminator 128/3D GLH\n\t\t5333 8904  86C365 Trio3D AGP\n\t8905  Trio 64V+ family\n\t8906  Trio 64V+ family\n\t8907  Trio 64V+ family\n\t8908  Trio 64V+ family\n\t8909  Trio 64V+ family\n\t890a  Trio 64V+ family\n\t890b  Trio 64V+ family\n\t890c  Trio 64V+ family\n\t890d  Trio 64V+ family\n\t890e  Trio 64V+ family\n\t890f  Trio 64V+ family\n\t8a01  86c375 [ViRGE/DX] or 86c385 [ViRGE/GX]\n\t\t0e11 b032  ViRGE/GX\n\t\t10b4 1617  Nitro 3D\n\t\t10b4 1717  Nitro 3D\n\t\t5333 8a01  ViRGE/DX\n\t8a10  ViRGE/GX2\n\t\t1092 8a10  Stealth 3D 4000\n\t8a13  86c360 [Trio 3D/1X], 86c362, 86c368 [Trio 3D/2X]\n\t\t5333 8a13  Trio3D/2X\n\t8a20  86c794 [Savage 3D]\n\t\t5333 8a20  86C391 Savage3D\n\t8a21  86c390 [Savage 3D/MV]\n\t\t5333 8a21  86C390 Savage3D/MV\n\t8a22  Savage 4\n\t\t1033 8068  Savage 4\n\t\t1033 8069  Savage 4\n\t\t1033 8110  Savage 4 LT\n\t\t105d 0018  SR9 8Mb SDRAM\n\t\t105d 002a  SR9 Pro 16Mb SDRAM\n\t\t105d 003a  SR9 Pro 32Mb SDRAM\n\t\t105d 092f  SR9 Pro+ 16Mb SGRAM\n\t\t1092 4207  Stealth III S540\n\t\t1092 4800  Stealth III S540\n\t\t1092 4807  SpeedStar A90\n\t\t1092 4808  Stealth III S540\n\t\t1092 4809  Stealth III S540\n\t\t1092 480e  Stealth III S540\n\t\t1092 4904  Stealth III S520\n\t\t1092 4905  SpeedStar A200\n\t\t1092 4a09  Stealth III S540\n\t\t1092 4a0b  Stealth III S540 Xtreme\n\t\t1092 4a0f  Stealth III S540\n\t\t1092 4e01  Stealth III S540\n\t\t1102 101d  3d Blaster Savage 4\n\t\t1102 101e  3d Blaster Savage 4\n\t\t5333 8100  86C394-397 Savage4 SDRAM 100\n\t\t5333 8110  86C394-397 Savage4 SDRAM 110\n\t\t5333 8125  86C394-397 Savage4 SDRAM 125\n\t\t5333 8143  86C394-397 Savage4 SDRAM 143\n\t\t5333 8a22  86C394-397 Savage4\n\t\t5333 8a2e  86C394-397 Savage4 32bit\n\t\t5333 9125  86C394-397 Savage4 SGRAM 125\n\t\t5333 9143  86C394-397 Savage4 SGRAM 143\n\t8a23  Savage 4\n\t8a25  ProSavage PM133\n\t\t0303 0303  D9840-60001 [Brio BA410 Motherboard]\n\t8a26  ProSavage KM133\n\t8c00  ViRGE/M3\n\t8c01  ViRGE/MX\n\t\t1179 0001  ViRGE/MX\n\t8c02  ViRGE/MX+\n\t8c03  ViRGE/MX+MV\n\t8c10  86C270-294 [SavageMX-MV]\n\t8c11  82C270-294 [SavageMX]\n\t8c12  86C270-294 [SavageIX-MV]\n\t\t1014 017f  ThinkPad T20/T22\n\t\t1179 0001  86C584 SuperSavage/IXC Toshiba\n\t8c13  86C270-294 [SavageIX]\n\t\t1179 0001  Magnia Z310\n\t8c22  SuperSavage MX/128\n\t8c24  SuperSavage MX/64\n\t8c26  SuperSavage MX/64C\n\t8c2a  SuperSavage IX/128 SDR\n\t8c2b  SuperSavage IX/128 DDR\n\t8c2c  SuperSavage IX/64 SDR\n\t8c2d  SuperSavage IX/64 DDR\n\t8c2e  SuperSavage IX/C SDR\n\t\t1014 01fc  ThinkPad T23\n\t8c2f  SuperSavage IX/C DDR\n\t8d01  86C380 [ProSavageDDR K4M266]\n\t8d02  VT8636A [ProSavage KN133] AGP4X VGA Controller (TwisterK)\n\t8d03  VT8751 [ProSavageDDR P4M266]\n\t8d04  VT8375 [ProSavage8 KM266/KL266]\n\t8e00  DeltaChrome\n\t8e26  ProSavage\n\t8e40  2300E Graphics Processor\n\t8e48  Matrix [Chrome S25 / S27]\n\t\t5333 0130  Chrome S27 256M DDR2\n\t9043  Chrome 430 GT\n\t9045  Chrome 430 ULP / 435 ULP / 440 GTX\n\t9060  Chrome 530 GT\n\t9102  86C410 [Savage 2000]\n\t\t1092 5932  Viper II Z200\n\t\t1092 5934  Viper II Z200\n\t\t1092 5952  Viper II Z200\n\t\t1092 5954  Viper II Z200\n\t\t1092 5a35  Viper II Z200\n\t\t1092 5a37  Viper II Z200\n\t\t1092 5a55  Viper II Z200\n\t\t1092 5a57  Viper II Z200\n\tca00  SonicVibes\n5431  AuzenTech, Inc.\n544c  Teralogic Inc\n\t0350  TL880-based HDTV/ATSC tuner\n544d  TBS Technologies\n\t6178  DVB Tuner PCIe Card\n\t\t544d 6904  TBS6904 DVB-S2 Quad Tuner PCIe Card\n\t\t544d 6905  TBS6905 DVB-S2 Quad Tuner PCIe Card\n\t\t6205 0001  TBS6205 DVB-T2/T/C Quad TV Tuner PCIe Card\n\t\t6209 0001  TBS6209 DVB-T2/C2/T/C/ISDB-T OctaTV Tuner\n5452  SCANLAB AG\n\t3443  RTC4\n5455  Technische Universitaet Berlin\n\t4458  S5933\n5456  GoTView\n5519  Cnet Technologies, Inc.\n5544  Dunord Technologies\n\t0001  I-30xx Scanner Interface\n5555  Genroco, Inc\n\t0003  TURBOstor HFP-832 [HiPPI NIC]\n\t3b00  Epiphan DVI2PCIe video capture card\n5646  Vector Fabrics BV\n5654  VoiceTronix Pty Ltd\n5678  Dawicontrol Computersysteme GmbH\n5700  Netpower\n# alternately Extreme Engineering Solutions, Inc.\n5845  X-ES, Inc.\n584d  AuzenTech Co., Ltd.\n5851  Exacq Technologies\n\t8008  tDVR8008 8-port video capture card\n\t8016  tDVR8016 16-chan video capture card\n\t8032  tDVR8032 32-chan video capture card\n5853  XenSource, Inc.\n\t0001  Xen Platform Device\n\tc000  Citrix XenServer PCI Device for Windows Update\n# Virtual device surfaced in guests to provide HID events.\n\tc110  Virtualized HID\n# Device surfaced in guests to provide 2d graphics capabilities\n\tc147  Virtualized Graphics Device\n\tc200  XCP-ng Project PCI Device for Windows Update\n5854  GoTView\n5ace  Beholder International Ltd.\n6205  TBS Technologies (wrong ID)\n6209  TBS Technologies (wrong ID)\n631c  SmartInfra Ltd\n\t1652  PXI-1652 Signal Generator\n\t2504  PXI-2504 Signal Interrogator\n6356  UltraStor\n6374  c't Magazin fuer Computertechnik\n\t6773  GPPCI\n6409  Logitec Corp.\n6549  Teradici Corp.\n\t1200  TERA1200 PC-over-IP Host\n6666  Decision Computer International Co.\n\t0001  PCCOM4\n\t0002  PCCOM8\n\t0004  PCCOM2\n\t0101  PCI 8255/8254 I/O Card\n\t0200  12-bit AD/DA Card\n\t0201  14-bit AD/DA Card\n\t1011  Industrial Card\n\t1021  8 photo couple 8 relay Card\n\t1022  4 photo couple 4 relay Card\n\t1025  16 photo couple 16 relay Card\n\t4000  WatchDog Card\n6688  Zycoo Co., Ltd\n\t1200  CooVox TDM Analog Module\n\t1400  CooVOX TDM GSM Module\n\t1600  CooVOX TDM E1/T1 Module\n\t1800  CooVOX TDM BRI Module\n# nee Qumranet\n6900  Red Hat, Inc.\n7063  pcHDTV\n\t2000  HD-2000\n\t3000  HD-3000\n\t5500  HD5500 HDTV\n7284  HT OMEGA Inc.\n7357  IOxOS Technologies SA\n\t7910  7910 [Althea]\n7401  EndRun Technologies\n\te100  PTP3100 PCIe PTP Slave Clock\n7470  TP-LINK Technologies Co., Ltd.\n7604  O.N. Electronic Co Ltd.\n7bde  MIDAC Corporation\n7fed  PowerTV\n8008  Quancom Electronic GmbH\n\t0010  WDOG1 [PCI-Watchdog 1]\n\t0011  PWDOG2 [PCI-Watchdog 2]\n\t0015  Clock77/PCI & Clock77/PCIe (DCF-77 receiver)\n# Wrong ID used in subsystem ID of AsusTek PCI-USB2 PCI card.\n807d  Asustek Computer, Inc.\n8086  Intel Corporation\n\t0007  82379AB\n\t0008  Extended Express System Support Controller\n\t0039  21145 Fast Ethernet\n\t0040  Core Processor DRAM Controller\n\t0041  Core Processor PCI Express x16 Root Port\n\t0042  Core Processor Integrated Graphics Controller\n\t0043  Core Processor Secondary PCI Express Root Port\n\t0044  Core Processor DRAM Controller\n\t\t1025 0347  Aspire 7740G\n\t\t1025 0487  TravelMate 5742\n\t\t1028 040a  Latitude E6410\n\t\t144d c06a  R730 Laptop\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t\te4bf 50c1  PC1-GROOVE\n\t0045  Core Processor PCI Express x16 Root Port\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t0046  Core Processor Integrated Graphics Controller\n\t\t1028 040a  Latitude E6410\n\t\t144d c06a  R730 Laptop\n\t\t17c0 10d9  Medion Akoya E7214 Notebook PC [MD98410]\n\t\te4bf 50c1  PC1-GROOVE\n\t0047  Core Processor Secondary PCI Express Root Port\n\t0048  Core Processor DRAM Controller\n\t0049  Core Processor PCI Express x16 Root Port\n\t004a  Core Processor Integrated Graphics Controller\n\t004b  Core Processor Secondary PCI Express Root Port\n\t0050  Core Processor Thermal Management Controller\n\t0069  Core Processor DRAM Controller\n\t0082  Centrino Advanced-N 6205 [Taylor Peak]\n\t\t8086 1301  Centrino Advanced-N 6205 AGN\n\t\t8086 1306  Centrino Advanced-N 6205 ABG\n\t\t8086 1307  Centrino Advanced-N 6205 BG\n\t\t8086 1321  Centrino Advanced-N 6205 AGN\n\t\t8086 1326  Centrino Advanced-N 6205 ABG\n\t0083  Centrino Wireless-N 1000 [Condor Peak]\n\t\t8086 1205  Centrino Wireless-N 1000 BGN\n\t\t8086 1206  Centrino Wireless-N 1000 BG\n\t\t8086 1225  Centrino Wireless-N 1000 BGN\n\t\t8086 1226  Centrino Wireless-N 1000 BG\n\t\t8086 1305  Centrino Wireless-N 1000 BGN\n\t\t8086 1306  Centrino Wireless-N 1000 BG\n\t\t8086 1325  Centrino Wireless-N 1000 BGN\n\t\t8086 1326  Centrino Wireless-N 1000 BG\n\t0084  Centrino Wireless-N 1000 [Condor Peak]\n\t\t8086 1215  Centrino Wireless-N 1000 BGN\n\t\t8086 1216  Centrino Wireless-N 1000 BG\n\t\t8086 1315  Centrino Wireless-N 1000 BGN\n\t\t8086 1316  Centrino Wireless-N 1000 BG\n\t0085  Centrino Advanced-N 6205 [Taylor Peak]\n\t\t8086 1311  Centrino Advanced-N 6205 (802.11a/b/g/n)\n\t\t8086 1316  Centrino Advanced-N 6205 ABG\n\t0087  Centrino Advanced-N + WiMAX 6250 [Kilmer Peak]\n\t\t8086 1301  Centrino Advanced-N + WiMAX 6250 2x2 AGN\n\t\t8086 1306  Centrino Advanced-N + WiMAX 6250 2x2 ABG\n\t\t8086 1321  Centrino Advanced-N + WiMAX 6250 2x2 AGN\n\t\t8086 1326  Centrino Advanced-N + WiMAX 6250 2x2 ABG\n\t0089  Centrino Advanced-N + WiMAX 6250 [Kilmer Peak]\n\t\t8086 1311  Centrino Advanced-N + WiMAX 6250 2x2 AGN\n\t\t8086 1316  Centrino Advanced-N + WiMAX 6250 2x2 ABG\n\t008a  Centrino Wireless-N 1030 [Rainbow Peak]\n\t\t8086 5305  Centrino Wireless-N 1030 BGN\n\t\t8086 5307  Centrino Wireless-N 1030 BG\n\t\t8086 5325  Centrino Wireless-N 1030 BGN\n\t\t8086 5327  Centrino Wireless-N 1030 BG\n\t008b  Centrino Wireless-N 1030 [Rainbow Peak]\n\t\t8086 5315  Centrino Wireless-N 1030 BGN\n\t\t8086 5317  Centrino Wireless-N 1030 BG\n\t0090  Centrino Advanced-N 6230 [Rainbow Peak]\n\t\t8086 5211  Centrino Advanced-N 6230 AGN\n\t\t8086 5215  Centrino Advanced-N 6230 BGN\n\t\t8086 5216  Centrino Advanced-N 6230 ABG\n\t0091  Centrino Advanced-N 6230 [Rainbow Peak]\n\t\t8086 5201  Centrino Advanced-N 6230 AGN\n\t\t8086 5205  Centrino Advanced-N 6230 BGN\n\t\t8086 5206  Centrino Advanced-N 6230 ABG\n\t\t8086 5207  Centrino Advanced-N 6230 BG\n\t\t8086 5221  Centrino Advanced-N 6230 AGN\n\t\t8086 5225  Centrino Advanced-N 6230 BGN\n\t\t8086 5226  Centrino Advanced-N 6230 ABG\n\t0100  2nd Generation Core Processor Family DRAM Controller\n\t\t1028 04aa  XPS 8300\n\t\t1043 844d  P8P67/P8H67 Series Motherboard\n\t0101  Xeon E3-1200/2nd Generation Core Processor Family PCI Express Root Port\n\t\t1028 04b2  Vostro 3350\n\t\t106b 00dc  MacBookPro8,2 [Core i7, 15\", 2011]\n\t\t144d c652  NP300E5C series laptop\n\t0102  2nd Generation Core Processor Family Integrated Graphics Controller\n\t\t1028 04aa  XPS 8300\n\t\t1043 0102  P8H67 Series Motherboard\n\t0104  2nd Generation Core Processor Family DRAM Controller\n\t\t1028 04a3  Precision M4600\n\t\t1028 04b2  Vostro 3350\n\t\t1028 04da  Vostro 3750\n\t\t106b 00dc  MacBookPro8,2 [Core i7, 15\", 2011]\n\t\t144d c652  NP300E5C series laptop\n\t\t17aa 21cf  ThinkPad T520\n\t0105  Xeon E3-1200/2nd Generation Core Processor Family PCI Express Root Port\n\t\t106b 00dc  MacBookPro8,2 [Core i7, 15\", 2011]\n\t0106  2nd Generation Core Processor Family Integrated Graphics Controller\n\t0108  Xeon E3-1200 Processor Family DRAM Controller\n\t0109  Xeon E3-1200/2nd Generation Core Processor Family PCI Express Root Port\n\t010a  Xeon E3-1200 Processor Family Integrated Graphics Controller\n\t010b  Xeon E3-1200/2nd Generation Core Processor Family Integrated Graphics Controller\n\t010c  Xeon E3-1200/2nd Generation Core Processor Family DRAM Controller\n\t010d  Xeon E3-1200/2nd Generation Core Processor Family PCI Express Root Port\n\t010e  Xeon E3-1200/2nd Generation Core Processor Family Integrated Graphics Controller\n\t0112  2nd Generation Core Processor Family Integrated Graphics Controller\n\t0116  2nd Generation Core Processor Family Integrated Graphics Controller\n\t\t1028 04da  Vostro 3750\n\t\t144d c652  integrated HD 3000 graphics controller on NP300E5C series laptop\n\t0122  2nd Generation Core Processor Family Integrated Graphics Controller\n\t0126  2nd Generation Core Processor Family Integrated Graphics Controller\n\t\t1028 04cc  Vostro 3350\n\t\t17aa 21ce  ThinkPad T420\n\t\t17aa 21cf  ThinkPad T520\n\t0150  Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller\n\t\t1043 84ca  P8 series motherboard\n\t\t1458 d000  Ivy Bridge GT1 [HD Graphics]\n\t\t15d9 0624  X9SCM-F Motherboard\n\t\t1849 0150  Motherboard\n\t0151  Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port\n\t\t1043 1477  N56VZ\n\t\t1043 844d  P8 series motherboard\n\t\t1043 84ca  P8H77-I Motherboard\n\t\t8086 2010  Server Board S1200BTS\n\t0152  Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller\n\t\t1043 84ca  P8H77-I Motherboard\n\t0153  3rd Gen Core Processor Thermal Subsystem\n\t\t1043 1517  Zenbook Prime UX31A\n\t0154  3rd Gen Core processor DRAM Controller\n\t\t1025 0806  Aspire E1-470G\n\t\t1025 0813  Aspire R7-571\n\t\t103c 17f6  ProBook 4540s\n\t\t1043 108d  VivoBook X202EV\n\t\t1043 1477  N56VZ\n\t\t1043 1517  Zenbook Prime UX31A\n\t0155  Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port\n\t\t8086 2010  Server Board S1200BTS\n\t0156  3rd Gen Core processor Graphics Controller\n\t\t1043 108d  VivoBook X202EV\n\t0158  Xeon E3-1200 v2/Ivy Bridge DRAM Controller\n\t\t1043 844d  P8 series motherboard\n\t\t8086 2010  Server Board S1200BT Family\n\t0159  Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port\n\t015a  Xeon E3-1200 v2/Ivy Bridge Graphics Controller\n\t015c  Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller\n\t015d  Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port\n\t\t1043 844d  P8 series motherboard\n\t015e  Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller\n\t0162  Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller\n\t\t1043 84ca  P8 series motherboard\n\t\t1849 0162  Motherboard\n\t0166  3rd Gen Core processor Graphics Controller\n\t\t1043 1517  Zenbook Prime UX31A\n\t\t1043 2103  N56VZ\n\t016a  Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller\n\t\t1043 844d  P8B WS Motherboard\n\t0172  Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller\n\t0176  3rd Gen Core processor Graphics Controller\n\t02a4  Comet Lake SPI (flash) Controller\n\t02a6  Comet Lake North Peak\n\t02d3  Comet Lake SATA AHCI Controller\n\t02e0  Comet Lake Management Engine Interface\n\t02e8  Serial IO I2C Host Controller\n\t02f0  Wireless-AC 9462\n\t02f9  Comet Lake Thermal Subsytem\n\t02fc  Comet Lake Integrated Sensor Solution\n\t0309  80303 I/O Processor PCI-to-PCI Bridge\n\t030d  80312 I/O Companion Chip PCI-to-PCI Bridge\n\t0326  6700/6702PXH I/OxAPIC Interrupt Controller A\n\t\t103c 3208  ProLiant DL140 G2\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t0327  6700PXH I/OxAPIC Interrupt Controller B\n\t\t103c 3208  ProLiant DL140 G2\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t0329  6700PXH PCI Express-to-PCI Bridge A\n\t032a  6700PXH PCI Express-to-PCI Bridge B\n\t032c  6702PXH PCI Express-to-PCI Bridge A\n\t0330  80332 [Dobson] I/O processor (A-Segment Bridge)\n\t0331  80332 [Dobson] I/O processor (A-Segment IOAPIC)\n\t0332  80332 [Dobson] I/O processor (B-Segment Bridge)\n\t0333  80332 [Dobson] I/O processor (B-Segment IOAPIC)\n\t0334  80332 [Dobson] I/O processor (ATU)\n\t0335  80331 [Lindsay] I/O processor (PCI-X Bridge)\n\t0336  80331 [Lindsay] I/O processor (ATU)\n\t0340  41210 [Lanai] Serial to Parallel PCI Bridge (A-Segment Bridge)\n\t0341  41210 [Lanai] Serial to Parallel PCI Bridge (B-Segment Bridge)\n\t0370  80333 Segment-A PCIe Express to PCI-X bridge\n\t0371  80333 A-Bus IOAPIC\n\t0372  80333 Segment-B PCIe Express to PCI-X bridge\n\t0373  80333 B-Bus IOAPIC\n\t0374  80333 Address Translation Unit\n\t0402  Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller\n\t0406  Haswell Integrated Graphics Controller\n\t040a  Xeon E3-1200 v3 Processor Integrated Graphics Controller\n\t0412  Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller\n\t\t17aa 309f  ThinkCentre M83\n\t0416  4th Gen Core Processor Integrated Graphics Controller\n\t\t17aa 220e  ThinkPad T440p\n\t041a  Xeon E3-1200 v3 Processor Integrated Graphics Controller\n\t041e  4th Generation Core Processor Family Integrated Graphics Controller\n\t0434  DH89XXCC Series QAT\n\t0435  DH895XCC Series QAT\n\t0436  DH8900CC Null Device\n\t0438  DH8900CC Series Gigabit Network Connection\n\t043a  DH8900CC Series Gigabit Fiber Network Connection\n\t043c  DH8900CC Series Gigabit Backplane Network Connection\n\t0440  DH8900CC Series Gigabit SFP Network Connection\n\t0442  DH89XXCC Series QAT Virtual Function\n\t0443  DH895XCC Series QAT Virtual Function\n\t0482  82375EB/SB PCI to EISA Bridge\n\t0483  82424TX/ZX [Saturn] CPU to PCI bridge\n\t0484  82378ZB/IB, 82379AB (SIO, SIO.A) PCI to ISA Bridge\n\t0486  82425EX/ZX [Aries] PCIset with ISA bridge\n\t04a3  82434LX/NX [Mercury/Neptune] Processor to PCI bridge\n\t04d0  82437FX [Triton FX]\n\t0500  E8870 Processor bus control\n\t0501  E8870 Memory controller\n# and registers common to both SPs\n\t0502  E8870 Scalability Port 0\n# and global performance monitoring\n\t0503  E8870 Scalability Port 1\n\t0510  E8870IO Hub Interface Port 0 registers (8-bit compatibility port)\n\t0511  E8870IO Hub Interface Port 1 registers\n\t0512  E8870IO Hub Interface Port 2 registers\n\t0513  E8870IO Hub Interface Port 3 registers\n\t0514  E8870IO Hub Interface Port 4 registers\n\t0515  E8870IO General SIOH registers\n\t0516  E8870IO RAS registers\n\t0530  E8870SP Scalability Port 0 registers\n\t0531  E8870SP Scalability Port 1 registers\n\t0532  E8870SP Scalability Port 2 registers\n\t0533  E8870SP Scalability Port 3 registers\n\t0534  E8870SP Scalability Port 4 registers\n\t0535  E8870SP Scalability Port 5 registers\n# (bi-interleave 0) and global registers that are neither per-port nor per-interleave\n\t0536  E8870SP Interleave registers 0 and 1\n# (bi-interleave 1)\n\t0537  E8870SP Interleave registers 2 and 3\n\t0600  RAID Controller\n\t\t8086 0136  SRCU31L\n\t\t8086 01af  SRCZCR\n\t\t8086 01c1  ICP Vortex GDT8546RZ\n\t\t8086 01f7  SCRU32\n# uninitialized SRCU32 RAID Controller\n\t061f  80303 I/O Processor\n\t0700  CE Media Processor A/V Bridge\n\t0701  CE Media Processor NAND Flash Controller\n\t0703  CE Media Processor Media Control Unit 1\n\t0704  CE Media Processor Video Capture Interface\n\t0707  CE Media Processor SPI Slave\n\t0708  CE Media Processor 4100\n\t0800  Moorestown SPI Ctrl 0\n\t0801  Moorestown SPI Ctrl 1\n\t0802  Moorestown I2C 0\n\t0803  Moorestown I2C 1\n\t0804  Moorestown I2C 2\n\t0805  Moorestown Keyboard Ctrl\n\t0806  Moorestown USB Ctrl\n\t0807  Moorestown SD Host Ctrl 0\n\t0808  Moorestown SD Host Ctrl 1\n\t0809  Moorestown NAND Ctrl\n\t080a  Moorestown Audio Ctrl\n\t080b  Moorestown ISP\n\t080c  Moorestown Security Controller\n\t080d  Moorestown External Displays\n\t080e  Moorestown SCU IPC\n\t080f  Moorestown GPIO Controller\n\t0810  Moorestown Power Management Unit\n\t0811  Moorestown OTG Ctrl\n\t0812  Moorestown SPI Ctrl 2\n\t0813  Moorestown SC DMA\n\t0814  Moorestown LPE DMA\n\t0815  Moorestown SSP0\n\t0817  Medfield Serial IO I2C Controller #3\n\t0818  Medfield Serial IO I2C Controller #4\n\t0819  Medfield Serial IO I2C Controller #5\n\t081a  Medfield GPIO Controller [Core]\n\t081b  Medfield Serial IO HSUART Controller #1\n\t081c  Medfield Serial IO HSUART Controller #2\n\t081d  Medfield Serial IO HSUART Controller #3\n\t081e  Medfield Serial IO HSUART DMA Controller\n\t081f  Medfield GPIO Controller [AON]\n\t0820  Medfield SD Host Controller\n\t0821  Medfield SDIO Controller #1\n\t0822  Medfield SDIO Controller #2\n\t0823  Medfield eMMC Controller #0\n\t0824  Medfield eMMC Controller #1\n\t0827  Medfield Serial IO DMA Controller\n\t0828  Medfield Power Management Unit\n\t0829  Medfield USB Device Controller (OTG)\n\t082a  Medfield SCU IPC\n\t082c  Medfield Serial IO I2C Controller #0\n\t082d  Medfield Serial IO I2C Controller #1\n\t082e  Medfield Serial IO I2C Controller #2\n\t0885  Centrino Wireless-N + WiMAX 6150\n\t\t8086 1305  Centrino Wireless-N + WiMAX 6150 BGN\n\t\t8086 1307  Centrino Wireless-N + WiMAX 6150 BG\n\t\t8086 1325  Centrino Wireless-N + WiMAX 6150 BGN\n\t\t8086 1327  Centrino Wireless-N + WiMAX 6150 BG\n\t0886  Centrino Wireless-N + WiMAX 6150\n\t\t8086 1315  Centrino Wireless-N + WiMAX 6150 BGN\n\t\t8086 1317  Centrino Wireless-N + WiMAX 6150 BG\n\t0887  Centrino Wireless-N 2230\n\t\t8086 4062  Centrino Wireless-N 2230 BGN\n\t\t8086 4462  Centrino Wireless-N 2230 BGN\n\t0888  Centrino Wireless-N 2230\n\t\t8086 4262  Centrino Wireless-N 2230 BGN\n\t088e  Centrino Advanced-N 6235\n\t\t8086 4060  Centrino Advanced-N 6235 AGN\n\t\t8086 4460  Centrino Advanced-N 6235 AGN\n\t088f  Centrino Advanced-N 6235\n\t\t8086 4260  Centrino Advanced-N 6235 AGN\n\t0890  Centrino Wireless-N 2200\n\t\t8086 4022  Centrino Wireless-N 2200 BGN\n\t\t8086 4422  Centrino Wireless-N 2200 BGN\n\t\t8086 4822  Centrino Wireless-N 2200 BGN\n\t0891  Centrino Wireless-N 2200\n\t\t8086 4222  Centrino Wireless-N 2200 BGN\n\t0892  Centrino Wireless-N 135\n\t\t8086 0062  Centrino Wireless-N 135 BGN\n\t\t8086 0462  Centrino Wireless-N 135 BGN\n\t0893  Centrino Wireless-N 135\n\t\t8086 0262  Centrino Wireless-N 135 BGN\n\t0894  Centrino Wireless-N 105\n\t\t8086 0022  Centrino Wireless-N 105 BGN\n\t\t8086 0422  Centrino Wireless-N 105 BGN\n\t\t8086 0822  Centrino Wireless-N 105 BGN\n\t0895  Centrino Wireless-N 105\n\t\t8086 0222  Centrino Wireless-N 105 BGN\n\t0896  Centrino Wireless-N 130\n\t\t8086 5005  Centrino Wireless-N 130 BGN\n\t\t8086 5007  Centrino Wireless-N 130 BG\n\t\t8086 5025  Centrino Wireless-N 130 BGN\n\t\t8086 5027  Centrino Wireless-N 130 BG\n\t0897  Centrino Wireless-N 130\n\t\t8086 5015  Centrino Wireless-N 130 BGN\n\t\t8086 5017  Centrino Wireless-N 130 BG\n\t08a7  Quark SoC X1000 SDIO / eMMC Controller\n\t08ae  Centrino Wireless-N 100\n\t\t8086 1005  Centrino Wireless-N 100 BGN\n\t\t8086 1007  Centrino Wireless-N 100 BG\n\t\t8086 1025  Centrino Wireless-N 100 BGN\n\t\t8086 1027  Centrino Wireless-N 100 BG\n\t08af  Centrino Wireless-N 100\n\t\t8086 1015  Centrino Wireless-N 100 BGN\n\t\t8086 1017  Centrino Wireless-N 100 BG\n\t08b1  Wireless 7260\n# Wilkins Peak 2\n\t\t8086 4020  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 402a  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4060  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4062  Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 406a  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4070  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 4072  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 4160  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4162  Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4170  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 4420  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4460  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4462  Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 446a  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4470  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 4472  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 4560  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4570  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 486e  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 4870  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 4a6c  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 4a6e  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 4a70  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 4c60  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 4c70  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 5070  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 5072  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 5170  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 5770  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 c020  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c02a  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c060  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c062  Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c06a  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c070  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 c072  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 c160  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c162  Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c170  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 c360  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c420  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c460  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c462  Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c470  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 c472  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 c560  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c570  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 c760  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c770  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 cc60  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 cc70  Dual Band Wireless-AC 7260\n\t08b2  Wireless 7260\n# Wilkins Peak 2\n\t\t8086 4220  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4260  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4262  Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 426a  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4270  Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4272  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 4360  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 4370  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 c220  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c260  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c262  Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c26a  Dual Band Wireless-N 7260\n# Wilkins Peak 2\n\t\t8086 c270  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 c272  Dual Band Wireless-AC 7260\n# Wilkins Peak 2\n\t\t8086 c370  Dual Band Wireless-AC 7260\n\t08b3  Wireless 3160\n# Wilkins Peak 1\n\t\t8086 0060  Dual Band Wireless-N 3160\n# Wilkins Peak 1\n\t\t8086 0062  Wireless-N 3160\n# Wilkins Peak 1\n\t\t8086 0070  Dual Band Wireless-AC 3160\n# Wilkins Peak 1\n\t\t8086 0072  Dual Band Wireless-AC 3160\n# Wilkins Peak 1\n\t\t8086 0170  Dual Band Wireless-AC 3160\n# Wilkins Peak 1\n\t\t8086 0172  Dual Band Wireless-AC 3160\n# Wilkins Peak 1\n\t\t8086 0260  Dual Band Wireless-N 3160\n# Wilkins Peak 1\n\t\t8086 0470  Dual Band Wireless-AC 3160\n# Wilkins Peak 1\n\t\t8086 0472  Dual Band Wireless-AC 3160\n# Wilkins Peak 1\n\t\t8086 1070  Dual Band Wireless-AC 3160\n# Wilkins Peak 1\n\t\t8086 1170  Dual Band Wireless-AC 3160\n# Wilkins Peak 1\n\t\t8086 8060  Dual Band Wireless N-3160\n# Wilkins Peak 1\n\t\t8086 8062  Wireless N-3160\n# Wilkins Peak 1\n\t\t8086 8070  Dual Band Wireless AC 3160\n# Wilkins Peak 1\n\t\t8086 8072  Dual Band Wireless AC 3160\n# Wilkins Peak 1\n\t\t8086 8170  Dual Band Wireless AC 3160\n# Wilkins Peak 1\n\t\t8086 8172  Dual Band Wireless AC 3160\n# Wilkins Peak 1\n\t\t8086 8470  Dual Band Wireless AC 3160\n# Wilkins Peak 1\n\t\t8086 8570  Dual Band Wireless AC 3160\n\t08b4  Wireless 3160\n# Wilkins Peak 1\n\t\t8086 0270  Dual Band Wireless-AC 3160\n# Wilkins Peak 1\n\t\t8086 0272  Dual Band Wireless-AC 3160\n# Wilkins Peak 1\n\t\t8086 0370  Dual Band Wireless-AC 3160\n# Wilkins Peak 1\n\t\t8086 8260  Dual Band Wireless AC 3160\n# Wilkins Peak 1\n\t\t8086 8270  Dual Band Wireless AC 3160\n# Wilkins Peak 1\n\t\t8086 8272  Dual Band Wireless AC 3160\n# Wilkins Peak 1\n\t\t8086 8370  Dual Band Wireless AC 3160\n# PowerVR SGX 545\n\t08cf  Atom Processor Z2760 Integrated Graphics Controller\n\t0934  Quark SoC X1000 I2C Controller and GPIO Controller\n\t0935  Quark SoC X1000 SPI Controller\n\t0936  Quark SoC X1000 HS-UART\n\t0937  Quark SoC X1000 10/100 Ethernet MAC\n\t0939  Quark SoC X1000 USB EHCI Host Controller / USB 2.0 Device\n\t093a  Quark SoC X1000 USB OHCI Host Controller\n\t0953  PCIe Data Center SSD\n\t\t8086 3702  DC P3700 SSD\n\t\t8086 3703  DC P3700 SSD [2.5\" SFF]\n\t\t8086 3704  DC P3500 SSD [Add-in Card]\n\t\t8086 3705  DC P3500 SSD [2.5\" SFF]\n\t\t8086 3709  DC P3600 SSD [Add-in Card]\n\t\t8086 370a  DC P3600 SSD [2.5\" SFF]\n\t\t8086 370d  SSD 750 Series [Add-in Card]\n\t\t8086 370e  SSD 750 Series [2.5\" SFF]\n\t0958  Quark SoC X1000 Host Bridge\n\t095a  Wireless 7265\n# Stone Peak 2 AC\n\t\t8086 1010  Dual Band Wireless-AC 7265\n# Stone Peak 2 AGN\n\t\t8086 5000  Dual Band Wireless-N 7265\n# Stone Peak 2 BGN\n\t\t8086 5002  Wireless-N 7265\n# Stone Peak 2 AGN\n\t\t8086 500a  Dual Band Wireless-N 7265\n# Stone Peak 2 AC\n\t\t8086 5010  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 5012  Dual Band Wireless-AC 7265\n# Stone Peak 2 AGN\n\t\t8086 5020  Dual Band Wireless-N 7265\n# Stone Peak 2 AGN\n\t\t8086 502a  Dual Band Wireless-N 7265\n# Maple Peak AC\n\t\t8086 5090  Dual Band Wireless-AC 7265\n# Stone Peak 2 AGN\n\t\t8086 5100  Dual Band Wireless-AC 7265\n# Stone Peak 2 BGN\n\t\t8086 5102  Wireless-N 7265\n# Stone Peak 2 AGN\n\t\t8086 510a  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 5110  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 5112  Dual Band Wireless-AC 7265\n# Maple Peak AC\n\t\t8086 5190  Dual Band Wireless-AC 7265\n# Stone Peak 2 AGN\n\t\t8086 5400  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 5410  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 5412  Dual Band Wireless-AC 7265\n# Stone Peak 2 AGN\n\t\t8086 5420  Dual Band Wireless-N 7265\n# Maple Peak AC\n\t\t8086 5490  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 5510  Dual Band Wireless-AC 7265\n# Maple Peak AC\n\t\t8086 5590  Dual Band Wireless-AC 7265\n# Stone Peak 2 AGN\n\t\t8086 9000  Dual Band Wireless-AC 7265\n# Stone Peak 2 AGN\n\t\t8086 900a  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 9010  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 9012  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 9110  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 9112  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 9210  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 9310  Dual Band Wireless-AC 7265\n# Stone Peak 2 AGN\n\t\t8086 9400  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 9410  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 9510  Dual Band Wireless-AC 7265\n\t095b  Wireless 7265\n# Stone Peak 2 AGN\n\t\t8086 5200  Dual Band Wireless-N 7265\n# Stone Peak 2 BGN\n\t\t8086 5202  Wireless-N 7265\n# Stone Peak 2 AGN\n\t\t8086 520a  Dual Band Wireless-N 7265\n# Stone Peak 2 AC\n\t\t8086 5210  Dual Band Wireless-AC 7265\n# Stone Peak 2 AC\n\t\t8086 5212  Dual Band Wireless-AC 7265\n# Maple Peak AC\n\t\t8086 5290  Dual Band Wireless-AC 7265\n# Stone Peak 2 BGN\n\t\t8086 5302  Wireless-N 7265\n# Stone Peak 2 AC\n\t\t8086 5310  Dual Band Wireless-AC 7265\n# Stone Peak 2 AGN\n\t\t8086 9200  Dual Band Wireless-AC 7265\n\t095e  Quark SoC X1000 Legacy Bridge\n\t0960  80960RP (i960RP) Microprocessor/Bridge\n\t0962  80960RM (i960RM) Bridge\n\t0964  80960RP (i960RP) Microprocessor/Bridge\n\t0a03  Haswell-ULT Thermal Subsystem\n\t0a04  Haswell-ULT DRAM Controller\n\t\t17aa 2214  ThinkPad X240\n\t0a06  Haswell-ULT Integrated Graphics Controller\n\t0a0c  Haswell-ULT HD Audio Controller\n\t\t17aa 2214  ThinkPad X240\n\t0a16  Haswell-ULT Integrated Graphics Controller\n\t\t17aa 2214  ThinkPad X240\n\t0a22  Haswell-ULT Integrated Graphics Controller\n\t0a26  Haswell-ULT Integrated Graphics Controller\n\t0a2a  Haswell-ULT Integrated Graphics Controller\n\t0a2e  Haswell-ULT Integrated Graphics Controller\n\t0a53  DC P3520 SSD\n\t0a54  NVMe Datacenter SSD [3DNAND, Beta Rock Controller]\n\t\t1028 1fe1  Express Flash NVMe 1TB 2.5\" U.2 (P4500)\n\t\t1028 1fe2  Express Flash NVMe 2TB 2.5\" U.2 (P4500)\n\t\t1028 1fe3  Express Flash NVMe 4TB 2.5\" U.2 (P4500)\n\t\t1028 1fe4  Express Flash NVMe 4TB HHHL AIC (P4500)\n\t\t1028 1fee  Express Flash NVMe 1.6TB 2.5\" U.2 (P4610)\n\t\t1028 1fef  Express Flash NVMe 3.2TB 2.5\" U.2 (P4610)\n\t\t1028 1ff0  Express Flash NVMe 6.4TB 2.5\" U.2 (P4610)\n\t\t1028 1fff  Express Flash NVMe 8.0TB 2.5\" U.2 (P4510)\n\t\t1028 2003  Express Flash NVMe 1.0 TB 2.5\" U.2 (P4510)\n\t\t1028 2004  Express Flash NVMe 2.0TB 2.5\" U.2 (P4510)\n\t\t1028 2005  Express Flash NVMe 4.0TB 2.5\" U.2 (P4510)\n\t\t108e 4870  NVMe PCIe 3.0 SSD 6.4TB AIC (P4608)\n\t\t108e 4871  NVMe PCIe 3.0 SSD 6.4TB 2.5-inch (P4600)\n\t\t108e 4879  NVMe PCIe 3.0 SSD v2 6.4TB AIC (P4618)\n\t\t108e 487a  NVMe PCIe 3.0 SSD v2 6.4TB 2.5-inch (P4610)\n\t\t1137 0227  NVMe Datacenter SSD [3DNAND] 1.6TB 2.5\" U.2 (P4600)\n\t\t1137 0228  NVMe Datacenter SSD [3DNAND] 2.0TB 2.5\" U.2 (P4600)\n\t\t1137 0229  NVMe Datacenter SSD [3DNAND] 3.2TB 2.5\" U.2 (P4600)\n\t\t1137 022b  NVMe Datacenter SSD [3DNAND] 1.0TB 2.5\" U.2 (P4500)\n\t\t1137 022c  NVMe Datacenter SSD [3DNAND] 2.0TB 2.5\" U.2 (P4500)\n\t\t1137 022d  NVMe Datacenter SSD [3DNAND] 4.0TB 2.5\" U.2 (P4500)\n\t\t1137 0231  NVMe Datacenter SSD [3DNAND] 0.5TB 2.5\" U.2 (P4501)\n\t\t1137 0232  NVMe Datacenter SSD [3DNAND] 1.0TB 2.5\" U.2 (P4501)\n\t\t1137 0233  NVMe Datacenter SSD [3DNAND] 2.0TB 2.5\" U.2 (P4501)\n\t\t1137 0258  NVMe Datacenter SSD [3DNAND] 1.6TB 2.5\" U.2 (P4610)\n\t\t1137 025a  NVMe Datacenter SSD [3DNAND] 3.2TB 2.5\" U.2 (P4610)\n\t\t1137 025b  NVMe Datacenter SSD [3DNAND] 1.0TB 2.5\" U.2 (P4510)\n\t\t1137 025c  NVMe Datacenter SSD [3DNAND] 2.0TB 2.5\" U.2 (P4510)\n\t\t1137 025d  NVMe Datacenter SSD [3DNAND] 4.0TB 2.5\" U.2 (P4510)\n\t\t1137 025e  NVMe Datacenter SSD [3DNAND] 8.0TB 2.5\" U.2 (P4510)\n\t\t1590 025d  NVMe Datacenter SSD [3DNAND] 1.0TB 2.5\" U.2 (P4500)\n\t\t1590 025e  NVMe Datacenter SSD [3DNAND] 2.0TB 2.5\" U.2 (P4500)\n\t\t1590 025f  NVMe Datacenter SSD [3DNAND] 4.0TB 2.5\" U.2 (P4500)\n\t\t1590 0262  NVMe Datacenter SSD [3DNAND] 1.6TB 2.5\" U.2 (P4600)\n\t\t1590 0264  NVMe Datacenter SSD [3DNAND] 3.2TB 2.5\" U.2 (P4600)\n\t\t1590 0265  NVMe Datacenter SSD [3DNAND] 6.4TB 2.5\" U.2 (P4600)\n\t\t1590 026c  NVMe Datacenter SSD [3DNAND] 4.0TB AIC (P4500)\n\t\t1d49 4702  Thinksystem Intel P4500 NVMe U.2\n\t\t1d49 4704  Thinksystem Intel P4500 NVMe AIC\n\t\t1d49 4712  Thinksystem Intel P4600 NVMe U.2\n\t\t1d49 4714  Thinksystem Intel P4600 NVMe AIC\n\t\t1d49 4802  Thinksystem U.2 P4510 NVMe SSD\n\t\t1d49 4812  Thinksystem U.2 P4610 NVMe SSD\n\t\t8086 4308  Intel SSD D5-P4320 and D5-P4326\n\t\t8086 4702  NVMe Datacenter SSD [3DNAND] SE 2.5\" U.2 (P4500)\n\t\t8086 4704  NVMe Datacenter SSD [3DNAND] SE AIC (P4500)\n\t\t8086 4712  NVMe Datacenter SSD [3DNAND] ME 2.5\" U.2 (P4600)\n\t\t8086 4714  NVMe Datacenter SSD [3DNAND] ME AIC (P4600)\n\t\t8086 4802  NVMe Datacenter SSD [3DNAND] SE 2.5\" U.2 (P4510)\n\t\t8086 4804  NVMe Datacenter SSD [3DNAND] SE AIC (P4510)\n\t\t8086 4805  NVMe Datacenter SSD [3DNAND] SE M.2 (P4511)\n\t\t8086 4812  NVMe Datacenter SSD [3DNAND] ME 2.5\" U.2 (P4610)\n\t\t8086 4814  NVMe Datacenter SSD [3DNAND] ME AIC (P4610)\n\t0a55  NVMe DC SSD [3DNAND, Beta Rock Controller]\n\t\t1028 1fe5  Express Flash NVMe 1.6TB 2.5\" U.2 (P4600)\n\t\t1028 1fe6  Express Flash NVMe 2TB 2.5\" U.2 (P4600)\n\t\t1028 1fe7  Express Flash NVMe 3.2TB 2.5\" U.2 (P4600)\n\t\t1028 1fe8  Express Flash NVMe 2.0TB HHHL AIC (P4600)\n\t\t1028 1fe9  Express Flash NVMe 4.0TB HHHL AIC (P4600)\n\t0be0  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0be1  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t\t105b 0d7c  D270S/D250S Motherboard\n\t0be2  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0be3  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0be4  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0be5  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0be6  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0be7  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0be8  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0be9  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0bea  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0beb  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0bec  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0bed  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0bee  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0bef  Atom Processor D2xxx/N2xxx Integrated Graphics Controller\n\t0bf0  Atom Processor D2xxx/N2xxx DRAM Controller\n\t0bf1  Atom Processor D2xxx/N2xxx DRAM Controller\n\t0bf2  Atom Processor D2xxx/N2xxx DRAM Controller\n\t0bf3  Atom Processor D2xxx/N2xxx DRAM Controller\n\t0bf4  Atom Processor D2xxx/N2xxx DRAM Controller\n\t0bf5  Atom Processor D2xxx/N2xxx DRAM Controller\n\t\t105b 0d7c  D270S/D250S Motherboard\n\t0bf6  Atom Processor D2xxx/N2xxx DRAM Controller\n\t0bf7  Atom Processor D2xxx/N2xxx DRAM Controller\n\t0c00  4th Gen Core Processor DRAM Controller\n\t\t17aa 309f  ThinkCentre M83\n\t0c01  Xeon E3-1200 v3/4th Gen Core Processor PCI Express x16 Controller\n\t0c04  Xeon E3-1200 v3/4th Gen Core Processor DRAM Controller\n\t\t103c 1909  ZBook 15\n\t\t17aa 220e  ThinkPad T440p\n\t0c05  Xeon E3-1200 v3/4th Gen Core Processor PCI Express x8 Controller\n\t0c08  Xeon E3-1200 v3 Processor DRAM Controller\n\t0c09  Xeon E3-1200 v3/4th Gen Core Processor PCI Express x4 Controller\n\t0c0c  Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller\n\t\t17aa 220e  ThinkPad T440p\n\t\t17aa 309f  ThinkCentre M83\n\t0c46  Atom Processor S1200 PCI Express Root Port 1\n\t0c47  Atom Processor S1200 PCI Express Root Port 2\n\t0c48  Atom Processor S1200 PCI Express Root Port 3\n\t0c49  Atom Processor S1200 PCI Express Root Port 4\n\t0c4e  Atom Processor S1200 NTB Primary\n\t0c50  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QuickData Technology Device\n\t0c51  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QuickData Technology Device\n\t0c52  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QuickData Technology Device\n\t0c53  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QuickData Technology Device\n\t0c54  Atom Processor S1200 Internal\n\t0c55  Atom Processor S1200 DFX 1\n\t0c56  Atom Processor S1200 DFX 2\n\t0c59  Atom Processor S1200 SMBus 2.0 Controller 0\n\t0c5a  Atom Processor S1200 SMBus 2.0 Controller 1\n\t0c5b  Atom Processor S1200 SMBus Controller 2\n\t0c5c  Atom Processor S1200 SMBus Controller 3\n\t0c5d  Atom Processor S1200 SMBus Controller 4\n\t0c5e  Atom Processor S1200 SMBus Controller 5\n\t0c5f  Atom Processor S1200 UART\n\t0c60  Atom Processor S1200 Integrated Legacy Bus\n\t0c70  Atom Processor S1200 Internal\n\t0c71  Atom Processor S1200 Internal\n\t0c72  Atom Processor S1200 Internal\n\t0c73  Atom Processor S1200 Internal\n\t0c74  Atom Processor S1200 Internal\n\t0c75  Atom Processor S1200 Internal\n\t0c76  Atom Processor S1200 Internal\n\t0c77  Atom Processor S1200 Internal\n\t0c78  Atom Processor S1200 Internal\n\t0c79  Atom Processor S1200 Internal\n\t0c7a  Atom Processor S1200 Internal\n\t0c7b  Atom Processor S1200 Internal\n\t0c7c  Atom Processor S1200 Internal\n\t0c7d  Atom Processor S1200 Internal\n\t0c7e  Atom Processor S1200 Internal\n\t0c7f  Atom Processor S1200 Internal\n\t0cf8  Ethernet Controller X710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking\n\t\t8086 0000  Ethernet Controller X710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking\n\t\t8086 0001  Ethernet Controller X710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking\n\t0d00  Crystal Well DRAM Controller\n\t0d01  Crystal Well PCI Express x16 Controller\n\t0d04  Crystal Well DRAM Controller\n\t0d05  Crystal Well PCI Express x8 Controller\n\t0d09  Crystal Well PCI Express x4 Controller\n\t0d0c  Crystal Well HD Audio Controller\n\t0d16  Crystal Well Integrated Graphics Controller\n\t0d26  Crystal Well Integrated Graphics Controller\n\t0d36  Crystal Well Integrated Graphics Controller\n\t0d4c  Ethernet Connection (11) I219-LM\n\t0d4d  Ethernet Connection (11) I219-V\n\t0d4e  Ethernet Connection (10) I219-LM\n\t0d4f  Ethernet Connection (10) I219-V\n\t0d53  Ethernet Connection (12) I219-LM\n\t0d55  Ethernet Connection (12) I219-V\n\t0d58  Ethernet Controller XXV710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking\n\t\t8086 0000  Ethernet Controller XXV710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking\n\t\t8086 0001  Ethernet Controller XXV710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking\n\t0e00  Xeon E7 v2/Xeon E5 v2/Core i7 DMI2\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t0e01  Xeon E7 v2/Xeon E5 v2/Core i7 PCI Express Root Port in DMI2 Mode\n\t0e02  Xeon E7 v2/Xeon E5 v2/Core i7 PCI Express Root Port 1a\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t0e03  Xeon E7 v2/Xeon E5 v2/Core i7 PCI Express Root Port 1b\n\t0e04  Xeon E7 v2/Xeon E5 v2/Core i7 PCI Express Root Port 2a\n\t0e05  Xeon E7 v2/Xeon E5 v2/Core i7 PCI Express Root Port 2b\n\t0e06  Xeon E7 v2/Xeon E5 v2/Core i7 PCI Express Root Port 2c\n\t0e07  Xeon E7 v2/Xeon E5 v2/Core i7 PCI Express Root Port 2d\n\t0e08  Xeon E7 v2/Xeon E5 v2/Core i7 PCI Express Root Port 3a\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t0e09  Xeon E7 v2/Xeon E5 v2/Core i7 PCI Express Root Port 3b\n\t0e0a  Xeon E7 v2/Xeon E5 v2/Core i7 PCI Express Root Port 3c\n\t0e0b  Xeon E7 v2/Xeon E5 v2/Core i7 PCI Express Root Port 3d\n\t0e10  Xeon E7 v2/Xeon E5 v2/Core i7 IIO Configuration Registers\n\t0e13  Xeon E7 v2/Xeon E5 v2/Core i7 IIO Configuration Registers\n\t0e17  Xeon E7 v2/Xeon E5 v2/Core i7 IIO Configuration Registers\n\t0e18  Xeon E7 v2/Xeon E5 v2/Core i7 IIO Configuration Registers\n\t0e1c  Xeon E7 v2/Xeon E5 v2/Core i7 IIO Configuration Registers\n\t0e1d  Xeon E7 v2/Xeon E5 v2/Core i7 R2PCIe\n\t0e1e  Xeon E7 v2/Xeon E5 v2/Core i7 UBOX Registers\n\t0e1f  Xeon E7 v2/Xeon E5 v2/Core i7 UBOX Registers\n\t0e20  Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 0\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t0e21  Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 1\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t0e22  Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 2\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t0e23  Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 3\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t0e24  Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 4\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t0e25  Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 5\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t0e26  Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 6\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t0e27  Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 7\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t0e28  Xeon E7 v2/Xeon E5 v2/Core i7 VTd/Memory Map/Misc\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t0e29  Xeon E7 v2/Xeon E5 v2/Core i7 Memory Hotplug\n\t0e2a  Xeon E7 v2/Xeon E5 v2/Core i7 IIO RAS\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t0e2c  Xeon E7 v2/Xeon E5 v2/Core i7 IOAPIC\n\t\t15d9 066b  X9SRL-F\n\t0e2e  Xeon E7 v2/Xeon E5 v2/Core i7 CBDMA\n\t0e2f  Xeon E7 v2/Xeon E5 v2/Core i7 CBDMA\n\t0e30  Xeon E7 v2/Xeon E5 v2/Core i7 Home Agent 0\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t0e32  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link 0\n\t0e33  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link 1\n\t0e34  Xeon E7 v2/Xeon E5 v2/Core i7 R2PCIe\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t0e36  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Ring Performance Ring Monitoring\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t0e37  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Ring Performance Ring Monitoring\n\t0e38  Xeon E7 v2/Xeon E5 v2/Core i7 Home Agent 1\n\t0e3a  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link 2\n\t0e3e  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Ring Performance Ring Monitoring\n\t0e3f  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Ring Performance Ring Monitoring\n\t0e40  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link 2\n\t0e41  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Ring Registers\n\t0e43  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link Reut 2\n\t0e44  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link Reut 2\n\t0e45  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link Agent Register\n\t0e47  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link Agent Register\n\t0e60  Xeon E7 v2/Xeon E5 v2/Core i7 Home Agent 1\n\t0e68  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 Target Address/Thermal Registers\n\t0e6a  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel Target Address Decoder Registers\n\t0e6b  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel Target Address Decoder Registers\n\t0e6c  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel Target Address Decoder Registers\n\t0e6d  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel Target Address Decoder Registers\n\t0e71  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 RAS Registers\n\t0e74  Xeon E7 v2/Xeon E5 v2/Core i7 R2PCIe\n\t0e75  Xeon E7 v2/Xeon E5 v2/Core i7 R2PCIe\n\t0e77  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Ring Registers\n\t0e79  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 RAS Registers\n\t0e7d  Xeon E7 v2/Xeon E5 v2/Core i7 UBOX Registers\n\t0e7f  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Ring Registers\n\t0e80  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link 0\n\t0e81  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Ring Registers\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t0e83  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link Reut 0\n\t0e84  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link Reut 0\n\t0e85  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link Agent Register\n\t0e87  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Registers\n\t0e90  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link 1\n\t0e93  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link 1\n\t0e94  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link Reut 1\n\t0e95  Xeon E7 v2/Xeon E5 v2/Core i7 QPI Link Agent Register\n\t0ea0  Xeon E7 v2/Xeon E5 v2/Core i7 Home Agent 0\n\t\t1028 04f7  Xeon E5 v2 on PowerEdge R320 server\n\t0ea8  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 Target Address/Thermal Registers\n\t0eaa  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel Target Address Decoder Registers\n\t0eab  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel Target Address Decoder Registers\n\t0eac  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel Target Address Decoder Registers\n\t0ead  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel Target Address Decoder Registers\n\t0eae  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO Registers\n\t0eaf  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO Registers\n\t0eb0  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 Thermal Control 0\n\t0eb1  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 Thermal Control 1\n\t0eb2  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 ERROR Registers 0\n\t0eb3  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 ERROR Registers 1\n\t0eb4  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 Thermal Control 2\n\t0eb5  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 Thermal Control 3\n\t0eb6  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 ERROR Registers 2\n\t0eb7  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 ERROR Registers 3\n\t0ebc  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO Registers\n\t0ebe  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO Registers\n\t0ebf  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO Registers\n\t0ec0  Xeon E7 v2/Xeon E5 v2/Core i7 Power Control Unit 0\n\t0ec1  Xeon E7 v2/Xeon E5 v2/Core i7 Power Control Unit 1\n\t0ec2  Xeon E7 v2/Xeon E5 v2/Core i7 Power Control Unit 2\n\t0ec3  Xeon E7 v2/Xeon E5 v2/Core i7 Power Control Unit 3\n\t0ec4  Xeon E7 v2/Xeon E5 v2/Core i7 Power Control Unit 4\n\t0ec8  Xeon E7 v2/Xeon E5 v2/Core i7 System Address Decoder\n\t0ec9  Xeon E7 v2/Xeon E5 v2/Core i7 Broadcast Registers\n\t0eca  Xeon E7 v2/Xeon E5 v2/Core i7 Broadcast Registers\n\t0ed8  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO\n\t0ed9  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO\n\t0edc  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO\n\t0edd  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO\n\t0ede  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO\n\t0edf  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO\n\t0ee0  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0ee1  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0ee2  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0ee3  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0ee4  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0ee5  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0ee6  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0ee7  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0ee8  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0ee9  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0eea  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0eeb  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0eec  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0eed  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0eee  Xeon E7 v2/Xeon E5 v2/Core i7 Unicast Registers\n\t0ef0  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 Thermal Control 0\n\t0ef1  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 Thermal Control 1\n\t0ef2  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 ERROR Registers 0\n\t0ef3  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 ERROR Registers 1\n\t0ef4  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 Thermal Control 2\n\t0ef5  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 Thermal Control 3\n\t0ef6  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 ERROR Registers 2\n\t0ef7  Xeon E7 v2/Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 ERROR Registers 3\n\t0ef8  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO\n\t0ef9  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO\n\t0efa  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO\n\t0efb  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO\n\t0efc  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO\n\t0efd  Xeon E7 v2/Xeon E5 v2/Core i7 DDRIO\n\t0f00  Atom Processor Z36xxx/Z37xxx Series SoC Transaction Register\n\t0f04  Atom Processor Z36xxx/Z37xxx Series High Definition Audio Controller\n\t0f06  Atom Processor Z36xxx/Z37xxx Series LPIO1 DMA Controller\n\t0f08  Atom Processor Z36xxx/Z37xxx Series LPIO1 PWM Controller\n\t0f09  Atom Processor Z36xxx/Z37xxx Series LPIO1 PWM Controller\n\t0f0a  Atom Processor Z36xxx/Z37xxx Series LPIO1 HSUART Controller #1\n\t0f0c  Atom Processor Z36xxx/Z37xxx Series LPIO1 HSUART Controller #2\n\t0f0e  Atom Processor Z36xxx/Z37xxx Series LPIO1 SPI Controller\n\t0f12  Atom Processor E3800 Series SMBus Controller\n\t0f14  Atom Processor Z36xxx/Z37xxx Series SDIO Controller\n\t0f15  Atom Processor Z36xxx/Z37xxx Series SDIO Controller\n\t0f16  Atom Processor Z36xxx/Z37xxx Series SDIO Controller\n\t0f18  Atom Processor Z36xxx/Z37xxx Series Trusted Execution Engine\n\t0f1c  Atom Processor Z36xxx/Z37xxx Series Power Control Unit\n\t0f20  Atom Processor E3800 Series SATA IDE Controller\n\t0f21  Atom Processor E3800 Series SATA IDE Controller\n\t0f22  Atom Processor E3800 Series SATA AHCI Controller\n\t0f23  Atom Processor E3800 Series SATA AHCI Controller\n\t0f28  Atom Processor Z36xxx/Z37xxx Series LPE Audio Controller\n\t0f31  Atom Processor Z36xxx/Z37xxx Series Graphics & Display\n\t0f34  Atom Processor Z36xxx/Z37xxx Series USB EHCI\n\t0f35  Atom Processor Z36xxx/Z37xxx, Celeron N2000 Series USB xHCI\n\t\t1025 0936  Aspire ES1\n\t0f37  Atom Processor Z36xxx/Z37xxx Series OTG USB Device\n\t0f38  Atom Processor Z36xxx/Z37xxx Series Camera ISP\n\t0f40  Atom Processor Z36xxx/Z37xxx Series LPIO2 DMA Controller\n\t0f41  Atom Processor Z36xxx/Z37xxx Series LPIO2 I2C Controller #1\n\t0f42  Atom Processor Z36xxx/Z37xxx Series LPIO2 I2C Controller #2\n\t0f43  Atom Processor Z36xxx/Z37xxx Series LPIO2 I2C Controller #3\n\t0f44  Atom Processor Z36xxx/Z37xxx Series LPIO2 I2C Controller #4\n\t0f45  Atom Processor Z36xxx/Z37xxx Series LPIO2 I2C Controller #5\n\t0f46  Atom Processor Z36xxx/Z37xxx Series LPIO2 I2C Controller #6\n\t0f47  Atom Processor Z36xxx/Z37xxx Series LPIO2 I2C Controller #7\n\t0f48  Atom Processor E3800 Series PCI Express Root Port 1\n\t0f4a  Atom Processor E3800 Series PCI Express Root Port 2\n\t0f4c  Atom Processor E3800 Series PCI Express Root Port 3\n\t0f4e  Atom Processor E3800 Series PCI Express Root Port 4\n\t0f50  Atom Processor E3800 Series eMMC 4.5 Controller\n\t1000  82542 Gigabit Ethernet Controller (Fiber)\n\t\t0e11 b0df  NC6132 Gigabit Ethernet Adapter (1000-SX)\n\t\t0e11 b0e0  NC6133 Gigabit Ethernet Adapter (1000-LX)\n\t\t0e11 b123  NC6134 Gigabit Ethernet Adapter (1000-LX)\n\t\t1014 0119  Netfinity Gigabit Ethernet SX Adapter\n\t\t8086 1000  PRO/1000 Gigabit Server Adapter\n\t1001  82543GC Gigabit Ethernet Controller (Fiber)\n\t\t0e11 004a  NC6136 Gigabit Server Adapter\n\t\t1014 01ea  Netfinity Gigabit Ethernet SX Adapter\n\t\t8086 1002  PRO/1000 F Server Adapter\n\t\t8086 1003  PRO/1000 F Server Adapter\n\t1002  Pro 100 LAN+Modem 56 Cardbus II\n\t\t8086 200e  Pro 100 LAN+Modem 56 Cardbus II\n\t\t8086 2013  Pro 100 SR Mobile Combo Adapter\n\t\t8086 2017  Pro 100 S Combo Mobile Adapter\n\t1004  82543GC Gigabit Ethernet Controller (Copper)\n\t\t0e11 0049  NC7132 Gigabit Upgrade Module\n\t\t0e11 b1a4  NC7131 Gigabit Server Adapter\n\t\t1014 10f2  Gigabit Ethernet Server Adapter\n\t\t8086 1004  PRO/1000 T Server Adapter\n\t\t8086 2004  PRO/1000 T Server Adapter\n\t1008  82544EI Gigabit Ethernet Controller (Copper)\n\t\t1014 0269  iSeries 1000/100/10 Ethernet Adapter\n\t\t1028 011b  PowerEdge 1650/2550\n\t\t1028 011c  PRO/1000 XT Network Connection\n\t\t8086 1107  PRO/1000 XT Server Adapter\n\t\t8086 2107  PRO/1000 XT Server Adapter\n\t\t8086 2110  PRO/1000 XT Desktop Adapter\n\t\t8086 3108  PRO/1000 XT Network Connection\n\t1009  82544EI Gigabit Ethernet Controller (Fiber)\n\t\t1014 0268  iSeries Gigabit Ethernet Adapter\n\t\t8086 1109  PRO/1000 XF Server Adapter\n\t\t8086 2109  PRO/1000 XF Server Adapter\n\t100a  82540EM Gigabit Ethernet Controller\n\t100c  82544GC Gigabit Ethernet Controller (Copper)\n\t\t8086 1112  PRO/1000 T Desktop Adapter\n\t\t8086 2112  PRO/1000 T Desktop Adapter\n\t100d  82544GC Gigabit Ethernet Controller (LOM)\n\t\t1028 0123  PRO/1000 XT Network Connection\n\t\t1079 891f  82544GC Based Network Connection\n\t\t4c53 1080  CT8 mainboard\n\t\t8086 110d  82544GC Based Network Connection\n\t100e  82540EM Gigabit Ethernet Controller\n\t\t1014 0265  PRO/1000 MT Network Connection\n\t\t1014 0267  PRO/1000 MT Network Connection\n\t\t1014 026a  PRO/1000 MT Network Connection\n\t\t1028 002e  Optiplex GX260\n\t\t1028 0134  PowerEdge 600SC\n\t\t1028 0151  Optiplex GX270\n\t\t107b 8920  PRO/1000 MT Desktop Adapter\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 001e  PRO/1000 MT Desktop Adapter\n\t\t8086 002e  PRO/1000 MT Desktop Adapter\n\t\t8086 1376  PRO/1000 GT Desktop Adapter\n\t\t8086 1476  PRO/1000 GT Desktop Adapter\n\t100f  82545EM Gigabit Ethernet Controller (Copper)\n\t\t1014 0269  iSeries 1000/100/10 Ethernet Adapter\n\t\t1014 028e  PRO/1000 MT Network Connection\n\t\t15ad 0750  PRO/1000 MT Single Port Adapter\n\t\t8086 1000  PRO/1000 MT Network Connection\n\t\t8086 1001  PRO/1000 MT Server Adapter\n\t1010  82546EB Gigabit Ethernet Controller (Copper)\n\t\t0e11 00db  NC7170 Gigabit Server Adapter\n\t\t1014 027c  PRO/1000 MT Dual Port Network Adapter\n\t\t15ad 0760  PRO/1000 MT Dual Port Adapter\n\t\t18fb 7872  RESlink-X\n\t\t1fc1 0026  Niagara 2260 Bypass Card\n\t\t4c53 1080  CT8 mainboard\n\t\t4c53 10a0  CA3/CR3 mainboard\n\t\t8086 1011  PRO/1000 MT Dual Port Server Adapter\n\t\t8086 1012  PRO/1000 MT Dual Port Server Adapter\n\t\t8086 101a  PRO/1000 MT Dual Port Network Connection\n\t\t8086 3424  SE7501HG2 Mainboard\n\t1011  82545EM Gigabit Ethernet Controller (Fiber)\n\t\t1014 0268  iSeries Gigabit Ethernet Adapter\n\t\t8086 1002  PRO/1000 MF Server Adapter\n\t\t8086 1003  PRO/1000 MF Server Adapter (LX)\n\t1012  82546EB Gigabit Ethernet Controller (Fiber)\n\t\t0e11 00dc  NC6170 Gigabit Server Adapter\n\t\t8086 1012  PRO/1000 MF Dual Port Server Adapter\n\t1013  82541EI Gigabit Ethernet Controller\n\t\t8086 0013  PRO/1000 MT Network Connection\n\t\t8086 1013  PRO/1000 MT Network Connection\n\t\t8086 1113  PRO/1000 MT Desktop Adapter\n\t1014  82541ER Gigabit Ethernet Controller\n\t\t8086 0014  PRO/1000 MT Desktop Connection\n\t\t8086 1014  PRO/1000 MT Network Connection\n\t1015  82540EM Gigabit Ethernet Controller (LOM)\n\t\t8086 1015  PRO/1000 MT Mobile Connection\n\t1016  82540EP Gigabit Ethernet Controller (Mobile)\n\t\t1014 052c  PRO/1000 MT Mobile Connection\n\t\t1179 0001  PRO/1000 MT Mobile Connection\n\t\t8086 1016  PRO/1000 MT Mobile Connection\n\t1017  82540EP Gigabit Ethernet Controller\n\t\t8086 1017  PR0/1000 MT Desktop Connection\n\t1018  82541EI Gigabit Ethernet Controller\n\t\t8086 1018  PRO/1000 MT Mobile Connection\n\t1019  82547EI Gigabit Ethernet Controller\n\t\t1458 1019  GA-8IPE1000 Pro2 motherboard (865PE)\n\t\t1458 e000  Intel Gigabit Ethernet (Kenai II)\n\t\t8086 1019  PRO/1000 CT Desktop Connection\n\t\t8086 301f  D865PERL mainboard\n\t\t8086 3025  D875PBZ motherboard\n\t\t8086 302c  D865GBF Mainboard\n\t\t8086 3427  S875WP1-E mainboard\n\t101a  82547EI Gigabit Ethernet Controller (Mobile)\n\t\t8086 101a  PRO/1000 CT Mobile Connection\n\t101d  82546EB Gigabit Ethernet Controller\n\t\t8086 1000  PRO/1000 MT Quad Port Server Adapter\n\t101e  82540EP Gigabit Ethernet Controller (Mobile)\n\t\t1014 0549  Thinkpad\n\t\t1179 0001  PRO/1000 MT Mobile Connection\n\t\t8086 101e  PRO/1000 MT Mobile Connection\n\t1026  82545GM Gigabit Ethernet Controller\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t\t1028 0169  Precision 470\n\t\t8086 1000  PRO/1000 MT Server Connection\n\t\t8086 1001  PRO/1000 MT Server Adapter\n\t\t8086 1002  PRO/1000 MT Server Adapter\n\t\t8086 1003  PRO/1000 GT Server Adapter\n\t\t8086 1026  PRO/1000 MT Server Connection\n\t1027  82545GM Gigabit Ethernet Controller\n\t\t103c 3103  NC310F PCI-X Gigabit Server Adapter\n\t\t8086 1001  PRO/1000 MF Server Adapter(LX)\n\t\t8086 1002  PRO/1000 MF Server Adapter(LX)\n\t\t8086 1003  PRO/1000 MF Server Adapter(LX)\n\t\t8086 1027  PRO/1000 MF Server Adapter\n\t1028  82545GM Gigabit Ethernet Controller\n\t\t8086 1028  PRO/1000 MB Server Connection\n\t1029  82559 Ethernet Controller\n\t1030  82559 InBusiness 10/100\n\t1031  82801CAM (ICH3) PRO/100 VE (LOM) Ethernet Controller\n\t\t1014 0209  ThinkPad A/T/X Series\n\t\t104d 80e7  Vaio PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP\n\t\t104d 813c  Vaio PCG-GRV616G\n\t\t107b 5350  EtherExpress PRO/100 VE\n\t\t1179 0001  EtherExpress PRO/100 VE\n\t\t144d c000  EtherExpress PRO/100 VE\n\t\t144d c001  EtherExpress PRO/100 VE\n\t\t144d c003  EtherExpress PRO/100 VE\n\t\t144d c006  vpr Matrix 170B4\n\t1032  82801CAM (ICH3) PRO/100 VE Ethernet Controller\n\t1033  82801CAM (ICH3) PRO/100 VM (LOM) Ethernet Controller\n\t1034  82801CAM (ICH3) PRO/100 VM Ethernet Controller\n\t1035  82801CAM (ICH3)/82562EH (LOM) Ethernet Controller\n\t1036  82801CAM (ICH3) 82562EH Ethernet Controller\n\t1037  82801CAM (ICH3) Chipset Ethernet Controller\n\t1038  82801CAM (ICH3) PRO/100 VM (KM) Ethernet Controller\n\t\t0e11 0098  Evo N600c\n\t1039  82801DB PRO/100 VE (LOM) Ethernet Controller\n\t\t1014 0267  NetVista A30p\n\t\t114a 0582  PC8 onboard ethernet ETH1\n\t103a  82801DB PRO/100 VE (CNR) Ethernet Controller\n\t103b  82801DB PRO/100 VM (LOM) Ethernet Controller\n\t103c  82801DB PRO/100 VM (CNR) Ethernet Controller\n\t103d  82801DB PRO/100 VE (MOB) Ethernet Controller\n\t\t1014 0522  ThinkPad R40\n\t\t1028 2002  Latitude D500\n\t\t8086 103d  82562EZ 10/100 Ethernet Controller\n\t103e  82801DB PRO/100 VM (MOB) Ethernet Controller\n\t1040  536EP Data Fax Modem\n\t\t16be 1040  V.9X DSP Data Fax Modem\n\t1043  PRO/Wireless LAN 2100 3B Mini PCI Adapter\n\t\t103c 08b0  tc1100 tablet\n\t\t8086 2522  Samsung X10/P30 integrated WLAN\n\t\t8086 2527  MIM2000/Centrino\n\t\t8086 2561  Dell Latitude D800\n\t\t8086 2581  Toshiba Satellite M10\n\t1048  82597EX 10GbE Ethernet Controller\n\t\t8086 a01f  PRO/10GbE LR Server Adapter\n\t\t8086 a11f  PRO/10GbE LR Server Adapter\n\t1049  82566MM Gigabit Network Connection\n\t\t103c 30c1  Compaq 6910p\n\t\t17aa 20b9  ThinkPad T61/R61\n\t104a  82566DM Gigabit Network Connection\n\t104b  82566DC Gigabit Network Connection\n\t104c  82562V 10/100 Network Connection\n\t104d  82566MC Gigabit Network Connection\n\t104e  Ethernet Controller X710 for 10 Gigabit SFP+\n\t104f  Ethernet Controller X710 for 10 Gigabit backplane\n\t1050  82562EZ 10/100 Ethernet Controller\n\t\t1028 019d  Dimension 3000\n\t\t1462 728c  865PE Neo2 (MS-6728)\n\t\t1462 758c  MS-6758 (875P Neo)\n\t\t8086 3020  D865PERL mainboard\n\t\t8086 302f  Desktop Board D865GBF\n\t\t8086 3427  S875WP1-E mainboard\n\t1051  82801EB/ER (ICH5/ICH5R) integrated LAN Controller\n\t1052  PRO/100 VM Network Connection\n\t1053  PRO/100 VM Network Connection\n\t1054  PRO/100 VE Network Connection\n\t1055  PRO/100 VM Network Connection\n\t1056  PRO/100 VE Network Connection\n\t1057  PRO/100 VE Network Connection\n\t1059  82551QM Ethernet Controller\n\t105b  82546GB Gigabit Ethernet Controller (Copper)\n\t105e  82571EB/82571GB Gigabit Ethernet Controller D0/D1 (copper applications)\n\t\t103c 7044  NC360T PCI Express Dual Port Gigabit Server Adapter\n\t\t103c 704e  Dual Port 1000Base-T (PCIe) [AD337A]\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t1775 6003  Telum GE-QT\n\t\t18df 1214  2x 1GbE, PCIe x1, dual Intel 82571EB chips\n\t\t8086 005e  PRO/1000 PT Dual Port Server Connection\n\t\t8086 105e  PRO/1000 PT Dual Port Network Connection\n\t\t8086 10d5  82571PT Gigabit PT Quad Port Server ExpressModule\n\t\t8086 115e  PRO/1000 PT Dual Port Server Adapter\n\t\t8086 125e  PRO/1000 PT Dual Port Server Adapter\n\t\t8086 135e  PRO/1000 PT Dual Port Server Adapter\n\t105f  82571EB Gigabit Ethernet Controller\n\t\t103c 704f  Dual Port 1000Base-SX (PCIe) [AD338A]\n\t\t8086 005a  PRO/1000 PF Dual Port Server Adapter\n\t\t8086 115f  PRO/1000 PF Dual Port Server Adapter\n\t\t8086 125f  PRO/1000 PF Dual Port Server Adapter\n\t\t8086 135f  PRO/1000 PF Dual Port Server Adapter\n\t1060  82571EB Gigabit Ethernet Controller\n\t\t8086 0060  PRO/1000 PB Dual Port Server Connection\n\t\t8086 1060  PRO/1000 PB Dual Port Server Connection\n\t1064  82562ET/EZ/GT/GZ - PRO/100 VE (LOM) Ethernet Controller\n\t\t1043 80f8  P5GD1-VW Mainboard\n\t1065  82562ET/EZ/GT/GZ - PRO/100 VE Ethernet Controller\n\t1066  82562 EM/EX/GX - PRO/100 VM (LOM) Ethernet Controller\n\t1067  82562 EM/EX/GX - PRO/100 VM Ethernet Controller\n\t1068  82562ET/EZ/GT/GZ - PRO/100 VE (LOM) Ethernet Controller Mobile\n\t\t103c 30d5  530 Laptop\n\t1069  82562EM/EX/GX - PRO/100 VM (LOM) Ethernet Controller Mobile\n\t106a  82562G - PRO/100 VE (LOM) Ethernet Controller\n\t106b  82562G - PRO/100 VE Ethernet Controller Mobile\n\t1075  82547GI Gigabit Ethernet Controller\n\t\t1028 0165  PowerEdge 750\n\t\t8086 0075  PRO/1000 CT Network Connection\n\t\t8086 1075  PRO/1000 CT Network Connection\n\t1076  82541GI Gigabit Ethernet Controller\n\t\t1028 0165  PRO/1000 MT Network Connection\n\t\t1028 016d  PRO/1000 MT Network Connection\n\t\t1028 019a  PRO/1000 MT Network Connection\n\t\t1028 106d  PRO/1000 MT Network Connection\n\t\t8086 0076  PRO/1000 MT Network Connection\n\t\t8086 1076  PRO/1000 MT Network Connection\n\t\t8086 1176  PRO/1000 MT Desktop Adapter\n\t\t8086 1276  PRO/1000 MT Network Adapter\n\t1077  82541GI Gigabit Ethernet Controller\n\t\t1179 0001  PRO/1000 MT Mobile Connection\n\t\t8086 0077  PRO/1000 MT Mobile Connection\n\t\t8086 1077  PRO/1000 MT Mobile Connection\n\t1078  82541ER Gigabit Ethernet Controller\n\t\t8086 1078  82541ER-based Network Connection\n\t1079  82546GB Gigabit Ethernet Controller\n\t\t103c 12a6  Dual Port 1000Base-T [A9900A]\n\t\t103c 12cf  Core Dual Port 1000Base-T [AB352A]\n\t\t1775 10d0  V5D Single Board Computer Gigabit Ethernet\n\t\t1775 ce90  CE9\n\t\t1fc1 0027  Niagara 2261 Failover NIC\n\t\t4c53 1090  Cx9 / Vx9 mainboard\n\t\t4c53 10b0  CL9 mainboard\n\t\t8086 0079  PRO/1000 MT Dual Port Network Connection\n\t\t8086 1079  PRO/1000 MT Dual Port Network Connection\n\t\t8086 1179  PRO/1000 MT Dual Port Server Adapter\n\t\t8086 117a  PRO/1000 MT Dual Port Server Adapter\n\t107a  82546GB Gigabit Ethernet Controller\n\t\t103c 12a8  Dual Port 1000base-SX [A9899A]\n\t\t8086 107a  PRO/1000 MF Dual Port Server Adapter\n\t\t8086 127a  PRO/1000 MF Dual Port Server Adapter\n\t107b  82546GB Gigabit Ethernet Controller\n\t\t8086 007b  PRO/1000 MB Dual Port Server Connection\n\t\t8086 107b  PRO/1000 MB Dual Port Server Connection\n\t107c  82541PI Gigabit Ethernet Controller\n\t\t8086 1376  PRO/1000 GT Desktop Adapter\n\t\t8086 1476  PRO/1000 GT Desktop Adapter\n\t107d  82572EI Gigabit Ethernet Controller (Copper)\n\t\t8086 1082  PRO/1000 PT Server Adapter\n\t\t8086 1084  PRO/1000 PT Server Adapter\n\t\t8086 1092  PRO/1000 PT Server Adapter\n\t107e  82572EI Gigabit Ethernet Controller (Fiber)\n\t\t8086 1084  PRO/1000 PF Server Adapter\n\t\t8086 1085  PRO/1000 PF Server Adapter\n\t\t8086 1094  PRO/1000 PF Server Adapter\n\t107f  82572EI Gigabit Ethernet Controller\n\t1080  FA82537EP 56K V.92 Data/Fax Modem PCI\n\t1081  631xESB/632xESB LAN Controller Copper\n\t1082  631xESB/632xESB LAN Controller fiber\n\t1083  631xESB/632xESB LAN Controller SERDES\n\t1084  631xESB/632xESB IDE Redirection\n\t1085  631xESB/632xESB Serial Port Redirection\n\t1086  631xESB/632xESB IPMI/KCS0\n\t1087  631xESB/632xESB UHCI Redirection\n\t1089  631xESB/632xESB BT\n\t108a  82546GB Gigabit Ethernet Controller\n\t\t8086 108a  PRO/1000 P Dual Port Server Adapter\n\t\t8086 118a  PRO/1000 P Dual Port Server Adapter\n\t108b  82573V Gigabit Ethernet Controller (Copper)\n\t\t1462 176c  on board on MSI 945P - NEO (MS-7176)\n\t108c  82573E Gigabit Ethernet Controller (Copper)\n\t108e  82573E KCS (Active Management)\n\t108f  Active Management Technology - SOL\n\t1091  PRO/100 VM Network Connection\n\t1092  PRO/100 VE Network Connection\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t1093  PRO/100 VM Network Connection\n\t1094  PRO/100 VE Network Connection\n\t1095  PRO/100 VE Network Connection\n\t1096  80003ES2LAN Gigabit Ethernet Controller (Copper)\n\t\t15d9 1096  Motherboard\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t1097  631xESB/632xESB DPT LAN Controller (Fiber)\n\t1098  80003ES2LAN Gigabit Ethernet Controller (Serdes)\n\t1099  82546GB Gigabit Ethernet Controller (Copper)\n\t\t8086 1099  PRO/1000 GT Quad Port Server Adapter\n\t109a  82573L Gigabit Ethernet Controller\n\t\t1179 ff10  PRO/1000 PL\n\t\t17aa 2001  ThinkPad T60\n\t\t17aa 207e  ThinkPad X60/X60s\n\t\t8086 109a  PRO/1000 PL Network Connection\n\t\t8086 309c  Desktop Board D945GTP\n\t\t8086 30a5  Desktop Board D975XBX\n\t109b  82546GB PRO/1000 GF Quad Port Server Adapter\n\t109e  82597EX 10GbE Ethernet Controller\n\t\t8086 a01f  PRO/10GbE CX4 Server Adapter\n\t\t8086 a11f  PRO/10GbE CX4 Server Adapter\n\t10a0  82571EB PRO/1000 AT Quad Port Bypass Adapter\n\t10a1  82571EB PRO/1000 AF Quad Port Bypass Adapter\n\t10a4  82571EB Gigabit Ethernet Controller\n\t\t8086 10a4  PRO/1000 PT Quad Port Server Adapter\n\t\t8086 11a4  PRO/1000 PT Quad Port Server Adapter\n\t10a5  82571EB Gigabit Ethernet Controller (Fiber)\n\t\t8086 10a5  PRO/1000 PF Quad Port Server Adapter\n\t\t8086 10a6  PRO/1000 PF Quad Port Server Adapter\n\t10a6  82599EB 10-Gigabit Dummy Function\n\t10a7  82575EB Gigabit Network Connection\n\t\t8086 10a8  82575EB Gigabit Riser Card\n\t10a9  82575EB Gigabit Backplane Connection\n\t10b0  82573L PRO/1000 PL Network Connection\n\t10b2  82573V PRO/1000 PM Network Connection\n\t10b3  82573E PRO/1000 PM Network Connection\n\t10b4  82573L PRO/1000 PL Network Connection\n\t10b5  82546GB Gigabit Ethernet Controller (Copper)\n\t\t103c 3109  NC340T PCI-X Quad-port Gigabit Server Adapter\n\t\t8086 1099  PRO/1000 GT Quad Port Server Adapter\n\t\t8086 1199  PRO/1000 GT Quad Port Server Adapter\n\t10b6  82598 10GbE PCI-Express Ethernet Controller\n\t10b9  82572EI Gigabit Ethernet Controller (Copper)\n\t\t103c 704a  110T PCIe Gigabit Server Adapter\n\t\t8086 1083  PRO/1000 PT Desktop Adapter\n\t\t8086 1093  PRO/1000 PT Desktop Adapter\n\t10ba  80003ES2LAN Gigabit Ethernet Controller (Copper)\n\t10bb  80003ES2LAN Gigabit Ethernet Controller (Serdes)\n\t10bc  82571EB/82571GB Gigabit Ethernet Controller (Copper)\n\t\t1014 0368  4-Port 10/100/1000 Base-TX PCI Express Adapter for POWER\n\t\t103c 704b  NC364T PCI Express Quad Port Gigabit Server Adapter\n# 375-3481-01 REV:50\n\t\t108e 11bc  Quad Port Adapter\n\t\t8086 10bc  PRO/1000 PT Quad Port LP Server Adapter\n\t\t8086 11bc  PRO/1000 PT Quad Port LP Server Adapter (Kirkwood Low Profile)\n\t10bd  82566DM-2 Gigabit Network Connection\n\t\t1028 0211  OptiPlex 755\n\t10bf  82567LF Gigabit Network Connection\n\t10c0  82562V-2 10/100 Network Connection\n\t\t1028 020d  Inspiron 530\n\t10c2  82562G-2 10/100 Network Connection\n\t10c3  82562GT-2 10/100 Network Connection\n\t10c4  82562GT 10/100 Network Connection\n\t10c5  82562G 10/100 Network Connection\n\t10c6  82598EB 10-Gigabit AF Dual Port Network Connection\n\t\t8086 a05f  10-Gigabit XF SR Dual Port Server Adapter\n\t\t8086 a15f  10-Gigabit XF SR Dual Port Server Adapter\n\t10c7  82598EB 10-Gigabit AF Network Connection\n\t\t1014 037f  10-Gigabit XF SR Server Adapter\n\t\t1014 0380  10-Gigabit XF LR Server Adapter\n\t\t8086 a05f  10-Gigabit XF SR Server Adapter\n\t\t8086 a15f  10-Gigabit XF SR Server Adapter\n\t\t8086 a16f  10-Gigabit XF SR Server Adapter\n\t10c8  82598EB 10-Gigabit AT Network Connection\n\t\t8086 a10c  10-Gigabit AT Server Adapter\n\t\t8086 a11c  10-Gigabit AT Server Adapter\n\t\t8086 a12c  10-Gigabit AT Server Adapter\n\t10c9  82576 Gigabit Network Connection\n\t\t103c 31ef  NC362i Integrated Dual port Gigabit Server Adapter\n\t\t103c 323f  NC362i Integrated Dual port Gigabit Server Adapter\n\t\t10a9 8028  UV-BaseIO dual-port GbE\n\t\t13a3 0037  DS4100 Secure Multi-Gigabit Server Adapter with Compression\n\t\t15d9 a811  H8DGU\n\t\t8086 a01c  Gigabit ET Dual Port Server Adapter\n\t\t8086 a03c  Gigabit ET Dual Port Server Adapter\n\t\t8086 a04c  Gigabit ET Dual Port Server Adapter\n\t10ca  82576 Virtual Function\n\t10cb  82567V Gigabit Network Connection\n\t10cc  82567LM-2 Gigabit Network Connection\n\t10cd  82567LF-2 Gigabit Network Connection\n\t10ce  82567V-2 Gigabit Network Connection\n\t10d3  82574L Gigabit Network Connection\n\t\t103c 1785  NC112i 1-port Ethernet Server Adapter\n\t\t103c 3250  NC112T PCI Express single Port Gigabit Server Adapter\n\t\t1043 8369  Motherboard\n\t\t1093 76e9  PCIe-8233 Ethernet Adapter\n\t\t10a9 8029  Prism XL Single Port Gigabit Ethernet\n\t\t15d9 0605  X8SIL\n\t\t15d9 060a  X7SPA-H/X7SPA-HF Motherboard\n\t\t15d9 060d  C7SIM-Q Motherboard\n\t\t8086 0001  Gigabit CT2 Desktop Adapter\n\t\t8086 3578  Server Board S1200BTLR\n\t\t8086 357a  Server Board S1200BTS\n\t\t8086 a01f  Gigabit CT Desktop Adapter\n\t\te4bf 50c1  PC1-GROOVE\n\t\te4bf 50c2  PC2-LIMBO\n\t10d4  Matrox Concord GE (customized Intel 82574)\n\t10d5  82571PT Gigabit PT Quad Port Server ExpressModule\n\t10d6  82575GB Gigabit Network Connection\n\t\t8086 10d6  Gigabit VT Quad Port Server Adapter\n\t\t8086 145a  Gigabit VT Quad Port Server Adapter\n\t\t8086 147a  Gigabit VT Quad Port Server Adapter\n\t10d8  82599EB 10 Gigabit Unprogrammed\n\t10d9  82571EB Dual Port Gigabit Mezzanine Adapter\n\t\t103c 1716  NC360m Dual Port 1GbE BL-c Adapter\n\t10da  82571EB Quad Port Gigabit Mezzanine Adapter\n\t\t103c 1717  NC364m Quad Port 1GbE BL-c Adapter\n\t10db  82598EB 10-Gigabit Dual Port Network Connection\n\t10dd  82598EB 10-Gigabit AT CX4 Network Connection\n\t10de  82567LM-3 Gigabit Network Connection\n\t10df  82567LF-3 Gigabit Network Connection\n\t10e1  82598EB 10-Gigabit AF Dual Port Network Connection\n\t\t8086 a15f  10-Gigabit SR Dual Port Express Module\n\t10e2  82575GB Gigabit Network Connection\n\t\t8086 10e2  Gigabit VT Quad Port Server Adapter\n\t10e5  82567LM-4 Gigabit Network Connection\n\t10e6  82576 Gigabit Network Connection\n\t\t8086 a01f  Gigabit EF Dual Port Server Adapter\n\t\t8086 a02f  Gigabit EF Dual Port Server Adapter\n\t10e7  82576 Gigabit Network Connection\n\t\t103c 31ff  NC362i Integrated Dual Port BL-c Gigabit Server Adapter\n\t10e8  82576 Gigabit Network Connection\n\t\t8086 a02b  Gigabit ET Quad Port Server Adapter\n\t\t8086 a02c  Gigabit ET Quad Port Server Adapter\n\t10ea  82577LM Gigabit Network Connection\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\te4bf 50c1  PC1-GROOVE\n\t10eb  82577LC Gigabit Network Connection\n\t10ec  82598EB 10-Gigabit AT CX4 Network Connection\n\t\t8086 a01f  10-Gigabit CX4 Dual Port Server Adapter\n\t\t8086 a11f  10-Gigabit CX4 Dual Port Server Adapter\n\t10ed  82599 Ethernet Controller Virtual Function\n\t10ef  82578DM Gigabit Network Connection\n\t\t1028 02da  OptiPlex 980\n\t\t15d9 060d  C7SIM-Q Motherboard\n\t10f0  82578DC Gigabit Network Connection\n\t10f1  82598EB 10-Gigabit AF Dual Port Network Connection\n\t\t8086 a20f  10-Gigabit AF DA Dual Port Server Adapter\n\t\t8086 a21f  10-Gigabit AF DA Dual Port Server Adapter\n\t10f4  82598EB 10-Gigabit AF Network Connection\n\t\t8086 106f  10-Gigabit XF LR Server Adapter\n\t\t8086 a06f  10-Gigabit XF LR Server Adapter\n\t10f5  82567LM Gigabit Network Connection\n\t\t17aa 20ee  ThinkPad T400\n\t10f6  82574L Gigabit Network Connection\n\t10f7  10 Gigabit BR KX4 Dual Port Network Connection\n\t\t108e 7b12  Sun Dual 10GbE PCIe 2.0 FEM\n\t\t8086 000d  Ethernet Mezzanine Adapter X520-KX4-2\n\t10f8  82599 10 Gigabit Dual Port Backplane Connection\n\t\t1028 1f63  10GbE 2P X520k bNDC\n\t\t103c 17d2  Ethernet 10Gb 2-port 560M Adapter\n\t\t103c 18d0  Ethernet 10Gb 2-port 560FLB Adapter\n\t\t1059 0111  T4007 10GbE interface\n\t\t1059 0130  T4009 10GbE interface\n\t\t8086 000c  Ethernet X520 10GbE Dual Port KX4-KR Mezz\n\t10f9  82599 10 Gigabit Dual Port Network Connection\n\t10fb  82599ES 10-Gigabit SFI/SFP+ Network Connection\n\t\t1028 1f72  Ethernet 10G 4P X520/I350 rNDC\n\t\t103c 17d0  Ethernet 10Gb 2-port 560FLR-SFP+ Adapter\n\t\t103c 17d2  Ethernet 10Gb 2-port 560M Adapter\n\t\t103c 17d3  Ethernet 10Gb 2-port 560SFP+ Adapter\n\t\t103c 211b  Ethernet 10Gb 1-port P560FLR-SFP+ Adapter\n\t\t103c 2147  Ethernet 10Gb 1-port 561i Adapter\n\t\t103c 2159  Ethernet 10Gb 2-port 562i Adapter\n\t\t108e 7b11  Ethernet Server Adapter X520-2\n\t\t1170 004c  82599 DP 10G Mezzanine Adapter\n\t\t15d9 0611  AOC-STGN-I2S [REV 1.01]\n\t\t1734 11a9  10 Gigabit Dual Port Network Connection\n\t\t17aa 1071  ThinkServer X520-2 AnyFabric\n\t\t17aa 4007  82599ES 10-Gigabit SFI/SFP+ Network Connection\n\t\t17aa 402b  82599ES 10Gb 2-port Server Adapter X520-DA2\n\t\t17aa 402f  FPGA Card XC7VX690T-3FFG1157E\n\t\t18d4 0c09  82599ES 10Gb 2-port SFP+ OCP Mezz Card MOP81-I-10GS2\n\t\t193d 1004  560F-B\n\t\t1bd4 001b  10G SFP+ DP ER102Fi4 Rack Adapter\n\t\t1bd4 002f  10G SFP+ DP EP102Fi4A Adapter\n\t\t1bd4 0032  10G SFP+ DP EP102Fi4 Adapter\n\t\t8086 0002  Ethernet Server Adapter X520-DA2\n\t\t8086 0003  Ethernet Server Adapter X520-2\n\t\t8086 0006  Ethernet Server Adapter X520-1\n\t\t8086 0008  Ethernet OCP Server Adapter X520-2\n\t\t8086 000a  Ethernet Server Adapter X520-1\n\t\t8086 000c  Ethernet Server Adapter X520-2\n\t\t8086 10a6  82599ES 10Gb 2 port Server Adapter X520-DA2\n\t\t8086 7a11  Ethernet Server Adapter X520-2\n\t\t8086 7a12  Ethernet Server Adapter X520-2\n\t10fc  82599 10 Gigabit Dual Port Network Connection\n\t10fe  82552 10/100 Network Connection\n\t1107  PRO/1000 MF Server Adapter (LX)\n\t1130  82815 815 Chipset Host Bridge and Memory Controller Hub\n\t\t1025 1016  Travelmate 612 TX\n\t\t1043 8027  TUSL2-C Mainboard\n\t\t104d 80df  Vaio PCG-FX403\n\t\t8086 4532  Desktop Board D815EEA2/D815EFV\n\t\t8086 4557  D815EGEW Mainboard\n\t1131  82815 815 Chipset AGP Bridge\n\t1132  82815 Chipset Graphics Controller (CGC)\n\t\t1025 1016  Travelmate 612 TX\n\t\t103c 2001  e-pc 40\n\t\t104d 80df  Vaio PCG-FX403\n\t\t8086 4532  Desktop Board D815EEA2/D815EFV\n\t\t8086 4541  D815EEA Motherboard\n\t\t8086 4557  D815EGEW Mainboard\n\t1161  82806AA PCI64 Hub Advanced Programmable Interrupt Controller\n\t\t8086 1161  82806AA PCI64 Hub APIC\n\t1162  Xscale 80200 Big Endian Companion Chip\n\t1190  Merrifield SD/SDIO/eMMC Controller\n\t1191  Merrifield Serial IO HSUART Controller\n\t1192  Merrifield Serial IO HSUART DMA Controller\n\t1194  Merrifield Serial IO SPI Controller\n\t1195  Merrifield Serial IO I2C Controller\n\t1196  Merrifield Serial IO I2C Controller\n\t1199  Merrifield GPIO Controller\n\t119e  Merrifield USB Device Controller (OTG)\n\t11a0  Merrifield SCU IPC\n\t11a1  Merrifield Power Management Unit\n\t11a2  Merrifield Serial IO DMA Controller\n\t11a5  Merrifield Serial IO PWM Controller\n\t11c3  Quark SoC X1000 PCIe Root Port 0\n\t11c4  Quark SoC X1000 PCIe Root Port 1\n\t1200  IXP1200 Network Processor\n\t\t172a 0000  AEP SSL Accelerator\n\t1209  8255xER/82551IT Fast Ethernet Controller\n\t\t140b 0610  PMC610 quad Ethernet board\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t4c53 1050  CT7 mainboard\n\t\t4c53 1051  CE7 mainboard\n\t\t4c53 1070  PC6 mainboard\n\t1221  82092AA PCI to PCMCIA Bridge\n\t1222  82092AA IDE Controller\n\t1223  SAA7116\n\t1225  82452KX/GX [Orion]\n\t1226  82596 PRO/10 PCI\n\t1227  82865 EtherExpress PRO/100A\n\t1228  82556 EtherExpress PRO/100 Smart\n\t1229  82557/8/9/0/1 Ethernet Pro 100\n\t\t0e11 3001  82559 Fast Ethernet LOM with Alert on LAN*\n\t\t0e11 3002  82559 Fast Ethernet LOM with Alert on LAN*\n\t\t0e11 3003  82559 Fast Ethernet LOM with Alert on LAN*\n\t\t0e11 3004  82559 Fast Ethernet LOM with Alert on LAN*\n\t\t0e11 3005  82559 Fast Ethernet LOM with Alert on LAN*\n\t\t0e11 3006  82559 Fast Ethernet LOM with Alert on LAN*\n\t\t0e11 3007  82559 Fast Ethernet LOM with Alert on LAN*\n\t\t0e11 b01e  NC3120 Fast Ethernet NIC\n\t\t0e11 b01f  NC3122 Fast Ethernet NIC (dual port)\n\t\t0e11 b02f  NC1120 Ethernet NIC\n\t\t0e11 b04a  Netelligent 10/100TX NIC with Wake on LAN\n\t\t0e11 b0c6  NC3161 Fast Ethernet NIC (embedded, WOL)\n\t\t0e11 b0c7  NC3160 Fast Ethernet NIC (embedded)\n\t\t0e11 b0d7  NC3121 Fast Ethernet NIC (WOL)\n\t\t0e11 b0dd  NC3131 Fast Ethernet NIC (dual port)\n\t\t0e11 b0de  NC3132 Fast Ethernet Module (dual port)\n\t\t0e11 b0e1  NC3133 Fast Ethernet Module (100-FX)\n\t\t0e11 b134  NC3163 Fast Ethernet NIC (embedded, WOL)\n\t\t0e11 b13c  NC3162 Fast Ethernet NIC (embedded)\n\t\t0e11 b144  NC3123 Fast Ethernet NIC (WOL)\n\t\t0e11 b163  NC3134 Fast Ethernet NIC (dual port)\n\t\t0e11 b164  NC3135 Fast Ethernet Upgrade Module (dual port)\n\t\t0e11 b1a4  NC7131 Gigabit Server Adapter\n\t\t1014 005c  82558B Ethernet Pro 10/100\n\t\t1014 01bc  82559 Fast Ethernet LAN On Motherboard\n\t\t1014 01f1  10/100 Ethernet Server Adapter\n\t\t1014 01f2  10/100 Ethernet Server Adapter\n\t\t1014 0207  Ethernet Pro/100 S\n\t\t1014 0232  10/100 Dual Port Server Adapter\n\t\t1014 023a  ThinkPad R30\n\t\t1014 105c  Netfinity 10/100\n\t\t1014 2205  ThinkPad A22p\n\t\t1014 305c  10/100 EtherJet Management Adapter\n\t\t1014 405c  10/100 EtherJet Adapter with Alert on LAN\n\t\t1014 505c  10/100 EtherJet Secure Management Adapter\n\t\t1014 605c  10/100 EtherJet Secure Management Adapter\n\t\t1014 705c  10/100 Netfinity 10/100 Ethernet Security Adapter\n\t\t1014 805c  10/100 Netfinity 10/100 Ethernet Security Adapter\n\t\t1028 009b  10/100 Ethernet Server Adapter\n\t\t1028 00ce  10/100 Ethernet Server Adapter\n\t\t1033 8000  PC-9821X-B06\n\t\t1033 8016  PK-UG-X006\n\t\t1033 801f  PK-UG-X006\n\t\t1033 8026  PK-UG-X006\n\t\t1033 8063  82559-based Fast Ethernet Adapter\n\t\t1033 8064  82559-based Fast Ethernet Adapter\n\t\t103c 10c0  NetServer 10/100TX\n\t\t103c 10c3  NetServer 10/100TX\n\t\t103c 10ca  NetServer 10/100TX\n\t\t103c 10cb  NetServer 10/100TX\n\t\t103c 10e3  NetServer 10/100TX\n\t\t103c 10e4  NetServer 10/100TX\n\t\t103c 1200  NetServer 10/100TX\n\t\t108e 10cf  EtherExpress PRO/100(B)\n\t\t10c3 1100  SmartEther100 SC1100\n\t\t10cf 1115  8255x-based Ethernet Adapter (10/100)\n\t\t10cf 1143  8255x-based Ethernet Adapter (10/100)\n\t\t110a 008b  82551QM Fast Ethernet Multifuction PCI/CardBus Controller\n\t\t114a 0582  PC8 onboard ethernet ETH2\n\t\t1179 0001  8255x-based Ethernet Adapter (10/100)\n\t\t1179 0002  PCI FastEther LAN on Docker\n\t\t1179 0003  8255x-based Fast Ethernet\n\t\t1259 2560  AT-2560 100\n\t\t1259 2561  AT-2560 100 FX Ethernet Adapter\n\t\t1266 0001  NE10/100 Adapter\n\t\t13e9 1000  6221L-4U\n\t\t144d 2501  SEM-2000 MiniPCI LAN Adapter\n\t\t144d 2502  SEM-2100IL MiniPCI LAN Adapter\n\t\t1668 1100  EtherExpress PRO/100B (TX) (MiniPCI Ethernet+Modem)\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t1775 ce90  CE9\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t4c53 1080  CT8 mainboard\n\t\t4c53 10e0  PSL09 PrPMC\n\t\t8086 0001  EtherExpress PRO/100B (TX)\n\t\t8086 0002  EtherExpress PRO/100B (T4)\n\t\t8086 0003  EtherExpress PRO/10+\n\t\t8086 0004  EtherExpress PRO/100 WfM\n\t\t8086 0005  82557 10/100\n\t\t8086 0006  82557 10/100 with Wake on LAN\n\t\t8086 0007  82558 10/100 Adapter\n\t\t8086 0008  82558 10/100 with Wake on LAN\n\t\t8086 0009  82558B PRO/100+ PCI (TP)\n\t\t8086 000a  EtherExpress PRO/100+ Management Adapter\n\t\t8086 000b  EtherExpress PRO/100+\n\t\t8086 000c  EtherExpress PRO/100+ Management Adapter\n\t\t8086 000d  EtherExpress PRO/100+ Alert On LAN II* Adapter\n\t\t8086 000e  EtherExpress PRO/100+ Management Adapter with Alert On LAN*\n\t\t8086 000f  EtherExpress PRO/100 Desktop Adapter\n\t\t8086 0010  EtherExpress PRO/100 S Management Adapter\n\t\t8086 0011  EtherExpress PRO/100 S Management Adapter\n\t\t8086 0012  EtherExpress PRO/100 S Advanced Management Adapter (D)\n\t\t8086 0013  EtherExpress PRO/100 S Advanced Management Adapter (E)\n\t\t8086 0030  EtherExpress PRO/100  Management Adapter with Alert On LAN* GC\n\t\t8086 0031  EtherExpress PRO/100 Desktop Adapter\n\t\t8086 0040  EtherExpress PRO/100 S Desktop Adapter\n\t\t8086 0041  EtherExpress PRO/100 S Desktop Adapter\n\t\t8086 0042  EtherExpress PRO/100 Desktop Adapter\n\t\t8086 0050  EtherExpress PRO/100 S Desktop Adapter\n\t\t8086 1009  EtherExpress PRO/100+ Server Adapter\n\t\t8086 100c  EtherExpress PRO/100+ Server Adapter (PILA8470B)\n\t\t8086 1012  EtherExpress PRO/100 S Server Adapter (D)\n\t\t8086 1013  EtherExpress PRO/100 S Server Adapter (E)\n\t\t8086 1015  EtherExpress PRO/100 S Dual Port Server Adapter\n\t\t8086 1017  EtherExpress PRO/100+ Dual Port Server Adapter\n\t\t8086 1030  EtherExpress PRO/100+ Management Adapter with Alert On LAN* G Server\n\t\t8086 1040  EtherExpress PRO/100 S Server Adapter\n\t\t8086 1041  EtherExpress PRO/100 S Server Adapter\n\t\t8086 1042  EtherExpress PRO/100 Server Adapter\n\t\t8086 1050  EtherExpress PRO/100 S Server Adapter\n\t\t8086 1051  EtherExpress PRO/100 Server Adapter\n\t\t8086 1052  EtherExpress PRO/100 Server Adapter\n\t\t8086 10f0  EtherExpress PRO/100+ Dual Port Adapter\n\t\t8086 1229  82557/8/9 [Ethernet Pro 100]\n\t\t8086 2009  EtherExpress PRO/100 S Mobile Adapter\n\t\t8086 200d  EtherExpress PRO/100 Cardbus\n\t\t8086 200e  EtherExpress PRO/100 LAN+V90 Cardbus Modem\n\t\t8086 200f  EtherExpress PRO/100 SR Mobile Adapter\n\t\t8086 2010  EtherExpress PRO/100 S Mobile Combo Adapter\n\t\t8086 2013  EtherExpress PRO/100 SR Mobile Combo Adapter\n\t\t8086 2016  EtherExpress PRO/100 S Mobile Adapter\n\t\t8086 2017  EtherExpress PRO/100 S Combo Mobile Adapter\n\t\t8086 2018  EtherExpress PRO/100 SR Mobile Adapter\n\t\t8086 2019  EtherExpress PRO/100 SR Combo Mobile Adapter\n\t\t8086 2101  EtherExpress PRO/100 P Mobile Adapter\n\t\t8086 2102  EtherExpress PRO/100 SP Mobile Adapter\n\t\t8086 2103  EtherExpress PRO/100 SP Mobile Adapter\n\t\t8086 2104  EtherExpress PRO/100 SP Mobile Adapter\n\t\t8086 2105  EtherExpress PRO/100 SP Mobile Adapter\n\t\t8086 2106  EtherExpress PRO/100 P Mobile Adapter\n\t\t8086 2107  EtherExpress PRO/100 Network Connection\n\t\t8086 2108  EtherExpress PRO/100 Network Connection\n\t\t8086 2200  EtherExpress PRO/100 P Mobile Combo Adapter\n\t\t8086 2201  EtherExpress PRO/100 P Mobile Combo Adapter\n\t\t8086 2202  EtherExpress PRO/100 SP Mobile Combo Adapter\n\t\t8086 2203  EtherExpress PRO/100+ MiniPCI\n\t\t8086 2204  EtherExpress PRO/100+ MiniPCI\n\t\t8086 2205  EtherExpress PRO/100 SP Mobile Combo Adapter\n\t\t8086 2206  EtherExpress PRO/100 SP Mobile Combo Adapter\n\t\t8086 2207  EtherExpress PRO/100 SP Mobile Combo Adapter\n\t\t8086 2208  EtherExpress PRO/100 P Mobile Combo Adapter\n\t\t8086 2402  EtherExpress PRO/100+ MiniPCI\n\t\t8086 2407  EtherExpress PRO/100+ MiniPCI\n\t\t8086 2408  EtherExpress PRO/100+ MiniPCI\n\t\t8086 2409  EtherExpress PRO/100+ MiniPCI\n\t\t8086 240f  EtherExpress PRO/100+ MiniPCI\n\t\t8086 2410  EtherExpress PRO/100+ MiniPCI\n\t\t8086 2411  EtherExpress PRO/100+ MiniPCI\n\t\t8086 2412  EtherExpress PRO/100+ MiniPCI\n\t\t8086 2413  EtherExpress PRO/100+ MiniPCI\n\t\t8086 3000  82559 Fast Ethernet LAN on Motherboard\n\t\t8086 3001  82559 Fast Ethernet LOM with Basic Alert on LAN*\n\t\t8086 3002  82559 Fast Ethernet LOM with Alert on LAN II*\n\t\t8086 3006  EtherExpress PRO/100 S Network Connection\n\t\t8086 3007  EtherExpress PRO/100 S Network Connection\n\t\t8086 3008  EtherExpress PRO/100 Network Connection\n\t\t8086 3010  EtherExpress PRO/100 S Network Connection\n\t\t8086 3011  EtherExpress PRO/100 S Network Connection\n\t\t8086 3012  EtherExpress PRO/100 Network Connection\n\t\t8086 301a  S845WD1-E mainboard\n\t\t8086 3411  SDS2 Mainboard\n\t122d  430FX - 82437FX TSC [Triton I]\n\t122e  82371FB PIIX ISA [Triton I]\n\t1230  82371FB PIIX IDE [Triton I]\n\t1231  DSVD Modem\n\t1234  430MX - 82371MX Mobile PCI I/O IDE Xcelerator (MPIIX)\n\t1235  430MX - 82437MX Mob. System Ctrlr (MTSC) & 82438MX Data Path (MTDP)\n\t1237  440FX - 82441FX PMC [Natoma]\n\t\t1af4 1100  Qemu virtual machine\n\t1239  82371FB PIIX IDE Interface\n\t123b  82380PB PCI to PCI Docking Bridge\n\t123c  82380AB (MISA) Mobile PCI-to-ISA Bridge\n\t123d  683053 Programmable Interrupt Device\n\t123e  82466GX (IHPC) Integrated Hot-Plug Controller (hidden mode)\n\t123f  82466GX Integrated Hot-Plug Controller (IHPC)\n\t1240  82752 (752) AGP Graphics Accelerator\n\t124b  82380FB (MPCI2) Mobile Docking Controller\n\t1250  430HX - 82439HX TXC [Triton II]\n\t1360  82806AA PCI64 Hub PCI Bridge\n\t1361  82806AA PCI64 Hub Controller (HRes)\n\t\t8086 1361  82806AA PCI64 Hub Controller (HRes)\n\t\t8086 8000  82806AA PCI64 Hub Controller (HRes)\n\t1460  82870P2 P64H2 Hub PCI Bridge\n\t1461  82870P2 P64H2 I/OxAPIC\n\t\t15d9 3480  P4DP6\n\t\t4c53 1090  Cx9/Vx9 mainboard\n\t1462  82870P2 P64H2 Hot Plug Controller\n\t1501  82567V-3 Gigabit Network Connection\n\t1502  82579LM Gigabit Network Connection (Lewisville)\n\t\t1028 04a3  Precision M4600\n\t\t17aa 21ce  ThinkPad T520\n\t\t8086 3578  Server Board S1200BTLR\n\t\t8086 357a  Server Board S1200BTS\n\t1503  82579V Gigabit Network Connection\n\t\t1043 849c  P8P67 Deluxe Motherboard\n\t1507  Ethernet Express Module X520-P2\n\t1508  82598EB Gigabit BX Network Connection\n\t1509  82580 Gigabit Network Connection\n\t150a  82576NS Gigabit Network Connection\n\t150b  82598EB 10-Gigabit AT2 Server Adapter\n\t\t8086 a10c  82598EB 10-Gigabit AT2 Server Adapter\n\t\t8086 a11c  82598EB 10-Gigabit AT2 Server Adapter\n\t\t8086 a12c  82598EB 10-Gigabit AT2 Server Adapter\n\t150c  82583V Gigabit Network Connection\n\t150d  82576 Gigabit Backplane Connection\n\t\t8086 a10c  Gigabit ET Quad Port Mezzanine Card\n\t150e  82580 Gigabit Network Connection\n\t\t103c 1780  NC365T 4-port Ethernet Server Adapter\n\t\t8086 12a1  Ethernet Server Adapter I340-T4\n\t\t8086 12a2  Ethernet Server Adapter I340-T4\n\t150f  82580 Gigabit Fiber Network Connection\n\t1510  82580 Gigabit Backplane Connection\n\t1511  82580 Gigabit SFP Connection\n\t1513  CV82524 Thunderbolt Controller [Light Ridge 4C 2010]\n\t1514  Ethernet X520 10GbE Dual Port KX4 Mezz\n\t\t8086 000b  Ethernet X520 10GbE Dual Port KX4 Mezz\n\t1515  X540 Ethernet Controller Virtual Function\n\t1516  82580 Gigabit Network Connection\n\t\t8086 12b1  Ethernet Server Adapter I340-T2\n\t\t8086 12b2  Ethernet Server Adapter I340-T2\n\t1517  82599ES 10 Gigabit Network Connection\n\t\t1137 006a  UCS CNA M61KR-I Intel Converged Network Adapter\n\t1518  82576NS SerDes Gigabit Network Connection\n\t151a  DSL2310 Thunderbolt Controller [Eagle Ridge 2C 2011]\n\t151b  CVL2510 Thunderbolt Controller [Light Peak 2C 2010]\n\t151c  82599 10 Gigabit TN Network Connection\n\t\t108e 7b13  Dual 10GBASE-T LP\n\t1520  I350 Ethernet Controller Virtual Function\n\t1521  I350 Gigabit Network Connection\n\t\t1028 0602  Gigabit 2P I350-t LOM\n\t\t1028 0693  Gigabit 2P I350-t LOM\n\t\t1028 06e2  Gigabit 2P I350-t LOM\n\t\t1028 0757  Gigabit I350-t LOM\n\t\t1028 075a  Gigabit I350-t LOM\n\t\t1028 1f60  Gigabit 4P I350-t rNDC\n\t\t1028 1f62  Gigabit 4P X540/I350 rNDC\n\t\t1028 1fa8  Ethernet 10G 4P X550/I350 rNDC\n\t\t1028 1fa9  Ethernet 10G 4P X550 rNDC\n\t\t1028 1faa  Gigabit 4P X550/I350 rNDC\n\t\t1028 ff9a  Gigabit 4P X710/I350 rNDC\n\t\t103c 17d1  Ethernet 1Gb 4-port 366FLR Adapter\n\t\t103c 2003  Ethernet 1Gb 2-port 367i Adapter\n\t\t103c 2226  Ethernet 1Gb 1-port 364i Adapter\n\t\t103c 337f  Ethernet 1Gb 2-port 361i Adapter\n\t\t103c 3380  Ethernet 1Gb 4-port 366i Adapter\n\t\t103c 339e  Ethernet 1Gb 2-port 361T Adapter\n\t\t103c 8157  Ethernet 1Gb 4-port 366T Adapter\n\t\t108e 7b16  Quad Port GbE PCIe 2.0 ExpressModule, UTP\n\t\t108e 7b18  Quad Port GbE PCIe 2.0 Low Profile Adapter, UTP\n\t\t1093 7648  PCIe-8237R Ethernet Adapter\n\t\t1093 7649  PCIe-8236 Ethernet Adapter\n\t\t1093 76b1  PCIe-8237R-S Ethernet Adapter\n\t\t1093 775b  PCIe-8237 Ethernet Adapter\n\t\t10a9 802a  UV2-BaseIO dual-port GbE\n\t\t1137 023e  1GigE I350 LOM\n\t\t15d9 0652  Dual Port i350 GbE MicroLP [AOC-CGP-i2]\n\t\t17aa 1074  ThinkServer I350-T4 AnyFabric\n\t\t17aa 4005  I350 Gigabit Network Connection\n\t\t18d4 0c07  I350 1Gb 2-port RJ45 OCP Mezz Card MOP41-I-1GT2\n\t\t193d 1005  360T-B\n\t\t193d 1007  360T-L\n\t\t1bd4 001d  1G base-T QP EP014Ti1 Adapter\n\t\t1bd4 0035  1G base-T QP EP014Ti1 Adapter\n\t\t8086 0001  Ethernet Server Adapter I350-T4\n\t\t8086 0002  Ethernet Server Adapter I350-T2\n\t\t8086 0003  Ethernet Network Adapter I350-T4 for OCP NIC 3.0\n\t\t8086 00a1  Ethernet Server Adapter I350-T4\n\t\t8086 00a2  Ethernet Server Adapter I350-T2\n\t\t8086 00a3  Ethernet Network Adapter I350-T4 for OCP NIC 3.0\n\t\t8086 00aa  Ethernet Network Adapter I350-T4 for OCP NIC 3.0\n\t\t8086 5001  Ethernet Server Adapter I350-T4\n\t\t8086 5002  Ethernet Server Adapter I350-T2\n\t\t8086 5003  Ethernet 1G 4P I350-t OCP\n\t1522  I350 Gigabit Fiber Network Connection\n\t\t108e 7b17  Quad Port GbE PCIe 2.0 ExpressModule, MMF\n\t\t108e 7b19  Dual Port GbE PCIe 2.0 Low Profile Adapter, MMF\n\t\t8086 0002  Ethernet Server Adapter I350-T2\n\t\t8086 0003  Ethernet Server Adapter I350-F4\n\t\t8086 0004  Ethernet Server Adapter I350-F2\n\t\t8086 0005  Ethernet Server Adapter I350-F1\n\t\t8086 00a2  Ethernet Server Adapter I350-T2\n\t\t8086 00a3  Ethernet Server Adapter I350-F4\n\t\t8086 00a4  Ethernet Server Adapter I350-F2\n\t1523  I350 Gigabit Backplane Connection\n\t\t1028 0060  Gigabit 2P I350 LOM\n\t\t1028 1f9b  Gigabit 4P I350-t bNDC\n\t\t103c 1784  Ethernet 1Gb 2-port 361FLB Adapter\n\t\t103c 18d1  Ethernet 1Gb 2-port 361FLB Adapter\n\t\t103c 1989  Ethernet 1Gb 2-port 363i Adapter\n\t\t103c 339f  Ethernet 1Gb 4-port 366M Adapter\n\t\t8086 1f52  1GbE 4P I350 Mezz\n\t1524  I350 Gigabit Connection\n\t1525  82567V-4 Gigabit Network Connection\n\t1526  82576 Gigabit Network Connection\n\t\t8086 a05c  Gigabit ET2 Quad Port Server Adapter\n\t\t8086 a06c  Gigabit ET2 Quad Port Server Adapter\n\t1527  82580 Gigabit Fiber Network Connection\n\t\t8086 0001  Ethernet Server Adapter I340-F4\n\t\t8086 0002  Ethernet Server Adapter I340-F4\n\t1528  Ethernet Controller 10-Gigabit X540-AT2\n\t\t1028 1f61  Ethernet 10G 4P X540/I350 rNDC\n\t\t103c 192d  561FLR-T 2-port 10Gb Ethernet Adapter\n\t\t103c 2004  Ethernet 10Gb 2-port 561i Adapter\n\t\t103c 211a  Ethernet 10Gb 2-port 561T Adapter\n\t\t108e 4853  Ethernet Controller 10-Gigabit X540-AT2\n\t\t108e 7b14  Sun Dual Port 10 GbE PCIe 2.0 ExpressModule, Base-T\n\t\t108e 7b15  Sun Dual Port 10 GbE PCIe 2.0 Low Profile Adapter, Base-T\n\t\t1137 00bf  Ethernet Converged Network Adapter X540-T2\n\t\t1170 0052  Ethernet Controller 10-Gigabit X540-AT2\n\t\t17aa 1073  ThinkServer X540-T2 AnyFabric\n\t\t17aa 4006  Ethernet Controller 10-Gigabit X540-AT2\n\t\t1bd4 001a  10G base-T DP ER102Ti3 Rack Adapter\n\t\t1bd4 0033  10G base-T DP EP102Ti3 Adapter\n\t\t1bd4 0034  10G base-T DP EP102Ti3A Adapter\n\t\t8086 0001  Ethernet Converged Network Adapter X540-T2\n\t\t8086 0002  Ethernet Converged Network Adapter X540-T1\n\t\t8086 001a  Ethernet Converged Network Adapter X540-T2\n\t\t8086 00a2  Ethernet Converged Network Adapter X540-T1\n\t\t8086 1f61  Ethernet 10G 4P X540/I350 rNDC\n\t\t8086 5003  Ethernet 10G 2P X540-t Adapter\n\t\t8086 5004  Ethernet 10G 2P X540-t Adapter\n\t1529  82599 10 Gigabit Dual Port Network Connection with FCoE\n\t152a  82599 10 Gigabit Dual Port Backplane Connection with FCoE\n\t152e  82599 Virtual Function\n\t152f  I350 Virtual Function\n\t1530  X540 Virtual Function\n\t1531  I210 Gigabit Unprogrammed\n\t1533  I210 Gigabit Network Connection\n\t\t103c 0003  Ethernet I210-T1 GbE NIC\n\t\t1059 0180  RD10019 1GbE interface\n\t\t1093 7706  Compact Vision System Ethernet Adapter\n\t\t10a9 802c  UV300 BaseIO single-port GbE\n\t\t10a9 802d  UV3000 BaseIO GbE Network\n\t\t17aa 1100  ThinkServer Ethernet Server Adapter\n\t\t8086 0001  Ethernet Server Adapter I210-T1\n\t\t8086 0002  Ethernet Server Adapter I210-T1\n\t1536  I210 Gigabit Fiber Network Connection\n\t1537  I210 Gigabit Backplane Connection\n\t\t1059 0110  T4005 1GbE interface\n\t\t1059 0111  T4007 1GbE interface\n\t\t1059 0120  T4008 1GbE interface\n\t\t1059 0130  T4009 1GbE interface\n\t\t1059 0140  T2035 1GbE interface\n\t\t1059 0150  RD-01068 1GbE interface\n\t\t1059 0170  RD-01213 10GbE interface\n\t1538  I210 Gigabit Network Connection\n\t1539  I211 Gigabit Network Connection\n\t153a  Ethernet Connection I217-LM\n\t\t103c 1909  ZBook 15\n\t\t17aa 220e  ThinkPad T440p\n\t\t17aa 309f  ThinkCentre M83\n\t153b  Ethernet Connection I217-V\n\t1547  DSL3510 Thunderbolt Controller [Cactus Ridge 4C 2012]\n\t1548  DSL3310 Thunderbolt Controller [Cactus Ridge 2C 2012]\n\t1549  DSL2210 Thunderbolt Controller [Port Ridge 1C 2011]\n\t154a  Ethernet Server Adapter X520-4\n\t\t8086 011a  Ethernet Converged Network Adapter X520-4\n\t\t8086 011b  Ethernet Converged Network Adapter X520-4\n\t\t8086 011c  Ethernet Converged Network Adapter X520-4\n\t154c  Ethernet Virtual Function 700 Series\n\t154d  Ethernet 10G 2P X520 Adapter\n\t\t8086 7b11  10GbE 2P X520 Adapter\n\t1557  82599 10 Gigabit Network Connection\n\t\t17aa 4008  82599EN 10 Gigabit Network Connection\n\t\t1bd4 001c  10G SFP+ SP ER101Fi4 Rack Adapter\n\t\t1bd4 0030  10G SFP+ SP EP101Fi4A Adapter\n\t\t8086 0001  Ethernet OCP Server Adapter X520-1\n\t1558  Ethernet Converged Network Adapter X520-Q1\n\t\t8086 011a  Ethernet Converged Network Adapter X520-Q1\n\t\t8086 011b  Ethernet Converged Network Adapter X520-Q1\n\t1559  Ethernet Connection I218-V\n\t155a  Ethernet Connection I218-LM\n\t\t17aa 2214  ThinkPad X240\n\t155c  Ethernet Server Bypass Adapter\n\t\t8086 0001  Ethernet Server Bypass Adapter X540-T2\n\t155d  Ethernet Server Bypass Adapter\n\t\t8086 0001  Ethernet Server Bypass Adapter X520-SR2\n\t\t8086 0002  Ethernet Server Bypass Adapter X520-LR2\n\t1560  Ethernet Controller X540\n\t1563  Ethernet Controller 10G X550T\n\t\t1028 1fa8  Ethernet 10G 4P X550/I350 rNDC\n\t\t1028 1fa9  Ethernet 10G 4P X550 rNDC\n\t\t1137 02b2  X550-TX 10 Gig LOM\n\t\t1137 02b3  X550-TX 10 Gig LOM\n\t\t1170 0001  Intel Ethernet Controller X550-T2 OCP card\n\t\t14c0 1201  X550 10Gb 2P RJ45 OCP Mezz\n\t\t1590 00d1  Ethernet 10Gb 2-port 562T Adapter\n\t\t1590 00d2  Ethernet 10Gb 2-port 562FLR-T Adapter\n\t\t16b8 7217  Twin10G Thunderbolt 3 Edition\n\t\t18d4 0c08  X550 10Gb 2-port RJ45 OCP Mezz Card MOP81-I-10GT2\n\t\t193d 1008  560T-B\n\t\t193d 1009  560T-L\n\t\t8086 0001  Ethernet Converged Network Adapter X550-T2\n\t\t8086 001a  Ethernet Converged Network Adapter X550-T2\n\t\t8086 001b  Ethernet Server Adapter X550-T2 for OCP\n\t\t8086 001d  Ethernet 10G 2P X550-t Adapter\n\t\t8086 0022  Ethernet Converged Network Adapter X550-T2\n\t1564  X550 Virtual Function\n\t1565  X550 Virtual Function\n\t1566  DSL4410 Thunderbolt NHI [Redwood Ridge 2C 2013]\n\t1567  DSL4410 Thunderbolt Bridge [Redwood Ridge 2C 2013]\n\t1568  DSL4510 Thunderbolt NHI [Redwood Ridge 4C 2013]\n\t1569  DSL4510 Thunderbolt Bridge [Redwood Ridge 4C 2013]\n\t156a  DSL5320 Thunderbolt 2 NHI [Falcon Ridge 2C 2013]\n\t156b  DSL5320 Thunderbolt 2 Bridge [Falcon Ridge 2C 2013]\n\t156c  DSL5520 Thunderbolt 2 NHI [Falcon Ridge 4C 2013]\n\t156d  DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]\n\t156f  Ethernet Connection I219-LM\n\t\t1028 06dc  Latitude E7470\n\t\t103c 8079  EliteBook 840 G3\n\t1570  Ethernet Connection I219-V\n\t1571  Ethernet Virtual Function 700 Series\n\t1572  Ethernet Controller X710 for 10GbE SFP+\n\t\t1028 0000  Ethernet 10G X710 rNDC\n\t\t1028 1f99  Ethernet 10G 4P X710/I350 rNDC\n\t\t1028 1f9c  Ethernet 10G 4P X710 SFP+ rNDC\n\t\t103c 0000  Ethernet 10Gb 562SFP+ Adapter\n\t\t103c 22fc  Ethernet 10Gb 2-port 562FLR-SFP+ Adapter\n\t\t103c 22fd  Ethernet 10Gb 2-port 562SFP+ Adapter\n\t\t1137 0000  Ethernet Converged NIC X710-DA\n\t\t1137 013b  Ethernet Converged NIC X710-DA4\n\t\t1137 020a  Ethernet Converged NIC X710-DA2\n\t\t1590 0000  Ethernet Controller X710 for 10GbE SFP+\n\t\t1590 0225  Ethernet 10GbE 4P 563SFP+ Adapter\n\t\t1590 022f  Ethernet 10Gb 2-port 564i Communication Board\n\t\t17aa 0000  ThinkServer X710 AnyFabric for 10GbE SFP+\n\t\t17aa 4001  ThinkServer X710-4 AnyFabric for 10GbE SFP+\n\t\t17aa 4002  ThinkServer X710-2 AnyFabric for 10GbE SFP+\n\t\t19e5 d11c  Ethernet 2-port X710 10Gb SFP+ Adapter SP330\n\t\t8086 0000  Ethernet Converged Network Adapter X710\n\t\t8086 0001  Ethernet Converged Network Adapter X710-4\n\t\t8086 0002  Ethernet Converged Network Adapter X710-4\n\t\t8086 0004  Ethernet Converged Network Adapter X710-4\n\t\t8086 0005  Ethernet 10G 4P X710 Adapter\n\t\t8086 0006  Ethernet 10G 2P X710 Adapter\n\t\t8086 0007  Ethernet Converged Network Adapter X710-2\n\t\t8086 0008  Ethernet Converged Network Adapter X710-2\n\t\t8086 0009  Ethernet Controller X710 for 10GbE SFP+\n\t\t8086 000a  Ethernet Controller X710 for 10GbE SFP+\n\t\t8086 000b  Ethernet Server Adapter X710-DA2 for OCP\n\t\t8086 000d  Ethernet Controller X710 for 10GbE SFP+\n\t\t8086 000e  Ethernet Server Adapter OCP X710-2\n\t\t8086 000f  Ethernet Server Adapter OCP X710-2\n\t\t8086 0010  Ethernet Converged Network Adapter X710\n\t\t8086 0011  Ethernet Network Adapter X710-2 for OCP NIC 3.0\n\t\t8086 0012  Ethernet Network Adapter X710-4 for OCP NIC 3.0\n\t\t8086 0013  Ethernet 10G 2P X710 OCP\n\t\t8086 0014  Ethernet 10G 4P X710 OCP\n\t\t8086 0015  Ethernet Server Adapter X710-DA2 for OCP\n\t\t8086 00a1  Ethernet Network Adapter X710-2 for OCP NIC 3.0\n\t\t8086 00a2  Ethernet Network Adapter X710-4 for OCP NIC 3.0\n\t\t8086 4005  Ethernet Controller X710 for 10GbE SFP+\n\t\t8086 4006  Ethernet Controller X710 for 10GbE SFP+\n\t\t8086 4007  Ethernet Controller X710 for 10GbE SFP+\n\t1574  Ethernet Controller XL710 Emulation\n\t1575  DSL6340 Thunderbolt 3 NHI [Alpine Ridge 2C 2015]\n\t1576  DSL6340 Thunderbolt 3 Bridge [Alpine Ridge 2C 2015]\n\t1577  DSL6540 Thunderbolt 3 NHI [Alpine Ridge 4C 2015]\n\t1578  DSL6540 Thunderbolt 3 Bridge [Alpine Ridge 4C 2015]\n\t157b  I210 Gigabit Network Connection\n\t157c  I210 Gigabit Backplane Connection\n\t157d  DSL5110 Thunderbolt 2 NHI (Low Power) [Win Ridge 2C 2014]\n\t157e  DSL5110 Thunderbolt 2 Bridge (Low Power) [Win Ridge 2C 2014]\n\t1580  Ethernet Controller XL710 for 40GbE backplane\n\t1581  Ethernet Controller X710 for 10GbE backplane\n\t\t1028 0000  Ethernet 10G X710-k bNDC\n\t\t1028 1f98  Ethernet 10G 4P X710-k bNDC\n\t\t1028 1f9e  Ethernet 10G 2P X710-k bNDC\n\t\t1059 0150  RD-01068 10GbE-KR interface\n\t\t1059 0170  RD-01213 10GbE interface\n\t\t1590 0000  Ethernet 2-port 563i Adapter\n\t\t1590 00f8  Ethernet 2-port 563i Adapter\n\t\t8086 0000  Ethernet Converged Network Adapter XL710-Q2\n\t1583  Ethernet Controller XL710 for 40GbE QSFP+\n\t\t1028 0000  Ethernet 40G 2P XL710 QSFP+ rNDC\n\t\t1028 1f9f  Ethernet 40G 2P XL710 QSFP+ rNDC\n\t\t108e 0000  10 Gb/40 Gb Ethernet Adapter\n\t\t108e 7b1b  10 Gb/40 Gb Ethernet Adapter\n\t\t108e 7b1d  10Gb/40Gb Ethernet Adapter\n\t\t1137 0000  Ethernet Converged NIC XL710-QDA2\n\t\t1137 013c  Ethernet Converged NIC XL710-QDA2\n\t\t8086 0000  Ethernet Converged Network Adapter XL710-Q2\n\t\t8086 0001  Ethernet Converged Network Adapter XL710-Q2\n\t\t8086 0002  Ethernet Converged Network Adapter XL710-Q2\n\t\t8086 0003  Ethernet I/O Module XL710-Q2\n\t\t8086 0004  Ethernet Server Adapter XL710-Q2OCP\n\t\t8086 0006  Ethernet Converged Network Adapter XL710-Q2\n\t1584  Ethernet Controller XL710 for 40GbE QSFP+\n\t\t8086 0000  Ethernet Converged Network Adapter XL710-Q1\n\t\t8086 0001  Ethernet Converged Network Adapter XL710-Q1\n\t\t8086 0002  Ethernet Converged Network Adapter XL710-Q1\n\t\t8086 0003  Ethernet I/O Module XL710-Q1\n\t\t8086 0004  Ethernet Server Adapter XL710-Q1OCP\n\t1585  Ethernet Controller X710 for 10GbE QSFP+\n\t1586  Ethernet Controller X710 for 10GBASE-T\n\t\t108e 0000  Ethernet Controller X710 for 10GBASE-T\n\t\t108e 4857  Ethernet Controller X710 for 10GBASE-T\n\t1587  Ethernet Controller XL710 for 20GbE backplane\n\t\t103c 0000  Ethernet 10/20Gb 2-port 660FLB Adapter\n\t\t103c 22fe  Ethernet 10/20Gb 2-port 660FLB Adapter\n\t1588  Ethernet Controller XL710 for 20GbE backplane\n\t\t103c 0000  Ethernet 10/20Gb 2-port 660M Adapter\n\t\t103c 22ff  Ethernet 10/20Gb 2-port 660M Adapter\n\t\t1137 0000  Ethernet Network Adapter XXV710\n\t\t1137 02b4  Ethernet Network Adapter XXV710 OCP 2.0\n\t1589  Ethernet Controller X710/X557-AT 10GBASE-T\n\t\t108e 0000  Quad Port 10GBase-T Adapter\n\t\t108e 7b1c  Quad Port 10GBase-T Adapter\n\t\t8086 0000  Ethernet Converged Network Adapter X710-T\n\t\t8086 0001  Ethernet Converged Network Adapter X710-T4\n\t\t8086 0002  Ethernet Converged Network Adapter X710-T4\n\t\t8086 0003  Ethernet Converged Network Adapter X710-T\n\t\t8086 00a0  Ethernet Converged Network Adapter X710-T4\n\t\t8086 1003  Ethernet Converged Network Adapter X710-T\n\t158a  Ethernet Controller XXV710 for 25GbE backplane\n\t\t1590 0000  10/25Gb Ethernet Adapter\n\t\t1590 0286  Synergy 4610C 10/25Gb Ethernet Adapter\n\t\t8086 0000  Ethernet Controller XXV710 for 25GbE backplane\n\t\t8086 000a  Ethernet 25G 2P XXV710 Mezz\n\t158b  Ethernet Controller XXV710 for 25GbE SFP28\n\t\t1137 0000  Ethernet Network Adapter XXV710\n\t\t1137 0225  Ethernet Network Adapter XXV710\n\t\t1137 02b4  Ethernet Network Adapter XXV710 OCP 2.0\n\t\t1590 0000  Ethernet Network Adapter XXV710-2\n\t\t1590 0253  Ethernet 10/25/Gb 2-port 661SFP28 Adapter\n\t\t8086 0000  Ethernet Network Adapter XXV710\n\t\t8086 0001  Ethernet Network Adapter XXV710-2\n\t\t8086 0002  Ethernet Network Adapter XXV710-2\n\t\t8086 0003  Ethernet Network Adapter XXV710-1\n\t\t8086 0004  Ethernet Network Adapter XXV710-1\n\t\t8086 0005  Ethernet Network Adapter OCP XXV710-2\n\t\t8086 0006  Ethernet Network Adapter OCP XXV710-2\n\t\t8086 0007  Ethernet Network Adapter OCP XXV710-1\n\t\t8086 0008  Ethernet Network Adapter OCP XXV710-1\n\t\t8086 0009  Ethernet 25G 2P XXV710 Adapter\n\t\t8086 000a  Ethernet 25G 2P XXV710 OCP\n\t\t8086 4001  Ethernet Network Adapter XXV710-2\n\t1591  Ethernet Controller E810-C for backplane\n\t1592  Ethernet Controller E810-C for QSFP\n\t\t8086 0002  Ethernet Network Adapter E810-C-Q2\n\t\t8086 0004  Ethernet Network Adapter E810-C-Q2\n\t\t8086 0005  Ethernet Network Adapter E810-C-Q1 for OCP3.0\n\t\t8086 0006  Ethernet Network Adapter E810-C-Q2 for OCP3.0\n\t\t8086 0009  Ethernet Network Adapter E810-C-Q1\n\t1593  Ethernet Controller E810-C for SFP\n\t\t8086 0002  Ethernet Network Adapter E810-L-2\n\t\t8086 0005  Ethernet Network Adapter E810-XXV-4\n\t\t8086 0006  Ethernet Network Adapter E810-XXV-4\n\t\t8086 0007  Ethernet Network Adapter E810-XXV-4\n\t\t8086 0008  Ethernet Network Adapter E810-XXV-2\n\t\t8086 0009  Ethernet Network Adapter E810-XXV-2 for OCP 2.0\n\t15a0  Ethernet Connection (2) I218-LM\n\t15a1  Ethernet Connection (2) I218-V\n\t15a2  Ethernet Connection (3) I218-LM\n\t15a3  Ethernet Connection (3) I218-V\n\t15a4  Ethernet Switch FM10000 Host Interface\n\t15a5  Ethernet Switch FM10000 Host Virtual Interface\n\t15a8  Ethernet Connection X552 Virtual Function\n\t15a9  X552 Virtual Function\n\t15aa  Ethernet Connection X552 10 GbE Backplane\n\t\t1059 0120  T4008 10GbE interface\n\t15ab  Ethernet Connection X552 10 GbE Backplane\n\t\t1059 0150  RD-01068 10GbE interface\n\t\t1059 0170  RD-01213 10GbE interface\n\t15ac  Ethernet Connection X552 10 GbE SFP+\n\t\t1059 0160  RD-01167 10GbE interface\n\t15ad  Ethernet Connection X552/X557-AT 10GBASE-T\n\t15ae  Ethernet Connection X552 1000BASE-T\n\t15b0  Ethernet Connection X552 Backplane\n\t15b4  X553 Virtual Function\n\t15b5  DSL6340 USB 3.1 Controller [Alpine Ridge]\n\t15b6  DSL6540 USB 3.1 Controller [Alpine Ridge]\n\t15b7  Ethernet Connection (2) I219-LM\n\t15b8  Ethernet Connection (2) I219-V\n\t15b9  Ethernet Connection (3) I219-LM\n\t15bb  Ethernet Connection (7) I219-LM\n\t15bc  Ethernet Connection (7) I219-V\n\t15bd  Ethernet Connection (6) I219-LM\n\t15be  Ethernet Connection (6) I219-V\n\t15bf  JHL6240 Thunderbolt 3 NHI (Low Power) [Alpine Ridge LP 2016]\n\t15c0  JHL6240 Thunderbolt 3 Bridge (Low Power) [Alpine Ridge LP 2016]\n\t15c1  JHL6240 Thunderbolt 3 USB 3.1 Controller (Low Power) [Alpine Ridge LP 2016]\n\t15c2  Ethernet Connection X553 Backplane\n\t15c3  Ethernet Connection X553 Backplane\n\t15c4  Ethernet Connection X553 10 GbE SFP+\n\t15c5  X553 Virtual Function\n\t15c6  Ethernet Connection X553 1GbE\n\t15c7  Ethernet Connection X553 1GbE\n\t15c8  Ethernet Connection X553/X557-AT 10GBASE-T\n\t15ce  Ethernet Connection X553 10 GbE SFP+\n\t15d0  Ethernet SDI Adapter\n\t\t8086 0001  Ethernet SDI Adapter FM10420-100GbE-QDA2\n\t\t8086 0002  Ethernet SDI Adapter FM10840-MTP2\n\t15d1  Ethernet Controller 10G X550T\n\t\t8086 0002  Ethernet Converged Network Adapter X550-T1\n\t\t8086 001b  Ethernet Server Adapter X550-T1 for OCP\n\t\t8086 0021  Ethernet Converged Network Adapter X550-T1\n\t\t8086 00a2  Ethernet Converged Network Adapter X550-T1\n\t15d2  JHL6540 Thunderbolt 3 NHI (C step) [Alpine Ridge 4C 2016]\n\t15d3  JHL6540 Thunderbolt 3 Bridge (C step) [Alpine Ridge 4C 2016]\n\t15d4  JHL6540 Thunderbolt 3 USB Controller (C step) [Alpine Ridge 4C 2016]\n\t15d5  Ethernet SDI Adapter FM10420-25GbE-DA2\n\t\t8086 0001  Intel(R) Ethernet SDI Adapter FM10420-25GbE-DA2\n\t15d6  Ethernet Connection (5) I219-V\n\t15d7  Ethernet Connection (4) I219-LM\n\t15d8  Ethernet Connection (4) I219-V\n\t\t17aa 2247  ThinkPad T570\n\t\t17aa 224f  ThinkPad X1 Carbon 5th Gen\n\t\t17aa 225d  ThinkPad T480\n\t15d9  JHL6340 Thunderbolt 3 NHI (C step) [Alpine Ridge 2C 2016]\n\t15da  JHL6340 Thunderbolt 3 Bridge (C step) [Alpine Ridge 2C 2016]\n\t15db  JHL6340 Thunderbolt 3 USB 3.1 Controller (C step) [Alpine Ridge 2C 2016]\n\t15df  Ethernet Connection (8) I219-LM\n\t15e0  Ethernet Connection (8) I219-V\n\t15e1  Ethernet Connection (9) I219-LM\n\t15e2  Ethernet Connection (9) I219-V\n\t15e3  Ethernet Connection (5) I219-LM\n\t15e4  Ethernet Connection X553 1GbE\n\t15e5  Ethernet Connection X553 1GbE\n\t15e7  JHL7540 Thunderbolt 3 Bridge [Titan Ridge 2C 2018]\n\t15e8  JHL7540 Thunderbolt 3 NHI [Titan Ridge 2C 2018]\n\t15e9  JHL7540 Thunderbolt 3 USB Controller [Titan Ridge 2C 2018]\n\t15ea  JHL7540 Thunderbolt 3 Bridge [Titan Ridge 4C 2018]\n\t15eb  JHL7540 Thunderbolt 3 NHI [Titan Ridge 4C 2018]\n\t15ec  JHL7540 Thunderbolt 3 USB Controller [Titan Ridge 4C 2018]\n\t15ef  JHL7540 Thunderbolt 3 Bridge [Titan Ridge DD 2018]\n\t15f0  JHL7540 Thunderbolt 3 USB Controller [Titan Ridge DD 2018]\n\t15f6  I210 Gigabit Ethernet Connection\n\t15ff  Ethernet Controller X710 for 10GBASE-T\n\t\t1137 0000  X710TLG GbE RJ45 PCIe NIC\n\t\t1137 02c1  X710T2LG 2x10 GbE RJ45 PCIe NIC\n\t\t1137 02c2  X710T4LG 4x10 GbE RJ45 PCIe NIC\n\t\t8086 0000  Ethernet Network Adapter X710-TL\n\t\t8086 0001  Ethernet Network Adapter X710-T4L\n\t\t8086 0002  Ethernet Network Adapter X710-T4L\n\t\t8086 0003  Ethernet Network Adapter X710-T2L\n\t\t8086 0004  Ethernet Network Adapter X710-T2L\n\t\t8086 0005  Ethernet 10G 2P X710-T2L-t Adapter\n\t\t8086 0006  Ethernet 10G 4P X710-T4L-t Adapter\n\t\t8086 0007  Ethernet 10G 2P X710-T2L-t OCP\n\t\t8086 0008  Ethernet 10G 4P X710-T4L-t OCP\n\t\t8086 0009  Ethernet Network Adapter X710-T4L for OCP 3.0\n\t\t8086 000a  Ethernet Network Adapter X710-T4L for OCP 3.0\n\t\t8086 000b  Ethernet Network Adapter X710-T2L for OCP 3.0\n\t\t8086 000c  Ethernet Network Adapter X710-T2L for OCP 3.0\n\t\t8086 000f  Ethernet Network Adapter X710-T2L for OCP 3.0\n\t1600  Broadwell-U Host Bridge -OPI\n\t1601  Broadwell-U PCI Express x16 Controller\n\t1602  Broadwell-U Integrated Graphics\n\t1603  Broadwell-U Processor Thermal Subsystem\n\t1604  Broadwell-U Host Bridge -OPI\n\t1605  Broadwell-U PCI Express x8 Controller\n\t1606  HD Graphics\n\t1607  Broadwell-U CHAPS Device\n\t1608  Broadwell-U Host Bridge -OPI\n\t1609  Broadwell-U x4 PCIe\n\t160a  Broadwell-U Integrated Graphics\n\t160b  Broadwell-U Integrated Graphics\n\t160c  Broadwell-U Audio Controller\n\t160d  Broadwell-U Integrated Graphics\n\t160e  Broadwell-U Integrated Graphics\n\t160f  Broadwell-U SoftSKU\n\t1610  Broadwell-U Host Bridge - DMI\n\t1612  HD Graphics 5600\n\t1614  Broadwell-U Host Bridge - DMI\n\t1616  HD Graphics 5500\n\t\t103c 2216  ZBook 15u G2 Mobile Workstation\n\t1618  Broadwell-U Host Bridge - DMI\n\t161a  Broadwell-U Integrated Graphics\n\t161b  Broadwell-U Integrated Graphics\n\t161d  Broadwell-U Integrated Graphics\n\t161e  HD Graphics 5300\n\t1622  Iris Pro Graphics 6200\n\t1626  HD Graphics 6000\n\t162a  Iris Pro Graphics P6300\n\t162b  Iris Graphics 6100\n\t162d  Broadwell-U Integrated Graphics\n\t162e  Broadwell-U Integrated Graphics\n\t1632  Broadwell-U Integrated Graphics\n\t1636  Broadwell-U Integrated Graphics\n\t163a  Broadwell-U Integrated Graphics\n\t163b  Broadwell-U Integrated Graphics\n\t163d  Broadwell-U Integrated Graphics\n\t163e  Broadwell-U Integrated Graphics\n\t1889  Ethernet Adaptive Virtual Function\n\t18a0  C4xxx Series QAT\n\t18a1  C4XXX Series QAT Virtual Function\n\t1900  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers\n\t1901  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor PCIe Controller (x16)\n\t1902  HD Graphics 510\n\t1903  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Thermal Subsystem\n\t\t1028 06dc  Latitude E7470\n\t\t1028 06e4  XPS 15 9550\n\t\t17aa 225d  ThinkPad T480\n\t1904  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers\n\t\t1028 06dc  Latitude E7470\n\t\t1028 06f3  Latitude 3570\n\t\t103c 8079  EliteBook 840 G3\n\t\t17aa 382a  B51-80 Laptop\n\t1905  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor PCIe Controller (x8)\n\t1906  HD Graphics 510\n\t\t17aa 382a  B51-80 Laptop\n\t1908  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers\n\t1909  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor PCIe Controller (x4)\n\t190c  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers\n\t190f  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers\n\t1910  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers\n\t\t1028 06e4  XPS 15 9550\n\t1911  Xeon E3-1200 v5/v6 / E3-1500 v5 / 6th/7th/8th Gen Core Processor Gaussian Mixture Model\n\t\t17aa 2247  ThinkPad T570\n\t\t17aa 224f  ThinkPad X1 Carbon 5th Gen\n\t\t17aa 225d  ThinkPad T480\n\t1912  HD Graphics 530\n\t1916  Skylake GT2 [HD Graphics 520]\n\t\t1028 06dc  Latitude E7470\n\t\t1028 06f3  Latitude 3570\n\t\t103c 8079  EliteBook 840 G3\n\t1918  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers\n\t1919  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Imaging Unit\n\t191b  HD Graphics 530\n\t\t1028 06e4  XPS 15 9550\n\t191d  HD Graphics P530\n\t191e  HD Graphics 515\n\t191f  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers\n\t1921  HD Graphics 520\n\t1926  Iris Graphics 540\n\t1927  Iris Graphics 550\n\t192b  Iris Graphics 555\n\t192d  Iris Graphics P555\n\t1932  Iris Pro Graphics 580\n\t193a  Iris Pro Graphics P580\n\t193b  Iris Pro Graphics 580\n\t193d  Iris Pro Graphics P580\n\t1960  80960RP (i960RP) Microprocessor\n\t\t101e 0431  MegaRAID 431 RAID Controller\n\t\t101e 0438  MegaRAID 438 Ultra2 LVD RAID Controller\n\t\t101e 0466  MegaRAID 466 Express Plus RAID Controller\n\t\t101e 0467  MegaRAID 467 Enterprise 1500 RAID Controller\n\t\t101e 0490  MegaRAID 490 Express 300 RAID Controller\n\t\t101e 0762  MegaRAID 762 Express RAID Controller\n\t\t101e 09a0  PowerEdge Expandable RAID Controller 2/SC\n\t\t1028 0467  PowerEdge Expandable RAID Controller 2/DC\n\t\t1028 1111  PowerEdge Expandable RAID Controller 2/SC\n\t\t103c 03a2  MegaRAID\n\t\t103c 10c6  MegaRAID 438, NetRAID-3Si\n\t\t103c 10c7  MegaRAID T5, Integrated NetRAID\n\t\t103c 10cc  MegaRAID, Integrated NetRAID\n\t\t103c 10cd  NetRAID-1Si\n\t\t105a 0000  SuperTrak\n\t\t105a 2168  SuperTrak Pro\n\t\t105a 5168  SuperTrak66/100\n\t\t1111 1111  MegaRAID 466, PowerEdge Expandable RAID Controller 2/SC\n\t\t1111 1112  PowerEdge Expandable RAID Controller 2/SC\n\t\t113c 03a2  MegaRAID\n\t\te4bf 1010  CG1-RADIO\n\t\te4bf 1020  CU2-QUARTET\n\t\te4bf 1040  CU1-CHORUS\n\t\te4bf 3100  CX1-BAND\n\t1962  80960RM (i960RM) Microprocessor\n\t\t105a 0000  SuperTrak SX6000 I2O CPU\n\t1964  80960RN (i960RN) Microprocessor\n\t1980  Atom Processor C3000 Series System Agent\n\t19a1  Atom Processor C3000 Series Error Registers\n\t19a2  Atom Processor C3000 Series Root Complex Event Collector\n\t19a3  Atom Processor C3000 Series Integrated QAT Root Port\n\t19a4  Atom Processor C3000 Series PCI Express Root Port #0\n\t19a5  Atom Processor C3000 Series PCI Express Root Port #1\n\t19a6  Atom Processor C3000 Series PCI Express Root Port #2\n\t19a7  Atom Processor C3000 Series PCI Express Root Port #3\n\t19a8  Atom Processor C3000 Series PCI Express Root Port #4\n\t19a9  Atom Processor C3000 Series PCI Express Root Port #5\n\t19aa  Atom Processor C3000 Series PCI Express Root Port #6\n\t19ab  Atom Processor C3000 Series PCI Express Root Port #7\n\t19ac  Atom Processor C3000 Series SMBus Contoller - Host\n\t19b0  Atom Processor C3000 Series SATA Controller 0\n\t19b1  Atom Processor C3000 Series SATA Controller 0\n\t19b2  Atom Processor C3000 Series SATA Controller 0\n\t19b3  Atom Processor C3000 Series SATA Controller 0\n\t19b4  Atom Processor C3000 Series SATA Controller 0\n\t19b5  Atom Processor C3000 Series SATA Controller 0\n\t19b6  Atom Processor C3000 Series SATA Controller 0\n\t19b7  Atom Processor C3000 Series SATA Controller 0\n\t19be  Atom Processor C3000 Series SATA Controller 0\n\t19bf  Atom Processor C3000 Series SATA Controller 0\n\t19c0  Atom Processor C3000 Series SATA Controller 1\n\t19c1  Atom Processor C3000 Series SATA Controller 1\n\t19c2  Atom Processor C3000 Series SATA Controller 1\n\t19c3  Atom Processor C3000 Series SATA Controller 1\n\t19c4  Atom Processor C3000 Series SATA Controller 1\n\t19c5  Atom Processor C3000 Series SATA Controller 1\n\t19c6  Atom Processor C3000 Series SATA Controller 1\n\t19c7  Atom Processor C3000 Series SATA Controller 1\n\t19ce  Atom Processor C3000 Series SATA Controller 1\n\t19cf  Atom Processor C3000 Series SATA Controller 1\n\t19d0  Atom Processor C3000 Series USB 3.0 xHCI Controller\n\t19d1  Atom Processor C3000 Series Integrated LAN Root Port #0\n\t19d2  Atom Processor C3000 Series Integrated LAN Root Port #1\n\t19d3  Atom Processor C3000 Series ME HECI 1\n\t19d4  Atom Processor C3000 Series ME HECI 2\n\t19d5  Atom Processor C3000 Series ME KT Controller\n\t19d6  Atom Processor C3000 Series ME HECI 3\n\t19d8  Atom Processor C3000 Series HSUART Controller\n\t19dc  Atom Processor C3000 Series LPC or eSPI\n\t19dd  Atom Processor C3000 Series Primary to Side Band (P2SB) Bridge\n\t19de  Atom Processor C3000 Series Power Management Controller\n\t19df  Atom Processor C3000 Series SMBus controller\n\t19e0  Atom Processor C3000 Series SPI Controller\n\t19e2  Atom Processor C3000 Series QuickAssist Technology\n\t1a21  82840 840 [Carmel] Chipset Host Bridge (Hub A)\n\t1a23  82840 840 [Carmel] Chipset AGP Bridge\n\t1a24  82840 840 [Carmel] Chipset PCI Bridge (Hub B)\n\t1a30  82845 845 [Brookdale] Chipset Host Bridge\n\t\t1028 010e  Optiplex GX240\n\t\t147b 0505  BL7 motherboard\n\t\t15d9 3280  Supermicro P4SBE Mainboard\n\t1a31  82845 845 [Brookdale] Chipset AGP Bridge\n\t1a38  5000 Series Chipset DMA Engine\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t1a48  82597EX 10GbE Ethernet Controller\n\t\t8086 a01f  PRO/10GbE SR Server Adapter\n\t\t8086 a11f  PRO/10GbE SR Server Adapter\n\t1b48  82597EX 10GbE Ethernet Controller\n\t\t8086 a01f  PRO/10GbE LR Server Adapter\n\t\t8086 a11f  PRO/10GbE LR Server Adapter\n\t1c00  6 Series/C200 Series Chipset Family Desktop SATA Controller (IDE mode, ports 0-3)\n\t1c01  6 Series/C200 Series Chipset Family Mobile SATA Controller (IDE mode, ports 0-3)\n\t1c02  6 Series/C200 Series Chipset Family 6 port Desktop SATA AHCI Controller\n\t\t1028 04aa  XPS 8300\n\t\t1043 844d  P8 series motherboard\n\t\t8086 7270  Server Board S1200BT Family\n\t1c03  6 Series/C200 Series Chipset Family 6 port Mobile SATA AHCI Controller\n\t\t1028 04a3  Precision M4600\n\t\t1028 04b2  Vostro 3350\n\t\t1028 04da  Vostro 3750\n\t\t17aa 21cf  ThinkPad T520\n\t\t8086 7270  Apple MacBookPro8,2 [Core i7, 15\", 2011]\n\t1c04  6 Series/C200 Series Desktop SATA RAID Controller\n\t\t103c 3118  Smart Array B110i SATA RAID Controller\n\t1c05  6 Series/C200 Series Mobile SATA RAID Controller\n\t1c06  Z68 Express Chipset SATA RAID Controller\n\t1c08  6 Series/C200 Series Chipset Family Desktop SATA Controller (IDE mode, ports 4-5)\n\t1c09  6 Series/C200 Series Chipset Family Mobile SATA Controller (IDE mode, ports 4-5)\n\t1c10  6 Series/C200 Series Chipset Family PCI Express Root Port 1\n\t\t1028 04aa  XPS 8300\n\t\t1028 04da  Vostro 3750\n\t\t1043 844d  P8 series motherboard\n\t\t17aa 21cf  ThinkPad T520\n\t\t8086 7270  Server Board S1200BTS / Apple MacBook Pro 8,1/8,2\n\t1c12  6 Series/C200 Series Chipset Family PCI Express Root Port 2\n\t\t1028 04aa  XPS 8300\n\t\t17aa 21cf  ThinkPad T520\n\t\t8086 7270  Apple MacBookPro8,2 [Core i7, 15\", 2011]\n\t1c14  6 Series/C200 Series Chipset Family PCI Express Root Port 3\n\t\t1028 04da  Vostro 3750\n\t\t8086 7270  Apple MacBookPro8,2 [Core i7, 15\", 2011]\n\t1c16  6 Series/C200 Series Chipset Family PCI Express Root Port 4\n\t\t1028 04aa  XPS 8300\n\t\t17aa 21cf  ThinkPad T520\n\t1c18  6 Series/C200 Series Chipset Family PCI Express Root Port 5\n\t\t1028 04da  Vostro 3750\n\t\t17aa 21cf  ThinkPad T520\n\t\t8086 7270  Server Board S1200BTS\n\t1c1a  6 Series/C200 Series Chipset Family PCI Express Root Port 6\n\t\t1028 04da  Vostro 3750\n\t\t1043 844d  P8 series motherboard\n\t1c1c  6 Series/C200 Series Chipset Family PCI Express Root Port 7\n\t1c1e  6 Series/C200 Series Chipset Family PCI Express Root Port 8\n\t\t1043 844d  P8 series motherboard\n\t1c20  6 Series/C200 Series Chipset Family High Definition Audio Controller\n\t\t1028 0490  Alienware M17x R3\n\t\t1028 04a3  Precision M4600\n\t\t1028 04aa  XPS 8300\n\t\t1028 04b2  Vostro 3350\n\t\t1028 04da  Vostro 3750\n\t\t1043 8418  P8P67 Deluxe Motherboard\n\t\t1043 841b  P8H67 Series Motherboard\n\t\t17aa 21cf  ThinkPad T520\n# Realtek ALC888 audio codec\n\t\t8086 2008  DQ67SW board\n\t\t8086 7270  Apple MacBookPro8,2 [Core i7, 15\", 2011]\n\t1c22  6 Series/C200 Series Chipset Family SMBus Controller\n\t\t1028 04a3  Precision M4600\n\t\t1028 04aa  XPS 8300\n\t\t1028 04b2  Vostro 3350\n\t\t1028 04da  Vostro 3750\n\t\t1043 844d  P8 series motherboard\n\t\t17aa 21cf  ThinkPad T520\n\t\t8086 7270  Server Board S1200BT Family / Apple MacBook Pro 8,1/8,2\n\t1c24  6 Series/C200 Series Chipset Family Thermal Management Controller\n\t1c25  6 Series/C200 Series Chipset Family DMI to PCI Bridge\n\t1c26  6 Series/C200 Series Chipset Family USB Enhanced Host Controller #1\n\t\t1028 04a3  Precision M4600\n\t\t1028 04aa  XPS 8300\n\t\t1028 04b2  Vostro 3350\n\t\t1028 04da  Vostro 3750\n\t\t1043 844d  P8 series motherboard\n\t\t17aa 21cf  ThinkPad T520\n\t\t8086 7270  Server Board S1200BT Family / Apple MacBook Pro 8,1/8,2\n\t1c27  6 Series/C200 Series Chipset Family USB Universal Host Controller #1\n\t\t8086 7270  Apple MacBookPro8,2 [Core i7, 15\", 2011]\n\t1c2c  6 Series/C200 Series Chipset Family USB Universal Host Controller #5\n\t\t8086 7270  Apple MacBookPro8,2 [Core i7, 15\", 2011]\n\t1c2d  6 Series/C200 Series Chipset Family USB Enhanced Host Controller #2\n\t\t1028 04a3  Precision M4600\n\t\t1028 04aa  XPS 8300\n\t\t1028 04b2  Vostro 3350\n\t\t1028 04da  Vostro 3750\n\t\t1043 844d  P8 series motherboard\n\t\t17aa 21cf  ThinkPad T520\n\t\t8086 7270  Server Board S1200BT Family / Apple MacBook Pro 8,1/8,2\n\t1c33  6 Series/C200 Series Chipset Family LAN Controller\n\t1c35  6 Series/C200 Series Chipset Family VECI Controller\n\t1c3a  6 Series/C200 Series Chipset Family MEI Controller #1\n\t\t1028 04a3  Precision M4600\n\t\t1028 04aa  XPS 8300\n\t\t1028 04b2  Vostro 3350\n\t\t1028 04da  Vostro 3750\n\t\t1043 844d  P8 series motherboard\n\t\t17aa 21cf  ThinkPad T520\n\t\t8086 7270  Apple MacBookPro8,2 [Core i7, 15\", 2011]\n\t1c3b  6 Series/C200 Series Chipset Family MEI Controller #2\n\t1c3c  6 Series/C200 Series Chipset Family IDE-r Controller\n\t1c3d  6 Series/C200 Series Chipset Family KT Controller\n\t1c40  6 Series/C200 Series Chipset Family LPC Controller\n\t1c41  Mobile SFF 6 Series Chipset Family LPC Controller\n\t1c42  6 Series/C200 Series Chipset Family LPC Controller\n\t1c43  Mobile 6 Series Chipset Family LPC Controller\n\t1c44  Z68 Express Chipset LPC Controller\n\t1c45  6 Series/C200 Series Chipset Family LPC Controller\n\t1c46  P67 Express Chipset LPC Controller\n\t\t1043 844d  P8P67 Deluxe Motherboard\n\t1c47  UM67 Express Chipset LPC Controller\n\t1c48  6 Series/C200 Series Chipset Family LPC Controller\n\t1c49  HM65 Express Chipset LPC Controller\n\t\t8086 7270  Apple MacBookPro8,2 [Core i7, 15\", 2011]\n\t1c4a  H67 Express Chipset LPC Controller\n\t\t1028 04aa  XPS 8300\n\t\t1043 844d  P8H67 Series Motherboard\n\t1c4b  HM67 Express Chipset LPC Controller\n\t\t1028 04b2  Vostro 3350\n\t\t1028 04da  Vostro 3750\n\t1c4c  Q65 Express Chipset LPC Controller\n\t1c4d  QS67 Express Chipset LPC Controller\n\t1c4e  Q67 Express Chipset LPC Controller\n\t1c4f  QM67 Express Chipset LPC Controller\n\t\t1028 04a3  Precision M4600\n\t\t17aa 21cf  ThinkPad T520\n\t1c50  B65 Express Chipset LPC Controller\n\t1c51  6 Series/C200 Series Chipset Family LPC Controller\n\t1c52  C202 Chipset LPC Controller\n\t\t8086 7270  Server Board S1200BTS\n\t1c53  6 Series/C200 Series Chipset Family LPC Controller\n\t1c54  C204 Chipset LPC Controller\n\t1c55  6 Series/C200 Series Chipset Family LPC Controller\n\t1c56  C206 Chipset LPC Controller\n\t\t1043 844d  P8B WS Motherboard\n\t1c57  6 Series/C200 Series Chipset Family LPC Controller\n\t1c58  Upgraded B65 Express Chipset LPC Controller\n\t1c59  Upgraded HM67 Express Chipset LPC Controller\n\t1c5a  Upgraded Q67 Express Chipset LPC Controller\n\t1c5b  6 Series/C200 Series Chipset Family LPC Controller\n\t1c5c  H61 Express Chipset LPC Controller\n\t1c5d  6 Series/C200 Series Chipset Family LPC Controller\n\t1c5e  6 Series/C200 Series Chipset Family LPC Controller\n\t1c5f  6 Series/C200 Series Chipset Family LPC Controller\n\t1d00  C600/X79 series chipset 4-Port SATA IDE Controller\n\t1d02  C600/X79 series chipset 6-Port SATA AHCI Controller\n\t\t1028 04f7  C602J on PowerEdge R320 server\n\t1d04  C600/X79 series chipset SATA RAID Controller\n\t1d06  C600/X79 series chipset SATA Premium RAID Controller\n\t1d08  C600/X79 series chipset 2-Port SATA IDE Controller\n\t1d10  C600/X79 series chipset PCI Express Root Port 1\n\t\t1028 04f7  C602J on PowerEdge R320 server\n\t1d11  C600/X79 series chipset PCI Express Root Port 1\n\t1d12  C600/X79 series chipset PCI Express Root Port 2\n\t1d13  C600/X79 series chipset PCI Express Root Port 2\n\t1d14  C600/X79 series chipset PCI Express Root Port 3\n\t1d15  C600/X79 series chipset PCI Express Root Port 3\n\t1d16  C600/X79 series chipset PCI Express Root Port 4\n\t1d17  C600/X79 series chipset PCI Express Root Port 4\n\t1d18  C600/X79 series chipset PCI Express Root Port 5\n\t\t1028 04f7  C602J on PowerEdge R320 server\n\t1d19  C600/X79 series chipset PCI Express Root Port 5\n\t1d1a  C600/X79 series chipset PCI Express Root Port 6\n\t1d1b  C600/X79 series chipset PCI Express Root Port 6\n\t1d1c  C600/X79 series chipset PCI Express Root Port 7\n\t1d1d  C600/X79 series chipset PCI Express Root Port 7\n\t1d1e  C600/X79 series chipset PCI Express Root Port 8\n\t\t1028 04f7  C602J on PowerEdge R320 server\n\t1d1f  C600/X79 series chipset PCI Express Root Port 8\n\t1d20  C600/X79 series chipset High Definition Audio Controller\n\t1d22  C600/X79 series chipset SMBus Host Controller\n\t\t15d9 066b  X9SRL-F\n\t1d24  C600/X79 series chipset Thermal Management Controller\n\t\t15d9 066b  X9SRL-F\n\t1d25  C600/X79 series chipset DMI to PCI Bridge\n\t1d26  C600/X79 series chipset USB2 Enhanced Host Controller #1\n\t\t1028 04f7  C602J on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t1d2d  C600/X79 series chipset USB2 Enhanced Host Controller #2\n\t\t1028 04f7  C602J on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t1d33  C600/X79 series chipset LAN Controller\n\t1d35  C600/X79 series chipset VECI Controller\n\t1d3a  C600/X79 series chipset MEI Controller #1\n\t\t1028 04f7  C602J on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t1d3b  C600/X79 series chipset MEI Controller #2\n\t\t1028 04f7  C602J on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t1d3c  C600/X79 series chipset IDE-r Controller\n\t1d3d  C600/X79 series chipset KT Controller\n\t1d3e  C600/X79 series chipset PCI Express Virtual Root Port\n\t\t1028 04f7  C602J on PowerEdge R320 server\n\t1d3f  C608/C606/X79 series chipset PCI Express Virtual Switch Port\n\t1d40  C600/X79 series chipset LPC Controller\n\t1d41  C600/X79 series chipset LPC Controller\n\t\t1028 04f7  C602J on PowerEdge R320 server\n\t\t15d9 066b  X9SRL-F\n\t1d50  C608 chipset Dual 4-Port SATA/SAS Storage Control Unit\n\t1d54  C600/X79 series chipset Dual 4-Port SATA/SAS Storage Control Unit\n\t1d55  C600/X79 series chipset 4-Port SATA/SAS Storage Control Unit\n\t1d58  C606 chipset Dual 4-Port SATA/SAS Storage Control Unit\n\t1d59  C604/X79 series chipset 4-Port SATA/SAS Storage Control Unit\n\t1d5a  C600/X79 series chipset Dual 4-Port SATA Storage Control Unit\n\t1d5b  C602 chipset 4-Port SATA Storage Control Unit\n\t1d5c  C600/X79 series chipset Dual 4-Port SATA/SAS Storage Control Unit\n\t1d5d  C600/X79 series chipset 4-Port SATA/SAS Storage Control Unit\n\t1d5e  C600/X79 series chipset Dual 4-Port SATA Storage Control Unit\n\t1d5f  C600/X79 series chipset 4-Port SATA Storage Control Unit\n\t1d60  C608 chipset Dual 4-Port SATA/SAS Storage Control Unit\n\t1d64  C600/X79 series chipset Dual 4-Port SATA/SAS Storage Control Unit\n\t1d65  C600/X79 series chipset 4-Port SATA/SAS Storage Control Unit\n\t1d68  C606 chipset Dual 4-Port SATA/SAS Storage Control Unit\n\t1d69  C604/X79 series chipset 4-Port SATA/SAS Storage Control Unit\n\t1d6a  C600/X79 series chipset Dual 4-Port SATA Storage Control Unit\n\t1d6b  C602 chipset 4-Port SATA Storage Control Unit\n\t\t0497 1028  Dell Precision T3600\n\t1d6c  C600/X79 series chipset Dual 4-Port SATA/SAS Storage Control Unit\n\t1d6d  C600/X79 series chipset 4-Port SATA/SAS Storage Control Unit\n\t1d6e  C600/X79 series chipset Dual 4-Port SATA Storage Control Unit\n\t1d6f  C600/X79 series chipset 4-Port SATA Storage Control Unit\n\t1d70  C600/X79 series chipset SMBus Controller 0\n\t1d71  C608/C606/X79 series chipset SMBus Controller 1\n\t1d72  C608 chipset SMBus Controller 2\n\t1d74  C608/C606/X79 series chipset PCI Express Upstream Port\n\t1d76  C600/X79 series chipset Multi-Function Glue\n\t1e00  7 Series/C210 Series Chipset Family 4-port SATA Controller [IDE mode]\n\t1e01  7 Series Chipset Family 4-port SATA Controller [IDE mode]\n\t\t144d c652  NP300E5C series laptop\n\t1e02  7 Series/C210 Series Chipset Family 6-port SATA Controller [AHCI mode]\n\t\t1043 84ca  P8 series motherboard\n\t\t1849 1e02  Motherboard\n\t1e03  7 Series Chipset Family 6-port SATA Controller [AHCI mode]\n\t\t1043 108d  VivoBook X202EV\n\t\t1043 1477  N56VZ\n\t\t1043 1517  Zenbook Prime UX31A\n\t\t144d c652  NP300E5C series laptop\n\t1e04  7 Series/C210 Series Chipset Family SATA Controller [RAID mode]\n\t1e05  7 Series Chipset SATA Controller [RAID mode]\n\t1e06  7 Series/C210 Series Chipset Family SATA Controller [RAID mode]\n\t1e07  7 Series Chipset Family SATA Controller [RAID mode]\n\t1e08  7 Series/C210 Series Chipset Family 2-port SATA Controller [IDE mode]\n\t1e09  7 Series Chipset Family 2-port SATA Controller [IDE mode]\n\t\t144d c652  NP300E5C series laptop\n\t1e0e  7 Series/C210 Series Chipset Family SATA Controller [RAID mode]\n\t1e10  7 Series/C216 Chipset Family PCI Express Root Port 1\n\t\t1043 108d  VivoBook X202EV\n\t\t1043 1477  N56VZ\n\t\t1043 1517  Zenbook Prime UX31A\n\t\t1043 84ca  P8H77-I Motherboard\n\t\t144d c652  NP300E5C series laptop\n\t\t1849 1e10  Motherboard\n\t1e12  7 Series/C210 Series Chipset Family PCI Express Root Port 2\n\t\t1043 108d  VivoBook X202EV\n\t\t1043 1477  N56VZ\n\t\t1043 1517  Zenbook Prime UX31A\n\t1e14  7 Series/C210 Series Chipset Family PCI Express Root Port 3\n\t1e16  7 Series/C216 Chipset Family PCI Express Root Port 4\n\t\t1043 108d  VivoBook X202EV\n\t\t1043 1477  N56VZ\n\t\t144d c652  NP300E5C series laptop\n\t\t1849 1618  Z77 Extreme4 motherboard\n\t1e18  7 Series/C210 Series Chipset Family PCI Express Root Port 5\n\t\t1043 84ca  P8H77-I Motherboard\n\t\t1849 1e18  Motherboard\n\t1e1a  7 Series/C210 Series Chipset Family PCI Express Root Port 6\n\t\t1849 1e1a  Motherboard\n\t1e1c  7 Series/C210 Series Chipset Family PCI Express Root Port 7\n\t1e1e  7 Series/C210 Series Chipset Family PCI Express Root Port 8\n\t\t1849 1e1e  Motherboard\n\t1e20  7 Series/C216 Chipset Family High Definition Audio Controller\n\t\t1028 054b  XPS One 2710\n\t\t1043 108d  VivoBook X202EV\n\t\t1043 1477  N56VZ\n\t\t1043 1517  Zenbook Prime UX31A\n\t\t1043 8415  P8H77-I Motherboard\n\t\t1043 8445  P8Z77-V LX Motherboard\n\t\t144d c652  NP300E5C series laptop\n\t\t1849 1898  Z77 Extreme4 motherboard\n\t1e22  7 Series/C216 Chipset Family SMBus Controller\n\t\t1043 108d  VivoBook X202EV\n\t\t1043 1477  N56VZ\n\t\t1043 1517  Zenbook Prime UX31A\n\t\t1043 84ca  P8 series motherboard\n\t\t144d c652  NP300E5C series laptop\n\t\t1849 1e22  Motherboard\n\t1e24  7 Series/C210 Series Chipset Family Thermal Management Controller\n\t\t1043 1517  Zenbook Prime UX31A\n\t1e25  7 Series/C210 Series Chipset Family DMI to PCI Bridge\n\t1e26  7 Series/C216 Chipset Family USB Enhanced Host Controller #1\n\t\t1043 108d  VivoBook X202EV\n\t\t1043 1477  N56VZ\n\t\t1043 1517  Zenbook Prime UX31A\n\t\t1043 84ca  P8 series motherboard\n\t\t144d c652  NP300E5C series laptop\n\t\t1849 1e26  Motherboard\n\t1e2d  7 Series/C216 Chipset Family USB Enhanced Host Controller #2\n\t\t1043 108d  VivoBook X202EV\n\t\t1043 1477  N56VZ\n\t\t1043 1517  Zenbook Prime UX31A\n\t\t1043 84ca  P8 series motherboard\n\t\t144d c652  NP300E5C series laptop\n\t\t1849 1e2d  Motherboard\n\t1e31  7 Series/C210 Series Chipset Family USB xHCI Host Controller\n\t\t103c 179b  Elitebook 8470p\n\t\t103c 17ab  ProBook 6570b\n\t\t1043 108d  VivoBook X202EV\n\t\t1043 1477  N56VZ\n\t\t1043 1517  Zenbook Prime UX31A\n\t\t1043 84ca  P8 series motherboard\n\t\t17aa 21f3  ThinkPad T430\n\t\t1849 1e31  Motherboard\n\t1e33  7 Series/C210 Series Chipset Family LAN Controller\n\t1e3a  7 Series/C216 Chipset Family MEI Controller #1\n\t\t1043 108d  VivoBook X202EV\n\t\t1043 1477  N56VZ\n\t\t1043 1517  Zenbook Prime UX31A\n\t\t1043 84ca  P8 series motherboard\n\t\t144d c652  NP300E5C series laptop\n\t\t1849 1e3a  Motherboard\n\t1e3b  7 Series/C210 Series Chipset Family MEI Controller #2\n\t1e3c  7 Series/C210 Series Chipset Family IDE-r Controller\n\t1e3d  7 Series/C210 Series Chipset Family KT Controller\n\t1e41  7 Series Chipset Family LPC Controller\n\t1e42  7 Series Chipset Family LPC Controller\n\t1e43  7 Series Chipset Family LPC Controller\n\t1e44  Z77 Express Chipset LPC Controller\n\t\t1043 84ca  P8 series motherboard\n\t\t1849 1e44  Motherboard\n\t1e45  7 Series Chipset Family LPC Controller\n\t1e46  Z75 Express Chipset LPC Controller\n\t1e47  Q77 Express Chipset LPC Controller\n\t1e48  Q75 Express Chipset LPC Controller\n\t1e49  B75 Express Chipset LPC Controller\n\t1e4a  H77 Express Chipset LPC Controller\n\t\t1043 84ca  P8H77-I Motherboard\n\t1e4b  7 Series Chipset Family LPC Controller\n\t1e4c  7 Series Chipset Family LPC Controller\n\t1e4d  7 Series Chipset Family LPC Controller\n\t1e4e  7 Series Chipset Family LPC Controller\n\t1e4f  7 Series Chipset Family LPC Controller\n\t1e50  7 Series Chipset Family LPC Controller\n\t1e51  7 Series Chipset Family LPC Controller\n\t1e52  7 Series Chipset Family LPC Controller\n\t1e53  C216 Series Chipset LPC Controller\n\t1e54  7 Series Chipset Family LPC Controller\n\t1e55  QM77 Express Chipset LPC Controller\n\t1e56  QS77 Express Chipset LPC Controller\n\t1e57  HM77 Express Chipset LPC Controller\n\t1e58  UM77 Express Chipset LPC Controller\n\t1e59  HM76 Express Chipset LPC Controller\n\t\t1043 1477  N56VZ\n\t\t1043 1517  Zenbook Prime UX31A\n\t1e5a  7 Series Chipset Family LPC Controller\n\t1e5b  UM77 Express Chipset LPC Controller\n\t1e5c  7 Series Chipset Family LPC Controller\n\t1e5d  HM75 Express Chipset LPC Controller\n\t\t144d c652  NP300E5C series laptop\n\t1e5e  HM70 Express Chipset LPC Controller\n\t\t1043 108d  VivoBook X202EV\n\t1e5f  NM70 Express Chipset LPC Controller\n\t1f00  Atom processor C2000 SoC Transaction Router\n\t1f01  Atom processor C2000 SoC Transaction Router\n\t1f02  Atom processor C2000 SoC Transaction Router\n\t1f03  Atom processor C2000 SoC Transaction Router\n\t1f04  Atom processor C2000 SoC Transaction Router\n\t1f05  Atom processor C2000 SoC Transaction Router\n\t1f06  Atom processor C2000 SoC Transaction Router\n\t1f07  Atom processor C2000 SoC Transaction Router\n\t1f08  Atom processor C2000 SoC Transaction Router\n\t1f09  Atom processor C2000 SoC Transaction Router\n\t1f0a  Atom processor C2000 SoC Transaction Router\n\t1f0b  Atom processor C2000 SoC Transaction Router\n\t1f0c  Atom processor C2000 SoC Transaction Router\n\t1f0d  Atom processor C2000 SoC Transaction Router\n\t1f0e  Atom processor C2000 SoC Transaction Router\n\t1f0f  Atom processor C2000 SoC Transaction Router\n\t1f10  Atom processor C2000 PCIe Root Port 1\n\t1f11  Atom processor C2000 PCIe Root Port 2\n\t1f12  Atom processor C2000 PCIe Root Port 3\n\t1f13  Atom processor C2000 PCIe Root Port 4\n\t1f14  Atom processor C2000 RAS\n\t1f15  Atom processor C2000 SMBus 2.0\n\t1f16  Atom processor C2000 RCEC\n\t1f18  Atom processor C2000 QAT\n\t1f19  Atom processor C2000 QAT\n\t1f20  Atom processor C2000 4-Port IDE SATA2 Controller\n\t1f21  Atom processor C2000 4-Port IDE SATA2 Controller\n\t1f22  Atom processor C2000 AHCI SATA2 Controller\n\t1f23  Atom processor C2000 AHCI SATA2 Controller\n\t1f24  Atom processor C2000 RAID SATA2 Controller\n\t1f25  Atom processor C2000 RAID SATA2 Controller\n\t1f26  Atom processor C2000 RAID SATA2 Controller\n\t1f27  Atom processor C2000 RAID SATA2 Controller\n\t1f2c  Atom processor C2000 USB Enhanced Host Controller\n\t1f2e  Atom processor C2000 RAID SATA2 Controller\n\t1f2f  Atom processor C2000 RAID SATA2 Controller\n\t1f30  Atom processor C2000 2-Port IDE SATA3 Controller\n\t1f31  Atom processor C2000 2-Port IDE SATA3 Controller\n\t1f32  Atom processor C2000 AHCI SATA3 Controller\n\t1f33  Atom processor C2000 AHCI SATA3 Controller\n\t1f34  Atom processor C2000 RAID SATA3 Controller\n\t1f35  Atom processor C2000 RAID SATA3 Controller\n\t1f36  Atom processor C2000 RAID SATA3 Controller\n\t1f37  Atom processor C2000 RAID SATA3 Controller\n\t1f38  Atom processor C2000 PCU\n\t1f39  Atom processor C2000 PCU\n\t1f3a  Atom processor C2000 PCU\n\t1f3b  Atom processor C2000 PCU\n\t1f3c  Atom processor C2000 PCU SMBus\n\t1f3d  Atom Processor C2000 PECI SMBus\n\t1f3e  Atom processor C2000 RAID SATA3 Controller\n\t1f3f  Atom processor C2000 RAID SATA3 Controller\n\t1f40  Ethernet Connection I354 1.0 GbE Backplane\n\t\t1028 05f1  Ethernet Connection I354 1.0 GbE Backplane\n\t1f41  Ethernet Connection I354\n\t1f42  Atom processor C2000 GbE\n\t1f44  Atom processor C2000 GbE Virtual Function\n\t1f45  Ethernet Connection I354 2.5 GbE Backplane\n\t2014  Sky Lake-E Ubox Registers\n\t2015  Sky Lake-E Ubox Registers\n\t2016  Sky Lake-E Ubox Registers\n\t2018  Sky Lake-E M2PCI Registers\n\t201a  Sky Lake-E Non-Transparent Bridge Registers\n\t201c  Sky Lake-E Non-Transparent Bridge Registers\n\t201d  Volume Management Device NVMe RAID Controller\n\t2020  Sky Lake-E DMI3 Registers\n\t\t15d9 095d  X11SPM-TF\n\t2021  Sky Lake-E CBDMA Registers\n\t2024  Sky Lake-E MM/Vt-d Configuration Registers\n\t2025  Sky Lake-E RAS\n\t2026  Sky Lake-E IOAPIC\n\t2030  Sky Lake-E PCI Express Root Port A\n\t2031  Sky Lake-E PCI Express Root Port B\n\t2032  Sky Lake-E PCI Express Root Port C\n\t2033  Sky Lake-E PCI Express Root Port D\n\t2034  Sky Lake-E VT-d\n\t2035  Sky Lake-E RAS Configuration Registers\n\t2036  Sky Lake-E IOxAPIC Configuration Registers\n\t2040  Sky Lake-E Integrated Memory Controller\n\t2041  Sky Lake-E Integrated Memory Controller\n\t2042  Sky Lake-E Integrated Memory Controller\n\t2043  Sky Lake-E Integrated Memory Controller\n\t2044  Sky Lake-E Integrated Memory Controller\n\t2045  Sky Lake-E LM Channel 1\n\t2046  Sky Lake-E LMS Channel 1\n\t2047  Sky Lake-E LMDP Channel 1\n\t2048  Sky Lake-E DECS Channel 2\n\t2049  Sky Lake-E LM Channel 2\n\t204a  Sky Lake-E LMS Channel 2\n\t204b  Sky Lake-E LMDP Channel 2\n\t204c  Sky Lake-E M3KTI Registers\n\t204d  Sky Lake-E M3KTI Registers\n\t204e  Sky Lake-E M3KTI Registers\n\t2054  Sky Lake-E CHA Registers\n\t2055  Sky Lake-E CHA Registers\n\t2056  Sky Lake-E CHA Registers\n\t2057  Sky Lake-E CHA Registers\n\t2058  Sky Lake-E KTI 0\n\t2059  Sky Lake-E UPI Registers\n\t2066  Sky Lake-E Integrated Memory Controller\n\t2068  Sky Lake-E DDRIO Registers\n\t2069  Sky Lake-E DDRIO Registers\n\t206a  Sky Lake-E IOxAPIC Configuration Registers\n\t206e  Sky Lake-E DDRIO Registers\n\t206f  Sky Lake-E DDRIO Registers\n\t2078  Sky Lake-E PCU Registers\n\t207a  Sky Lake-E PCU Registers\n\t2080  Sky Lake-E PCU Registers\n\t2081  Sky Lake-E PCU Registers\n\t2082  Sky Lake-E PCU Registers\n\t2083  Sky Lake-E PCU Registers\n\t2084  Sky Lake-E PCU Registers\n\t2085  Sky Lake-E PCU Registers\n\t2086  Sky Lake-E PCU Registers\n\t2088  Sky Lake-E DDRIO Registers\n\t208d  Sky Lake-E CHA Registers\n\t208e  Sky Lake-E CHA Registers\n\t2241  Larrabee\n\t2250  Xeon Phi coprocessor 5100 series\n\t225c  Xeon Phi coprocessor SE10/7120 series\n\t225d  Xeon Phi coprocessor 3120 series\n\t225e  Xeon Phi coprocessor 31S1\n\t2262  Xeon Phi coprocessor 7220\n\t2280  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series SoC Transaction Register\n\t2284  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series High Definition Audio Controller\n\t2286  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series LPIO1 DMA Controller\n\t228a  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series LPIO1 HSUART Controller #1\n\t228c  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series LPIO1 HSUART Controller #2\n\t2292  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx SMBus Controller\n\t2294  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series MMC Controller\n\t2295  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series SDIO Controller\n\t2296  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series SD Controller\n\t2298  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series Trusted Execution Engine\n\t229c  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series PCU\n\t22a3  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series SATA Controller\n\t22a4  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series SATA AHCI Controller\n\t22a8  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series Low Power Engine Audio\n\t22b0  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Integrated Graphics Controller\n\t22b1  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Integrated Graphics Controller\n\t22b5  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series USB xHCI Controller\n\t22b8  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series Imaging Unit\n\t22c0  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series LPIO2 DMA Controller\n\t22c1  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series LPIO2 I2C Controller #1\n\t22c2  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series LPIO2 I2C Controller #2\n\t22c3  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series LPIO2 I2C Controller #3\n\t22c4  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series LPIO2 I2C Controller #4\n\t22c5  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series LPIO2 I2C Controller #5\n\t22c6  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series LPIO2 I2C Controller #6\n\t22c7  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series LPIO2 I2C Controller #7\n\t22c8  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series PCI Express Port #1\n\t22ca  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series PCI Express Port #2\n\t22cc  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series PCI Express Port #3\n\t22ce  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series PCI Express Port #4\n\t22dc  Atom/Celeron/Pentium Processor x5-E8000/J3xxx/N3xxx Series Power Management Controller\n\t2310  DH89xxCC LPC Controller\n\t2323  DH89xxCC 4 Port SATA AHCI Controller\n\t2330  DH89xxCC SMBus Controller\n\t2331  DH89xxCC Chap Counter\n\t2332  DH89xxCC Thermal Subsystem\n\t2334  DH89xxCC USB2 Enhanced Host Controller #1\n\t2335  DH89xxCC USB2 Enhanced Host Controller #1\n\t2342  DH89xxCC PCI Express Root Port #1\n\t2343  DH89xxCC PCI Express Root Port #1\n\t2344  DH89xxCC PCI Express Root Port #2\n\t2345  DH89xxCC PCI Express Root Port #2\n\t2346  DH89xxCC PCI Express Root Port #3\n\t2347  DH89xxCC PCI Express Root Port #3\n\t2348  DH89xxCC PCI Express Root Port #4\n\t2349  DH89xxCC PCI Express Root Port #4\n\t2360  DH89xxCC Watchdog Timer\n\t2364  DH89xxCC MEI 0\n\t2365  DH89xxCC MEI 1\n\t2390  DH895XCC Series LPC Controller\n\t23a1  DH895XCC Series 2-Port SATA Controller [IDE Mode]\n\t23a3  DH895XCC Series 4-Port SATA Controller [AHCI Mode]\n\t23a6  DH895XCC Series 2-Port SATA Controller [IDE Mode]\n\t23b0  DH895XCC Series SMBus Controller\n\t23b1  DH895XCC Series CHAP Counter\n\t23b2  DH895XCC Series Thermal Management Controller\n\t23b4  DH895XCC Series USB2 Enhanced Host Controller #1\n\t23b5  DH895XCC Series USB2 Enhanced Host Controller #1\n\t23c2  DH895XCC Series PCI Express Root Port #1\n\t23c3  DH895XCC Series PCI Express Root Port #1\n\t23c4  DH895XCC Series PCI Express Root Port #2\n\t23c5  DH895XCC Series PCI Express Root Port #2\n\t23c6  CDH895XCC Series PCI Express Root Port #3\n\t23c7  DH895XCC Series PCI Express Root Port #3\n\t23c8  DH895XCC Series PCI Express Root Port #4\n\t23c9  DH895XCC Series PCI Express Root Port #4\n\t23e0  DH895XCC Series Watchdog Timer\n\t23e4  DH895XCC Series MEI Controller #1\n\t23e5  DH895XCC Series MEI Controller #2\n\t2410  82801AA ISA Bridge (LPC)\n\t2411  82801AA IDE Controller\n\t2412  82801AA USB Controller\n\t2413  82801AA SMBus Controller\n\t2415  82801AA AC'97 Audio Controller\n\t\t1028 0095  Precision Workstation 220 Integrated Digital Audio\n\t\t1028 00b4  OptiPlex GX110\n\t\t110a 0051  Activy 2xx\n\t\t11d4 0040  SoundMAX Integrated Digital Audio\n\t\t11d4 0048  SoundMAX Integrated Digital Audio\n\t\t11d4 5340  SoundMAX Integrated Digital Audio\n\t\t1734 1025  Activy 3xx\n\t\t1af4 1100  QEMU Virtual Machine\n\t2416  82801AA AC'97 Modem Controller\n\t2418  82801AA PCI Bridge\n\t2420  82801AB ISA Bridge (LPC)\n\t2421  82801AB IDE Controller\n\t2422  82801AB USB Controller\n\t2423  82801AB SMBus Controller\n\t2425  82801AB AC'97 Audio Controller\n\t\t11d4 0040  SoundMAX Integrated Digital Audio\n\t\t11d4 0048  SoundMAX Integrated Digital Audio\n\t2426  82801AB AC'97 Modem Controller\n\t2428  82801AB PCI Bridge\n\t2440  82801BA ISA Bridge (LPC)\n\t\t8086 5744  S845WD1-E\n\t2442  82801BA/BAM UHCI USB 1.1 Controller #1\n\t\t1014 01c6  Netvista A40/A40p\n\t\t1025 1016  Travelmate 612 TX\n\t\t1028 00c7  Dimension 8100\n\t\t1028 00d8  Precision 530\n\t\t1028 010e  Optiplex GX240\n\t\t103c 126f  e-pc 40\n\t\t1043 8027  TUSL2-C Mainboard\n\t\t104d 80df  Vaio PCG-FX403\n\t\t147b 0505  BL7 motherboard\n\t\t147b 0507  TH7II-RAID\n\t\t8086 4532  Desktop Board D815EEA2/D815EFV\n\t\t8086 4557  D815EGEW Mainboard\n\t\t8086 5744  S845WD1-E mainboard\n\t2443  82801BA/BAM SMBus Controller\n\t\t1014 01c6  Netvista A40/A40p\n\t\t1025 1016  Travelmate 612 TX\n\t\t1028 00c7  Dimension 8100\n\t\t1028 00d8  Precision 530\n\t\t1028 010e  Optiplex GX240\n\t\t103c 126f  e-pc 40\n\t\t1043 8027  TUSL2-C Mainboard\n\t\t104d 80df  Vaio PCG-FX403\n\t\t147b 0505  BL7 motherboard\n\t\t147b 0507  TH7II-RAID\n\t\t15d9 3280  Supermicro P4SBE Mainboard\n\t\t8086 4532  Desktop Board D815EEA2/D815EFV\n\t\t8086 4557  D815EGEW Mainboard\n\t\t8086 5744  S845WD1-E mainboard\n\t2444  82801BA/BAM UHCI USB 1.1 Controller #2\n\t\t1025 1016  Travelmate 612 TX\n\t\t1028 00c7  Dimension 8100\n\t\t1028 00d8  Precision 530\n\t\t1028 010e  Optiplex GX240\n\t\t103c 126f  e-pc 40\n\t\t1043 8027  TUSL2-C Mainboard\n\t\t104d 80df  Vaio PCG-FX403\n\t\t147b 0505  BL7 motherboard\n\t\t147b 0507  TH7II-RAID\n\t\t8086 4532  Desktop Board D815EEA2/D815EFV\n\t\t8086 5744  S845WD1-E mainboard\n\t2445  82801BA/BAM AC'97 Audio Controller\n\t\t0e11 000b  Compaq Deskpro EN Audio\n\t\t0e11 0088  Evo D500\n\t\t1014 01c6  Netvista A40/A40p\n\t\t1025 1016  Travelmate 612 TX\n\t\t1028 00d8  Precision 530\n\t\t103c 126f  e-pc 40\n\t\t104d 80df  Vaio PCG-FX403\n\t\t1462 3370  STAC9721 AC\n\t\t147b 0505  BL7 motherboard\n\t\t147b 0507  TH7II-RAID\n\t\t8086 4557  D815EGEW Mainboard\n\t\t8086 4656  Desktop Board D815EFV\n\t2446  82801BA/BAM AC'97 Modem Controller\n\t\t1025 1016  Travelmate 612 TX\n\t\t104d 80df  Vaio PCG-FX403\n\t2448  82801 Mobile PCI Bridge\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\t103c 0934  Compaq nw8240 Mobile Workstation\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t103c 099c  NX6110/NC6120\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a3  Compaq nw8440\n\t\t103c 30c1  Compaq 6910p\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t105b 0d7c  D270S/D250S Motherboard\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t144d c00c  P30 notebook\n\t\t144d c06a  R730 Laptop\n\t\t144d c072  Notebook N150P\n\t\t1458 5000  GA-D525TUD\n\t\t1734 1055  Amilo M1420\n\t\t17aa 2013  ThinkPad R60e\n\t\t17aa 20ae  ThinkPad T61/R61\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t\t8086 544b  Desktop Board D425KT\n\t\te4bf cc47  CCG-RUMBA\n\t2449  82801BA/BAM/CA/CAM Ethernet Controller\n\t\t0e11 0012  EtherExpress PRO/100 VM\n\t\t0e11 0091  EtherExpress PRO/100 VE\n\t\t1014 01ce  EtherExpress PRO/100 VE\n\t\t1014 01dc  EtherExpress PRO/100 VE\n\t\t1014 01eb  EtherExpress PRO/100 VE\n\t\t1014 01ec  EtherExpress PRO/100 VE\n\t\t1014 0202  EtherExpress PRO/100 VE\n\t\t1014 0205  EtherExpress PRO/100 VE\n\t\t1014 0217  EtherExpress PRO/100 VE\n\t\t1014 0234  EtherExpress PRO/100 VE\n\t\t1014 023d  EtherExpress PRO/100 VE\n\t\t1014 0244  EtherExpress PRO/100 VE\n\t\t1014 0245  EtherExpress PRO/100 VE\n\t\t1014 0265  PRO/100 VE Desktop Connection\n\t\t1014 0267  PRO/100 VE Desktop Connection\n\t\t1014 026a  PRO/100 VE Desktop Connection\n\t\t109f 315d  EtherExpress PRO/100 VE\n\t\t109f 3181  EtherExpress PRO/100 VE\n\t\t1179 ff01  PRO/100 VE Network Connection\n\t\t1186 7801  EtherExpress PRO/100 VE\n\t\t144d 2602  HomePNA 1M CNR\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 3010  EtherExpress PRO/100 VE\n\t\t8086 3011  EtherExpress PRO/100 VM\n\t\t8086 3012  82562EH based Phoneline\n\t\t8086 3013  EtherExpress PRO/100 VE\n\t\t8086 3014  EtherExpress PRO/100 VM\n\t\t8086 3015  82562EH based Phoneline\n\t\t8086 3016  EtherExpress PRO/100 P Mobile Combo\n\t\t8086 3017  EtherExpress PRO/100 P Mobile\n\t\t8086 3018  EtherExpress PRO/100\n\t244a  82801BAM IDE U100 Controller\n\t\t1025 1016  Travelmate 612TX\n\t\t104d 80df  Vaio PCG-FX403\n\t244b  82801BA IDE U100 Controller\n\t\t1014 01c6  Netvista A40/A40p\n\t\t1028 00c7  Dimension 8100\n\t\t1028 00d8  Precision 530\n\t\t1028 010e  Optiplex GX240\n\t\t103c 126f  e-pc 40\n\t\t1043 8027  TUSL2-C Mainboard\n\t\t147b 0505  BL7 motherboard\n\t\t147b 0507  TH7II-RAID\n\t\t15d9 3280  Supermicro P4SBE Mainboard\n\t\t8086 4532  Desktop Board D815EEA2/D815EFV\n\t\t8086 4557  D815EGEW Mainboard\n\t\t8086 5744  S845WD1-E mainboard\n\t244c  82801BAM ISA Bridge (LPC)\n\t244e  82801 PCI Bridge\n\t\t1014 0267  NetVista A30p\n\t\t1028 020d  Inspiron 530\n\t\t1028 0211  Optiplex 755\n\t\t1028 02da  OptiPlex 980\n\t\t1028 04f7  PowerEdge R320 server\n\t\t103c 2a3b  Pavilion A1512X\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t103c 31fe  ProLiant DL140 G3\n\t\t103c 330b  ProLiant ML150 G6 Server\n# same ID possibly also on other ASUS boards\n\t\t1043 8277  P5K PRO Motherboard\n\t\t1043 844d  P8 series motherboard\n\t\t1043 8534  ASUS B85-PLUS\n\t\t1458 5000  Motherboard\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t\t1462 7418  Wind PC MS-7418\n\t\t15d9 060d  C7SIM-Q Motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t1775 11cc  CC11/CL11\n\t\t8086 7270  Server Board S1200BTS\n\t2450  82801E ISA Bridge (LPC)\n\t2452  82801E USB Controller\n\t2453  82801E SMBus Controller\n\t2459  82801E Ethernet Controller 0\n\t245b  82801E IDE U100 Controller\n\t245d  82801E Ethernet Controller 1\n\t245e  82801E PCI Bridge\n\t2480  82801CA LPC Interface Controller\n\t2482  82801CA/CAM USB Controller #1\n\t\t0e11 0030  Evo N600c\n\t\t1014 0220  ThinkPad A/T/X Series\n\t\t104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP\n\t\t15d9 3480  P4DP6\n\t\t8086 1958  vpr Matrix 170B4\n\t\t8086 3424  SE7501HG2 Mainboard\n\t\t8086 4541  Latitude C640\n\t2483  82801CA/CAM SMBus Controller\n\t\t1014 0220  ThinkPad A/T/X Series\n\t\t104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP\n\t\t15d9 3480  P4DP6\n\t\t8086 1958  vpr Matrix 170B4\n\t2484  82801CA/CAM USB Controller #2\n\t\t0e11 0030  Evo N600c\n\t\t1014 0220  ThinkPad A/T/X Series\n\t\t104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP\n\t\t15d9 3480  P4DP6\n\t\t8086 1958  vpr Matrix 170B4\n\t2485  82801CA/CAM AC'97 Audio Controller\n\t\t1013 5959  Crystal WMD Audio Codec\n\t\t1014 0222  ThinkPad A30/A30p/T23\n\t\t1014 0508  ThinkPad T30\n\t\t1014 051c  ThinkPad A/T/X Series\n\t\t1043 1583  L3C (SPDIF)\n\t\t1043 1623  L2B (no SPDIF)\n\t\t1043 1643  L3F\n\t\t104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP\n\t\t144d c006  vpr Matrix 170B4\n\t2486  82801CA/CAM AC'97 Modem Controller\n\t\t1014 0223  ThinkPad A/T/X Series\n\t\t1014 0503  ThinkPad R31\n\t\t1014 051a  ThinkPad A/T/X Series\n\t\t101f 1025  620 Series\n\t\t1043 1496  PCtel HSP56 MR\n\t\t104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP\n\t\t134d 4c21  Dell Inspiron 2100 internal modem\n\t\t144d 2115  vpr Matrix 170B4 internal modem\n\t\t14f1 5421  MD56ORD V.92 MDC Modem\n\t2487  82801CA/CAM USB Controller #3\n\t\t0e11 0030  Evo N600c\n\t\t1014 0220  ThinkPad A/T/X Series\n\t\t104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP\n\t\t15d9 3480  P4DP6\n\t\t8086 1958  vpr Matrix 170B4\n\t248a  82801CAM IDE U100 Controller\n\t\t0e11 0030  Evo N600c\n\t\t1014 0220  ThinkPad A/T/X Series\n\t\t104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP\n\t\t8086 1958  vpr Matrix 170B4\n\t\t8086 4541  Latitude C640\n\t248b  82801CA Ultra ATA Storage Controller\n\t\t15d9 3480  P4DP6\n\t248c  82801CAM ISA Bridge (LPC)\n\t24c0  82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge\n\t\t1014 0267  NetVista A30p\n\t\t1462 5800  845PE Max (MS-6580)\n\t24c1  82801DBL (ICH4-L) IDE Controller\n\t24c2  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1\n\t\t1014 0267  NetVista A30p\n\t\t1014 052d  ThinkPad\n\t\t1025 005a  TravelMate 290\n\t\t1025 0064  Extensa 3000 series laptop: Intel 82801DBM (ICH4-M)\n\t\t1028 0126  Optiplex GX260\n\t\t1028 0160  Dimension 2400\n\t\t1028 0163  Latitude D505\n\t\t1028 018d  Inspiron 700m/710m\n\t\t1028 0196  Inspiron 5160\n\t\t103c 088c  NC8000 laptop\n\t\t103c 0890  NC6000 laptop\n\t\t103c 08b0  tc1100 tablet\n\t\t1043 8089  P4B533\n\t\t1071 8160  MIM2000\n\t\t114a 0582  PC8 onboard USB 1.x\n\t\t144d c005  X10 Laptop\n\t\t144d c00c  P30/P35 notebook\n\t\t1462 5800  845PE Max (MS-6580)\n\t\t1509 2990  Averatec 5110H laptop\n\t\t1734 1004  D1451 Mainboard (SCENIC N300, i845GV)\n\t\t1734 1055  Amilo M1420\n\t\t4c53 1090  Cx9 / Vx9 mainboard\n\t\t8086 24c2  Latitude X300\n\t\t8086 4541  Latitude D400/D500\n\t\te4bf 0cc9  CC9-SAMBA\n\t\te4bf 0cd2  CD2-BEBOP\n\t24c3  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) SMBus Controller\n\t\t1014 0267  NetVista A30p\n\t\t1014 052d  ThinkPad\n\t\t1025 005a  TravelMate 290\n\t\t1025 0064  Extensa 3000 series laptop: Intel 82801DBM (ICH4-M)\n\t\t1028 0126  Optiplex GX260\n\t\t1028 014f  Latitude X300\n\t\t1028 0160  Dimension 2400\n\t\t1028 018d  Inspiron 700m/710m\n\t\t103c 088c  NC8000 laptop\n\t\t103c 0890  NC6000 laptop\n\t\t103c 08b0  tc1100 tablet\n\t\t1071 8160  MIM2000\n\t\t114a 0582  PC8 onboard SMbus\n\t\t144d c005  X10 Laptop\n\t\t144d c00c  P30/P35 notebook\n\t\t1458 24c2  GA-8PE667 Ultra\n\t\t1462 5800  845PE Max (MS-6580)\n\t\t1734 1004  D1451 Mainboard (SCENIC N300, i845GV)\n\t\t1734 1055  Amilo M1420\n\t\t4c53 1090  Cx9 / Vx9 mainboard\n\t\te4bf 0cc9  CC9-SAMBA\n\t\te4bf 0cd2  CD2-BEBOP\n\t24c4  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2\n\t\t1014 0267  NetVista A30p\n\t\t1014 052d  ThinkPad\n\t\t1025 005a  TravelMate 290\n\t\t1025 0064  Extensa 3000 series laptop: Intel 82801DBM (ICH4-M)\n\t\t1028 0126  Optiplex GX260\n\t\t1028 0160  Dimension 2400\n\t\t1028 0163  Latitude D505\n\t\t1028 018d  Inspiron 700m/710m\n\t\t1028 0196  Inspiron 5160\n\t\t103c 088c  NC8000 laptop\n\t\t103c 0890  NC6000 laptop\n\t\t103c 08b0  tc1100 tablet\n\t\t1043 8089  P4B533\n\t\t1071 8160  MIM2000\n\t\t144d c00c  P30/P35 notebook\n\t\t1462 5800  845PE Max (MS-6580)\n\t\t1509 2990  Averatec 5110H\n\t\t1734 1004  D1451 Mainboard (SCENIC N300, i845GV)\n\t\t4c53 1090  Cx9 / Vx9 mainboard\n\t\t8086 24c2  Latitude X300\n\t\t8086 4541  Latitude D400/D500\n\t\te4bf 0cc9  CC9-SAMBA\n\t\te4bf 0cd2  CD2-BEBOP\n\t24c5  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller\n\t\t0e11 00b8  Analog Devices Inc. codec [SoundMAX]\n\t\t1014 0267  NetVista A30p\n\t\t1014 0537  ThinkPad T4x Series\n\t\t1014 055f  Thinkpad R50e model 1634\n\t\t1025 005a  TravelMate 290\n\t\t1025 0064  Extensa 3000 series laptop: Intel 82801DBM (ICH4-M)\n\t\t1028 0139  Latitude D400\n\t\t1028 014f  Latitude X300\n\t\t1028 0152  Latitude D500\n\t\t1028 0160  Dimension 2400\n\t\t1028 0163  Latitude D505\n\t\t1028 018d  Inspiron 700m/710m [SigmaTel STAC9750,51]\n\t\t1028 0196  Inspiron 5160\n\t\t103c 088c  NC8000 laptop\n\t\t103c 0890  NC6000 laptop\n\t\t103c 08b0  tc1100 tablet\n\t\t1043 1713  M2400N/M6800N laptop\n\t\t1043 80b0  P4B533\n\t\t1071 8160  MIM2000\n\t\t1179 0201  Toshiba Tecra M1\n\t\t144d c005  X10 Laptop\n\t\t144d c00c  P30/P35 notebook\n\t\t1458 a002  GA-8PE667 Ultra\n\t\t1462 5800  845PE Max (MS-6580)\n\t\t1734 1005  D1451 (SCENIC N300, i845GV) Sigmatel STAC9750T\n\t\t1734 1055  Amilo M1420\n\t24c6  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Modem Controller\n\t\t1014 0524  ThinkPad T4x Series\n\t\t1014 0525  ThinkPad\n\t\t1014 0559  ThinkPad R50e\n\t\t1025 003c  Aspire 2001WLCi (Compal CL50 motherboard) implementation\n\t\t1025 005a  TravelMate 290\n\t\t1025 0064  Extensa 3000 series laptop: Intel 82801DBM (ICH4-M)\n\t\t1028 0196  Inspiron 5160\n\t\t103c 088c  NC8000 laptop\n\t\t103c 0890  NC6000 laptop\n\t\t103c 08b0  tc1100 tablet\n\t\t1043 1716  M2400N laptop\n\t\t1043 1826  M6800N\n\t\t1071 8160  MIM2000\n\t\t134d 4c21  Latitude D500\n\t\t144d 2115  X10 Laptop\n\t\t144d c00c  P30/P35 notebook\n# Conexant HSF Softmodem (CXT22)\n\t\t14f1 5422  D480 MDC V.9x Modem\n\t24c7  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3\n\t\t1014 0267  NetVista A30p\n\t\t1014 052d  ThinkPad\n\t\t1025 005a  TravelMate 290\n\t\t1025 0064  Extensa 3000 series laptop: Intel 82801DBM (ICH4-M)\n\t\t1028 0126  Optiplex GX260\n\t\t1028 0160  Dimension 2400\n\t\t1028 0163  Latitude D505\n\t\t1028 018d  Inspiron 700m/710m\n\t\t1028 0196  Inspiron 5160\n\t\t103c 088c  NC8000 laptop\n\t\t103c 0890  NC6000 laptop\n\t\t103c 08b0  tc1100 tablet\n\t\t1043 8089  P4B533\n\t\t1071 8160  MIM2000\n\t\t144d c00c  P30/P35 notebook\n\t\t1462 5800  845PE Max (MS-6580)\n\t\t1509 2990  Averatec 5110H\n\t\t1734 1004  D1451 Mainboard (SCENIC N300, i845GV)\n\t\t4c53 1090  Cx9 / Vx9 mainboard\n\t\t8086 24c2  Latitude X300\n\t\t8086 4541  Latitude D400/D500\n\t\te4bf 0cc9  CC9-SAMBA\n\t\te4bf 0cd2  CD2-BEBOP\n\t24ca  82801DBM (ICH4-M) IDE Controller\n\t\t1014 052d  ThinkPad\n\t\t1025 005a  TravelMate 290\n\t\t1025 0064  Extensa 3000 series laptop: Intel 82801DBM (ICH4-M)\n\t\t1028 014f  Latitude X300\n\t\t1028 0163  Latitude D505\n\t\t1028 018d  Inspiron 700m/710m\n\t\t1028 0196  Inspiron 5160\n\t\t103c 088c  NC8000 laptop\n\t\t103c 0890  NC6000 laptop\n\t\t103c 08b0  tc1100 tablet\n\t\t1071 8160  MIM2000\n\t\t144d c005  X10 Laptop\n\t\t144d c00c  P30/P35 notebook\n\t\t1734 1055  Amilo M1420\n\t\t8086 4541  Latitude D400/D500\n\t24cb  82801DB (ICH4) IDE Controller\n\t\t1014 0267  NetVista A30p\n\t\t1028 0126  Optiplex GX260\n\t\t1028 0160  Dimension 2400\n\t\t1043 8089  P4B533\n\t\t114a 0582  PC8 onboard IDE\n\t\t1458 24c2  GA-8PE667 Ultra\n\t\t1462 5800  845PE Max (MS-6580)\n\t\t1734 1004  D1451 Mainboard (SCENIC N300, i845GV)\n\t\t4c53 1090  Cx9 / Vx9 mainboard\n\t\te4bf 0cc9  CC9-SAMBA\n\t\te4bf 0cd2  CD2-BEBOP\n\t24cc  82801DBM (ICH4-M) LPC Interface Bridge\n\t\t144d c00c  P30 notebook\n\t\t1734 1055  Amilo M1420\n\t24cd  82801DB/DBM (ICH4/ICH4-M) USB2 EHCI Controller\n\t\t1014 0267  NetVista A30p\n\t\t1014 052e  ThinkPad\n\t\t1025 005a  TravelMate 290\n\t\t1025 0064  Extensa 3000 series laptop: Intel 82801DBM (ICH4-M)\n\t\t1028 011d  Latitude D600\n\t\t1028 0126  Optiplex GX260\n\t\t1028 0139  Latitude D400\n\t\t1028 0152  Latitude D500\n\t\t1028 0160  Dimension 2400\n\t\t1028 0163  Latitude D505\n\t\t1028 018d  Inspiron 700m/710m\n\t\t1028 0196  Inspiron 5160\n\t\t103c 088c  NC8000 laptop\n\t\t103c 0890  NC6000 laptop\n\t\t103c 08b0  tc1100 tablet\n\t\t1043 8089  P4B533\n\t\t1071 8160  MIM2000\n\t\t114a 0582  PC8 onboard USB 2.0\n\t\t1179 ff00  Satellite 2430\n\t\t144d c005  X10 Laptop\n\t\t144d c00c  P30/P35 notebook\n\t\t1462 3981  845PE Max (MS-6580)\n\t\t1509 1968  Averatec 5110H\n\t\t1734 1004  D1451 Mainboard (SCENIC N300, i845GV)\n\t\t1734 1055  Amilo M1420\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t4c53 1090  Cx9 / Vx9 mainboard\n\t\t8086 24c2  Latitude X300\n\t\te4bf 0cc9  CC9-SAMBA\n\t\te4bf 0cd2  CD2-BEBOP\n\t24d0  82801EB/ER (ICH5/ICH5R) LPC Interface Bridge\n\t24d1  82801EB (ICH5) SATA Controller\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t\t1028 0169  Precision 470\n\t\t1028 019a  PowerEdge SC1425\n\t\t103c 12bc  d530 CMT (DG746A)\n\t\t103c 3208  ProLiant DL140 G2\n\t\t1043 80a6  P4P800 series motherboard\n\t\t1458 24d1  GA-8IPE1000 Pro2 motherboard (865PE)\n\t\t1462 7280  865PE Neo2 (MS-6728)\n\t\t1462 7650  Hetis 865GV-E (MS-7065)\n\t\t1565 5200  P4TSV Motherboard (865G)\n\t\t15d9 4580  P4SCE Mainboard\n\t\t8086 3427  S875WP1-E mainboard\n\t\t8086 4246  Desktop Board D865GBF\n\t\t8086 4c43  Desktop Board D865GLC\n\t\t8086 524c  D865PERL mainboard\n\t24d2  82801EB/ER (ICH5/ICH5R) USB UHCI Controller #1\n\t\t1014 02dd  eServer xSeries server mainboard\n\t\t1014 02ed  eServer xSeries server mainboard\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t\t1028 0169  Precision 470\n\t\t1028 016c  PowerEdge 1850 onboard UHCI\n\t\t1028 016d  PowerEdge 2850 onboard UHCI\n\t\t1028 0170  PowerEdge 6850 onboard UHCI\n\t\t1028 0183  PowerEdge 1800\n\t\t1028 019a  PowerEdge SC1425\n\t\t103c 006a  NX9500\n\t\t103c 12bc  d530 CMT (DG746A)\n\t\t103c 3208  ProLiant DL140 G2\n\t\t1043 80a6  P4P800/P5P800 series motherboard\n\t\t1458 24d2  GA-8IPE1000/8KNXP motherboard\n\t\t1462 7280  865PE Neo2 (MS-6728)\n\t\t1565 3101  P4TSV Motherboard (865G)\n\t\t15d9 4580  P4SCE Mainboard\n\t\t1734 101c  PRIMERGY RX/TX series onboard UHCI\n\t\t8086 3427  S875WP1-E mainboard\n\t\t8086 4246  Desktop Board D865GBF\n\t\t8086 4c43  Desktop Board D865GLC\n\t\t8086 524c  D865PERL mainboard\n\t24d3  82801EB/ER (ICH5/ICH5R) SMBus Controller\n\t\t1014 02dd  eServer xSeries server mainboard\n\t\t1014 02ed  eServer xSeries server mainboard\n\t\t1028 0156  Precision 360\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t\t1028 0169  Precision 470\n\t\t103c 12bc  d330 uT\n\t\t103c 3208  ProLiant DL140 G2\n\t\t1043 80a6  P4P800/P5P800 series motherboard\n\t\t1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)\n\t\t1462 7280  865PE Neo2 (MS-6728)\n\t\t1462 7650  Hetis 865GV-E (MS-7065)\n\t\t1565 3101  P4TSV Motherboard (865G)\n\t\t15d9 4580  P4SCE Mainboard\n\t\t1734 101c  PRIMERGY RX/TX S2 series SMBus\n\t\t8086 3427  S875WP1-E mainboard\n\t\t8086 4246  Desktop Board D865GBF\n\t\t8086 4c43  Desktop Board D865GLC\n\t\t8086 524c  D865PERL mainboard\n\t24d4  82801EB/ER (ICH5/ICH5R) USB UHCI Controller #2\n\t\t1014 02dd  eServer xSeries server mainboard\n\t\t1014 02ed  eServer xSeries server mainboard\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t\t1028 0169  Precision 470\n\t\t1028 016c  PowerEdge 1850 onboard UHCI\n\t\t1028 016d  PowerEdge 2850 onboard UHCI\n\t\t1028 0170  PowerEdge 6850 onboard UHCI\n\t\t1028 0183  PowerEdge 1800\n\t\t1028 019a  PowerEdge SC1425\n\t\t103c 006a  NX9500\n\t\t103c 12bc  d530 CMT (DG746A)\n\t\t103c 3208  ProLiant DL140 G2\n\t\t1043 80a6  P4P800/P5P800 series motherboard\n\t\t1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)\n\t\t1462 7280  865PE Neo2 (MS-6728)\n\t\t1462 7650  Hetis 865GV-E (MS-7065)\n\t\t1565 3101  P4TSV Motherboard (865G)\n\t\t15d9 4580  P4SCE Mainboard\n\t\t1734 101c  PRIMERGY RX/TX S2 series onboard UHCI\n\t\t8086 3427  S875WP1-E mainboard\n\t\t8086 4246  Desktop Board D865GBF\n\t\t8086 4c43  Desktop Board D865GLC\n\t\t8086 524c  D865PERL mainboard\n\t24d5  82801EB/ER (ICH5/ICH5R) AC'97 Audio Controller\n\t\t100a 147b  Abit IS7-E motherboard\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t\t1028 0169  Precision 470\n\t\t103c 006a  NX9500\n\t\t103c 12bc  d330 uT\n\t\t1043 80f3  P4P800 series motherboard\n\t\t1043 810f  P5P800-MX Mainboard\n\t\t1458 a002  GA-8IPE1000/8KNXP motherboard\n\t\t1462 0080  865PE Neo2-V (MS-6788) Mainboard\n\t\t1462 7280  865PE Neo2 (MS-6728)\n\t\t1462 7650  Hetis 865GV-E (MS-7065)\n\t\t8086 a000  D865PERL mainboard\n\t\t8086 e000  D865PERL mainboard\n\t\t8086 e001  Desktop Board D865GBF\n\t\t8086 e002  SoundMax Integrated Digital Audio\n\t24d6  82801EB/ER (ICH5/ICH5R) AC'97 Modem Controller\n\t\t103c 006a  NX9500\n\t24d7  82801EB/ER (ICH5/ICH5R) USB UHCI Controller #3\n\t\t1014 02ed  xSeries server mainboard\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t\t1028 0169  Precision 470\n\t\t1028 016c  PowerEdge 1850 onboard UHCI\n\t\t1028 016d  PowerEdge 2850 onboard UHCI\n\t\t1028 0170  PowerEdge 6850 onboard UHCI\n\t\t1028 0183  PowerEdge 1800\n\t\t103c 006a  NX9500\n\t\t103c 12bc  d530 CMT (DG746A)\n\t\t1043 80a6  P4P800/P5P800 series motherboard\n\t\t1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)\n\t\t1462 7280  865PE Neo2 (MS-6728)\n\t\t1462 7650  Hetis 865GV-E (MS-7065)\n\t\t1565 3101  P4TSV Motherboard (865G)\n\t\t15d9 4580  P4SCE Mainboard\n\t\t1734 101c  PRIMERGY RX/TX S2 series onboard UHCI\n\t\t8086 3427  S875WP1-E mainboard\n\t\t8086 4246  Desktop Board D865GBF\n\t\t8086 4c43  Desktop Board D865GLC\n\t\t8086 524c  D865PERL mainboard\n\t24db  82801EB/ER (ICH5/ICH5R) IDE Controller\n\t\t1014 02dd  eServer xSeries server mainboard\n\t\t1014 02ed  eServer xSeries server mainboard\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t\t1028 0169  Precision 470\n\t\t1028 016c  PowerEdge 1850 IDE Controller\n\t\t1028 016d  PowerEdge 2850 IDE Controller\n\t\t1028 0170  PowerEdge 6850 IDE Controller\n\t\t1028 019a  PowerEdge SC1425\n\t\t103c 006a  NX9500\n\t\t103c 12bc  d530 CMT (DG746A)\n\t\t1043 80a6  P4P800/P5P800 series motherboard\n\t\t1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)\n\t\t1462 7280  865PE Neo2 (MS-6728)\n\t\t1462 7580  MSI 875P\n\t\t1462 7650  Hetis 865GV-E (MS-7065)\n\t\t1565 3101  P4TSV Motherboard (865G)\n\t\t15d9 4580  P4SCE Mainboard\n\t\t1734 101c  PRIMERGY RX/TX S2 series onboard IDE\n\t\t8086 24db  P4C800 Mainboard\n\t\t8086 3427  S875WP1-E mainboard\n\t\t8086 4246  Desktop Board D865GBF\n\t\t8086 4c43  Desktop Board D865GLC\n\t\t8086 524c  D865PERL mainboard\n\t24dc  82801EB (ICH5) LPC Interface Bridge\n\t24dd  82801EB/ER (ICH5/ICH5R) USB2 EHCI Controller\n\t\t1014 02dd  eServer xSeries server mainboard\n\t\t1014 02ed  eServer xSeries server mainboard\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t\t1028 0169  Precision 470\n\t\t1028 016c  PowerEdge 1850 onboard EHCI\n\t\t1028 016d  PowerEdge 2850 onboard EHCI\n\t\t1028 0170  PowerEdge 6850 onboard EHCI\n\t\t1028 0183  PowerEdge 1800\n\t\t1028 019a  PowerEdge SC1425\n\t\t103c 006a  NX9500\n\t\t103c 12bc  d530 CMT (DG746A)\n\t\t103c 3208  ProLiant DL140 G2\n\t\t1043 80a6  P4P800/P5P800 series motherboard\n\t\t1458 5006  GA-8IPE1000 Pro2 motherboard (865PE)\n\t\t1462 7280  865PE Neo2 (MS-6728)\n\t\t1462 7650  Hetis 865GV-E (MS-7065)\n\t\t8086 3427  S875WP1-E mainboard\n\t\t8086 4246  Desktop Board D865GBF\n\t\t8086 4c43  Desktop Board D865GLC\n\t\t8086 524c  D865PERL mainboard\n\t24de  82801EB/ER (ICH5/ICH5R) USB UHCI Controller #4\n\t\t1014 02ed  xSeries server mainboard\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t\t1028 0169  Precision 470\n\t\t1043 80a6  P4P800/P5P800 series motherboard\n\t\t1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)\n\t\t1462 7280  865PE Neo2 (MS-6728)\n\t\t1462 7650  Hetis 865GV-E (MS-7065)\n\t\t1565 3101  P4TSV Motherboard (865G)\n\t\t15d9 4580  P4SCE Mainboard\n\t\t1734 101c  PRIMERGY RX/TX S2 series onboard UHCI\n\t\t8086 3427  S875WP1-E mainboard\n\t\t8086 4246  Desktop Board D865GBF\n\t\t8086 4c43  Desktop Board D865GLC\n\t\t8086 524c  D865PERL mainboard\n\t24df  82801ER (ICH5R) SATA Controller\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t24f0  Omni-Path HFI Silicon 100 Series [discrete]\n\t\t10a9 802e  Omni-path HFI 100 Series, 1-port A-board\n\t\t10a9 802f  Omni-path HFI 100 Series, 2-port A-board\n\t\t10a9 8030  Omni-path HFI 100 Series, 1-port B-board\n\t\t10a9 8031  Omni-path HFI 100 Series, 2-port B-board\n\t\t1590 00e7  100Gb 1-port OP101 QSFP28 x8 PCIe Gen3 with Intel Omni-Path Adapter\n\t\t1590 00e8  100Gb 1-port OP101 QSFP28 x16 PCIe Gen3 with Intel Omni-Path Adapter\n\t\t1590 021c  Apollo 100Gb 1-port Intel Omni-Path Architecture 860z Mezzanine FIO Adapter\n\t\t15d9 0934  Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x16, SIOM Module\n\t\t15d9 099b  Omni-path HFI Mezz AOC, 1 Port, PCIe x16.\n\t\t1cb8 0001  Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x16, TC4600 QSFP28\n\t\t1cb8 0002  Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x16, TC6600 Fixed Port\n\t\t1cb8 0003  Omni-Path HFI Adapter 100 Series, 2 Port, 2 PCIe x16, Earth Simulation QSFP28\n\t\t1cb8 0004  Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x16, TC4600E QSFP28\n\t\t8086 2628  Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x16\n\t\t8086 2629  Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x8\n\t\t8086 262a  Omni-Path HFI Adapter 100 Series, 2 Ports, Split PCIe x16\n\t\t8086 262d  Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x16, IO Module AHWKPTP100HF\n\t24f1  Omni-Path HFI Silicon 100 Series [integrated]\n\t24f3  Wireless 8260\n# Snow Field Peak AC\n\t\t8086 0010  Dual Band Wireless-AC 8260\n\t\t8086 1010  Dual Band Wireless-AC 8260\n\t24f4  Wireless 8260\n# Snow Field Peak AC\n\t\t8086 0030  Dual Band Wireless-AC 8260\n\t24fb  Dual Band Wireless-AC 3168NGW [Stone Peak]\n\t24fd  Wireless 8265 / 8275\n# Windstorm Peak\n\t\t8086 0010  Dual Band Wireless-AC 8265\n\t\t8086 0150  Dual Band Wireless-AC 8265\n\t\t8086 1010  Dual Band Wireless-AC 8265\n\t\t8086 1130  Dual Band Wireless-AC 8265\n\t2500  82820 820 (Camino) Chipset Host Bridge (MCH)\n\t\t1028 0095  Precision Workstation 220 Chipset\n\t\t1043 801c  P3C-2000 system chipset\n\t2501  82820 820 (Camino) Chipset Host Bridge (MCH)\n\t\t1043 801c  P3C-2000 system chipset\n\t250b  82820 820 (Camino) Chipset Host Bridge\n\t250f  82820 820 (Camino) Chipset AGP Bridge\n\t2520  82805AA MTH Memory Translator Hub\n\t2521  82804AA MRH-S Memory Repeater Hub for SDRAM\n\t2526  Wireless-AC 9260\n\t2530  82850 850 (Tehama) Chipset Host Bridge (MCH)\n\t\t1028 00c7  Dimension 8100\n\t\t147b 0507  TH7II-RAID\n\t2531  82860 860 (Wombat) Chipset Host Bridge (MCH)\n\t\t1028 00d8  Precision 530\n\t2532  82850 850 (Tehama) Chipset AGP Bridge\n\t2533  82860 860 (Wombat) Chipset AGP Bridge\n\t2534  82860 860 (Wombat) Chipset PCI Bridge\n\t2540  E7500 Memory Controller Hub\n\t\t15d9 3480  P4DP6\n\t2541  E7500/E7501 Host RASUM Controller\n\t\t15d9 3480  P4DP6\n\t\t4c53 1090  Cx9 / Vx9 mainboard\n\t\t8086 3424  SE7501HG2 Mainboard\n\t2543  E7500/E7501 Hub Interface B PCI-to-PCI Bridge\n\t2544  E7500/E7501 Hub Interface B RASUM Controller\n\t\t4c53 1090  Cx9 / Vx9 mainboard\n\t2545  E7500/E7501 Hub Interface C PCI-to-PCI Bridge\n\t2546  E7500/E7501 Hub Interface C RASUM Controller\n\t2547  E7500/E7501 Hub Interface D PCI-to-PCI Bridge\n\t2548  E7500/E7501 Hub Interface D RASUM Controller\n\t254c  E7501 Memory Controller Hub\n\t\t4c53 1090  Cx9 / Vx9 mainboard\n\t\t8086 3424  SE7501HG2 Mainboard\n\t2550  E7505 Memory Controller Hub\n\t2551  E7505/E7205 Series RAS Controller\n\t2552  E7505/E7205 PCI-to-AGP Bridge\n\t2553  E7505 Hub Interface B PCI-to-PCI Bridge\n\t2554  E7505 Hub Interface B PCI-to-PCI Bridge RAS Controller\n\t255d  E7205 Memory Controller Hub\n\t2560  82845G/GL[Brookdale-G]/GE/PE DRAM Controller/Host-Hub Interface\n\t\t1028 0126  Optiplex GX260\n\t\t1458 2560  GA-8PE667 Ultra\n\t\t1462 5800  845PE Max (MS-6580)\n\t2561  82845G/GL[Brookdale-G]/GE/PE Host-to-AGP Bridge\n\t2562  82845G/GL[Brookdale-G]/GE Chipset Integrated Graphics Device\n\t\t0e11 00b9  Evo D510 SFF\n\t\t1014 0267  NetVista A30p\n\t\t1028 0160  Dimension 2400\n\t\t1734 1003  D1521 Mainboard (Fujitsu-Siemens)\n\t\t1734 1004  D1451 Mainboard (SCENIC N300, i845GV)\n\t2570  82865G/PE/P DRAM Controller/Host-Hub Interface\n\t\t103c 006a  NX9500\n\t\t103c 12bc  d330 uT\n\t\t1043 80f2  P4P800/P5P800 series motherboard\n\t\t1458 2570  GA-8IPE1000 Pro2 motherboard (865PE)\n\t2571  82865G/PE/P AGP Bridge\n\t2572  82865G Integrated Graphics Controller\n\t\t1028 019d  Dimension 3000\n\t\t103c 12bc  D530 sff(dc578av)\n\t\t1043 80a5  P5P800-MX Mainboard\n\t\t1462 7650  Hetis 865GV-E (MS-7065)\n\t\t1734 101b  Fujitsu-Siemens Scenic E300 i865GV\n\t\t8086 4246  Desktop Board D865GBF\n\t\t8086 4c43  Desktop Board D865GLC\n\t2573  82865G/PE/P PCI to CSA Bridge\n\t2576  82865G/PE/P Processor to I/O Memory Interface\n\t2578  82875P/E7210 Memory Controller Hub\n\t\t1458 2578  GA-8KNXP motherboard (875P)\n\t\t1462 7580  MS-6758 (875P Neo)\n\t\t15d9 4580  P4SCE Motherboard\n\t2579  82875P Processor to AGP Controller\n\t257b  82875P/E7210 Processor to PCI to CSA Bridge\n\t257e  82875P/E7210 Processor to I/O Memory Interface\n\t2580  82915G/P/GV/GL/PL/910GL Memory Controller Hub\n\t\t1458 2580  GA-8I915ME-G Mainboard\n\t\t1462 7028  915P/G Neo2\n\t\t1734 105b  Scenic W620\n\t2581  82915G/P/GV/GL/PL/910GL PCI Express Root Port\n\t2582  82915G/GV/910GL Integrated Graphics Controller\n\t\t1028 1079  Optiplex GX280\n\t\t103c 3006  DC7100 SFF(DX878AV)\n\t\t1043 2582  P5GD1-VW Mainboard\n\t\t1458 2582  GA-8I915ME-G Mainboard\n\t\t1734 105b  Scenic W620\n\t\t1849 2582  ASRock P4Dual-915GL\n\t2584  82925X/XE Memory Controller Hub\n\t\t1028 0177  Dimension 8400\n\t2585  82925X/XE PCI Express Root Port\n\t2588  E7220/E7221 Memory Controller Hub\n\t2589  E7220/E7221 PCI Express Root Port\n\t258a  E7221 Integrated Graphics Controller\n\t2590  Mobile 915GM/PM/GMS/910GML Express Processor to DRAM Controller\n\t\t1014 0575  ThinkPad X41 / Z60t\n\t\t1028 0182  Latitude C610\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t103c 099c  NX6110/NC6120\n\t\t104d 81b7  Vaio VGN-S3XP\n\t\ta304 81b7  Vaio VGN-S3XP\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t2591  Mobile 915GM/PM Express PCI Express Root Port\n\t\t103c 0934  Compaq nw8240 Mobile Workstation\n\t2592  Mobile 915GM/GMS/910GML Express Graphics Controller\n\t\t1014 0582  ThinkPad X41\n\t\t103c 099c  NX6110/NC6120\n\t\t103c 308a  NC6220\n\t\t1043 1881  GMA 900 915GM Integrated Graphics\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t25a1  6300ESB LPC Interface Controller\n\t25a2  6300ESB PATA Storage Controller\n\t\t1734 1073  Primergy Econel 200 D2020 mainboard\n\t\t1775 10d0  V5D Single Board Computer IDE\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t1775 ce90  CE9\n\t\t4c53 10b0  CL9 mainboard\n\t\t4c53 10e0  PSL09 PrPMC\n\t25a3  6300ESB SATA Storage Controller\n\t\t1734 1073  Primergy Econel 200 D2020 mainboard\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t1775 ce90  CE9\n\t\t4c53 10b0  CL9 mainboard\n\t\t4c53 10d0  Telum ASLP10 Processor AMC\n\t\t4c53 10e0  PSL09 PrPMC\n\t25a4  6300ESB SMBus Controller\n\t\t1734 1073  Primergy Econel 200 D2020 mainboard\n\t\t1775 10d0  V5D Single Board Computer\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t1775 ce90  CE9\n\t\t4c53 10b0  CL9 mainboard\n\t\t4c53 10d0  Telum ASLP10 Processor AMC\n\t\t4c53 10e0  PSL09 PrPMC\n\t25a6  6300ESB AC'97 Audio Controller\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t1775 ce90  CE9\n\t\t4c53 10b0  CL9 mainboard\n\t25a7  6300ESB AC'97 Modem Controller\n\t25a9  6300ESB USB Universal Host Controller\n\t\t1734 1073  Primergy Econel 200 D2020 mainboard\n\t\t1775 10d0  V5D Single Board Computer USB\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t1775 ce90  CE9\n\t\t4c53 10b0  CL9 mainboard\n\t\t4c53 10d0  Telum ASLP10 Processor AMC\n\t\t4c53 10e0  PSL09 PrPMC\n\t25aa  6300ESB USB Universal Host Controller\n\t\t1734 1073  Primergy Econel 200 D2020 mainboard\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t1775 ce90  CE9\n\t\t4c53 10b0  CL9 mainboard\n\t\t4c53 10d0  Telum ASLP10 Processor AMC\n\t\t4c53 10e0  PSL09 PrPMC\n\t25ab  6300ESB Watchdog Timer\n\t\t1734 1073  Primergy Econel 200 D2020 mainboard\n\t\t1775 10d0  V5D Single Board Computer\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t1775 ce90  CE9\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t4c53 10b0  CL9 mainboard\n\t\t4c53 10d0  Telum ASLP10 Processor AMC\n\t\t4c53 10e0  PSL09 PrPMC\n\t25ac  6300ESB I/O Advanced Programmable Interrupt Controller\n\t\t1734 1073  Primergy Econel 200 D2020 mainboard\n\t\t1775 10d0  V5D Single Board Computer\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t1775 ce90  CE9\n\t\t4c53 10b0  CL9 mainboard\n\t\t4c53 10d0  Telum ASLP10 Processor AMC\n\t\t4c53 10e0  PSL09 PrPMC\n\t25ad  6300ESB USB2 Enhanced Host Controller\n\t\t1734 1073  Primergy Econel 200 D2020 mainboard\n\t\t1775 10d0  V5D Single Board Computer USB 2.0\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t1775 ce90  CE9\n\t\t4c53 10b0  CL9 mainboard\n\t\t4c53 10d0  Telum ASLP10 Processor AMC\n\t\t4c53 10e0  PSL09 PrPMC\n\t25ae  6300ESB 64-bit PCI-X Bridge\n\t25b0  6300ESB SATA RAID Controller\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t4c53 10d0  Telum ASLP10 Processor AMC\n\t\t4c53 10e0  PSL09 PrPMC\n\t25c0  5000X Chipset Memory Controller Hub\n\t25d0  5000Z Chipset Memory Controller Hub\n\t25d4  5000V Chipset Memory Controller Hub\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t25d8  5000P Chipset Memory Controller Hub\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t25e2  5000 Series Chipset PCI Express x4 Port 2\n\t25e3  5000 Series Chipset PCI Express x4 Port 3\n\t25e4  5000 Series Chipset PCI Express x4 Port 4\n\t25e5  5000 Series Chipset PCI Express x4 Port 5\n\t25e6  5000 Series Chipset PCI Express x4 Port 6\n\t25e7  5000 Series Chipset PCI Express x4 Port 7\n\t25f0  5000 Series Chipset FSB Registers\n\t\t1028 01bb  PowerEdge 1955 FSB Registers\n\t\t103c 31fd  ProLiant DL140 G3\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t25f1  5000 Series Chipset Reserved Registers\n\t\t103c 31fd  ProLiant DL140 G3\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t25f3  5000 Series Chipset Reserved Registers\n\t\t103c 31fd  ProLiant DL140 G3\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t25f5  5000 Series Chipset FBD Registers\n\t\t103c 31fd  ProLiant DL140 G3\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t25f6  5000 Series Chipset FBD Registers\n\t\t103c 31fd  ProLiant DL140 G3\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t25f7  5000 Series Chipset PCI Express x8 Port 2-3\n\t25f8  5000 Series Chipset PCI Express x8 Port 4-5\n\t25f9  5000 Series Chipset PCI Express x8 Port 6-7\n\t25fa  5000X Chipset PCI Express x16 Port 4-7\n\t2600  E8500/E8501 Hub Interface 1.5\n\t\t1028 0170  PowerEdge 6850 Hub Interface\n\t2601  E8500/E8501 PCI Express x4 Port D\n\t2602  E8500/E8501 PCI Express x4 Port C0\n\t2603  E8500/E8501 PCI Express x4 Port C1\n\t2604  E8500/E8501 PCI Express x4 Port B0\n\t2605  E8500/E8501 PCI Express x4 Port B1\n\t2606  E8500/E8501 PCI Express x4 Port A0\n\t2607  E8500/E8501 PCI Express x4 Port A1\n\t2608  E8500/E8501 PCI Express x8 Port C\n\t2609  E8500/E8501 PCI Express x8 Port B\n\t260a  E8500/E8501 PCI Express x8 Port A\n\t260c  E8500/E8501 IMI Registers\n\t2610  E8500/E8501 FSB Registers\n\t2611  E8500/E8501 Address Mapping Registers\n\t2612  E8500/E8501 RAS Registers\n\t2613  E8500/E8501 Reserved Registers\n\t2614  E8500/E8501 Reserved Registers\n\t2615  E8500/E8501 Miscellaneous Registers\n\t2617  E8500/E8501 Reserved Registers\n\t2618  E8500/E8501 Reserved Registers\n\t2619  E8500/E8501 Reserved Registers\n\t261a  E8500/E8501 Reserved Registers\n\t261b  E8500/E8501 Reserved Registers\n\t261c  E8500/E8501 Reserved Registers\n\t261d  E8500/E8501 Reserved Registers\n\t261e  E8500/E8501 Reserved Registers\n\t2620  E8500/E8501 eXternal Memory Bridge\n\t\t1028 0170  PowerEdge 6850 Memory Bridge\n\t2621  E8500/E8501 XMB Miscellaneous Registers\n\t\t1028 0170  PowerEdge 6850 XMB Registers\n\t2622  E8500/E8501 XMB Memory Interleaving Registers\n\t\t1028 0170  PowerEdge 6850 Memory Interleaving Registers\n\t2623  E8500/E8501 XMB DDR Initialization and Calibration\n\t\t1028 0170  PowerEdge 6850 DDR Initialization and Calibration\n\t2624  E8500/E8501 XMB Reserved Registers\n\t\t1028 0170  PowerEdge 6850 Reserved Registers\n\t2625  E8500/E8501 XMB Reserved Registers\n\t\t1028 0170  PowerEdge 6850 Reserved Registers\n\t2626  E8500/E8501 XMB Reserved Registers\n\t\t1028 0170  PowerEdge 6850 Reserved Registers\n\t2627  E8500/E8501 XMB Reserved Registers\n\t\t1028 0170  PowerEdge 6850 Reserved Registers\n\t2640  82801FB/FR (ICH6/ICH6R) LPC Interface Bridge\n\t\t1462 7028  915P/G Neo2\n\t\t1734 105c  Scenic W620\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t2641  82801FBM (ICH6M) LPC Interface Bridge\n\t\t1014 0568  ThinkPad X41\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t103c 099c  NX6110/NC6120\n\t2642  82801FW/FRW (ICH6W/ICH6RW) LPC Interface Bridge\n\t2651  82801FB/FW (ICH6/ICH6W) SATA Controller\n\t\t1028 0179  Optiplex GX280\n\t\t1043 2601  P5GD1-VW Mainboard\n\t\t1734 105c  Scenic W620\n\t\t8086 4147  D915GAG Motherboard\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t2652  82801FR/FRW (ICH6R/ICH6RW) SATA Controller\n\t\t1028 0177  Dimension 8400\n\t\t1462 7028  915P/G Neo2\n\t2653  82801FBM (ICH6M) SATA Controller\n\t\t1014 056a  ThinkPad X41\n\t2658  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #1\n\t\t1014 0565  ThinkPad X41\n\t\t1028 0177  Dimension 8400\n\t\t1028 0179  Optiplex GX280\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t103c 099c  NX6110/NC6120\n\t\t1043 80a6  P5GD1-VW Mainboard\n\t\t1458 2558  GA-8I915ME-G Mainboard\n\t\t1462 7028  915P/G Neo2\n\t\t1734 105c  Scenic W620\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t2659  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #2\n\t\t1014 0565  ThinkPad X41\n\t\t1028 0177  Dimension 8400\n\t\t1028 0179  Optiplex GX280\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t103c 099c  NX6110/NC6120\n\t\t1043 80a6  P5GD1-VW Mainboard\n\t\t1458 2659  GA-8I915ME-G Mainboard\n\t\t1462 7028  915P/G Neo2\n\t\t1734 105c  Scenic W620\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t265a  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #3\n\t\t1014 0565  ThinkPad X41\n\t\t1028 0177  Dimension 8400\n\t\t1028 0179  Optiplex GX280\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t103c 099c  NX6110/NC6120\n\t\t1043 80a6  P5GD1-VW Mainboard\n\t\t1458 265a  GA-8I915ME-G Mainboard\n\t\t1462 7028  915P/G Neo2\n\t\t1734 105c  Scenic W620\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t265b  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #4\n\t\t1014 0565  ThinkPad X41\n\t\t1028 0177  Dimension 8400\n\t\t1028 0179  Optiplex GX280\n\t\t103c 099c  NX6110/NC6120\n\t\t1043 80a6  P5GD1-VW Mainboard\n\t\t1458 265a  GA-8I915ME-G Mainboard\n\t\t1462 7028  915P/G Neo2\n\t\t1734 105c  Scenic W620\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t265c  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB2 EHCI Controller\n\t\t1014 0566  ThinkPad X41\n\t\t1028 0177  Dimension 8400\n\t\t1028 0179  Optiplex GX280\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t103c 099c  NX6110/NC6120\n\t\t1043 80a6  P5GD1-VW Mainboard\n\t\t1458 5006  GA-8I915ME-G Mainboard\n\t\t1462 7028  915P/G Neo2\n\t\t1734 105c  Scenic W620\n\t\t8086 265c  Dimension 3100\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t2660  82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 1\n\t\t103c 0934  Compaq nw8240 Mobile Workstation\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t103c 099c  NX6110/NC6120\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t2662  82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 2\n\t\t103c 0934  Compaq nw8240 Mobile Workstation\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t2664  82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 3\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t2666  82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 4\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t2668  82801FB/FBM/FR/FW/FRW (ICH6 Family) High Definition Audio Controller\n\t\t1014 05b7  ThinkPad Z60t\n# based on the PTGD1-LA motherboard\n\t\t103c 2a09  PufferM-UL8E\n\t\t1043 1173  A6VC\n\t\t1043 814e  P5GD1-VW Mainboard\n\t\t1462 7028  915P/G Neo2\n\t\t1af4 1100  QEMU Virtual Machine\n\t266a  82801FB/FBM/FR/FW/FRW (ICH6 Family) SMBus Controller\n\t\t1014 056b  ThinkPad X41\n\t\t1028 0177  Dimension 8400\n\t\t1028 0179  Optiplex GX280\n\t\t1043 80a6  P5GD1-VW Mainboard\n\t\t1458 266a  GA-8I915ME-G Mainboard\n\t\t1462 7028  915P/G Neo2\n\t\t1734 105c  Scenic W620\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t266c  82801FB/FBM/FR/FW/FRW (ICH6 Family) LAN Controller\n\t266d  82801FB/FBM/FR/FW/FRW (ICH6 Family) AC'97 Modem Controller\n\t\t1025 006a  Conexant AC'97 CoDec (in Acer TravelMate 2410 serie laptop)\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 099c  NX6110/NC6120\n\t266e  82801FB/FBM/FR/FW/FRW (ICH6 Family) AC'97 Audio Controller\n\t\t1014 0581  ThinkPad X41 (Analog Devices AD1981B codec)\n\t\t1025 006a  Realtek ALC 655 codec (in Acer TravelMate 2410 serie laptop)\n\t\t1028 0177  Dimension 8400\n\t\t1028 0179  Optiplex GX280\n\t\t1028 0182  Latitude D610 Laptop\n\t\t1028 0187  Precision M70 Laptop\n\t\t1028 0188  Inspiron 6000 laptop\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 0944  Compaq NC6220\n\t\t103c 099c  NX6110/NC6120\n\t\t103c 3006  DC7100 SFF(DX878AV)\n\t\t1458 a002  GA-8I915ME-G Mainboard\n\t\t152d 0745  Packard Bell A8550 Laptop\n\t\t1734 105a  Scenic W620\n\t266f  82801FB/FBM/FR/FW/FRW (ICH6 Family) IDE Controller\n\t\t1028 0177  Dimension 8400\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 0944  Compaq nc6220 Notebook PC\n\t\t103c 099c  NX6110/NC6120\n\t\t1043 80a6  P5GD1-VW Mainboard\n\t\t1458 266f  GA-8I915ME-G Mainboard\n\t\t1462 7028  915P/G Neo2\n\t\t1734 105c  Scenic W620\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t2670  631xESB/632xESB/3100 Chipset LPC Interface Controller\n\t\t103c 31fe  ProLiant DL140 G3\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t2680  631xESB/632xESB/3100 Chipset SATA IDE Controller\n\t2681  631xESB/632xESB SATA AHCI Controller\n\t\t103c 31fe  ProLiant DL140 G3\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t2682  631xESB/632xESB SATA RAID Controller\n\t\t103c 31fe  Adaptec Serial ATA HostRAID\n\t2683  631xESB/632xESB SATA RAID Controller\n\t2688  631xESB/632xESB/3100 Chipset UHCI USB Controller #1\n\t\t1028 01bb  PowerEdge 1955 onboard USB\n\t\t1028 01f0  PowerEdge R900 onboard USB\n\t\t103c 31fe  ProLiant DL140 G3\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t2689  631xESB/632xESB/3100 Chipset UHCI USB Controller #2\n\t\t1028 01bb  PowerEdge 1955 onboard USB\n\t\t1028 01f0  PowerEdge R900 onboard USB\n\t\t103c 31fe  ProLiant DL140 G3\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t268a  631xESB/632xESB/3100 Chipset UHCI USB Controller #3\n\t\t1028 01f0  PowerEdge R900 onboard USB\n\t\t103c 31fe  ProLiant DL140 G3\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t268b  631xESB/632xESB/3100 Chipset UHCI USB Controller #4\n\t\t1028 01f0  PowerEdge R900 onboard USB\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t268c  631xESB/632xESB/3100 Chipset EHCI USB2 Controller\n\t\t1028 01bb  PowerEdge 1955 onboard USB\n\t\t1028 01f0  PowerEdge R900 onboard USB\n\t\t103c 31fe  ProLiant DL140 G3\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t2690  631xESB/632xESB/3100 Chipset PCI Express Root Port 1\n\t\t103c 31fe  ProLiant DL140 G3\n\t\t15d9 9680  X7DBN Motherboard\n\t2692  631xESB/632xESB/3100 Chipset PCI Express Root Port 2\n\t\t103c 31fe  ProLiant DL140 G3\n\t2694  631xESB/632xESB/3100 Chipset PCI Express Root Port 3\n\t2696  631xESB/632xESB/3100 Chipset PCI Express Root Port 4\n\t2698  631xESB/632xESB AC '97 Audio Controller\n\t2699  631xESB/632xESB AC '97 Modem Controller\n\t269a  631xESB/632xESB High Definition Audio Controller\n\t269b  631xESB/632xESB/3100 Chipset SMBus Controller\n\t\t103c 31fe  ProLiant DL140 G3\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t\t8086 3476  S5000PSLSATA Server Board\n\t269e  631xESB/632xESB IDE Controller\n\t\t103c 31fe  ProLiant DL140 G3\n\t\t15d9 8680  X7DVL-E-O motherboard\n\t\t15d9 9680  X7DBN Motherboard\n\t2700  Optane SSD 900P Series\n\t\t8086 3900  900P Series [Add-in Card]\n\t\t8086 3901  900P Series [2.5\" SFF]\n\t2701  NVMe Datacenter SSD [Optane]\n\t\t1028 2000  Express Flash NVMe [Optane] 375GB 2.5\" U.2 (P4800X)\n\t\t1028 2001  Express Flash NVMe [Optane] 750GB 2.5\" U.2 (P4800X)\n\t\t1028 2002  Express Flash NVMe [Optane] 750GB AIC (P4800X)\n\t\t1028 200a  Express Flash NVMe [Optane] 375GB AIC (P4800X)\n\t\t8086 3904  NVMe Datacenter SSD [Optane] x4 AIC (P4800X)\n\t\t8086 3905  NVMe Datacenter SSD [Optane] 15mm 2.5\" U.2 (P4800X)\n\t2723  Wi-Fi 6 AX200\n\t\t8086 2723  Wireless AX200\n\t2770  82945G/GZ/P/PL Memory Controller Hub\n\t\t1028 01ad  OptiPlex GX620\n\t\t103c 2a3b  Pavilion A1512X\n\t\t1043 817a  P5LD2-VM Mainboard\n\t\t107b 5048  E4500\n\t\t1462 7418  Wind PC MS-7418\n\t\t1849 2770  ConRoe1333-D667\n\t\t8086 544e  DeskTop Board D945GTP\n\t2771  82945G/GZ/P/PL PCI Express Root Port\n\t2772  82945G/GZ Integrated Graphics Controller\n\t\t103c 2a3b  Pavilion A1512X\n\t\t1462 7418  Wind PC MS-7418\n\t\t1849 2772  ConRoe1333-D667\n\t\t8086 544e  DeskTop Board D945GTP\n\t\t8086 d605  Desktop Board D945GCCR\n\t2774  82955X Memory Controller Hub\n\t2775  82955X PCI Express Root Port\n\t2776  82945G/GZ Integrated Graphics Controller\n\t2778  E7230/3000/3010 Memory Controller Hub\n\t\t1028 01df  PowerEdge SC440\n\t\t1028 01e6  PowerEdge 860\n\t2779  E7230/3000/3010 PCI Express Root Port\n\t277a  82975X/3010 PCI Express Root Port\n\t277c  82975X Memory Controller Hub\n\t\t1043 8178  P5WDG2 WS Professional motherboard\n\t277d  82975X PCI Express Root Port\n\t2782  82915G Integrated Graphics Controller\n\t\t1043 2582  P5GD1-VW Mainboard\n\t\t1734 105b  Scenic W620\n\t2792  Mobile 915GM/GMS/910GML Express Graphics Controller\n\t\t1014 0582  ThinkPad X41\n\t\t103c 099c  NX6110/NC6120\n\t\t103c 308a  Compaq nc6220 Notebook PC\n\t\t1043 1881  GMA 900 915GM Integrated Graphics\n\t\te4bf 0ccd  CCD-CALYPSO\n\t\te4bf 0cd3  CD3-JIVE\n\t\te4bf 58b1  XB1\n\t27a0  Mobile 945GM/PM/GMS, 943/940GML and 945GT Express Memory Controller Hub\n\t\t1025 006c  9814 WKMI\n\t\t1028 01d7  XPS M1210\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a1  NC2400\n\t\t103c 30a3  Compaq nw8440\n\t\t103c 30d5  530 Laptop\n\t\t1043 1237  A6J-Q008\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t17aa 2015  ThinkPad T60\n\t\t17aa 2017  ThinkPad R60/T60/X60 series\n\t27a1  Mobile 945GM/PM/GMS, 943/940GML and 945GT Express PCI Express Root Port\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a3  Compaq nw8440\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t27a2  Mobile 945GM/GMS, 943/940GML Express Integrated Graphics Controller\n\t\t103c 30a1  NC2400\n\t\t103c 30d5  530 Laptop\n\t\t17aa 201a  ThinkPad R60/T60/X60 series\n\t\t9902 1584  CCE MPL-D10H120F\n\t27a6  Mobile 945GM/GMS/GME, 943/940GML Express Integrated Graphics Controller\n\t\t103c 30a1  NC2400\n\t\t103c 30d5  530 Laptop\n\t\t1775 11cc  CC11/CL11 integrated graphics (secondary)\n\t\t17aa 201a  ThinkPad R60/T60/X60 series\n\t27ac  Mobile 945GSE Express Memory Controller Hub\n\t\t1775 11cc  CC11/CL11\n\t27ad  Mobile 945GSE Express PCI Express Root Port\n\t27ae  Mobile 945GSE Express Integrated Graphics Controller\n\t\t1775 11cc  CC11/CL11 integrated graphics (primary)\n\t27b0  82801GH (ICH7DH) LPC Interface Bridge\n\t\t103c 2a3b  Pavilion A1512X\n\t\t8086 544e  DeskTop Board D945GTP\n\t27b8  82801GB/GR (ICH7 Family) LPC Interface Bridge\n\t\t1028 01e6  PowerEdge 860\n\t\t103c 2a8c  Compaq 500B Microtower\n\t\t1043 8179  P5KPL-VM Motherboard\n\t\t107b 5048  E4500\n\t\t1462 7418  Wind PC MS-7418\n\t\t1775 11cc  CC11/CL11\n\t\t8086 544e  DeskTop Board D945GTP\n\t27b9  82801GBM (ICH7-M) LPC Interface Bridge\n\t\t1028 01d7  XPS M1210\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a1  NC2400\n\t\t103c 30a3  Compaq nw8440\n\t\t103c 30d5  530 Laptop\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t10f7 8338  Panasonic CF-Y5 laptop\n\t\t17aa 2009  ThinkPad R60/T60/X60 series\n\t27bc  NM10 Family LPC Controller\n\t\t1043 83ad  Eee PC 1015PX\n\t\t105b 0d7c  D270S/D250S Motherboard\n\t\t144d c072  Notebook N150P\n\t\t1458 5001  GA-D525TUD\n\t\t8086 4f4d  DeskTop Board D510MO\n\t\t8086 544b  Desktop Board D425KT\n\t27bd  82801GHM (ICH7-M DH) LPC Interface Bridge\n\t\t1025 006c  9814 WKMI\n\t27c0  NM10/ICH7 Family SATA Controller [IDE mode]\n\t\t1028 01ad  OptiPlex GX620\n\t\t1028 01df  PowerEdge SC440\n\t\t1028 01e6  PowerEdge 860\n\t\t103c 2a8c  Compaq 500B Microtower\n\t\t1043 8179  P5KPL-VM Motherboard\n\t\t107b 5048  E4500\n\t\t1462 2310  MSI Hetis 945\n\t\t1462 7236  945P Neo3-F Rev. 2.2 motherboard\n\t\t1462 7418  Wind PC MS-7418\n\t\t1775 11cc  CC11/CL11\n\t\t8086 544b  Desktop Board D425KT\n\t\t8086 544e  DeskTop Board D945GTP\n\t27c1  NM10/ICH7 Family SATA Controller [AHCI mode]\n\t\t1028 01df  PowerEdge SC440\n\t\t103c 2a3b  Pavilion A1512X\n\t\t1043 83ad  Eee PC 1015PX\n\t\t105b 0d7c  D270S/D250S Motherboard\n\t\t144d c072  Notebook N150P\n\t\t1458 b005  GA-D525TUD\n\t\t1775 11cc  CC11/CL11\n\t\t8086 4f4d  DeskTop Board D510MO\n\t\t8086 5842  DeskTop Board D975XBX\n\t27c3  82801GR/GDH (ICH7R/ICH7DH) SATA Controller [RAID mode]\n\t\t1775 11cc  CC11/CL11\n\t\t8086 544e  DeskTop Board D945GTP\n\t27c4  82801GBM/GHM (ICH7-M Family) SATA Controller [IDE mode]\n\t\t1025 006c  9814 WKMI\n\t\t1028 01d7  XPS M1210\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t17aa 200e  ThinkPad T60\n\t27c5  82801GBM/GHM (ICH7-M Family) SATA Controller [AHCI mode]\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a3  Compaq nw8440\n\t\t103c 30d5  530 Laptop\n\t\t17aa 200d  ThinkPad R60/T60/X60 series\n\t27c6  82801GHM (ICH7-M DH) SATA Controller [RAID mode]\n\t27c8  NM10/ICH7 Family USB UHCI Controller #1\n\t\t1025 006c  9814 WKMI\n\t\t1028 01ad  OptiPlex GX620\n\t\t1028 01d7  XPS M1210\n\t\t1028 01df  PowerEdge SC440\n\t\t1028 01e6  PowerEdge 860\n\t\t103c 2a3b  Pavilion A1512X\n\t\t103c 2a8c  Compaq 500B Microtower\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a1  NC2400\n\t\t103c 30a3  Compaq nw8440\n\t\t103c 30d5  530 Laptop\n\t\t1043 1237  A6J-Q008\n\t\t1043 8179  P5KPL-VM,P5LD2-VM Mainboard\n\t\t1043 83ad  Eee PC 1015PX\n\t\t105b 0d7c  D270S/D250S Motherboard\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t107b 5048  E4500\n\t\t144d c072  Notebook N150P\n\t\t1458 5004  GA-D525TUD\n\t\t1462 7418  Wind PC MS-7418\n\t\t1775 11cc  CC11/CL11\n\t\t17aa 200a  ThinkPad R60/T60/X60 series\n\t\t8086 4f4d  DeskTop Board D510MO\n\t\t8086 544b  Desktop Board D425KT\n\t\t8086 544e  DeskTop Board D945GTP\n\t27c9  NM10/ICH7 Family USB UHCI Controller #2\n\t\t1025 006c  9814 WKMI\n\t\t1028 01ad  OptiPlex GX620\n\t\t1028 01d7  XPS M1210\n\t\t1028 01df  PowerEdge SC440\n\t\t1028 01e6  PowerEdge 860\n\t\t103c 2a3b  Pavilion A1512X\n\t\t103c 2a8c  Compaq 500B Microtower\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a1  NC2400\n\t\t103c 30a3  Compaq nw8440\n\t\t1043 1237  A6J-Q008\n\t\t1043 8179  P5KPL-VM,P5LD2-VM Mainboard\n\t\t1043 83ad  Eee PC 1015PX\n\t\t105b 0d7c  D270S/D250S Motherboard\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t107b 5048  E4500\n\t\t144d c072  Notebook N150P\n\t\t1458 5004  GA-D525TUD\n\t\t1462 7418  Wind PC MS-7418\n\t\t1775 11cc  CC11/CL11\n\t\t17aa 200a  ThinkPad R60/T60/X60 series\n\t\t8086 4f4d  DeskTop Board D510MO\n\t\t8086 544b  Desktop Board D425KT\n\t\t8086 544e  DeskTop Board D945GTP\n\t27ca  NM10/ICH7 Family USB UHCI Controller #3\n\t\t1025 006c  9814 WKMI\n\t\t1028 01ad  OptiPlex GX620\n\t\t1028 01d7  XPS M1210\n\t\t1028 01df  PowerEdge SC440\n\t\t1028 01e6  PowerEdge 860\n\t\t103c 2a3b  Pavilion A1512X\n\t\t103c 2a8c  Compaq 500B Microtower\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a1  NC2400\n\t\t103c 30a3  Compaq nw8440\n\t\t1043 1237  A6J-Q008\n\t\t1043 8179  P5KPL-VM,P5LD2-VM Mainboard\n\t\t1043 83ad  Eee PC 1015PX\n\t\t105b 0d7c  D270S/D250S Motherboard\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t107b 5048  E4500\n\t\t144d c072  Notebook N150P\n\t\t1458 5004  GA-D525TUD\n\t\t1462 7418  Wind PC MS-7418\n\t\t1775 11cc  CC11/CL11\n\t\t17aa 200a  ThinkPad R60/T60/X60 series\n\t\t8086 4f4d  DeskTop Board D510MO\n\t\t8086 544e  DeskTop Board D945GTP\n\t27cb  NM10/ICH7 Family USB UHCI Controller #4\n\t\t1025 006c  9814 WKMI\n\t\t1028 01ad  OptiPlex GX620\n\t\t1028 01d7  XPS M1210\n\t\t1028 01df  PowerEdge SC440\n\t\t103c 2a3b  Pavilion A1512X\n\t\t103c 2a8c  Compaq 500B Microtower\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a1  NC2400\n\t\t103c 30a3  Compaq nw8440\n\t\t1043 1237  A6J-Q008\n\t\t1043 8179  P5KPL-VM,P5LD2-VM Mainboard\n\t\t1043 83ad  Eee PC 1015PX\n\t\t105b 0d7c  D270S/D250S Motherboard\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t107b 5048  E4500\n\t\t144d c072  Notebook N150P\n\t\t1458 5004  GA-D525TUD\n\t\t1462 7418  Wind PC MS-7418\n\t\t1775 11cc  CC11/CL11\n\t\t17aa 200a  ThinkPad R60/T60/X60 series\n\t\t8086 4f4d  DeskTop Board D510MO\n\t\t8086 544e  DeskTop Board D945GTP\n\t27cc  NM10/ICH7 Family USB2 EHCI Controller\n\t\t1025 006c  9814 WKMI\n\t\t1028 01ad  OptiPlex GX620\n\t\t1028 01d7  XPS M1210\n\t\t1028 01df  PowerEdge SC440\n\t\t1028 01e6  PowerEdge 860\n\t\t103c 2a3b  Pavilion A1512X\n\t\t103c 2a8c  Compaq 500B Microtower\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a1  NC2400\n\t\t103c 30a3  Compaq nw8440\n\t\t103c 30d5  530 Laptop\n\t\t1043 1237  A6J-Q008\n\t\t1043 8179  P5KPL-VM,P5LD2-VM Mainboard\n\t\t1043 83ad  Eee PC 1015PX\n\t\t105b 0d7c  D270S/D250S Motherboard\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t144d c072  Notebook N150P\n\t\t1458 5006  GA-D525TUD\n\t\t1462 7418  Wind PC MS-7418\n\t\t1775 11cc  CC11/CL11\n\t\t17aa 200b  ThinkPad R60/T60/X60 series\n\t\t8086 4f4d  DeskTop Board D510MO\n\t\t8086 544b  Desktop Board D425KT\n\t\t8086 544e  DeskTop Board D945GTP\n\t27d0  NM10/ICH7 Family PCI Express Port 1\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a3  Compaq nw8440\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t144d c072  Notebook N150P\n\t\t1458 5001  GA-D525TUD\n\t\t1462 7418  Wind PC MS-7418\n\t\t1775 11cc  CC11/CL11\n\t\t17aa 2011  ThinkPad R60e\n\t\t8086 544b  Desktop Board D425KT\n\t27d2  NM10/ICH7 Family PCI Express Port 2\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a3  Compaq nw8440\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t144d c072  Notebook N150P\n\t\t1462 7418  Wind PC MS-7418\n\t\t1775 11cc  CC11/CL11\n\t\t17aa 2011  ThinkPad R60e\n\t\t8086 544b  Desktop Board D425KT\n\t27d4  NM10/ICH7 Family PCI Express Port 3\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t144d c072  Notebook N150P\n\t\t1462 7418  Wind PC MS-7418\n\t\t1775 11cc  CC11/CL11\n\t\t17aa 2011  ThinkPad R60e\n\t\t8086 544b  Desktop Board D425KT\n\t27d6  NM10/ICH7 Family PCI Express Port 4\n\t\t103c 30a3  Compaq nw8440\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t144d c072  Notebook N150P\n\t\t1462 7418  Wind PC MS-7418\n\t\t1775 11cc  CC11/CL11\n\t\t17aa 2011  ThinkPad R60e\n\t\t8086 544b  Desktop Board D425KT\n\t27d8  NM10/ICH7 Family High Definition Audio Controller\n\t\t1025 006c  9814 WKMI\n\t\t1028 01d7  XPS M1210\n\t\t103c 2a3b  Pavilion A1512X\n\t\t103c 2a8c  Compaq 500B Microtower\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a1  NC2400\n\t\t103c 30a3  Compaq nw8440\n\t\t103c 30d5  530 Laptop\n\t\t1043 1123  A6J-Q008\n\t\t1043 13c4  G2P\n\t\t1043 817f  P5LD2-VM Mainboard (Realtek ALC 882 codec)\n\t\t1043 8290  P5KPL-VM Motherboard\n\t\t1043 82ea  P5KPL-CM Motherboard\n\t\t1043 8437  Eee PC 1015PX\n\t\t105b 0d7c  D270S/D250S Motherboard\n\t\t1071 8207  Medion MIM 2240 Notebook PC [MD98100]\n\t\t107b 5048  E4500\n\t\t10f7 8338  Panasonic CF-Y5 laptop\n\t\t1179 ff10  Toshiba Satellite A100-796 audio (Realtek ALC861)\n\t\t1179 ff31  AC97 Data Fax SoftModem with SmartCP\n\t\t1447 1043  Asus A8JP (Analog Devices AD1986A)\n\t\t144d c072  Notebook N150P\n\t\t1458 a002  GA-D525TUD (Realtek ALC887)\n\t\t1458 a102  GA-8I945PG-RH Mainboard\n\t\t1462 7418  Wind PC MS-7418\n\t\t152d 0753  Softmodem\n\t\t1734 10ad  Conexant softmodem SmartCP\n\t\t17aa 2010  ThinkPad R60/T60/X60 series\n\t\t17aa 3802  3000 C200 audio [Realtek ALC861VD]\n\t\t8086 1112  DeskTop Board D945GTP\n\t\t8086 27d8  DeskTop Board D945GTP\n\t\t8086 d618  DeskTop Board D510MO\n\t\t8384 7680  STAC9221 HD Audio Codec\n\t27da  NM10/ICH7 Family SMBus Controller\n\t\t1025 006c  9814 WKMI\n\t\t1028 01ad  OptiPlex GX620\n\t\t1028 01d7  XPS M1210\n\t\t1028 01df  PowerEdge SC440\n\t\t1028 01e6  PowerEdge 860\n\t\t103c 2a3b  Pavilion A1512X\n\t\t103c 2a8c  Compaq 500B Microtower\n\t\t1043 8179  P5KPL-VM Motherboard\n\t\t105b 0d7c  D270S/D250S Motherboard\n\t\t1071 8209  Medion MIM 2240 Notebook PC [MD98100]\n\t\t10f7 8338  Panasonic CF-Y5 laptop\n\t\t144d c072  Notebook N150P\n\t\t1458 5001  GA-8I945PG-RH/GA-D525TUD Mainboard\n\t\t1462 7418  Wind PC MS-7418\n\t\t1775 11cc  CC11/CL11\n\t\t17aa 200f  ThinkPad R60/T60/X60 series\n\t\t8086 4f4d  DeskTop Board D510MO\n\t\t8086 544b  Desktop Board D425KT\n\t\t8086 544e  DeskTop Board D945GTP\n\t\t8086 5842  DeskTop Board D975XBX\n\t27dc  NM10/ICH7 Family LAN Controller\n\t\t103c 2a3b  Pavilion A1512X\n\t\t8086 308d  DeskTop Board D945GTP\n\t27dd  82801G (ICH7 Family) AC'97 Modem Controller\n\t27de  82801G (ICH7 Family) AC'97 Audio Controller\n\t\t1028 01ad  OptiPlex GX620\n\t\t1462 7267  Realtek ALC883 Audio Controller\n\t\t1775 11cc  CC11 integrated audio (AD1981BL codec)\n\t27df  82801G (ICH7 Family) IDE Controller\n\t\t1028 01df  PowerEdge SC440\n\t\t1028 01e6  PowerEdge 860\n\t\t103c 2a3b  Pavilion A1512X\n\t\t103c 2a8c  Compaq 500B Microtower\n\t\t103c 309f  Compaq nx9420 Notebook\n\t\t103c 30a1  NC2400\n\t\t103c 30a3  Compaq nw8440\n\t\t103c 30d5  530 Laptop\n\t\t1043 1237  A6J-Q008\n\t\t1043 8179  P5KPL-VM Motherboard\n\t\t107b 5048  E4500\n\t\t10f7 8338  Panasonic CF-Y5 laptop\n\t\t1462 7418  Wind PC MS-7418\n\t\t1775 11cc  CC11/CL11\n\t\t17aa 200c  ThinkPad R60/T60/X60 series\n\t\t8086 544e  DeskTop Board D945GTP\n\t27e0  82801GR/GH/GHM (ICH7 Family) PCI Express Port 5\n\t\t1775 11cc  CC11/CL11\n\t27e2  82801GR/GH/GHM (ICH7 Family) PCI Express Port 6\n\t\t1775 11cc  CC11/CL11\n\t280b  Intel(R) Display Audio\n\t2810  82801HB/HR (ICH8/R) LPC Interface Controller\n\t\t1043 81ec  P5B\n\t2811  82801HEM (ICH8M-E) LPC Interface Controller\n\t\t103c 30c1  Compaq 6910p\n\t\t17aa 20b6  ThinkPad T61/R61\n\t\te4bf cc47  CCG-RUMBA\n\t2812  82801HH (ICH8DH) LPC Interface Controller\n\t2814  82801HO (ICH8DO) LPC Interface Controller\n\t2815  82801HM (ICH8M) LPC Interface Controller\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30cc  Pavilion dv6700\n\t\t103c 30d9  Presario C700\n\t\t104d 9005  Vaio VGN-FZ260E\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t17aa 20a5  ThinkPad R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t2820  82801H (ICH8 Family) 4 port SATA Controller [IDE mode]\n\t\t1028 01da  OptiPlex 745\n\t\t1462 7235  P965 Neo MS-7235 mainboard\n\t2821  82801HR/HO/HH (ICH8R/DO/DH) 6 port SATA Controller [AHCI mode]\n\t2822  SATA Controller [RAID mode]\n\t\t1028 020d  Inspiron 530\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t2823  C610/X99 series chipset sSATA Controller [RAID mode]\n\t2824  82801HB (ICH8) 4 port SATA Controller [AHCI mode]\n\t\t1043 81ec  P5B\n\t2825  82801HR/HO/HH (ICH8R/DO/DH) 2 port SATA Controller [IDE mode]\n\t\t1028 01da  OptiPlex 745\n\t\t1462 7235  P965 Neo MS-7235 mainboard\n\t2826  C600/X79 series chipset SATA RAID Controller\n\t\t1d49 0100  Intel RSTe SATA Software RAID\n\t\t1d49 0101  Intel RSTe SATA Software RAID\n\t\t1d49 0102  Intel RSTe SATA Software RAID\n\t\t1d49 0103  Intel RSTe SATA Software RAID\n\t\t1d49 0104  Intel RSTe SATA Software RAID\n\t\t1d49 0105  Intel RSTe SATA Software RAID\n\t2827  C610/X99 series chipset sSATA Controller [RAID mode]\n\t2828  82801HM/HEM (ICH8M/ICH8M-E) SATA Controller [IDE mode]\n\t\t1028 01f3  Inspiron 1420\n\t\t103c 30c0  Compaq 6710b\n\t\t17aa 20a8  ThinkPad R61\n\t\te4bf cc47  CCG-RUMBA\n\t2829  82801HM/HEM (ICH8M/ICH8M-E) SATA Controller [AHCI mode]\n\t\t1025 0121  Aspire 5920G\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30c1  Compaq 6910p\n\t\t103c 30cc  Pavilion dv6700\n\t\t103c 30d9  Presario C700\n\t\t104d 9005  Vaio VGN-FZ260E\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t17aa 20a7  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t\te4bf cc47  CCG-RUMBA\n\t282a  82801 Mobile SATA Controller [RAID mode]\n\t\t1028 040b  Latitude E6510\n\t\te4bf 50c1  PC1-GROOVE\n\t2830  82801H (ICH8 Family) USB UHCI Controller #1\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01da  OptiPlex 745\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30c1  Compaq 6910p\n\t\t103c 30cc  Pavilion dv6700\n\t\t103c 30d9  Presario C700\n\t\t1043 81ec  P5B\n\t\t104d 9005  Vaio VGN-FZ260E\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t1462 7235  P965 Neo MS-7235 mainboard\n\t\t17aa 20aa  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t\te4bf cc47  CCG-RUMBA\n\t2831  82801H (ICH8 Family) USB UHCI Controller #2\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01da  OptiPlex 745\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30c1  Compaq 6910p\n\t\t103c 30cc  Pavilion dv6700\n\t\t103c 30d9  Presario C700\n\t\t1043 81ec  P5B\n\t\t104d 9005  Vaio VGN-FZ260E\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t1462 7235  P965 Neo MS-7235 mainboard\n\t\t17aa 20aa  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t\te4bf cc47  CCG-RUMBA\n\t2832  82801H (ICH8 Family) USB UHCI Controller #3\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01da  OptiPlex 745\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30c1  Compaq 6910p\n\t\t103c 30cc  Pavilion dv6700\n\t\t103c 30d9  Presario C700\n\t\t1043 81ec  P5B\n\t\t104d 9005  Vaio VGN-FZ260E\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t17aa 20aa  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t\te4bf cc47  CCG-RUMBA\n\t2833  82801H (ICH8 Family) USB UHCI Controller #4\n\t\t1043 81ec  P5B\n\t2834  82801H (ICH8 Family) USB UHCI Controller #4\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01da  OptiPlex 745\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30c1  Compaq 6910p\n\t\t103c 30cc  Pavilion dv6700\n\t\t1043 81ec  P5B\n\t\t104d 9005  Vaio VGN-FZ260E\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t1462 7235  P965 Neo MS-7235 mainboard\n\t\t17aa 20aa  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t\te4bf cc47  CCG-RUMBA\n\t2835  82801H (ICH8 Family) USB UHCI Controller #5\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01da  OptiPlex 745\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30c1  Compaq 6910p\n\t\t103c 30cc  Pavilion dv6700\n\t\t1043 81ec  P5B\n\t\t104d 9005  Vaio VGN-FZ260E\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t17aa 20aa  Thinkpad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t\te4bf cc47  CCG-RUMBA\n\t2836  82801H (ICH8 Family) USB2 EHCI Controller #1\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01da  OptiPlex 745\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30c1  Compaq 6910p\n\t\t103c 30cc  Pavilion dv6700\n\t\t103c 30d9  Presario C700\n\t\t1043 81ec  P5B\n\t\t104d 9005  Vaio VGN-FZ260E\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t1462 7235  P965 Neo MS-7235 mainboard\n\t\t17aa 20ab  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t\te4bf cc47  CCG-RUMBA\n\t283a  82801H (ICH8 Family) USB2 EHCI Controller #2\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01da  OptiPlex 745\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30c1  Compaq 6910p\n\t\t103c 30cc  Pavilion dv6700\n\t\t1043 81ec  P5B\n\t\t104d 9005  Vaio VGN-FZ260E\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t17aa 20ab  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t\te4bf cc47  CCG-RUMBA\n\t283e  82801H (ICH8 Family) SMBus Controller\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01da  OptiPlex 745\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30d9  Presario C700\n\t\t1043 81ec  P5B\n\t\t104d 9005  Vaio VGN-FZ260E\n\t\t104d 9008  Vaio VGN-SZ79SN_C\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t1462 7235  P965 Neo MS-7235 mainboard\n\t\t17aa 20a9  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t\te4bf cc47  CCG-RUMBA\n\t283f  82801H (ICH8 Family) PCI Express Port 1\n\t\t1028 01da  OptiPlex 745\n\t\t103c 30c1  Compaq 6910p\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t17aa 20ad  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t2841  82801H (ICH8 Family) PCI Express Port 2\n\t\t103c 30c1  Compaq 6910p\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t17aa 20ad  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t2843  82801H (ICH8 Family) PCI Express Port 3\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t17aa 20ad  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t2845  82801H (ICH8 Family) PCI Express Port 4\n\t\t17aa 20ad  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t2847  82801H (ICH8 Family) PCI Express Port 5\n\t\t1028 01da  OptiPlex 745\n\t\t103c 30c1  Compaq 6910p\n\t\t17aa 20ad  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t2849  82801H (ICH8 Family) PCI Express Port 6\n\t284b  82801H (ICH8 Family) HD Audio Controller\n\t\t1025 011f  Realtek ALC268 audio codec\n\t\t1025 0121  Aspire 5920G\n\t\t1025 0145  Realtek ALC889 (Aspire 8920G w. Dolby Theater)\n\t\t1028 01da  OptiPlex 745\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 01f9  Latitude D630\n\t\t1028 01ff  Precision M4300\n\t\t1028 022f  Inspiron 1525\n\t\t1028 0256  Studio 1735\n\t\t103c 2802  Compaq dc7700p\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30c1  Compaq 6910p\n\t\t103c 30cc  Pavilion dv6700\n\t\t1043 1339  M51S series\n\t\t1043 81ec  P5B\n\t\t104d 9005  Vaio VGN-FZ260E\n\t\t104d 9008  Vaio VGN-SZ79SN_C\n\t\t104d 9016  Sony VAIO VGN-AR51M\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t14f1 5051  Presario C700\n\t\t17aa 20ac  ThinkPad T61/R61\n\t\t17c0 4088  Medion WIM 2210 Notebook PC [MD96850]\n\t\t8384 7616  Dell Vostro 1400\n\t\te4bf cc47  CCG-RUMBA\n\t284f  82801H (ICH8 Family) Thermal Reporting Device\n\t2850  82801HM/HEM (ICH8M/ICH8M-E) IDE Controller\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30c1  Compaq 6910p\n\t\t103c 30cc  Pavilion dv6700\n\t\t103c 30d9  Presario C700\n\t\t104d 9005  Vaio VGN-FZ260E\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t17aa 20a6  ThinkPad T61/R61\n\t\t17c0 4083  Medion WIM 2210 Notebook PC [MD96850]\n\t\te4bf cc47  CCG-RUMBA\n\t2912  82801IH (ICH9DH) LPC Interface Controller\n\t2914  82801IO (ICH9DO) LPC Interface Controller\n\t\t1028 0211  Optiplex 755\n\t2916  82801IR (ICH9R) LPC Interface Controller\n\t\t1028 020d  Inspiron 530\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t1043 8277  P5K PRO Motherboard\n\t\t1462 7345  MS-7345 Motherboard\n\t\t8086 5044  Desktop Board DP35DP\n\t2917  ICH9M-E LPC Interface Controller\n\t\t17aa 20f5  ThinkPad T400\n\t\te4bf cc4d  CCM-BOOGIE\n\t2918  82801IB (ICH9) LPC Interface Controller\n\t\t1028 0236  PowerEdge R610 82801IB (ICH9) LPC Interface Controller\n\t\t1462 7360  G33/P35 Neo\n\t\t1af4 1100  QEMU Virtual Machine\n\t2919  ICH9M LPC Interface Controller\n\t2920  82801IR/IO/IH (ICH9R/DO/DH) 4 port SATA Controller [IDE mode]\n\t\t1028 020d  Inspiron 530\n\t\t1028 020f  PowerEdge R300 onboard SATA Controller\n\t\t1028 0210  PowerEdge T300 onboard SATA Controller\n\t\t1028 0211  Optiplex 755\n\t\t1028 023c  PowerEdge R200 onboard SATA Controller\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801IR [ICH9R]\n\t2921  82801IB (ICH9) 2 port SATA Controller [IDE mode]\n\t\t1028 0235  PowerEdge R710 SATA IDE Controller\n\t\t1028 0236  PowerEdge R610 SATA IDE Controller\n\t\t1028 0237  PowerEdge T610 SATA IDE Controller\n\t\t1462 7360  G33/P35 Neo\n\t2922  82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode]\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801IR [ICH9R]\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 5044  Desktop Board DP35DP\n\t2923  82801IB (ICH9) 4 port SATA Controller [AHCI mode]\n\t2925  82801IR/IO (ICH9R/DO) SATA Controller [RAID mode]\n\t\t1734 10e0  System Board D2542\n\t\t8086 2925  System Board D2542\n\t2926  82801I (ICH9 Family) 2 port SATA Controller [IDE mode]\n\t\t1028 020d  Inspiron 530\n\t\t1028 020f  PowerEdge R300 onboard SATA Controller\n\t\t1028 0210  PowerEdge T300 onboard SATA Controller\n\t\t1028 0211  Optiplex 755\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801IR [ICH9R]\n\t\t1462 7360  G33/P35 Neo\n\t2928  82801IBM/IEM (ICH9M/ICH9M-E) 2 port SATA Controller [IDE mode]\n\t2929  82801IBM/IEM (ICH9M/ICH9M-E) 4 port SATA Controller [AHCI mode]\n\t\t103c 3628  dv6-1190en\n\t\t17aa 20f8  ThinkPad T400\n\t\te4bf cc4d  CCM-BOOGIE\n\t292c  82801IEM (ICH9M-E) SATA Controller [RAID mode]\n\t292d  82801IBM/IEM (ICH9M/ICH9M-E) 2 port SATA Controller [IDE mode]\n\t\te4bf cc4d  CCM-BOOGIE\n\t2930  82801I (ICH9 Family) SMBus Controller\n\t\t1028 020d  Inspiron 530\n\t\t1028 0211  Optiplex 755\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t103c 3628  dv6-1190en\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t\t1462 7360  G33/P35 Neo\n\t\t17aa 20f9  ThinkPad T400\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 5044  Desktop Board DP35DP\n\t\te4bf cc4d  CCM-BOOGIE\n\t2932  82801I (ICH9 Family) Thermal Subsystem\n\t\t103c 3628  dv6-1190en\n\t2934  82801I (ICH9 Family) USB UHCI Controller #1\n\t\t1028 020d  Inspiron 530\n\t\t1028 020f  PowerEdge R300 onboard UHCI\n\t\t1028 0210  PowerEdge T300 onboard UHCI\n\t\t1028 0211  Optiplex 755\n\t\t1028 0235  PowerEdge R710 USB UHCI Controller\n\t\t1028 0236  PowerEdge R610 USB UHCI Controller\n\t\t1028 0237  PowerEdge T610 USB UHCI Controller\n\t\t1028 023c  PowerEdge R200 onboard UHCI\n\t\t1028 0287  PowerEdge M610 onboard UHCI\n\t\t1028 029c  PowerEdge M710 USB UHCI Controller\n\t\t1028 2011  Optiplex 755\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t\t1462 7360  G33/P35 Neo\n\t\t17aa 20f0  ThinkPad T400\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 5044  Desktop Board DP35DP\n\t\te4bf cc4d  CCM-BOOGIE\n\t2935  82801I (ICH9 Family) USB UHCI Controller #2\n\t\t1028 020d  Inspiron 530\n\t\t1028 020f  PowerEdge R300 onboard UHCI\n\t\t1028 0210  PowerEdge T300 onboard UHCI\n\t\t1028 0211  Optiplex 755\n\t\t1028 0235  PowerEdge R710 USB UHCI Controller\n\t\t1028 0236  PowerEdge R610 USB UHCI Controller\n\t\t1028 0237  PowerEdge T610 USB UHCI Controller\n\t\t1028 023c  PowerEdge R200 onboard UHCI\n\t\t1028 0287  PowerEdge M610 onboard UHCI\n\t\t1028 029c  PowerEdge M710 USB UHCI Controller\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t\t1462 7360  G33/P35 Neo\n\t\t17aa 20f0  ThinkPad T400\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 5044  Desktop Board DP35DP\n\t\te4bf cc4d  CCM-BOOGIE\n\t2936  82801I (ICH9 Family) USB UHCI Controller #3\n\t\t1028 020d  Inspiron 530\n\t\t1028 020f  PowerEdge R300 onboard UHCI\n\t\t1028 0210  PowerEdge T300 onboard UHCI\n\t\t1028 0211  Optiplex 755\n\t\t1028 0237  PowerEdge T610 USB UHCI Controller\n\t\t1028 023c  PowerEdge R200 onboard UHCI\n\t\t1028 0287  PowerEdge M610 onboard UHCI\n\t\t1028 029c  PowerEdge M710 USB UHCI Controller\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t\t1462 7360  G33/P35 Neo\n\t\t17aa 20f0  ThinkPad T400\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 5044  Desktop Board DP35DP\n\t\te4bf cc4d  CCM-BOOGIE\n\t2937  82801I (ICH9 Family) USB UHCI Controller #4\n\t\t1028 020d  Inspiron 530\n\t\t1028 0211  Optiplex 755\n\t\t1028 0235  PowerEdge R710 USB UHCI Controller\n\t\t1028 0236  PowerEdge R610 USB UHCI Controller\n\t\t1028 0237  PowerEdge T610 USB UHCI Controller\n\t\t1028 0287  PowerEdge M610 onboard UHCI\n\t\t1028 029c  PowerEdge M710 USB UHCI Controller\n\t\t1028 2011  Optiplex 755\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t\t1462 7360  G33/P35 Neo\n\t\t17aa 20f0  ThinkPad T400\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 2937  Optiplex 755\n\t\t8086 2942  828011 (ICH9 Family ) USB UHCI Controller\n\t\t8086 5044  Desktop Board DP35DP\n\t\te4bf cc4d  CCM-BOOGIE\n\t2938  82801I (ICH9 Family) USB UHCI Controller #5\n\t\t1028 020d  Inspiron 530\n\t\t1028 0211  Optiplex 755\n\t\t1028 0235  PowerEdge R710 USB UHCI Controller\n\t\t1028 0236  PowerEdge R610 USB UHCI Controller\n\t\t1028 0237  PowerEdge T610 USB UHCI Controller\n\t\t1028 0287  PowerEdge M610 onboard UHCI\n\t\t1028 029c  PowerEdge M710 USB UHCI Controller\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t\t1462 7360  G33/P35 Neo\n\t\t17aa 20f0  ThinkPad T400\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 2938  Optiplex 755\n\t\t8086 5044  Desktop Board DP35DP\n\t\te4bf cc4d  CCM-BOOGIE\n\t2939  82801I (ICH9 Family) USB UHCI Controller #6\n\t\t1028 020d  Inspiron 530\n\t\t1028 0210  PowerEdge T300 onboard UHCI\n\t\t1028 0237  PowerEdge T610 USB UHCI Controller\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t\t1462 7360  G33/P35 Neo\n\t\t17aa 20f0  ThinkPad T400\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 5044  Desktop Board DP35DP\n\t\te4bf cc4d  CCM-BOOGIE\n\t293a  82801I (ICH9 Family) USB2 EHCI Controller #1\n\t\t1028 020d  Inspiron 530\n\t\t1028 020f  PowerEdge R300 onboard EHCI\n\t\t1028 0210  PowerEdge T300 onboard EHCI\n\t\t1028 0211  Optiplex 755\n\t\t1028 0235  PowerEdge R710 USB EHCI Controller\n\t\t1028 0236  PowerEdge R610 USB EHCI Controller\n\t\t1028 0237  PowerEdge T610 USB EHCI Controller\n\t\t1028 023c  PowerEdge R200 onboard EHCI\n\t\t1028 0287  PowerEdge M610 onboard EHCI\n\t\t1028 029c  PowerEdge M710 USB EHCI Controller\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t\t1462 7360  G33/P35 Neo\n\t\t17aa 20f1  ThinkPad T400\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 5044  Desktop Board DP35DP\n\t\te4bf cc4d  CCM-BOOGIE\n\t293c  82801I (ICH9 Family) USB2 EHCI Controller #2\n\t\t1028 020d  Inspiron 530\n\t\t1028 0211  Optiplex 755\n\t\t1028 0235  PowerEdge R710 USB EHCI Controller\n\t\t1028 0236  PowerEdge R610 USB EHCI Controller\n\t\t1028 0237  PowerEdge T610 USB EHCI Controller\n\t\t1028 0287  PowerEdge M610 onboard EHCI\n\t\t1028 029c  PowerEdge M710 USB EHCI Controller\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t\t1462 7360  G33/P35 Neo\n\t\t17aa 20f1  ThinkPad T400\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 293c  Optiplex 755\n\t\t8086 5044  Desktop Board DP35DP\n\t\te4bf cc4d  CCM-BOOGIE\n\t293e  82801I (ICH9 Family) HD Audio Controller\n\t\t1028 020d  Inspiron 530\n\t\t1028 0211  Optiplex 755\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t103c 3628  dv6-1190en\n\t\t1043 829f  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 735a  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t\t1462 7360  G33/P35 Neo\n\t\t17aa 20f2  ThinkPad T400\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 293e  Optiplex 755\n\t\t8086 2940  Optiplex 755\n\t\te4bf cc4d  CCM-BOOGIE\n\t2940  82801I (ICH9 Family) PCI Express Port 1\n\t\t1028 020d  Inspiron 530\n\t\t1028 0211  Optiplex 755\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t\t8086 2940  Optiplex 755\n\t2942  82801I (ICH9 Family) PCI Express Port 2\n\t\t1028 020d  Inspiron 530\n\t2944  82801I (ICH9 Family) PCI Express Port 3\n\t\t1028 020d  Inspiron 530\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t2946  82801I (ICH9 Family) PCI Express Port 4\n\t\t1028 020d  Inspiron 530\n\t2948  82801I (ICH9 Family) PCI Express Port 5\n\t\t1028 020d  Inspiron 530\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t294a  82801I (ICH9 Family) PCI Express Port 6\n\t\t1028 020d  Inspiron 530\n\t\t1043 8277  P5K PRO Motherboard: 82801IR [ICH9R]\n\t\t1462 7345  MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]\n\t294c  82566DC-2 Gigabit Network Connection\n\t\t17aa 302e  82566DM-2 Gigabit Network Connection\n\t2970  82946GZ/PL/GL Memory Controller Hub\n\t2971  82946GZ/PL/GL PCI Express Root Port\n\t2972  82946GZ/GL Integrated Graphics Controller\n\t2973  82946GZ/GL Integrated Graphics Controller\n\t2974  82946GZ/GL HECI Controller\n\t2975  82946GZ/GL HECI Controller\n\t2976  82946GZ/GL PT IDER Controller\n\t2977  82946GZ/GL KT Controller\n\t2980  82G35 Express DRAM Controller\n\t2981  82G35 Express PCI Express Root Port\n\t2982  82G35 Express Integrated Graphics Controller\n\t2983  82G35 Express Integrated Graphics Controller\n\t2984  82G35 Express HECI Controller\n\t2990  82Q963/Q965 Memory Controller Hub\n\t\t1028 01da  OptiPlex 745\n\t2991  82Q963/Q965 PCI Express Root Port\n\t2992  82Q963/Q965 Integrated Graphics Controller\n\t2993  82Q963/Q965 Integrated Graphics Controller\n\t2994  82Q963/Q965 HECI Controller\n\t2995  82Q963/Q965 HECI Controller\n\t2996  82Q963/Q965 PT IDER Controller\n\t2997  82Q963/Q965 KT Controller\n\t29a0  82P965/G965 Memory Controller Hub\n\t\t1043 81ea  P5B\n\t\t1462 7276  MS-7276 [G965MDH]\n\t29a1  82P965/G965 PCI Express Root Port\n\t29a2  82G965 Integrated Graphics Controller\n\t\t1462 7276  MS-7276 [G965MDH]\n\t29a3  82G965 Integrated Graphics Controller\n\t29a4  82P965/G965 HECI Controller\n\t29a5  82P965/G965 HECI Controller\n\t29a6  82P965/G965 PT IDER Controller\n\t29a7  82P965/G965 KT Controller\n\t29b0  82Q35 Express DRAM Controller\n\t\t1028 0211  OptiPlex 755\n\t29b1  82Q35 Express PCI Express Root Port\n\t\t1028 0211  OptiPlex 755\n\t29b2  82Q35 Express Integrated Graphics Controller\n\t\t1028 0211  OptiPlex 755\n\t29b3  82Q35 Express Integrated Graphics Controller\n\t\t1028 0211  OptiPlex 755\n\t29b4  82Q35 Express MEI Controller\n\t\t1028 0211  OptiPlex 755\n\t29b5  82Q35 Express MEI Controller\n\t29b6  82Q35 Express PT IDER Controller\n\t\t1028 0211  OptiPlex 755\n\t29b7  82Q35 Express Serial KT Controller\n\t\t1028 0211  OptiPlex 755\n\t29c0  82G33/G31/P35/P31 Express DRAM Controller\n\t\t1028 020d  Inspiron 530\n\t\t103c 2a6f  Asus IPIBL-LB Motherboard\n\t\t1043 8276  P5K PRO Motherboard: Intel 82P35 Northbridge\n\t\t1043 82b0  P5KPL-VM Motherboard\n\t\t1462 7345  MS-7345 Motherboard: Intel 82G33/P35 Northbridge\n\t\t1462 7360  G33/P35 Neo\n\t\t1af4 1100  QEMU Virtual Machine\n\t\t8086 5044  Desktop Board DP35DP\n\t29c1  82G33/G31/P35/P31 Express PCI Express Root Port\n\t\t1028 020d  Inspiron 530\n\t\t1043 8276  P5K PRO Motherboard: Intel 82P35 Northbridge\n\t29c2  82G33/G31 Express Integrated Graphics Controller\n\t\t1028 020d  Inspiron 530\n\t\t1043 82b0  P5KPL-VM Motherboard\n\t29c3  82G33/G31 Express Integrated Graphics Controller\n\t\t1028 020d  Inspiron 530\n\t\t1043 82b0  P5KPL-VM Motherboard\n\t29c4  82G33/G31/P35/P31 Express MEI Controller\n\t\t8086 5044  Desktop Board DP35DP\n\t29c5  82G33/G31/P35/P31 Express MEI Controller\n\t29c6  82G33/G31/P35/P31 Express PT IDER Controller\n\t29c7  82G33/G31/P35/P31 Express Serial KT Controller\n\t29cf  Virtual HECI Controller\n\t29d0  82Q33 Express DRAM Controller\n\t29d1  82Q33 Express PCI Express Root Port\n\t29d2  82Q33 Express Integrated Graphics Controller\n\t29d3  82Q33 Express Integrated Graphics Controller\n\t29d4  82Q33 Express MEI Controller\n\t29d5  82Q33 Express MEI Controller\n\t29d6  82Q33 Express PT IDER Controller\n\t29d7  82Q33 Express Serial KT Controller\n\t29e0  82X38/X48 Express DRAM Controller\n\t29e1  82X38/X48 Express Host-Primary PCI Express Bridge\n\t29e4  82X38/X48 Express MEI Controller\n\t29e5  82X38/X48 Express MEI Controller\n\t29e6  82X38/X48 Express PT IDER Controller\n\t29e7  82X38/X48 Express Serial KT Controller\n\t29e9  82X38/X48 Express Host-Secondary PCI Express Bridge\n\t29f0  3200/3210 Chipset DRAM Controller\n\t29f1  3200/3210 Chipset Host-Primary PCI Express Bridge\n\t29f4  3200/3210 Chipset MEI Controller\n\t29f5  3200/3210 Chipset MEI Controller\n\t29f6  3200/3210 Chipset PT IDER Controller\n\t29f7  3200/3210 Chipset Serial KT Controller\n\t29f9  3210 Chipset Host-Secondary PCI Express Bridge\n\t2a00  Mobile PM965/GM965/GL960 Memory Controller Hub\n\t\t1025 0121  Aspire 5920G\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30c1  Compaq 6910p\n\t\t103c 30cc  Pavilion dv6700\n\t\t103c 30d9  Presario C700\n\t\t104d 9005  Vaio VGN-FZ260E\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t17aa 20b1  ThinkPad T61\n\t\t17aa 20b3  ThinkPad T61/R61\n\t\t17c0 4082  Medion WIM 2210 Notebook PC [MD96850]\n\t\te4bf cc47  CCG-RUMBA\n\t2a01  Mobile PM965/GM965/GL960 PCI Express Root Port\n\t2a02  Mobile GM965/GL960 Integrated Graphics Controller (primary)\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 01f9  Latitude D630\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30d9  Presario C700\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t17aa 20b5  GM965 [X3100] on ThinkPad T61/R61\n\t\t17c0 4082  GM965 on Medion WIM 2210 Notebook PC [MD96850]\n\t\te4bf cc47  CCG-RUMBA\n\t2a03  Mobile GM965/GL960 Integrated Graphics Controller (secondary)\n\t\t1028 01f3  Inspiron 1420\n\t\t1028 022f  Inspiron 1525\n\t\t103c 30c0  Compaq 6710b\n\t\t103c 30d9  Presario C700\n\t\t104d 902d  VAIO VGN-NR120E\n\t\t17aa 20b5  GM965 [X3100] on ThinkPad T61/R61\n\t\t17c0 4082  GM965 on Medion WIM 2210 Notebook PC [MD96850]\n\t\te4bf cc47  CCG-RUMBA\n\t2a04  Mobile PM965/GM965 MEI Controller\n\t\t103c 30c1  Compaq 6910p\n\t2a05  Mobile PM965/GM965 MEI Controller\n\t2a06  Mobile PM965/GM965 PT IDER Controller\n\t\t103c 30c1  Compaq 6910p\n\t2a07  Mobile PM965/GM965 KT Controller\n\t\t103c 30c1  Compaq 6910p\n\t2a10  Mobile GME965/GLE960 Memory Controller Hub\n\t\te4bf cc47  CCG-RUMBA\n\t2a11  Mobile GME965/GLE960 PCI Express Root Port\n\t2a12  Mobile GME965/GLE960 Integrated Graphics Controller\n\t\te4bf cc47  CCG-RUMBA\n\t2a13  Mobile GME965/GLE960 Integrated Graphics Controller\n\t\te4bf cc47  CCG-RUMBA\n\t2a14  Mobile GME965/GLE960 MEI Controller\n\t2a15  Mobile GME965/GLE960 MEI Controller\n\t2a16  Mobile GME965/GLE960 PT IDER Controller\n\t2a17  Mobile GME965/GLE960 KT Controller\n\t2a40  Mobile 4 Series Chipset Memory Controller Hub\n\t\t17aa 20e0  ThinkPad T400\n\t\te4bf cc4d  CCM-BOOGIE\n\t2a41  Mobile 4 Series Chipset PCI Express Graphics Port\n\t\te4bf cc4d  CCM-BOOGIE\n\t2a42  Mobile 4 Series Chipset Integrated Graphics Controller\n\t\t17aa 2112  ThinkPad T400\n\t\te4bf cc4d  CCM-BOOGIE\n\t2a43  Mobile 4 Series Chipset Integrated Graphics Controller\n\t\t17aa 2112  ThinkPad T400\n\t\te4bf cc4d  CCM-BOOGIE\n\t2a44  Mobile 4 Series Chipset MEI Controller\n\t\t17aa 20e6  ThinkPad T400\n\t2a45  Mobile 4 Series Chipset MEI Controller\n\t2a46  Mobile 4 Series Chipset PT IDER Controller\n\t2a47  Mobile 4 Series Chipset AMT SOL Redirection\n\t2a50  Cantiga MEI Controller\n\t2a51  Cantiga MEI Controller\n\t2a52  Cantiga PT IDER Controller\n\t2a53  Cantiga AMT SOL Redirection\n\t2b00  Xeon Processor E7 Product Family System Configuration Controller 1\n\t2b02  Xeon Processor E7 Product Family System Configuration Controller 2\n\t2b04  Xeon Processor E7 Product Family Power Controller\n\t2b08  Xeon Processor E7 Product Family Caching Agent 0\n\t2b0c  Xeon Processor E7 Product Family Caching Agent 1\n\t2b10  Xeon Processor E7 Product Family QPI Home Agent 0\n\t2b13  Xeon Processor E7 Product Family Memory Controller 0c\n\t2b14  Xeon Processor E7 Product Family Memory Controller 0a\n\t2b16  Xeon Processor E7 Product Family Memory Controller 0b\n\t2b18  Xeon Processor E7 Product Family QPI Home Agent 1\n\t2b1b  Xeon Processor E7 Product Family Memory Controller 1c\n\t2b1c  Xeon Processor E7 Product Family Memory Controller 1a\n\t2b1e  Xeon Processor E7 Product Family Memory Controller 1b\n\t2b20  Xeon Processor E7 Product Family Last Level Cache Coherence Engine 0\n\t2b22  Xeon Processor E7 Product Family System Configuration Controller 3\n\t2b24  Xeon Processor E7 Product Family Last Level Cache Coherence Engine 1\n\t2b28  Xeon Processor E7 Product Family Last Level Cache Coherence Engine 2\n\t2b2a  Xeon Processor E7 Product Family System Configuration Controller 4\n\t2b2c  Xeon Processor E7 Product Family Last Level Cache Coherence Engine 3\n\t2b30  Xeon Processor E7 Product Family Last Level Cache Coherence Engine 4\n\t2b34  Xeon Processor E7 Product Family Last Level Cache Coherence Engine 5\n\t2b38  Xeon Processor E7 Product Family Last Level Cache Coherence Engine 6\n\t2b3c  Xeon Processor E7 Product Family Last Level Cache Coherence Engine 7\n\t2b40  Xeon Processor E7 Product Family QPI Router Port 0-1\n\t2b42  Xeon Processor E7 Product Family QPI Router Port 2-3\n\t2b44  Xeon Processor E7 Product Family QPI Router Port 4-5\n\t2b46  Xeon Processor E7 Product Family QPI Router Port 6-7\n\t2b48  Xeon Processor E7 Product Family Test and Debug 0\n\t2b4c  Xeon Processor E7 Product Family Test and Debug 1\n\t2b50  Xeon Processor E7 Product Family QPI Physical Port 0: REUT control/status\n\t2b52  Xeon Processor E7 Product Family QPI Physical Port 0: Misc. control/status\n\t2b54  Xeon Processor E7 Product Family QPI Physical Port 1: REUT control/status\n\t2b56  Xeon Processor E7 Product Family QPI Physical Port 1: Misc. control/status\n\t2b58  Xeon Processor E7 Product Family QPI Physical Port 2: REUT control/status\n\t2b5a  Xeon Processor E7 Product Family QPI Physical Port 2: Misc. control/status\n\t2b5c  Xeon Processor E7 Product Family QPI Physical Port 3: REUT control/status\n\t2b5e  Xeon Processor E7 Product Family QPI Physical Port 3: Misc. control/status\n\t2b60  Xeon Processor E7 Product Family SMI Physical Port 0: REUT control/status\n\t2b62  Xeon Processor E7 Product Family SMI Physical Port 0: Misc control/status\n\t2b64  Xeon Processor E7 Product Family SMI Physical Port 1: REUT control/status\n\t2b66  Xeon Processor E7 Product Family SMI Physical Port 1: Misc control/status\n\t2b68  Xeon Processor E7 Product Family Last Level Cache Coherence Engine 8\n\t2b6c  Xeon Processor E7 Product Family Last Level Cache Coherence Engine 9\n\t2c01  Xeon 5500/Core i7 QuickPath Architecture System Address Decoder\n\t2c10  Xeon 5500/Core i7 QPI Link 0\n\t2c11  Xeon 5500/Core i7 QPI Physical 0\n\t2c14  Xeon 5500/Core i7 QPI Link 1\n\t2c15  Xeon 5500/Core i7 QPI Physical 1\n\t2c18  Xeon 5500/Core i7 Integrated Memory Controller\n\t2c19  Xeon 5500/Core i7 Integrated Memory Controller Target Address Decoder\n\t2c1a  Xeon 5500/Core i7 Integrated Memory Controller RAS Registers\n\t2c1c  Xeon 5500/Core i7 Integrated Memory Controller Test Registers\n\t2c20  Xeon 5500/Core i7 Integrated Memory Controller Channel 0 Control Registers\n\t2c21  Xeon 5500/Core i7 Integrated Memory Controller Channel 0 Address Registers\n\t2c22  Xeon 5500/Core i7 Integrated Memory Controller Channel 0 Rank Registers\n\t2c23  Xeon 5500/Core i7 Integrated Memory Controller Channel 0 Thermal Control Registers\n\t2c28  Xeon 5500/Core i7 Integrated Memory Controller Channel 1 Control Registers\n\t2c29  Xeon 5500/Core i7 Integrated Memory Controller Channel 1 Address Registers\n\t2c2a  Xeon 5500/Core i7 Integrated Memory Controller Channel 1 Rank Registers\n\t2c2b  Xeon 5500/Core i7 Integrated Memory Controller Channel 1 Thermal Control Registers\n\t2c30  Xeon 5500/Core i7 Integrated Memory Controller Channel 2 Control Registers\n\t2c31  Xeon 5500/Core i7 Integrated Memory Controller Channel 2 Address Registers\n\t2c32  Xeon 5500/Core i7 Integrated Memory Controller Channel 2 Rank Registers\n\t2c33  Xeon 5500/Core i7 Integrated Memory Controller Channel 2 Thermal Control Registers\n\t2c40  Xeon 5500/Core i7 QuickPath Architecture Generic Non-Core Registers\n\t2c41  Xeon 5500/Core i7 QuickPath Architecture Generic Non-Core Registers\n\t2c50  Core Processor QuickPath Architecture Generic Non-Core Registers\n\t2c51  Core Processor QuickPath Architecture Generic Non-Core Registers\n\t2c52  Core Processor QuickPath Architecture Generic Non-Core Registers\n\t2c53  Core Processor QuickPath Architecture Generic Non-Core Registers\n\t2c54  Core Processor QuickPath Architecture Generic Non-Core Registers\n\t2c55  Core Processor QuickPath Architecture Generic Non-Core Registers\n\t2c56  Core Processor QuickPath Architecture Generic Non-Core Registers\n\t2c57  Core Processor QuickPath Architecture Generic Non-Core Registers\n\t2c58  Xeon C5500/C3500 QPI Generic Non-core Registers\n\t2c59  Xeon C5500/C3500 QPI Generic Non-core Registers\n\t2c5a  Xeon C5500/C3500 QPI Generic Non-core Registers\n\t2c5b  Xeon C5500/C3500 QPI Generic Non-core Registers\n\t2c5c  Xeon C5500/C3500 QPI Generic Non-core Registers\n\t2c5d  Xeon C5500/C3500 QPI Generic Non-core Registers\n\t2c5e  Xeon C5500/C3500 QPI Generic Non-core Registers\n\t2c5f  Xeon C5500/C3500 QPI Generic Non-core Registers\n\t2c61  Core Processor QuickPath Architecture Generic Non-core Registers\n\t2c62  Core Processor QuickPath Architecture Generic Non-core Registers\n\t2c70  Xeon 5600 Series QuickPath Architecture Generic Non-core Registers\n\t2c81  Core Processor QuickPath Architecture System Address Decoder\n\t2c90  Core Processor QPI Link 0\n\t2c91  Core Processor QPI Physical 0\n\t2c98  Core Processor Integrated Memory Controller\n\t2c99  Core Processor Integrated Memory Controller Target Address Decoder\n\t2c9a  Core Processor Integrated Memory Controller Test Registers\n\t2c9c  Core Processor Integrated Memory Controller Test Registers\n\t2ca0  Core Processor Integrated Memory Controller Channel 0 Control Registers\n\t2ca1  Core Processor Integrated Memory Controller Channel 0 Address Registers\n\t2ca2  Core Processor Integrated Memory Controller Channel 0 Rank Registers\n\t2ca3  Core Processor Integrated Memory Controller Channel 0 Thermal Control Registers\n\t2ca8  Core Processor Integrated Memory Controller Channel 1 Control Registers\n\t2ca9  Core Processor Integrated Memory Controller Channel 1 Address Registers\n\t2caa  Core Processor Integrated Memory Controller Channel 1 Rank Registers\n\t2cab  Core Processor Integrated Memory Controller Channel 1 Thermal Control Registers\n\t2cc1  Xeon C5500/C3500 QPI System Address Decoder\n\t2cd0  Xeon C5500/C3500 QPI Link 0\n\t2cd1  Xeon C5500/C3500 QPI Physical 0\n\t2cd4  Xeon C5500/C3500 QPI Link 1\n\t2cd5  Xeon C5500/C3500 QPI Physical 1\n\t2cd8  Xeon C5500/C3500 Integrated Memory Controller Registers\n\t2cd9  Xeon C5500/C3500 Integrated Memory Controller Target Address Decoder\n\t2cda  Xeon C5500/C3500 Integrated Memory Controller RAS Registers\n\t2cdc  Xeon C5500/C3500 Integrated Memory Controller Test Registers\n\t2ce0  Xeon C5500/C3500 Integrated Memory Controller Channel 0 Control\n\t2ce1  Xeon C5500/C3500 Integrated Memory Controller Channel 0 Address\n\t2ce2  Xeon C5500/C3500 Integrated Memory Controller Channel 0 Rank\n\t2ce3  Xeon C5500/C3500 Integrated Memory Controller Channel 0 Thermal Control\n\t2ce8  Xeon C5500/C3500 Integrated Memory Controller Channel 1 Control\n\t2ce9  Xeon C5500/C3500 Integrated Memory Controller Channel 1 Address\n\t2cea  Xeon C5500/C3500 Integrated Memory Controller Channel 1 Rank\n\t2ceb  Xeon C5500/C3500 Integrated Memory Controller Channel 1 Thermal Control\n\t2cf0  Xeon C5500/C3500 Integrated Memory Controller Channel 2 Control\n\t2cf1  Xeon C5500/C3500 Integrated Memory Controller Channel 2 Address\n\t2cf2  Xeon C5500/C3500 Integrated Memory Controller Channel 2 Rank\n\t2cf3  Xeon C5500/C3500 Integrated Memory Controller Channel 2 Thermal Control\n\t2d01  Core Processor QuickPath Architecture System Address Decoder\n\t2d10  Core Processor QPI Link 0\n\t2d11  1st Generation Core i3/5/7 Processor QPI Physical 0\n\t2d12  1st Generation Core i3/5/7 Processor Reserved\n\t2d13  1st Generation Core i3/5/7 Processor Reserved\n\t2d81  Xeon 5600 Series QuickPath Architecture System Address Decoder\n\t2d90  Xeon 5600 Series QPI Link 0\n\t2d91  Xeon 5600 Series QPI Physical 0\n\t2d92  Xeon 5600 Series Mirror Port Link 0\n\t2d93  Xeon 5600 Series Mirror Port Link 1\n\t2d94  Xeon 5600 Series QPI Link 1\n\t2d95  Xeon 5600 Series QPI Physical 1\n\t2d98  Xeon 5600 Series Integrated Memory Controller Registers\n\t2d99  Xeon 5600 Series Integrated Memory Controller Target Address Decoder\n\t2d9a  Xeon 5600 Series Integrated Memory Controller RAS Registers\n\t2d9c  Xeon 5600 Series Integrated Memory Controller Test Registers\n\t2da0  Xeon 5600 Series Integrated Memory Controller Channel 0 Control\n\t2da1  Xeon 5600 Series Integrated Memory Controller Channel 0 Address\n\t2da2  Xeon 5600 Series Integrated Memory Controller Channel 0 Rank\n\t2da3  Xeon 5600 Series Integrated Memory Controller Channel 0 Thermal Control\n\t2da8  Xeon 5600 Series Integrated Memory Controller Channel 1 Control\n\t2da9  Xeon 5600 Series Integrated Memory Controller Channel 1 Address\n\t2daa  Xeon 5600 Series Integrated Memory Controller Channel 1 Rank\n\t2dab  Xeon 5600 Series Integrated Memory Controller Channel 1 Thermal Control\n\t2db0  Xeon 5600 Series Integrated Memory Controller Channel 2 Control\n\t2db1  Xeon 5600 Series Integrated Memory Controller Channel 2 Address\n\t2db2  Xeon 5600 Series Integrated Memory Controller Channel 2 Rank\n\t2db3  Xeon 5600 Series Integrated Memory Controller Channel 2 Thermal Control\n\t2e00  4 Series Chipset DRAM Controller\n\t2e01  4 Series Chipset PCI Express Root Port\n\t2e02  4 Series Chipset Integrated Graphics Controller\n\t2e03  4 Series Chipset Integrated Graphics Controller\n\t2e04  4 Series Chipset HECI Controller\n\t2e05  4 Series Chipset HECI Controller\n\t2e06  4 Series Chipset PT IDER Controller\n\t2e07  4 Series Chipset Serial KT Controller\n\t2e10  4 Series Chipset DRAM Controller\n\t2e11  4 Series Chipset PCI Express Root Port\n\t2e12  4 Series Chipset Integrated Graphics Controller\n\t\t17aa 3048  ThinkCentre M6258\n\t2e13  4 Series Chipset Integrated Graphics Controller\n\t2e14  4 Series Chipset HECI Controller\n\t2e15  4 Series Chipset HECI Controller\n\t2e16  4 Series Chipset PT IDER Controller\n\t2e17  4 Series Chipset Serial KT Controller\n\t2e20  4 Series Chipset DRAM Controller\n\t\t1028 0283  Vostro 220\n\t\t1043 82d3  P5Q Deluxe Motherboard\n\t\t1458 5000  GA-EP45-DS5/GA-EG45M-DS2H Motherboard\n\t2e21  4 Series Chipset PCI Express Root Port\n\t\t1043 82d3  P5Q Deluxe Motherboard\n\t\t1458 5000  GA-EP45-DS5 Motherboard\n\t2e22  4 Series Chipset Integrated Graphics Controller\n\t\t1458 d000  GA-EG45M-DS2H Mainboard\n\t2e23  4 Series Chipset Integrated Graphics Controller\n\t\t1458 d000  GA-EG45M-DS2H Mainboard\n\t2e24  4 Series Chipset HECI Controller\n\t2e25  4 Series Chipset HECI Controller\n\t2e26  4 Series Chipset PT IDER Controller\n\t2e27  4 Series Chipset Serial KT Controller\n\t2e29  4 Series Chipset PCI Express Root Port\n\t2e30  4 Series Chipset DRAM Controller\n\t\t103c 2a8c  Compaq 500B Microtower\n\t2e31  4 Series Chipset PCI Express Root Port\n\t2e32  4 Series Chipset Integrated Graphics Controller\n\t\t103c 2a8c  Compaq 500B Microtower\n\t2e33  4 Series Chipset Integrated Graphics Controller\n\t2e34  4 Series Chipset HECI Controller\n\t2e35  4 Series Chipset HECI Controller\n\t2e36  4 Series Chipset PT IDER Controller\n\t2e37  4 Series Chipset Serial KT Controller\n\t2e40  4 Series Chipset DRAM Controller\n\t2e41  4 Series Chipset PCI Express Root Port\n\t2e42  4 Series Chipset Integrated Graphics Controller\n\t2e43  4 Series Chipset Integrated Graphics Controller\n\t2e44  4 Series Chipset HECI Controller\n\t2e45  4 Series Chipset HECI Controller\n\t2e46  4 Series Chipset PT IDER Controller\n\t2e47  4 Series Chipset Serial KT Controller\n\t2e50  CE Media Processor CE3100\n\t2e52  CE Media Processor Clock and Reset Controller\n\t2e58  CE Media Processor Interrupt Controller\n\t2e5a  CE Media Processor CE3100 A/V Bridge\n\t2e5b  Graphics Media Accelerator 500 Graphics\n\t2e5c  CE Media Processor Video Decoder\n\t2e5d  CE Media Processor Transport Stream Interface\n\t2e5e  CE Media Processor Transport Stream Processor 0\n\t2e5f  CE Media Processor Audio DSP\n\t2e60  CE Media Processor Audio Interfaces\n\t2e61  CE Media Processor Video Display Controller\n\t2e62  CE Media Processor Video Processing Unit\n\t2e63  CE Media Processor HDMI Tx Interface\n\t2e65  CE Media Processor Expansion Bus Interface\n\t2e66  CE Media Processor UART\n\t2e67  CE Media Processor General Purpose I/Os\n\t2e68  CE Media Processor I2C Interface\n\t2e69  CE Media Processor Smart Card Interface\n\t2e6a  CE Media Processor SPI Master Interface\n\t2e6e  CE Media Processor Gigabit Ethernet Controller\n\t2e6f  CE Media Processor Media Timing Unit\n\t2e70  CE Media Processor USB\n\t2e71  CE Media Processor SATA\n\t2e73  CE Media Processor CE3100 PCI Express\n\t2e90  4 Series Chipset DRAM Controller\n\t2e91  4 Series Chipset PCI Express Root Port\n\t2e92  4 Series Chipset Integrated Graphics Controller\n\t2e93  4 Series Chipset Integrated Graphics Controller\n\t2e94  4 Series Chipset HECI Controller\n\t2e95  4 Series Chipset HECI Controller\n\t2e96  4 Series Chipset PT IDER Controller\n\t2f00  Xeon E7 v3/Xeon E5 v3/Core i7 DMI2\n\t2f01  Xeon E7 v3/Xeon E5 v3/Core i7 PCI Express Root Port 0\n\t2f02  Xeon E7 v3/Xeon E5 v3/Core i7 PCI Express Root Port 1\n\t2f03  Xeon E7 v3/Xeon E5 v3/Core i7 PCI Express Root Port 1\n\t2f04  Xeon E7 v3/Xeon E5 v3/Core i7 PCI Express Root Port 2\n\t2f05  Xeon E7 v3/Xeon E5 v3/Core i7 PCI Express Root Port 2\n\t2f06  Xeon E7 v3/Xeon E5 v3/Core i7 PCI Express Root Port 2\n\t2f07  Xeon E7 v3/Xeon E5 v3/Core i7 PCI Express Root Port 2\n\t2f08  Xeon E7 v3/Xeon E5 v3/Core i7 PCI Express Root Port 3\n\t2f09  Xeon E7 v3/Xeon E5 v3/Core i7 PCI Express Root Port 3\n\t2f0a  Xeon E7 v3/Xeon E5 v3/Core i7 PCI Express Root Port 3\n\t2f0b  Xeon E7 v3/Xeon E5 v3/Core i7 PCI Express Root Port 3\n\t2f0d  Haswell Xeon Non-Transparent Bridge (Back-to-back)\n\t2f0e  Haswell Xeon Non-Transparent Bridge (Primary Side)\n\t2f0f  Haswell Xeon Non-Transparent Bridge (Secondary Side)\n\t2f10  Xeon E7 v3/Xeon E5 v3/Core i7 IIO Debug\n\t2f11  Xeon E7 v3/Xeon E5 v3/Core i7 IIO Debug\n\t2f12  Xeon E7 v3/Xeon E5 v3/Core i7 IIO Debug\n\t2f13  Xeon E7 v3/Xeon E5 v3/Core i7 IIO Debug\n\t2f14  Xeon E7 v3/Xeon E5 v3/Core i7 IIO Debug\n\t2f15  Xeon E7 v3/Xeon E5 v3/Core i7 IIO Debug\n\t2f16  Xeon E7 v3/Xeon E5 v3/Core i7 IIO Debug\n\t2f17  Xeon E7 v3/Xeon E5 v3/Core i7 IIO Debug\n\t2f18  Xeon E7 v3/Xeon E5 v3/Core i7 IIO Debug\n\t2f19  Xeon E7 v3/Xeon E5 v3/Core i7 IIO Debug\n\t2f1a  Xeon E7 v3/Xeon E5 v3/Core i7 IIO Debug\n\t2f1b  Xeon E7 v3/Xeon E5 v3/Core i7 IIO Debug\n\t2f1c  Xeon E7 v3/Xeon E5 v3/Core i7 IIO Debug\n\t2f1d  Xeon E7 v3/Xeon E5 v3/Core i7 PCIe Ring Interface\n\t2f1e  Xeon E7 v3/Xeon E5 v3/Core i7 Scratchpad & Semaphore Registers\n\t2f1f  Xeon E7 v3/Xeon E5 v3/Core i7 Scratchpad & Semaphore Registers\n\t2f20  Xeon E7 v3/Xeon E5 v3/Core i7 DMA Channel 0\n\t2f21  Xeon E7 v3/Xeon E5 v3/Core i7 DMA Channel 1\n\t2f22  Xeon E7 v3/Xeon E5 v3/Core i7 DMA Channel 2\n\t2f23  Xeon E7 v3/Xeon E5 v3/Core i7 DMA Channel 3\n\t2f24  Xeon E7 v3/Xeon E5 v3/Core i7 DMA Channel 4\n\t2f25  Xeon E7 v3/Xeon E5 v3/Core i7 DMA Channel 5\n\t2f26  Xeon E7 v3/Xeon E5 v3/Core i7 DMA Channel 6\n\t2f27  Xeon E7 v3/Xeon E5 v3/Core i7 DMA Channel 7\n\t2f28  Xeon E7 v3/Xeon E5 v3/Core i7 Address Map, VTd_Misc, System Management\n\t2f29  Xeon E7 v3/Xeon E5 v3/Core i7 Hot Plug\n\t2f2a  Xeon E7 v3/Xeon E5 v3/Core i7 RAS, Control Status and Global Errors\n\t2f2c  Xeon E7 v3/Xeon E5 v3/Core i7 I/O APIC\n\t2f2e  Xeon E7 v3/Xeon E5 v3/Core i7 RAID 5/6\n\t2f2f  Xeon E7 v3/Xeon E5 v3/Core i7 RAID 5/6\n\t2f30  Xeon E7 v3/Xeon E5 v3/Core i7 Home Agent 0\n\t2f32  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 0\n\t2f33  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 1\n\t2f34  Xeon E7 v3/Xeon E5 v3/Core i7 PCIe Ring Interface\n\t2f36  Xeon E7 v3/Xeon E5 v3/Core i7 R3 QPI Link 0 & 1 Monitoring\n\t2f37  Xeon E7 v3/Xeon E5 v3/Core i7 R3 QPI Link 0 & 1 Monitoring\n\t2f38  Xeon E7 v3/Xeon E5 v3/Core i7 Home Agent 1\n\t2f39  Xeon E7 v3/Xeon E5 v3/Core i7 I/O Performance Monitoring\n\t2f3a  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 2\n\t2f3e  Xeon E7 v3/Xeon E5 v3/Core i7 R3 QPI Link 2 Monitoring\n\t2f3f  Xeon E7 v3/Xeon E5 v3/Core i7 R3 QPI Link 2 Monitoring\n\t2f40  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 2\n\t2f41  Xeon E7 v3/Xeon E5 v3/Core i7 R3 QPI Link 2 Monitoring\n\t2f43  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 2\n\t2f45  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 2 Debug\n\t2f46  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 2 Debug\n\t2f47  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 2 Debug\n\t2f60  Xeon E7 v3/Xeon E5 v3/Core i7 Home Agent 1\n\t2f68  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Target Address, Thermal & RAS Registers\n\t2f6a  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Channel Target Address Decoder\n\t2f6b  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Channel Target Address Decoder\n\t2f6c  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Channel Target Address Decoder\n\t2f6d  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Channel Target Address Decoder\n\t2f6e  Xeon E7 v3/Xeon E5 v3/Core i7 DDRIO Channel 2/3 Broadcast\n\t2f6f  Xeon E7 v3/Xeon E5 v3/Core i7 DDRIO Global Broadcast\n\t2f70  Xeon E7 v3/Xeon E5 v3/Core i7 Home Agent 0 Debug\n\t2f71  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Target Address, Thermal & RAS Registers\n\t2f76  Xeon E7 v3/Xeon E5 v3/Core i7 E3 QPI Link Debug\n\t2f78  Xeon E7 v3/Xeon E5 v3/Core i7 Home Agent 1 Debug\n\t2f79  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Target Address, Thermal & RAS Registers\n\t2f7d  Xeon E7 v3/Xeon E5 v3/Core i7 Scratchpad & Semaphore Registers\n\t2f7e  Xeon E7 v3/Xeon E5 v3/Core i7 E3 QPI Link Debug\n\t2f80  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 0\n\t2f81  Xeon E7 v3/Xeon E5 v3/Core i7 R3 QPI Link 0 & 1 Monitoring\n\t2f83  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 0\n\t2f85  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 0 Debug\n\t2f86  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 0 Debug\n\t2f87  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 0 Debug\n\t2f88  Xeon E7 v3/Xeon E5 v3/Core i7 VCU\n\t2f8a  Xeon E7 v3/Xeon E5 v3/Core i7 VCU\n\t2f90  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 1\n\t2f93  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 1\n\t2f95  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 1 Debug\n\t2f96  Xeon E7 v3/Xeon E5 v3/Core i7 QPI Link 1 Debug\n\t2f98  Xeon E7 v3/Xeon E5 v3/Core i7 Power Control Unit\n\t2f99  Xeon E7 v3/Xeon E5 v3/Core i7 Power Control Unit\n\t2f9a  Xeon E7 v3/Xeon E5 v3/Core i7 Power Control Unit\n\t2f9c  Xeon E7 v3/Xeon E5 v3/Core i7 Power Control Unit\n\t2fa0  Xeon E7 v3/Xeon E5 v3/Core i7 Home Agent 0\n\t2fa8  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Target Address, Thermal & RAS Registers\n\t2faa  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Channel Target Address Decoder\n\t2fab  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Channel Target Address Decoder\n\t2fac  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Channel Target Address Decoder\n\t2fad  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Channel Target Address Decoder\n\t2fae  Xeon E7 v3/Xeon E5 v3/Core i7 DDRIO Channel 0/1 Broadcast\n\t2faf  Xeon E7 v3/Xeon E5 v3/Core i7 DDRIO Global Broadcast\n\t2fb0  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Channel 0 Thermal Control\n\t2fb1  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Channel 1 Thermal Control\n\t2fb2  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Channel 0 ERROR Registers\n\t2fb3  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Channel 1 ERROR Registers\n\t2fb4  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Channel 2 Thermal Control\n\t2fb5  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Channel 3 Thermal Control\n\t2fb6  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Channel 2 ERROR Registers\n\t2fb7  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 0 Channel 3 ERROR Registers\n\t2fb8  Xeon E7 v3/Xeon E5 v3/Core i7 DDRIO (VMSE) 2 & 3\n\t2fb9  Xeon E7 v3/Xeon E5 v3/Core i7 DDRIO (VMSE) 2 & 3\n\t2fba  Xeon E7 v3/Xeon E5 v3/Core i7 DDRIO (VMSE) 2 & 3\n\t2fbb  Xeon E7 v3/Xeon E5 v3/Core i7 DDRIO (VMSE) 2 & 3\n\t2fbc  Xeon E7 v3/Xeon E5 v3/Core i7 DDRIO (VMSE) 0 & 1\n\t2fbd  Xeon E7 v3/Xeon E5 v3/Core i7 DDRIO (VMSE) 0 & 1\n\t2fbe  Xeon E7 v3/Xeon E5 v3/Core i7 DDRIO (VMSE) 0 & 1\n\t2fbf  Xeon E7 v3/Xeon E5 v3/Core i7 DDRIO (VMSE) 0 & 1\n\t2fc0  Xeon E7 v3/Xeon E5 v3/Core i7 Power Control Unit\n\t2fc1  Xeon E7 v3/Xeon E5 v3/Core i7 Power Control Unit\n\t2fc2  Xeon E7 v3/Xeon E5 v3/Core i7 Power Control Unit\n\t2fc3  Xeon E7 v3/Xeon E5 v3/Core i7 Power Control Unit\n\t2fc4  Xeon E7 v3/Xeon E5 v3/Core i7 Power Control Unit\n\t2fc5  Xeon E7 v3/Xeon E5 v3/Core i7 Power Control Unit\n\t2fd0  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Channel 0 Thermal Control\n\t2fd1  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Channel 1 Thermal Control\n\t2fd2  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Channel 0 ERROR Registers\n\t2fd3  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Channel 1 ERROR Registers\n\t2fd4  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Channel 2 Thermal Control\n\t2fd5  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Channel 3 Thermal Control\n\t2fd6  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Channel 2 ERROR Registers\n\t2fd7  Xeon E7 v3/Xeon E5 v3/Core i7 Integrated Memory Controller 1 Channel 3 ERROR Registers\n\t2fe0  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fe1  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fe2  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fe3  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fe4  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fe5  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fe6  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fe7  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fe8  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fe9  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fea  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2feb  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fec  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fed  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fee  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2fef  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2ff0  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2ff1  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2ff2  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2ff3  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2ff4  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2ff5  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2ff6  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2ff7  Xeon E7 v3/Xeon E5 v3/Core i7 Unicast Registers\n\t2ff8  Xeon E7 v3/Xeon E5 v3/Core i7 Buffered Ring Agent\n\t2ff9  Xeon E7 v3/Xeon E5 v3/Core i7 Buffered Ring Agent\n\t2ffa  Xeon E7 v3/Xeon E5 v3/Core i7 Buffered Ring Agent\n\t2ffb  Xeon E7 v3/Xeon E5 v3/Core i7 Buffered Ring Agent\n\t2ffc  Xeon E7 v3/Xeon E5 v3/Core i7 System Address Decoder & Broadcast Registers\n\t2ffd  Xeon E7 v3/Xeon E5 v3/Core i7 System Address Decoder & Broadcast Registers\n\t2ffe  Xeon E7 v3/Xeon E5 v3/Core i7 System Address Decoder & Broadcast Registers\n\t3165  Wireless 3165\n# Stone Peak 1x1\n\t\t8086 4010  Dual Band Wireless AC 3165\n# Stone Peak 1x1\n\t\t8086 4210  Dual Band Wireless AC 3165\n\t3166  Dual Band Wireless-AC 3165 Plus Bluetooth\n\t3184  UHD Graphics 605\n\t3185  UHD Graphics 605\n\t318c  Celeron/Pentium Silver Processor Dynamic Platform and Thermal Framework Processor Participant\n\t318e  Celeron/Pentium Silver Processor NorthPeak\n\t3192  Gemini Lake P2SB\n\t3197  Celeron/Pentium Silver Processor PCI-default ISA-bridge\n\t319a  Celeron/Pentium Silver Processor Trusted Execution Engine Interface\n\t31a2  Celeron/Pentium Silver Processor Integrated Sensor Solution\n\t31ac  Celeron/Pentium Silver Processor Serial IO I2C Host Controller\n\t31ae  Celeron/Pentium Silver Processor Serial IO I2C Host Controller\n\t31bc  Celeron/Pentium Silver Processor Serial IO UART Host Controller\n\t31be  Celeron/Pentium Silver Processor Serial IO UART Host Controller\n\t31c0  Celeron/Pentium Silver Processor Serial IO UART Host Controller\n\t31c2  Celeron/Pentium Silver Processor Serial IO SPI Host Controller\n\t31c4  Celeron/Pentium Silver Processor Serial IO SPI Host Controller\n\t31c6  Celeron/Pentium Silver Processor Serial IO SPI Host Controller\n\t31cc  Celeron/Pentium Silver Processor SDA Standard Compliant SD Host Controller\n\t31d4  Celeron/Pentium Silver Processor Gaussian Mixture Model\n\t31d6  Gemini Lake PCI Express Root Port\n\t31d7  Gemini Lake PCI Express Root Port\n\t31d8  Gemini Lake PCI Express Root Port\n\t31d9  Gemini Lake PCI Express Root Port\n\t31da  Gemini Lake PCI Express Root Port\n\t31db  Gemini Lake PCI Express Root Port\n\t31ee  Celeron/Pentium Silver Processor Serial IO UART Host Controller\n\t31f0  Gemini Lake Host Bridge\n\t3200  GD31244 PCI-X SATA HBA\n\t\t1775 c200  C2K onboard SATA host bus adapter\n\t3310  IOP348 I/O Processor\n\t\t1054 3030  HRA380 Hitachi RAID Adapter to PCIe\n\t\t1054 3034  HRA381 Hitachi RAID Adapter to PCIe\n\t3313  IOP348 I/O Processor (SL8e) in IOC Mode SAS/SATA\n\t331b  IOP348 I/O Processor (SL8x) in IOC Mode SAS/SATA\n\t3331  IOC340 I/O Controller (VV8e) SAS/SATA\n\t3339  IOC340 I/O Controller (VV8x) SAS/SATA\n\t3340  82855PM Processor to I/O Controller\n\t\t1014 0529  Thinkpad T40 series\n\t\t1025 005a  TravelMate 290\n\t\t103c 088c  NC8000 laptop\n\t\t103c 0890  NC6000 laptop\n\t\t103c 08b0  tc1100 tablet\n\t\t144d c005  X10 Laptop\n\t\t144d c00c  P30/P35 notebook\n\t3341  82855PM Processor to AGP Controller\n\t\t144d c00c  P30 notebook\n\t3363  IOC340 I/O Controller in IOC Mode SAS/SATA\n\t3382  81342 [Chevelon] I/O Processor (ATUe)\n\t33c3  IOP348 I/O Processor (SL8De) in IOC Mode SAS/SATA\n\t33cb  IOP348 I/O Processor (SL8Dx) in IOC Mode SAS/SATA\n\t3400  5520/5500/X58 I/O Hub to ESI Port\n\t3401  5520/5500/X58 I/O Hub to ESI Port\n\t3402  5520/5500/X58 I/O Hub to ESI Port\n\t3403  5500 I/O Hub to ESI Port\n\t\t1028 0236  PowerEdge R610 I/O Hub to ESI Port\n\t\t1028 0287  PowerEdge M610 I/O Hub to ESI Port\n\t\t1028 028c  PowerEdge R410 I/O Hub to ESI Port\n\t\t1028 028d  PowerEdge T410 I/O Hub to ESI Port\n\t\t103c 330b  ProLiant ML150 G6 Server\n\t3404  5520/5500/X58 I/O Hub to ESI Port\n\t3405  5520/5500/X58 I/O Hub to ESI Port\n\t3406  5520 I/O Hub to ESI Port\n\t\t103c 330b  ProLiant G6 series\n\t3407  5520/5500/X58 I/O Hub to ESI Port\n\t3408  5520/5500/X58 I/O Hub PCI Express Root Port 1\n\t\t103c 330b  ProLiant G6 series\n\t3409  5520/5500/X58 I/O Hub PCI Express Root Port 2\n\t340a  5520/5500/X58 I/O Hub PCI Express Root Port 3\n\t\t103c 330b  ProLiant ML150 G6 Server\n\t340b  5520/X58 I/O Hub PCI Express Root Port 4\n\t340c  5520/X58 I/O Hub PCI Express Root Port 5\n\t340d  5520/X58 I/O Hub PCI Express Root Port 6\n\t340e  5520/5500/X58 I/O Hub PCI Express Root Port 7\n\t\t103c 330b  ProLiant ML150 G6 Server\n\t340f  5520/5500/X58 I/O Hub PCI Express Root Port 8\n\t3410  7500/5520/5500/X58 I/O Hub PCI Express Root Port 9\n\t3411  7500/5520/5500/X58 I/O Hub PCI Express Root Port 10\n\t3418  7500/5520/5500/X58 Physical Layer Port 0\n\t3419  7500/5520/5500 Physical Layer Port 1\n\t3420  7500/5520/5500/X58 I/O Hub PCI Express Root Port 0\n\t3421  7500/5520/5500/X58 I/O Hub PCI Express Root Port 0\n\t3422  7500/5520/5500/X58 I/O Hub GPIO and Scratch Pad Registers\n\t\t103c 330b  ProLiant G6 series\n\t3423  7500/5520/5500/X58 I/O Hub Control Status and RAS Registers\n\t\t103c 330b  ProLiant G6 series\n\t3425  7500/5520/5500/X58 Physical and Link Layer Registers Port 0\n\t3426  7500/5520/5500/X58 Routing and Protocol Layer Registers Port 0\n\t3427  7500/5520/5500 Physical and Link Layer Registers Port 1\n\t3428  7500/5520/5500 Routing & Protocol Layer Register Port 1\n\t3429  5520/5500/X58 Chipset QuickData Technology Device\n\t342a  5520/5500/X58 Chipset QuickData Technology Device\n\t342b  5520/5500/X58 Chipset QuickData Technology Device\n\t342c  5520/5500/X58 Chipset QuickData Technology Device\n\t342d  7500/5520/5500/X58 I/O Hub I/OxAPIC Interrupt Controller\n\t342e  7500/5520/5500/X58 I/O Hub System Management Registers\n\t\t103c 330b  ProLiant G6 series\n\t342f  7500/5520/5500/X58 Trusted Execution Technology Registers\n\t3430  5520/5500/X58 Chipset QuickData Technology Device\n\t3431  5520/5500/X58 Chipset QuickData Technology Device\n\t3432  5520/5500/X58 Chipset QuickData Technology Device\n\t3433  5520/5500/X58 Chipset QuickData Technology Device\n\t3438  7500/5520/5500/X58 I/O Hub Throttle Registers\n\t3482  Ice Lake-LP LPC Controller\n\t34a3  Ice Lake-LP SMBus Controller\n\t34a4  Ice Lake-LP SPI Controller\n\t34a8  Ice Lake-LP Serial IO UART Controller #0\n\t34a9  Ice Lake-LP Serial IO UART Controller #1\n\t34aa  Ice Lake-LP Serial IO SPI Controller #0\n\t34ab  Ice Lake-LP Serial IO SPI Controller #1\n\t34b0  Ice Lake-LP PCI Express Root Port #9\n\t34bc  Ice Lake-LP PCI Express Root Port #5\n\t34c5  Ice Lake-LP Serial IO I2c Controller #4\n\t34c6  Ice Lake-LP Serial IO I2c Controller #5\n\t34c8  Smart Sound Technology Audio Controller\n\t34d3  Ice Lake-LP SATA Controller [AHCI mode]\n\t34e0  Management Engine Interface\n\t34e8  Ice Lake-LP Serial IO I2C Controller #0\n\t34e9  Ice Lake-LP Serial IO I2C Controller #1\n\t34ea  Ice Lake-LP Serial IO I2C Controller #2\n\t34eb  Ice Lake-LP Serial IO I2C Controller #3\n\t34ed  Ice Lake-LP USB 3.1 xHCI Host Controller\n\t34f0  Killer Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)\n\t34f8  Ice Lake-LP SD Controller\n\t3500  6311ESB/6321ESB PCI Express Upstream Port\n\t\t103c 31fe  ProLiant DL140 G3\n\t\t15d9 9680  X7DBN Motherboard\n\t3501  6310ESB PCI Express Upstream Port\n\t3504  6311ESB/6321ESB I/OxAPIC Interrupt Controller\n\t3505  6310ESB I/OxAPIC Interrupt Controller\n\t350c  6311ESB/6321ESB PCI Express to PCI-X Bridge\n\t\t103c 31fe  ProLiant DL140 G3\n\t\t15d9 9680  X7DBN Motherboard\n\t350d  6310ESB PCI Express to PCI-X Bridge\n\t3510  6311ESB/6321ESB PCI Express Downstream Port E1\n\t\t103c 31fe  ProLiant DL140 G3\n\t\t15d9 9680  X7DBN Motherboard\n\t3511  6310ESB PCI Express Downstream Port E1\n\t3514  6311ESB/6321ESB PCI Express Downstream Port E2\n\t3515  6310ESB PCI Express Downstream Port E2\n\t3518  6311ESB/6321ESB PCI Express Downstream Port E3\n\t\t15d9 9680  X7DBN Motherboard\n\t3519  6310ESB PCI Express Downstream Port E3\n\t3575  82830M/MG/MP Host Bridge\n\t\t0e11 0030  Evo N600c\n\t\t1014 021d  ThinkPad A/T/X Series\n\t\t104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP\n\t3576  82830M/MP AGP Bridge\n\t3577  82830M/MG Integrated Graphics Controller\n\t\t1014 0513  ThinkPad A/T/X Series\n\t3578  82830M/MG/MP Host Bridge\n\t3580  82852/82855 GM/GME/PM/GMV Processor to I/O Controller\n\t\t1014 055c  ThinkPad R50e\n\t\t1025 0064  Extensa 3000 series laptop\n\t\t1028 0139  Latitude D400\n\t\t1028 014f  Latitude X300\n\t\t1028 0152  Latitude D500\n\t\t1028 0163  Latitude D505\n\t\t1028 018d  Inspiron 700m/710m\n\t\t1028 0196  Inspiron 5160\n\t\t114a 0582  PC8\n\t\t1734 1055  Amilo M1420\n\t\t1775 10d0  V5D Single Board Computer\n\t\t1775 ce90  CE9\n\t\t4c53 10b0  CL9 mainboard\n\t\t4c53 10e0  PSL09 PrPMC\n\t\te4bf 0cc9  CC9-SAMBA\n\t\te4bf 0cd2  CD2-BEBOP\n\t3581  82852/82855 GM/GME/PM/GMV Processor to AGP Controller\n\t\t1734 1055  Amilo M1420\n\t3582  82852/855GM Integrated Graphics Device\n\t\t1014 0562  ThinkPad R50e\n\t\t1028 0139  Latitude D400\n\t\t1028 014f  Latitude X300\n\t\t1028 0152  Latitude D500\n\t\t1028 0163  Latitude D505\n\t\t1028 018d  Inspiron 700m/710m\n\t\t114a 0582  PC8 integrated graphics\n\t\t1775 10d0  V5D Single Board Computer VGA\n\t\t1775 ce90  CE9\n\t\t4c53 10b0  CL9 mainboard\n\t\t4c53 10e0  PSL09 PrPMC\n\t\te4bf 0cc9  CC9-SAMBA\n\t\te4bf 0cd2  CD2-BEBOP\n\t3584  82852/82855 GM/GME/PM/GMV Processor to I/O Controller\n\t\t1014 055d  ThinkPad R50e\n\t\t1025 0064  Extensa 3000 series laptop\n\t\t1028 0139  Latitude D400\n\t\t1028 014f  Latitude X300\n\t\t1028 0152  Latitude D500\n\t\t1028 0163  Latitude D505\n\t\t1028 018d  Inspiron 700m/710m\n\t\t1028 0196  Inspiron 5160\n\t\t114a 0582  PC8\n\t\t1734 1055  Amilo M1420\n\t\t1775 10d0  V5D Single Board Computer\n\t\t1775 ce90  CE9\n\t\t4c53 10b0  CL9 mainboard\n\t\t4c53 10e0  PSL09 PrPMC\n\t3585  82852/82855 GM/GME/PM/GMV Processor to I/O Controller\n\t\t1014 055e  ThinkPad R50e\n\t\t1025 0064  Extensa 3000 series laptop\n\t\t1028 0139  Latitude D400\n\t\t1028 014f  Latitude X300\n\t\t1028 0152  Latitude D500\n\t\t1028 0163  Latitude D505\n\t\t1028 018d  Inspiron 700m/710m\n\t\t1028 0196  Inspiron 5160\n\t\t114a 0582  PC8\n\t\t1734 1055  Amilo M1420\n\t\t1775 10d0  V5D Single Board Computer\n\t\t1775 ce90  CE9\n\t\t4c53 10b0  CL9 mainboard\n\t\t4c53 10e0  PSL09 PrPMC\n\t358c  82854 GMCH\n\t358e  82854 GMCH Integrated Graphics Device\n\t3590  E7520 Memory Controller Hub\n\t\t1014 02dd  eServer xSeries server mainboard\n\t\t1028 016c  PowerEdge 1850 Memory Controller Hub\n\t\t1028 016d  PowerEdge 2850 Memory Controller Hub\n\t\t1028 019a  PowerEdge SC1425\n\t\t1734 103e  PRIMERGY RX/TX S2 series\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t4c53 10d0  Telum ASLP10 Processor AMC\n\t3591  E7525/E7520 Error Reporting Registers\n\t\t1014 02dd  eServer xSeries server mainboard\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t\t1028 0169  Precision 470\n\t\t103c 3208  ProLiant DL140 G2\n\t\t4c53 10d0  Telum ASLP10 Processor AMC\n\t3592  E7320 Memory Controller Hub\n\t\t1734 1073  Primergy Econel 200 D2020 mainboard\n\t3593  E7320 Error Reporting Registers\n\t\t1734 1073  Primergy Econel 200 D2020 mainboard\n\t3594  E7520 DMA Controller\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t\t4c53 10d0  Telum ASLP10 Processor AMC\n\t3595  E7525/E7520/E7320 PCI Express Port A\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t3596  E7525/E7520/E7320 PCI Express Port A1\n\t3597  E7525/E7520 PCI Express Port B\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t3598  E7520 PCI Express Port B1\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t3599  E7520 PCI Express Port C\n\t\t1775 1100  CR11/VR11 Single Board Computer\n\t359a  E7520 PCI Express Port C1\n\t359b  E7525/E7520/E7320 Extended Configuration Registers\n\t\t1014 02dd  eServer xSeries server mainboard\n\t359e  E7525 Memory Controller Hub\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t\t1028 0169  Precision 470\n\t35b0  3100 Chipset Memory I/O Controller Hub\n\t35b1  3100 DRAM Controller Error Reporting Registers\n\t35b5  3100 Chipset Enhanced DMA Controller\n\t35b6  3100 Chipset PCI Express Port A\n\t35b7  3100 Chipset PCI Express Port A1\n\t35c8  3100 Extended Configuration Test Overflow Registers\n\t3600  7300 Chipset Memory Controller Hub\n\t3604  7300 Chipset PCI Express Port 1\n\t3605  7300 Chipset PCI Express Port 2\n\t3606  7300 Chipset PCI Express Port 3\n\t3607  7300 Chipset PCI Express Port 4\n\t3608  7300 Chipset PCI Express Port 5\n\t3609  7300 Chipset PCI Express Port 6\n\t360a  7300 Chipset PCI Express Port 7\n\t360b  7300 Chipset QuickData Technology Device\n\t360c  7300 Chipset FSB Registers\n\t\t1028 01f0  PowerEdge R900 7300 Chipset FSB Registers\n\t360d  7300 Chipset Snoop Filter Registers\n\t360e  7300 Chipset Debug and Miscellaneous Registers\n\t360f  7300 Chipset FBD Branch 0 Registers\n\t3610  7300 Chipset FBD Branch 1 Registers\n\t3700  Xeon C5500/C3500 DMI\n\t3701  Xeon C5500/C3500 DMI\n\t3702  Xeon C5500/C3500 DMI\n\t3703  Xeon C5500/C3500 DMI\n\t3704  Xeon C5500/C3500 DMI\n\t3705  Xeon C5500/C3500 DMI\n\t3706  Xeon C5500/C3500 DMI\n\t3707  Xeon C5500/C3500 DMI\n\t3708  Xeon C5500/C3500 DMI\n\t3709  Xeon C5500/C3500 DMI\n\t370a  Xeon C5500/C3500 DMI\n\t370b  Xeon C5500/C3500 DMI\n\t370c  Xeon C5500/C3500 DMI\n\t370d  Xeon C5500/C3500 DMI\n\t370e  Xeon C5500/C3500 DMI\n\t370f  Xeon C5500/C3500 DMI\n\t3710  Xeon C5500/C3500 CB3 DMA\n\t3711  Xeon C5500/C3500 CB3 DMA\n\t3712  Xeon C5500/C3500 CB3 DMA\n\t3713  Xeon C5500/C3500 CB3 DMA\n\t3714  Xeon C5500/C3500 CB3 DMA\n\t3715  Xeon C5500/C3500 CB3 DMA\n\t3716  Xeon C5500/C3500 CB3 DMA\n\t3717  Xeon C5500/C3500 CB3 DMA\n\t3718  Xeon C5500/C3500 CB3 DMA\n\t3719  Xeon C5500/C3500 CB3 DMA\n\t371a  Xeon C5500/C3500 QPI Link\n\t371b  Xeon C5500/C3500 QPI Routing and Protocol\n\t371d  Xeon C5500/C3500 QPI Routing and Protocol\n\t3720  Xeon C5500/C3500 PCI Express Root Port 0\n\t3721  Xeon C5500/C3500 PCI Express Root Port 1\n\t3722  Xeon C5500/C3500 PCI Express Root Port 2\n\t3723  Xeon C5500/C3500 PCI Express Root Port 3\n\t3724  Xeon C5500/C3500 PCI Express Root Port 4\n\t3725  Xeon C5500/C3500 NTB Primary\n\t3726  Xeon C5500/C3500 NTB Primary\n\t3727  Xeon C5500/C3500 NTB Secondary\n\t3728  Xeon C5500/C3500 Core\n\t3729  Xeon C5500/C3500 Core\n\t372a  Xeon C5500/C3500 Core\n\t372b  Xeon C5500/C3500 Core\n\t372c  Xeon C5500/C3500 Reserved\n\t373f  Xeon C5500/C3500 IOxAPIC\n\t37c8  C62x Chipset QuickAssist Technology\n\t37cc  Ethernet Connection X722\n\t37cd  Ethernet Virtual Function 700 Series\n\t37ce  Ethernet Connection X722 for 10GbE backplane\n\t\t1590 0215  Ethernet 10Gb 2-port 568i Adapter\n\t\t17aa 4023  Intel Ethernet Connection X722 for 10GbE backplane\n\t\t17aa 4025  Ethernet Connection X722 for 10GbE backplane\n\t37cf  Ethernet Connection X722 for 10GbE QSFP+\n\t37d0  Ethernet Connection X722 for 10GbE SFP+\n\t\t17aa 4020  Intel Ethernet Connection X722 for 10G SFP+\n\t\t17aa 4021  Intel Ethernet Connection X722 for 10G SFP+\n\t\t17aa 4022  Ethernet Connection X722 for 10GbE SFP+\n\t\t8086 0001  Ethernet Network Adapter X722-2\n\t\t8086 0002  Ethernet Network Adapter X722-2\n\t\t8086 0003  Ethernet Network Adapter X722-4\n\t\t8086 0004  Ethernet Network Adapter X722-4\n\t37d1  Ethernet Connection X722 for 1GbE\n\t\t14cd 0010  88E1514 Ethernet OCP 2x1G RJ45 Phy Card [USI-1514-1GbaseT]\n\t\t1590 0216  Ethernet 1Gb 2-port 368i Adapter\n\t\t1590 0217  Ethernet 1Gb 2-port 368FLR-MMT Adapter\n\t\t1590 0247  Ethernet 1Gb 4-port 369i Adapter\n\t\t17aa 4020  Ethernet Connection X722 for 1GbE\n\t\t17aa 4021  Ethernet Connection X722 for 1GbE\n\t\t17aa 4022  Ethernet Connection X722 for 1GbE\n\t\t17aa 4024  Ethernet Connection X722 for 1GbE\n\t37d2  Ethernet Connection X722 for 10GBASE-T\n\t\t1059 0180  RD10019 10GbE interface\n\t\t1170 37d2  Ethernet Connection X722 for 10GBASE-T\n\t\t14cd 0030  Ethernet OCP 2x10G RJ45 Phy Card [USI-X557-10GbaseT]\n\t\t1590 0218  Ethernet 10Gb 2-port 568FLR-MMT Adapter\n\t\t17aa 4020  Ethernet Connection X722 for 10GBASE-T\n\t\t17aa 4021  Ethernet Connection X722 for 10GBASE-T\n\t\t17aa 4022  Ethernet Connection X722 for 10GBASE-T\n\t\t17aa 4024  Ethernet Connection X722 for 10GBASE-T\n\t\t17aa 4025  Ethernet Connection X722 for 10GBASE-T\n\t37d3  Ethernet Connection X722 for 10GbE SFP+\n\t\t1590 0219  Ethernet 10Gb 2-port 568FLR-MMSFP+ Adapter\n\t\t17aa 4020  Ethernet Connection X722 for 10GbE SFP+\n\t\t17aa 4021  Ethernet Connection X722 for 10GbE SFP+\n\t\t17aa 4025  Ethernet Connection X722 for 10GbE SFP+\n\t37d4  Ethernet Connection X722 for 10GbE QSFP+\n\t37d9  X722 Hyper-V Virtual Function\n\t3a00  82801JD/DO (ICH10 Family) 4-port SATA IDE Controller\n\t3a02  82801JD/DO (ICH10 Family) SATA AHCI Controller\n\t3a05  82801JD/DO (ICH10 Family) SATA RAID Controller\n\t3a06  82801JD/DO (ICH10 Family) 2-port SATA IDE Controller\n\t3a14  82801JDO (ICH10DO) LPC Interface Controller\n\t3a16  82801JIR (ICH10R) LPC Interface Controller\n\t\t1028 028c  PowerEdge R410 LPC Interface Controller\n\t\t1028 028d  PowerEdge T410 LPC Interface Controller\n\t\t103c 330b  ProLiant G6 series\n\t\t1043 82d4  P5Q Deluxe Motherboard\n\t\t1458 5001  GA-EP45-DS5 Motherboard\n\t3a18  82801JIB (ICH10) LPC Interface Controller\n\t3a1a  82801JD (ICH10D) LPC Interface Controller\n\t3a20  82801JI (ICH10 Family) 4 port SATA IDE Controller #1\n\t\t1028 028c  PowerEdge R410 SATA IDE Controller\n\t\t1028 028d  PowerEdge T410 SATA IDE Controller\n\t3a22  82801JI (ICH10 Family) SATA AHCI Controller\n\t\t103c 330b  ProLiant G6 series\n\t\t1043 82d4  P5Q Deluxe Motherboard\n\t\t1458 b005  GA-EP45-DS5/GA-EG45M-DS2H Motherboard\n\t3a25  82801JIR (ICH10R) SATA RAID Controller\n\t\t1028 028c  PERC S100 Controller (PE R410)\n\t\t1028 028d  PERC S100 Controller (PE T410)\n\t\t1028 02f1  PERC S100 Controller (PE R510)\n\t3a26  82801JI (ICH10 Family) 2 port SATA IDE Controller #2\n\t\t1028 028c  PowerEdge R410 SATA IDE Controller\n\t\t1028 028d  PowerEdge T410 SATA IDE Controller\n\t3a30  82801JI (ICH10 Family) SMBus Controller\n\t\t1043 82d4  P5Q Deluxe Motherboard\n\t\t1458 5001  GA-EP45-DS5/GA-EG45M-DS2H Motherboard\n\t3a32  82801JI (ICH10 Family) Thermal Subsystem\n\t3a34  82801JI (ICH10 Family) USB UHCI Controller #1\n\t\t1028 028c  PowerEdge R410 USB UHCI Controller\n\t\t1028 028d  PowerEdge T410 USB UHCI Controller\n\t\t103c 330b  ProLiant G6 series\n\t\t1043 82d4  P5Q Deluxe Motherboard\n\t\t1458 5004  GA-EP45-DS5 Motherboard\n\t3a35  82801JI (ICH10 Family) USB UHCI Controller #2\n\t\t1028 028c  PowerEdge R410 USB UHCI Controller\n\t\t1028 028d  PowerEdge T410 USB UHCI Controller\n\t\t103c 330b  ProLiant G6 series\n\t\t1043 82d4  P5Q Deluxe Motherboard\n\t\t1458 5004  GA-EP45-DS5 Motherboard\n\t3a36  82801JI (ICH10 Family) USB UHCI Controller #3\n\t\t1028 028c  PowerEdge R410 USB UHCI Controller\n\t\t1028 028d  PowerEdge T410 USB UHCI Controller\n\t\t103c 330b  ProLiant G6 series\n\t\t1043 82d4  P5Q Deluxe Motherboard\n\t\t1458 5004  GA-EP45-DS5 Motherboard\n\t3a37  82801JI (ICH10 Family) USB UHCI Controller #4\n\t\t1028 028c  PowerEdge R410 USB UHCI Controller\n\t\t1028 028d  PowerEdge T410 USB UHCI Controller\n\t\t103c 330b  ProLiant G6 series\n\t\t1043 82d4  P5Q Deluxe Motherboard\n\t\t1458 5004  Motherboard\n\t3a38  82801JI (ICH10 Family) USB UHCI Controller #5\n\t\t1028 028c  PowerEdge R410 USB UHCI Controller\n\t\t1028 028d  PowerEdge T410 USB UHCI Controller\n\t\t103c 330b  ProLiant ML150 G6 Server\n\t\t1043 82d4  P5Q Deluxe Motherboard\n\t\t1458 5004  Motherboard\n\t3a39  82801JI (ICH10 Family) USB UHCI Controller #6\n\t\t1028 028c  PowerEdge R410 USB UHCI Controller\n\t\t1028 028d  PowerEdge T410 USB UHCI Controller\n\t\t103c 330b  ProLiant ML150 G6 Server\n\t\t1043 82d4  P5Q Deluxe Motherboard\n\t\t1458 5004  Motherboard\n\t3a3a  82801JI (ICH10 Family) USB2 EHCI Controller #1\n\t\t1028 028c  PowerEdge R410 USB EHCI Controller\n\t\t1028 028d  PowerEdge T410 USB EHCI Controller\n\t\t103c 330b  ProLiant G6 series\n\t\t1043 82d4  P5Q Deluxe Motherboard\n\t\t1458 5006  GA-EP45-DS5 Motherboard\n\t3a3c  82801JI (ICH10 Family) USB2 EHCI Controller #2\n\t\t1028 028c  PowerEdge R410 USB EHCI Controller\n\t\t1028 028d  PowerEdge T410 USB EHCI Controller\n\t\t103c 330b  ProLiant G6 series\n\t\t1043 82d4  P5Q Deluxe Motherboard\n\t\t1458 5006  Motherboard\n\t3a3e  82801JI (ICH10 Family) HD Audio Controller\n\t\t1043 8311  P5Q Deluxe Motherboard\n\t\t1458 a002  GA-EP45-UD3R Motherboard\n\t\t1458 a102  GA-EP45-DS5/GA-EG45M-DS2H Motherboard\n\t3a40  82801JI (ICH10 Family) PCI Express Root Port 1\n\t\t1028 028c  PowerEdge R410 PCI Express Port 1\n\t\t1028 028d  PowerEdge T410 PCI Express Port 1\n\t\t103c 330b  ProLiant ML150 G6 Server\n\t\t1043 82d4  P5Q Deluxe Motherboard\n\t\t1043 82ea  P6T DeLuxe Motherboard\n\t\t1458 5001  GA-EP45-DS5/GA-EG45M-DS2H Motherboard\n\t3a42  82801JI (ICH10 Family) PCI Express Port 2\n\t3a44  82801JI (ICH10 Family) PCI Express Root Port 3\n\t\t1043 82ea  P6T DeLuxe Motherboard\n\t3a46  82801JI (ICH10 Family) PCI Express Root Port 4\n\t\t1043 82ea  P6T DeLuxe Motherboard\n\t\t1458 5001  GA-EP45-DS5 Motherboard\n\t3a48  82801JI (ICH10 Family) PCI Express Root Port 5\n\t\t103c 330b  ProLiant ML150 G6 Server\n\t\t1043 82ea  P6T Deluxe Motherboard\n\t\t1458 5001  GA-EP45-DS5 Motherboard\n\t3a4a  82801JI (ICH10 Family) PCI Express Root Port 6\n\t\t103c 330b  ProLiant ML150 G6 Server\n\t\t1043 82d4  P5Q Deluxe Motherboard\n\t\t1043 82ea  P6T DeLuxe Motherboard\n\t\t1458 5001  GA-EP45-DS5/GA-EG45M-DS2H Motherboard\n\t3a4c  82801JI (ICH10 Family) Gigabit Ethernet Controller\n\t3a51  82801JDO (ICH10DO) VECI Controller\n\t3a55  82801JD/DO (ICH10 Family) Virtual SATA Controller\n\t3a60  82801JD/DO (ICH10 Family) SMBus Controller\n\t3a62  82801JD/DO (ICH10 Family) Thermal Subsystem\n\t3a64  82801JD/DO (ICH10 Family) USB UHCI Controller #1\n\t3a65  82801JD/DO (ICH10 Family) USB UHCI Controller #2\n\t3a66  82801JD/DO (ICH10 Family) USB UHCI Controller #3\n\t3a67  82801JD/DO (ICH10 Family) USB UHCI Controller #4\n\t3a68  82801JD/DO (ICH10 Family) USB UHCI Controller #5\n\t3a69  82801JD/DO (ICH10 Family) USB UHCI Controller #6\n\t3a6a  82801JD/DO (ICH10 Family) USB2 EHCI Controller #1\n\t3a6c  82801JD/DO (ICH10 Family) USB2 EHCI Controller #2\n\t3a6e  82801JD/DO (ICH10 Family) HD Audio Controller\n\t3a70  82801JD/DO (ICH10 Family) PCI Express Port 1\n\t3a72  82801JD/DO (ICH10 Family) PCI Express Port 2\n\t3a74  82801JD/DO (ICH10 Family) PCI Express Port 3\n\t3a76  82801JD/DO (ICH10 Family) PCI Express Port 4\n\t3a78  82801JD/DO (ICH10 Family) PCI Express Port 5\n\t3a7a  82801JD/DO (ICH10 Family) PCI Express Port 6\n\t3a7c  82801JD/DO (ICH10 Family) Gigabit Ethernet Controller\n\t3b00  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b01  Mobile 5 Series Chipset LPC Interface Controller\n\t3b02  P55 Chipset LPC Interface Controller\n\t3b03  PM55 Chipset LPC Interface Controller\n\t3b04  5 Series Chipset LPC Interface Controller\n\t3b05  Mobile 5 Series Chipset LPC Interface Controller\n\t3b06  H55 Chipset LPC Interface Controller\n\t3b07  QM57 Chipset LPC Interface Controller\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\te4bf 50c1  PC1-GROOVE\n\t3b08  H57 Chipset LPC Interface Controller\n\t3b09  HM55 Chipset LPC Interface Controller\n\t\t1025 0347  Aspire 7740G\n\t\t144d c06a  R730 Laptop\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t3b0a  Q57 Chipset LPC Interface Controller\n\t\t1028 02da  OptiPlex 980\n\t\t15d9 060d  C7SIM-Q Motherboard\n\t3b0b  HM57 Chipset LPC Interface Controller\n\t3b0c  5 Series Chipset LPC Interface Controller\n\t3b0d  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b0e  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b0f  QS57 Chipset LPC Interface Controller\n\t3b10  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b11  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b12  3400 Series Chipset LPC Interface Controller\n\t3b13  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b14  3420 Chipset LPC Interface Controller\n\t\t15d9 0605  X8SIL\n\t3b15  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b16  3450 Chipset LPC Interface Controller\n\t3b17  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b18  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b19  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b1a  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b1b  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b1c  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b1d  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b1e  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b1f  5 Series/3400 Series Chipset LPC Interface Controller\n\t3b20  5 Series/3400 Series Chipset 4 port SATA IDE Controller\n\t3b21  5 Series/3400 Series Chipset 2 port SATA IDE Controller\n\t3b22  5 Series/3400 Series Chipset 6 port SATA AHCI Controller\n\t\t1028 02da  OptiPlex 980\n\t\t15d9 0605  X8SIL\n\t\t15d9 060d  C7SIM-Q Motherboard\n\t3b23  5 Series/3400 Series Chipset 4 port SATA AHCI Controller\n\t3b25  5 Series/3400 Series Chipset SATA RAID Controller\n\t\t103c 3118  Smart Array B110i SATA RAID Controller\n\t3b26  5 Series/3400 Series Chipset 2 port SATA IDE Controller\n\t3b28  5 Series/3400 Series Chipset 4 port SATA IDE Controller\n\t\t144d c06a  R730 Laptop\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t3b29  5 Series/3400 Series Chipset 4 port SATA AHCI Controller\n\t\t1025 0347  Aspire 7740G\n\t\t144d c06a  R730 Laptop\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t3b2c  5 Series/3400 Series Chipset SATA RAID Controller\n\t3b2d  5 Series/3400 Series Chipset 2 port SATA IDE Controller\n\t\t144d c06a  R730 Laptop\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t\te4bf 50c1  PC1-GROOVE\n\t3b2e  5 Series/3400 Series Chipset 4 port SATA IDE Controller\n\t\te4bf 50c1  PC1-GROOVE\n\t3b2f  5 Series/3400 Series Chipset 6 port SATA AHCI Controller\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\te4bf 50c1  PC1-GROOVE\n\t3b30  5 Series/3400 Series Chipset SMBus Controller\n\t\t1025 0347  Aspire 7740G\n\t\t1028 02da  OptiPlex 980\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\t1043 3838  P7P55-M Motherboard\n\t\t1043 8383  P7P55-M Motherboard\n\t\t144d c06a  R730 Laptop\n\t\t15d9 0605  X8SIL\n\t\t15d9 060d  C7SIM-Q Motherboard\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t\te4bf 50c1  PC1-GROOVE\n\t3b32  5 Series/3400 Series Chipset Thermal Subsystem\n\t\t1025 0347  Aspire 7740G\n\t\t1028 040a  Latitude E6410\n\t\t144d c06a  R730 Laptop\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t3b34  5 Series/3400 Series Chipset USB2 Enhanced Host Controller\n\t\t1025 0347  Aspire 7740G\n\t\t1028 02da  OptiPlex 980\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\t144d c06a  R730 Laptop\n\t\t15d9 0605  X8SIL\n\t\t15d9 060d  C7SIM-Q Motherboard\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t\te4bf 50c1  PC1-GROOVE\n\t3b36  5 Series/3400 Series Chipset USB Universal Host Controller\n\t3b37  5 Series/3400 Series Chipset USB Universal Host Controller\n\t3b38  5 Series/3400 Series Chipset USB Universal Host Controller\n\t3b39  5 Series/3400 Series Chipset USB Universal Host Controller\n\t3b3a  5 Series/3400 Series Chipset USB Universal Host Controller\n\t3b3b  5 Series/3400 Series Chipset USB Universal Host Controller\n\t3b3c  5 Series/3400 Series Chipset USB2 Enhanced Host Controller\n\t\t1025 0347  Aspire 7740G\n\t\t1028 02da  OptiPlex 980\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\t144d c06a  R730 Laptop\n\t\t15d9 0605  X8SIL\n\t\t15d9 060d  C7SIM-Q Motherboard\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t\te4bf 50c1  PC1-GROOVE\n\t3b3e  5 Series/3400 Series Chipset USB Universal Host Controller\n\t3b3f  5 Series/3400 Series Chipset USB Universal Host Controller\n\t3b40  5 Series/3400 Series Chipset USB Universal Host Controller\n\t3b41  5 Series/3400 Series Chipset LAN Controller\n\t3b42  5 Series/3400 Series Chipset PCI Express Root Port 1\n\t\t1028 02da  OptiPlex 980\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\t144d c06a  R730 Laptop\n\t\t15d9 060d  C7SIM-Q Motherboard\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t3b44  5 Series/3400 Series Chipset PCI Express Root Port 2\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\t15d9 060d  C7SIM-Q Motherboard\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t3b46  5 Series/3400 Series Chipset PCI Express Root Port 3\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\t144d c06a  R730 Laptop\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t3b48  5 Series/3400 Series Chipset PCI Express Root Port 4\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\t144d c06a  R730 Laptop\n\t3b4a  5 Series/3400 Series Chipset PCI Express Root Port 5\n\t\t1028 02da  OptiPlex 980\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t3b4c  5 Series/3400 Series Chipset PCI Express Root Port 6\n\t3b4e  5 Series/3400 Series Chipset PCI Express Root Port 7\n\t3b50  5 Series/3400 Series Chipset PCI Express Root Port 8\n\t3b53  5 Series/3400 Series Chipset VECI Controller\n\t3b56  5 Series/3400 Series Chipset High Definition Audio\n\t\t1025 0347  Aspire 7740G\n\t\t1028 02da  OptiPlex 980\n\t\t1028 040a  Latitude E6410\n\t\t1028 040b  Latitude E6510\n\t\t1043 1373  G73-series gaming laptop\n\t\t144d c06a  R730 Laptop\n\t\t15d9 060d  C7SIM-Q Motherboard\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t\te4bf 50c1  PC1-GROOVE\n\t3b57  5 Series/3400 Series Chipset High Definition Audio\n\t3b64  5 Series/3400 Series Chipset HECI Controller\n\t\t1025 0347  Aspire 7740G\n\t\t15d9 060d  C7SIM-Q Motherboard\n\t\t17c0 10d2  Medion Akoya E7214 Notebook PC [MD98410]\n\t\te4bf 50c1  PC1-GROOVE\n\t3b65  5 Series/3400 Series Chipset HECI Controller\n\t3b66  5 Series/3400 Series Chipset PT IDER Controller\n\t3b67  5 Series/3400 Series Chipset KT Controller\n\t\te4bf 50c1  PC1-GROOVE\n\t3c00  Xeon E5/Core i7 DMI2\n\t3c01  Xeon E5/Core i7 DMI2 in PCI Express Mode\n\t3c02  Xeon E5/Core i7 IIO PCI Express Root Port 1a\n\t3c03  Xeon E5/Core i7 IIO PCI Express Root Port 1b\n\t3c04  Xeon E5/Core i7 IIO PCI Express Root Port 2a\n\t3c05  Xeon E5/Core i7 IIO PCI Express Root Port 2b\n\t3c06  Xeon E5/Core i7 IIO PCI Express Root Port 2c\n\t3c07  Xeon E5/Core i7 IIO PCI Express Root Port 2d\n\t3c08  Xeon E5/Core i7 IIO PCI Express Root Port 3a in PCI Express Mode\n\t3c09  Xeon E5/Core i7 IIO PCI Express Root Port 3b\n\t3c0a  Xeon E5/Core i7 IIO PCI Express Root Port 3c\n\t3c0b  Xeon E5/Core i7 IIO PCI Express Root Port 3d\n\t3c0d  Xeon E5/Core i7 Non-Transparent Bridge\n\t3c0e  Xeon E5/Core i7 Non-Transparent Bridge\n\t3c0f  Xeon E5/Core i7 Non-Transparent Bridge\n\t3c20  Xeon E5/Core i7 DMA Channel 0\n\t3c21  Xeon E5/Core i7 DMA Channel 1\n\t3c22  Xeon E5/Core i7 DMA Channel 2\n\t3c23  Xeon E5/Core i7 DMA Channel 3\n\t3c24  Xeon E5/Core i7 DMA Channel 4\n\t3c25  Xeon E5/Core i7 DMA Channel 5\n\t3c26  Xeon E5/Core i7 DMA Channel 6\n\t3c27  Xeon E5/Core i7 DMA Channel 7\n\t3c28  Xeon E5/Core i7 Address Map, VTd_Misc, System Management\n\t3c2a  Xeon E5/Core i7 Control Status and Global Errors\n\t3c2c  Xeon E5/Core i7 I/O APIC\n\t3c2e  Xeon E5/Core i7 DMA\n\t3c2f  Xeon E5/Core i7 DMA\n\t3c40  Xeon E5/Core i7 IIO Switch and IRP Performance Monitor\n\t3c43  Xeon E5/Core i7 Ring to PCI Express Performance Monitor\n\t3c44  Xeon E5/Core i7 Ring to QuickPath Interconnect Link 0 Performance Monitor\n\t3c45  Xeon E5/Core i7 Ring to QuickPath Interconnect Link 1 Performance Monitor\n\t3c46  Xeon E5/Core i7 Processor Home Agent Performance Monitoring\n\t3c71  Xeon E5/Core i7 Integrated Memory Controller RAS Registers\n\t3c80  Xeon E5/Core i7 QPI Link 0\n\t3c83  Xeon E5/Core i7 QPI Link Reut 0\n\t3c84  Xeon E5/Core i7 QPI Link Reut 0\n\t3c90  Xeon E5/Core i7 QPI Link 1\n\t3c93  Xeon E5/Core i7 QPI Link Reut 1\n\t3c94  Xeon E5/Core i7 QPI Link Reut 1\n\t3ca0  Xeon E5/Core i7 Processor Home Agent\n\t3ca8  Xeon E5/Core i7 Integrated Memory Controller Registers\n\t3caa  Xeon E5/Core i7 Integrated Memory Controller Target Address Decoder 0\n\t3cab  Xeon E5/Core i7 Integrated Memory Controller Target Address Decoder 1\n\t3cac  Xeon E5/Core i7 Integrated Memory Controller Target Address Decoder 2\n\t3cad  Xeon E5/Core i7 Integrated Memory Controller Target Address Decoder 3\n\t3cae  Xeon E5/Core i7 Integrated Memory Controller Target Address Decoder 4\n\t3cb0  Xeon E5/Core i7 Integrated Memory Controller Channel 0-3 Thermal Control 0\n\t3cb1  Xeon E5/Core i7 Integrated Memory Controller Channel 0-3 Thermal Control 1\n\t3cb2  Xeon E5/Core i7 Integrated Memory Controller ERROR Registers 0\n\t3cb3  Xeon E5/Core i7 Integrated Memory Controller ERROR Registers 1\n\t3cb4  Xeon E5/Core i7 Integrated Memory Controller Channel 0-3 Thermal Control 2\n\t3cb5  Xeon E5/Core i7 Integrated Memory Controller Channel 0-3 Thermal Control 3\n\t3cb6  Xeon E5/Core i7 Integrated Memory Controller ERROR Registers 2\n\t3cb7  Xeon E5/Core i7 Integrated Memory Controller ERROR Registers 3\n\t3cb8  Xeon E5/Core i7 DDRIO\n\t3cc0  Xeon E5/Core i7 Power Control Unit 0\n\t3cc1  Xeon E5/Core i7 Power Control Unit 1\n\t3cc2  Xeon E5/Core i7 Power Control Unit 2\n\t3cd0  Xeon E5/Core i7 Power Control Unit 3\n\t3ce0  Xeon E5/Core i7 Interrupt Control Registers\n\t3ce3  Xeon E5/Core i7 Semaphore and Scratchpad Configuration Registers\n\t3ce4  Xeon E5/Core i7 R2PCIe\n\t3ce6  Xeon E5/Core i7 QuickPath Interconnect Agent Ring Registers\n\t3ce8  Xeon E5/Core i7 Unicast Register 0\n\t3ce9  Xeon E5/Core i7 Unicast Register 5\n\t3cea  Xeon E5/Core i7 Unicast Register 1\n\t3ceb  Xeon E5/Core i7 Unicast Register 6\n\t3cec  Xeon E5/Core i7 Unicast Register 3\n\t3ced  Xeon E5/Core i7 Unicast Register 7\n\t3cee  Xeon E5/Core i7 Unicast Register 4\n\t3cef  Xeon E5/Core i7 Unicast Register 8\n\t3cf4  Xeon E5/Core i7 Integrated Memory Controller System Address Decoder 0\n\t3cf5  Xeon E5/Core i7 Integrated Memory Controller System Address Decoder 1\n\t3cf6  Xeon E5/Core i7 System Address Decoder\n\t3e10  8th Gen Core 4-core Processor Host Bridge/DRAM Registers [Coffee Lake H]\n\t3e18  8th Gen Core 4-core Workstation Processor Host Bridge/DRAM Registers [Coffee Lake S]\n\t3e1f  8th Gen Core 4-core Desktop Processor Host Bridge/DRAM Registers [Coffee Lake S]\n\t\t1458 5000  Z370 AORUS Gaming K3-CF\n\t3e30  8th Gen Core 8-core Desktop Processor Host Bridge/DRAM Registers [Coffee Lake S]\n\t3e33  8th/9th Gen Core Processor Host Bridge/DRAM Registers [Coffee Lake]\n\t3e34  Coffee Lake HOST and DRAM Controller\n\t3e81  8th Gen Core Processor PCIe Controller (x16)\n\t3e85  8th Gen Core Processor PCIe Controller (x8)\n\t3e89  8th Gen Core Processor PCIe Controller (x4)\n\t3e91  8th Gen Core Processor Gaussian Mixture Model\n\t3e92  UHD Graphics 630 (Desktop)\n\t3e93  UHD Graphics 610\n\t3e96  HD Graphics P630\n\t3e98  UHD Graphics 630 (Desktop 9 Series)\n\t3e9b  UHD Graphics 630 (Mobile)\n\t3ea0  UHD Graphics 620 (Whiskey Lake)\n\t\t1028 089e  Inspiron 5482\n\t3ea5  Iris Plus Graphics 655\n\t3ec2  8th Gen Core Processor Host Bridge/DRAM Registers\n\t\t1043 8694  PRIME H310M-D\n\t3ec4  8th Gen Core Processor Host Bridge/DRAM Registers\n\t3ec6  8th Gen Core Processor Host Bridge/DRAM Registers\n\t3eca  8th Gen Core Processor Host Bridge/DRAM Registers\n\t3ed0  8th Gen Core Processor Host Bridge/DRAM Registers\n\t4000  5400 Chipset Memory Controller Hub\n\t4001  5400 Chipset Memory Controller Hub\n\t4003  5400 Chipset Memory Controller Hub\n\t4021  5400 Chipset PCI Express Port 1\n\t4022  5400 Chipset PCI Express Port 2\n\t4023  5400 Chipset PCI Express Port 3\n\t4024  5400 Chipset PCI Express Port 4\n\t4025  5400 Chipset PCI Express Port 5\n\t4026  5400 Chipset PCI Express Port 6\n\t4027  5400 Chipset PCI Express Port 7\n\t4028  5400 Chipset PCI Express Port 8\n\t4029  5400 Chipset PCI Express Port 9\n\t402d  5400 Chipset IBIST Registers\n\t402e  5400 Chipset IBIST Registers\n\t402f  5400 Chipset QuickData Technology Device\n\t4030  5400 Chipset FSB Registers\n\t4031  5400 Chipset CE/SF Registers\n\t4032  5400 Chipset IOxAPIC\n\t4035  5400 Chipset FBD Registers\n\t4036  5400 Chipset FBD Registers\n\t4100  Moorestown Graphics and Video\n\t4108  Atom Processor E6xx Integrated Graphics Controller\n\t4109  Atom Processor E6xx Integrated Graphics Controller\n\t410a  Atom Processor E6xx Integrated Graphics Controller\n\t410b  Atom Processor E6xx Integrated Graphics Controller\n\t410c  Atom Processor E6xx Integrated Graphics Controller\n\t410d  Atom Processor E6xx Integrated Graphics Controller\n\t410e  Atom Processor E6xx Integrated Graphics Controller\n\t410f  Atom Processor E6xx Integrated Graphics Controller\n\t4114  Atom Processor E6xx PCI Host Bridge #1\n\t4115  Atom Processor E6xx PCI Host Bridge #2\n\t4116  Atom Processor E6xx PCI Host Bridge #3\n\t4117  Atom Processor E6xx PCI Host Bridge #4\n\t4220  PRO/Wireless 2200BG [Calexico2] Network Connection\n\t\t103c 0934  Compaq nw8240/nx8220\n\t\t103c 12f6  nc6120/nc6220/nw8240/nx8220\n\t\t8086 2701  WM3B2200BG Mini-PCI Card\n\t\t8086 2712  IBM ThinkPad R50e\n\t\t8086 2721  Dell B130 laptop integrated WLAN\n\t\t8086 2722  Dell Latitude D600\n\t\t8086 2731  Samsung P35 integrated WLAN\n\t4222  PRO/Wireless 3945ABG [Golan] Network Connection\n\t\t103c 135c  PRO/Wireless 3945ABG [Golan] Network Connection\n\t\t8086 1000  PRO/Wireless 3945ABG Network Connection\n\t\t8086 1001  WM3945ABG MOW2\n\t\t8086 1005  PRO/Wireless 3945BG Network Connection\n\t\t8086 1034  PRO/Wireless 3945BG Network Connection\n\t\t8086 1044  PRO/Wireless 3945BG Network Connection\n\t\t8086 1c00  PRO/Wireless 3945ABG Network Connection\n\t4223  PRO/Wireless 2915ABG [Calexico2] Network Connection\n\t\t1000 8086  mPCI 3B Americas/Europe ZZA\n\t\t1001 8086  mPCI 3B Europe ZZE\n\t\t1002 8086  mPCI 3B Japan ZZJ\n\t\t1003 8086  mPCI 3B High-Band ZZH\n\t\t103c 1351  Compaq nc6220\n\t4224  PRO/Wireless 2915ABG [Calexico2] Network Connection\n\t4227  PRO/Wireless 3945ABG [Golan] Network Connection\n\t\t8086 1010  ThinkPad R60e\n\t\t8086 1011  ThinkPad T60/R60e/X60s/R61\n\t\t8086 1014  PRO/Wireless 3945BG Network Connection\n\t4229  PRO/Wireless 4965 AG or AGN [Kedron] Network Connection\n\t\t8086 1100  Vaio VGN-SZ79SN_C\n\t\t8086 1101  PRO/Wireless 4965 AG or AGN\n\t422b  Centrino Ultimate-N 6300\n\t\t8086 1101  Centrino Ultimate-N 6300 3x3 AGN\n\t\t8086 1121  Centrino Ultimate-N 6300 3x3 AGN\n\t422c  Centrino Advanced-N 6200\n\t\t8086 1301  Centrino Advanced-N 6200 2x2 AGN\n\t\t8086 1306  Centrino Advanced-N 6200 2x2 ABG\n\t\t8086 1307  Centrino Advanced-N 6200 2x2 BG\n\t\t8086 1321  Centrino Advanced-N 6200 2x2 AGN\n\t\t8086 1326  Centrino Advanced-N 6200 2x2 ABG\n\t4230  PRO/Wireless 4965 AG or AGN [Kedron] Network Connection\n\t\t8086 1110  Lenovo ThinkPad T51\n\t\t8086 1111  Lenovo ThinkPad T61\n\t4232  WiFi Link 5100\n\t\t8086 1201  WiFi Link 5100 AGN\n\t\t8086 1204  WiFi Link 5100 AGN\n\t\t8086 1205  WiFi Link 5100 BGN\n\t\t8086 1206  WiFi Link 5100 ABG\n\t\t8086 1221  WiFi Link 5100 AGN\n\t\t8086 1224  WiFi Link 5100 AGN\n\t\t8086 1225  WiFi Link 5100 BGN\n\t\t8086 1226  WiFi Link 5100 ABG\n\t\t8086 1301  WiFi Link 5100 AGN\n\t\t8086 1304  WiFi Link 5100 AGN\n\t\t8086 1305  WiFi Link 5100 BGN\n\t\t8086 1306  WiFi Link 5100 ABG\n\t\t8086 1321  WiFi Link 5100 AGN\n\t\t8086 1324  WiFi Link 5100 AGN\n\t\t8086 1325  WiFi Link 5100 BGN\n\t\t8086 1326  WiFi Link 5100 ABG\n\t4235  Ultimate N WiFi Link 5300\n\t4236  Ultimate N WiFi Link 5300\n\t4237  PRO/Wireless 5100 AGN [Shiloh] Network Connection\n\t\t8086 1211  WiFi Link 5100 AGN\n\t\t8086 1214  WiFi Link 5100 AGN\n\t\t8086 1215  WiFi Link 5100 BGN\n\t\t8086 1216  WiFi Link 5100 ABG\n\t\t8086 1311  WiFi Link 5100 AGN\n\t\t8086 1314  WiFi Link 5100 AGN\n\t\t8086 1315  WiFi Link 5100 BGN\n\t\t8086 1316  WiFi Link 5100 ABG\n\t4238  Centrino Ultimate-N 6300\n\t\t8086 1111  Centrino Ultimate-N 6300 3x3 AGN\n\t4239  Centrino Advanced-N 6200\n\t\t8086 1311  Centrino Advanced-N 6200 2x2 AGN\n\t\t8086 1316  Centrino Advanced-N 6200 2x2 ABG\n\t423a  PRO/Wireless 5350 AGN [Echo Peak] Network Connection\n\t423b  PRO/Wireless 5350 AGN [Echo Peak] Network Connection\n\t423c  WiMAX/WiFi Link 5150\n\t\t8086 1201  WiMAX/WiFi Link 5150 AGN\n\t\t8086 1206  WiMAX/WiFi Link 5150 ABG\n\t\t8086 1221  WiMAX/WiFi Link 5150 AGN\n\t\t8086 1301  WiMAX/WiFi Link 5150 AGN\n\t\t8086 1306  WiMAX/WiFi Link 5150 ABG\n\t\t8086 1321  WiMAX/WiFi Link 5150 AGN\n\t423d  WiMAX/WiFi Link 5150\n\t\t8086 1211  WiMAX/WiFi Link 5150 AGN\n\t\t8086 1216  WiMAX/WiFi Link 5150 ABG\n\t\t8086 1311  WiMAX/WiFi Link 5150 AGN\n\t\t8086 1316  WiMAX/WiFi Link 5150 ABG\n\t444e  Turbo Memory Controller\n\t5001  LE80578\n\t5002  LE80578 Graphics Processor Unit\n\t5009  LE80578 Video Display Controller\n\t500d  LE80578 Expansion Bus\n\t500e  LE80578 UART Controller\n\t500f  LE80578 General Purpose IO\n\t5010  LE80578 I2C Controller\n\t5012  LE80578 Serial Peripheral Interface Bus\n\t5020  EP80579 Memory Controller Hub\n\t5021  EP80579 DRAM Error Reporting Registers\n\t5023  EP80579 EDMA Controller\n\t5024  EP80579 PCI Express Port PEA0\n\t5025  EP80579 PCI Express Port PEA1\n\t5028  EP80579 S-ATA IDE\n\t5029  EP80579 S-ATA AHCI\n\t502a  EP80579 S-ATA Reserved\n\t502b  EP80579 S-ATA Reserved\n\t502c  EP80579 Integrated Processor ASU\n\t502d  EP80579 Integrated Processor with QuickAssist ASU\n\t502e  EP80579 Reserved\n\t502f  EP80579 Reserved\n\t5030  EP80579 Reserved\n\t5031  EP80579 LPC Bus\n\t5032  EP80579 SMBus Controller\n\t5033  EP80579 USB 1.1 Controller\n\t5035  EP80579 USB 2.0 Controller\n\t5037  EP80579 PCI-PCI Bridge (transparent mode)\n\t5039  EP80579 Controller Area Network (CAN) interface #1\n\t503a  EP80579 Controller Area Network (CAN) interface #2\n\t503b  EP80579 Synchronous Serial Port (SPP)\n\t503c  EP80579 IEEE 1588 Hardware Assist\n\t503d  EP80579 Local Expansion Bus\n\t503e  EP80579 Global Control Unit (GCU)\n\t503f  EP80579 Reserved\n\t5040  EP80579 Integrated Processor Gigabit Ethernet MAC\n\t5041  EP80579 Integrated Processor with QuickAssist Gigabit Ethernet MAC\n\t5042  EP80579 Reserved\n\t5043  EP80579 Reserved\n\t5044  EP80579 Integrated Processor Gigabit Ethernet MAC\n\t5045  EP80579 Integrated Processor with QuickAssist Gigabit Ethernet MAC\n\t5046  EP80579 Reserved\n\t5047  EP80579 Reserved\n\t5048  EP80579 Integrated Processor Gigabit Ethernet MAC\n\t5049  EP80579 Integrated Processor with QuickAssist Gigabit Ethernet MAC\n\t504a  EP80579 Reserved\n\t504b  EP80579 Reserved\n\t504c  EP80579 Integrated Processor with QuickAssist TDM\n\t5200  EtherExpress PRO/100 Intelligent Server PCI Bridge\n\t5201  EtherExpress PRO/100 Intelligent Server Fast Ethernet Controller\n\t\t8086 0001  EtherExpress PRO/100 Server Ethernet Adapter\n\t530d  80310 (IOP) IO Processor\n\t5845  QEMU NVM Express Controller\n\t\t1af4 1100  QEMU Virtual Machine\n\t5900  Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers\n\t5901  Xeon E3-1200 v6/7th Gen Core Processor PCIe Controller (x16)\n\t5902  HD Graphics 610\n\t5904  Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers\n\t\t17aa 2247  ThinkPad T570\n\t\t17aa 224f  ThinkPad X1 Carbon 5th Gen\n\t5905  Xeon E3-1200 v6/7th Gen Core Processor PCIe Controller (x8)\n\t5909  Xeon E3-1200 v6/7th Gen Core Processor PCIe Controller (x4)\n\t590c  Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers\n\t590f  Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers\n\t\t1462 7a68  B250 KRAIT GAMING (MS-7A68)\n\t5910  Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers\n\t5911  Xeon E3-1200 v6/7th Gen Core Processor Gaussian Mixture Model\n\t5912  HD Graphics 630\n\t5914  Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers\n\t\t17aa 225d  ThinkPad T480\n\t5916  HD Graphics 620\n\t\t17aa 2248  ThinkPad T570\n\t\t17aa 224f  ThinkPad X1 Carbon 5th Gen\n\t5917  UHD Graphics 620\n\t\t17aa 225e  ThinkPad T480\n\t5918  Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers\n\t591b  HD Graphics 630\n\t591c  UHD Graphics 615\n\t591d  HD Graphics P630\n\t591e  HD Graphics 615\n\t591f  Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers\n\t5923  HD Graphics 635\n\t5926  Iris Plus Graphics 640\n\t5927  Iris Plus Graphics 650\n\t5a84  Celeron N3350/Pentium N4200/Atom E3900 Series Integrated Graphics Controller\n\t5a85  HD Graphics 500\n\t5a88  Celeron N3350/Pentium N4200/Atom E3900 Series Imaging Unit\n\t5a98  Celeron N3350/Pentium N4200/Atom E3900 Series Audio Cluster\n\t5a9a  Celeron N3350/Pentium N4200/Atom E3900 Series Trusted Execution Engine\n\t5aa2  Celeron N3350/Pentium N4200/Atom E3900 Series Integrated Sensor Hub\n\t5aa8  Celeron N3350/Pentium N4200/Atom E3900 Series USB xHCI\n\t5aac  Celeron N3350/Pentium N4200/Atom E3900 Series I2C Controller #1\n\t5aae  Celeron N3350/Pentium N4200/Atom E3900 Series I2C Controller #2\n\t5ab0  Celeron N3350/Pentium N4200/Atom E3900 Series I2C Controller #3\n\t5ab2  Celeron N3350/Pentium N4200/Atom E3900 Series I2C Controller #4\n\t5ab4  Celeron N3350/Pentium N4200/Atom E3900 Series I2C Controller #5\n\t5ab6  Celeron N3350/Pentium N4200/Atom E3900 Series I2C Controller #6\n\t5ab8  Celeron N3350/Pentium N4200/Atom E3900 Series I2C Controller #7\n\t5aba  Celeron N3350/Pentium N4200/Atom E3900 Series I2C Controller #8\n\t5abc  Celeron N3350/Pentium N4200/Atom E3900 Series HSUART Controller #1\n\t5abe  Celeron N3350/Pentium N4200/Atom E3900 Series HSUART Controller #2\n\t5ac0  Celeron N3350/Pentium N4200/Atom E3900 Series HSUART Controller #3\n\t5ac2  Celeron N3350/Pentium N4200/Atom E3900 Series SPI Controller #1\n\t5ac4  Celeron N3350/Pentium N4200/Atom E3900 Series SPI Controller #2\n\t5ac6  Celeron N3350/Pentium N4200/Atom E3900 Series SPI Controller #3\n\t5ac8  Celeron N3350/Pentium N4200/Atom E3900 Series PWM Pin Controller\n\t5aca  Celeron N3350/Pentium N4200/Atom E3900 Series SDXC/MMC Host Controller\n\t5acc  Celeron N3350/Pentium N4200/Atom E3900 Series eMMC Controller\n\t5ad0  Celeron N3350/Pentium N4200/Atom E3900 Series SDIO Controller\n\t5ad4  Celeron N3350/Pentium N4200/Atom E3900 Series SMBus Controller\n\t5ad6  Celeron N3350/Pentium N4200/Atom E3900 Series PCI Express Port B #1\n\t5ad7  Celeron N3350/Pentium N4200/Atom E3900 Series PCI Express Port B #2\n\t5ad8  Celeron N3350/Pentium N4200/Atom E3900 Series PCI Express Port A #1\n\t5ad9  Celeron N3350/Pentium N4200/Atom E3900 Series PCI Express Port A #2\n\t5ada  Celeron N3350/Pentium N4200/Atom E3900 Series PCI Express Port A #3\n\t5adb  Celeron N3350/Pentium N4200/Atom E3900 Series PCI Express Port A #4\n\t5ae3  Celeron N3350/Pentium N4200/Atom E3900 Series SATA AHCI Controller\n\t5ae8  Celeron N3350/Pentium N4200/Atom E3900 Series Low Pin Count Interface\n\t5aee  Celeron N3350/Pentium N4200/Atom E3900 Series HSUART Controller #4\n\t5af0  Celeron N3350/Pentium N4200/Atom E3900 Series Host Bridge\n\t65c0  5100 Chipset Memory Controller Hub\n\t65e2  5100 Chipset PCI Express x4 Port 2\n\t65e3  5100 Chipset PCI Express x4 Port 3\n\t65e4  5100 Chipset PCI Express x4 Port 4\n\t65e5  5100 Chipset PCI Express x4 Port 5\n\t65e6  5100 Chipset PCI Express x4 Port 6\n\t65e7  5100 Chipset PCI Express x4 Port 7\n\t65f0  5100 Chipset FSB Registers\n\t\t1028 020f  PowerEdge R300\n\t\t1028 0210  PowerEdge T300\n\t65f1  5100 Chipset Reserved Registers\n\t\t1028 0210  PowerEdge T300\n\t65f3  5100 Chipset Reserved Registers\n\t65f5  5100 Chipset DDR Channel 0 Registers\n\t65f6  5100 Chipset DDR Channel 1 Registers\n\t65f7  5100 Chipset PCI Express x8 Port 2-3\n\t65f8  5100 Chipset PCI Express x8 Port 4-5\n\t65f9  5100 Chipset PCI Express x8 Port 6-7\n\t65fa  5100 Chipset PCI Express x16 Port 4-7\n\t65ff  5100 Chipset DMA Engine\n\t6f00  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DMI2\n\t\t15d9 0832  X10SRL-F\n\t6f01  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 0\n\t6f02  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 1\n\t6f03  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 1\n\t6f04  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 2\n\t6f05  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 2\n\t6f06  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 2\n\t6f07  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 2\n\t6f08  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 3\n\t6f09  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 3\n\t6f0a  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 3\n\t6f0b  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 3\n\t6f10  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Debug\n\t6f11  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Debug\n\t6f12  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Debug\n\t6f13  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Debug\n\t6f14  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Debug\n\t6f15  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Debug\n\t6f16  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Debug\n\t6f17  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Debug\n\t6f18  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Debug\n\t6f19  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Debug\n\t6f1a  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Debug\n\t6f1b  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Debug\n\t6f1c  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Debug\n\t6f1d  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D R2PCIe Agent\n\t6f1e  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Ubox\n\t6f1f  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Ubox\n\t6f20  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 0\n\t\t15d9 0832  X10SRL-F\n\t6f21  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 1\n\t\t15d9 0832  X10SRL-F\n\t6f22  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 2\n\t\t15d9 0832  X10SRL-F\n\t6f23  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 3\n\t\t15d9 0832  X10SRL-F\n\t6f24  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 4\n\t\t15d9 0832  X10SRL-F\n\t6f25  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 5\n\t\t15d9 0832  X10SRL-F\n\t6f26  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 6\n\t\t15d9 0832  X10SRL-F\n\t6f27  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 7\n\t\t15d9 0832  X10SRL-F\n\t6f28  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Map/VTd_Misc/System Management\n\t\t15d9 0832  X10SRL-F\n\t6f29  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Hot Plug\n\t\t15d9 0832  X10SRL-F\n\t6f2a  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO RAS/Control Status/Global Errors\n\t\t15d9 0832  X10SRL-F\n\t6f2c  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D I/O APIC\n\t\t15d9 0832  X10SRL-F\n\t6f30  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Home Agent 0\n\t6f32  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 0\n\t6f33  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 1\n\t6f34  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D R2PCIe Agent\n\t6f36  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D R3 QPI Link 0/1\n\t6f37  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D R3 QPI Link 0/1\n\t6f38  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Home Agent 1\n\t6f39  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IO Performance Monitoring\n\t6f3a  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 2\n\t6f3e  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D R3 QPI Link 2\n\t6f3f  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D R3 QPI Link 2\n\t6f40  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 2\n\t6f41  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D R3 QPI Link 2\n\t6f43  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 2\n\t6f45  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 2 Debug\n\t6f46  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 2 Debug\n\t6f47  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 2 Debug\n\t6f50  Xeon Processor D Family QuickData Technology Register DMA Channel 0\n\t6f51  Xeon Processor D Family QuickData Technology Register DMA Channel 1\n\t6f52  Xeon Processor D Family QuickData Technology Register DMA Channel 2\n\t6f53  Xeon Processor D Family QuickData Technology Register DMA Channel 3\n\t6f54  Xeon Processor D Family QuickAssist Technology\n\t6f55  Xeon Processor D Family QuickAssist Technology Virtual Fuction\n\t6f60  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Home Agent 1\n\t6f68  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Target Address/Thermal/RAS\n\t6f6a  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Channel Target Address Decoder\n\t6f6b  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Channel Target Address Decoder\n\t6f6c  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Channel Target Address Decoder\n\t6f6d  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Channel Target Address Decoder\n\t6f6e  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DDRIO Channel 2/3 Broadcast\n\t6f6f  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DDRIO Global Broadcast\n\t6f70  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Home Agent 0 Debug\n\t6f71  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Target Address/Thermal/RAS\n\t6f76  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D R3 QPI Link Debug\n\t6f78  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Home Agent 1 Debug\n\t6f79  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Target Address/Thermal/RAS\n\t6f7d  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Ubox\n\t6f7e  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D R3 QPI Link Debug\n\t6f80  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 0\n\t6f81  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D R3 QPI Link 0/1\n\t6f83  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 0\n\t6f85  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 0 Debug\n\t6f86  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 0 Debug\n\t6f87  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 0 Debug\n\t6f88  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6f8a  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6f90  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 1\n\t6f93  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 1\n\t6f95  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 1 Debug\n\t6f96  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 1 Debug\n\t6f98  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6f99  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6f9a  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6f9c  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fa0  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Home Agent 0\n\t6fa8  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Target Address/Thermal/RAS\n\t6faa  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel Target Address Decoder\n\t6fab  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel Target Address Decoder\n\t6fac  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel Target Address Decoder\n\t6fad  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel Target Address Decoder\n\t6fae  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DDRIO Channel 0/1 Broadcast\n\t6faf  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DDRIO Global Broadcast\n\t6fb0  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel 0 Thermal Control\n\t6fb1  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel 1 Thermal Control\n\t6fb2  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel 0 Error\n\t6fb3  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel 1 Error\n\t6fb4  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel 2 Thermal Control\n\t6fb5  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel 3 Thermal Control\n\t6fb6  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel 2 Error\n\t6fb7  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel 3 Error\n\t6fb8  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DDRIO Channel 2/3 Interface\n\t6fb9  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DDRIO Channel 2/3 Interface\n\t6fba  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DDRIO Channel 2/3 Interface\n\t6fbb  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DDRIO Channel 2/3 Interface\n\t6fbc  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DDRIO Channel 0/1 Interface\n\t6fbd  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DDRIO Channel 0/1 Interface\n\t6fbe  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DDRIO Channel 0/1 Interface\n\t6fbf  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DDRIO Channel 0/1 Interface\n\t6fc0  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fc1  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fc2  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fc3  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fc4  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fc5  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fc6  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fc7  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fc8  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fc9  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fca  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fcb  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fcc  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fcd  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fce  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fcf  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Power Control Unit\n\t6fd0  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 1 - Channel 0 Thermal Control\n\t6fd1  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 1 - Channel 1 Thermal Control\n\t6fd2  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 1 - Channel 0 Error\n\t6fd3  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 1 - Channel 1 Error\n\t6fd4  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 1 - Channel 2 Thermal Control\n\t6fd5  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 1 - Channel 3 Thermal Control\n\t6fd6  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 1 - Channel 2 Error\n\t6fd7  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 1 - Channel 3 Error\n\t6fe0  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fe1  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fe2  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fe3  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fe4  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fe5  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fe6  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fe7  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fe8  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fe9  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fea  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6feb  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fec  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fed  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fee  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6fef  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6ff0  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6ff1  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6ff8  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6ff9  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6ffa  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6ffb  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6ffc  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6ffd  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t6ffe  Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Caching Agent\n\t7000  82371SB PIIX3 ISA [Natoma/Triton II]\n\t\t1af4 1100  Qemu virtual machine\n\t7010  82371SB PIIX3 IDE [Natoma/Triton II]\n\t\t1af4 1100  Qemu virtual machine\n\t7020  82371SB PIIX3 USB [Natoma/Triton II]\n\t\t1af4 1100  QEMU Virtual Machine\n\t7030  430VX - 82437VX TVX [Triton VX]\n\t7050  Intercast Video Capture Card\n\t7051  PB 642365-003 (Business Video Conferencing Card)\n\t7100  430TX - 82439TX MTXC\n\t7110  82371AB/EB/MB PIIX4 ISA\n\t\t15ad 1976  Virtual Machine Chipset\n\t7111  82371AB/EB/MB PIIX4 IDE\n\t\t15ad 1976  Virtual Machine Chipset\n\t7112  82371AB/EB/MB PIIX4 USB\n\t\t15ad 1976  Virtual Machine Chipset\n\t\t1af4 1100  QEMU Virtual Machine\n\t7113  82371AB/EB/MB PIIX4 ACPI\n\t\t15ad 1976  Virtual Machine Chipset\n\t\t1af4 1100  Qemu virtual machine\n\t7120  82810 GMCH (Graphics Memory Controller Hub)\n\t\t4c53 1040  CL7 mainboard\n\t\t4c53 1060  PC7 mainboard\n\t7121  82810 (CGC) Chipset Graphics Controller\n\t\t4c53 1040  CL7 mainboard\n\t\t4c53 1060  PC7 mainboard\n\t\t8086 4341  Cayman (CA810) Mainboard\n\t7122  82810 DC-100 (GMCH) Graphics Memory Controller Hub\n\t7123  82810 DC-100 (CGC) Chipset Graphics Controller\n\t7124  82810E DC-133 (GMCH) Graphics Memory Controller Hub\n\t\t1028 00b4  OptiPlex GX110\n\t7125  82810E DC-133 (CGC) Chipset Graphics Controller\n\t\t1028 00b4  OptiPlex GX110\n\t7126  82810 DC-133 System and Graphics Controller\n\t7128  82810-M DC-100 System and Graphics Controller\n\t712a  82810-M DC-133 System and Graphics Controller\n\t7180  440LX/EX - 82443LX/EX Host bridge\n\t7181  440LX/EX - 82443LX/EX AGP bridge\n\t7190  440BX/ZX/DX - 82443BX/ZX/DX Host bridge\n\t\t0e11 0500  Armada 1750 Laptop System Chipset\n\t\t0e11 b110  Armada M700/E500\n\t\t1028 008e  PowerEdge 1300 mainboard\n\t\t1043 803b  CUBX-L/E Mainboard\n\t\t1179 0001  Toshiba Tecra 8100 Laptop System Chipset\n\t\t15ad 1976  Virtual Machine Chipset\n\t\t4c53 1050  CT7 mainboard\n\t\t4c53 1051  CE7 mainboard\n\t7191  440BX/ZX/DX - 82443BX/ZX/DX AGP bridge\n\t\t1028 008e  PowerEdge 1300 mainboard\n\t7192  440BX/ZX/DX - 82443BX/ZX/DX Host bridge (AGP disabled)\n\t\t0e11 0460  Armada 1700 Laptop System Chipset\n\t\t1179 0001  Satellite 4010\n\t\t4c53 1000  CC7/CR7/CP7/VC7/VP7/VR7 mainboard\n\t\t8086 7190  Dell PowerEdge 350\n\t7194  82440MX Host Bridge\n\t\t1033 0000  Versa Note Vxi\n\t\t4c53 10a0  CA3/CR3 mainboard\n\t7195  82440MX AC'97 Audio Controller\n\t\t1033 80cc  Versa Note VXi\n\t\t10cf 1099  QSound_SigmaTel Stac97 PCI Audio\n\t\t11d4 0040  SoundMAX Integrated Digital Audio\n\t\t11d4 0048  SoundMAX Integrated Digital Audio\n\t7196  82440MX AC'97 Modem Controller\n\t7198  82440MX ISA Bridge\n\t7199  82440MX EIDE Controller\n\t719a  82440MX USB Universal Host Controller\n\t719b  82440MX Power Management Controller\n\t71a0  440GX - 82443GX Host bridge\n\t\t4c53 1050  CT7 mainboard\n\t\t4c53 1051  CE7 mainboard\n\t71a1  440GX - 82443GX AGP bridge\n\t71a2  440GX - 82443GX Host bridge (AGP disabled)\n\t\t4c53 1000  CC7/CR7/CP7/VC7/VP7/VR7 mainboard\n\t7360  XMM7360 LTE Advanced Modem\n\t7600  82372FB PIIX5 ISA\n\t7601  82372FB PIIX5 IDE\n\t7602  82372FB PIIX5 USB\n\t7603  82372FB PIIX5 SMBus\n\t7800  82740 (i740) AGP Graphics Accelerator\n\t\t003d 0008  Starfighter AGP\n\t\t003d 000b  Starfighter AGP\n\t\t1092 0100  Stealth II G460\n\t\t10b4 201a  Lightspeed 740\n\t\t10b4 202f  Lightspeed 740\n\t\t8086 0000  Terminator 2x/i\n\t\t8086 0100  Intel740 Graphics Accelerator\n\t8002  Trusted Execution Technology Registers\n\t8003  Trusted Execution Technology Registers\n\t8100  US15W/US15X SCH [Poulsbo] Host Bridge\n\t8101  US15L/UL11L SCH [Poulsbo] Host Bridge\n\t8108  US15W/US15X SCH [Poulsbo] Graphics Controller\n\t8109  US15L/UL11L SCH [Poulsbo] Graphics Controller\n\t8110  US15W/US15X/US15L/UL11L SCH [Poulsbo] PCI Express Port 1\n\t8112  US15W/US15X/US15L/UL11L SCH [Poulsbo] PCI Express Port 2\n\t8114  US15W/US15X/US15L/UL11L SCH [Poulsbo] USB UHCI Controller #1\n\t8115  US15W/US15X/US15L/UL11L SCH [Poulsbo] USB UHCI Controller #2\n\t8116  US15W/US15X/US15L/UL11L SCH [Poulsbo] USB UHCI Controller #3\n\t8117  US15W/US15X/US15L/UL11L SCH [Poulsbo] USB EHCI Controller\n\t8118  US15W/US15X/US15L/UL11L SCH [Poulsbo] USB Client Controller\n\t8119  US15W/US15X/US15L/UL11L SCH [Poulsbo] LPC Bridge\n\t811a  US15W/US15X/US15L/UL11L SCH [Poulsbo] IDE Controller\n\t811b  US15W/US15X/US15L/UL11L SCH [Poulsbo] HD Audio Controller\n\t811c  US15W/US15X/US15L/UL11L SCH [Poulsbo] SDIO/MMC Controller #1\n\t811d  US15W/US15X/US15L/UL11L SCH [Poulsbo] SDIO/MMC Controller #2\n\t811e  US15W/US15X/US15L/UL11L SCH [Poulsbo] SDIO/MMC Controller #3\n\t8180  Atom Processor E6xx PCI Express Port 3\n\t8181  Atom Processor E6xx PCI Express Port 4\n\t8182  Atom Processor E6xx Integrated Graphics Controller\n\t8183  Atom Processor E6xx Configuration Unit\n\t8184  Atom Processor E6xx PCI Express Port 1\n\t8185  Atom Processor E6xx PCI Express Port 2\n\t8186  Atom Processor E6xx LPC Bridge\n\t84c4  450KX/GX [Orion] - 82454KX/GX PCI bridge\n\t84c5  450KX/GX [Orion] - 82453KX/GX Memory controller\n\t84ca  450NX - 82451NX Memory & I/O Controller\n\t84cb  450NX - 82454NX/84460GX PCI Expander Bridge\n\t84e0  460GX - 84460GX System Address Controller (SAC)\n\t84e1  460GX - 84460GX System Data Controller (SDC)\n\t84e2  460GX - 84460GX AGP Bridge (GXB function 2)\n\t84e3  460GX - 84460GX Memory Address Controller (MAC)\n\t84e4  460GX - 84460GX Memory Data Controller (MDC)\n\t84e6  460GX - 82466GX Wide and fast PCI eXpander Bridge (WXB)\n\t84ea  460GX - 84460GX AGP Bridge (GXB function 1)\n\t8500  IXP4XX Network Processor (IXP420/421/422/425/IXC1100)\n\t\t1993 0ded  mGuard-PCI AV#2\n\t\t1993 0dee  mGuard-PCI AV#1\n\t\t1993 0def  mGuard-PCI AV#0\n\t87c0  UHD Graphics 617\n\t8800  Platform Controller Hub EG20T PCI Express Port\n\t8801  Platform Controller Hub EG20T Packet Hub\n\t8802  Platform Controller Hub EG20T Gigabit Ethernet Controller\n\t8803  Platform Controller Hub EG20T General Purpose IO Controller\n\t8804  Platform Controller Hub EG20T USB OHCI Controller #4\n\t8805  Platform Controller Hub EG20T USB OHCI Controller #5\n\t8806  Platform Controller Hub EG20T USB OHCI Controller #6\n\t8807  Platform Controller Hub EG20T USB2 EHCI Controller #2\n\t8808  Platform Controller Hub EG20T USB Client Controller\n\t8809  Platform Controller Hub EG20T SDIO Controller #1\n\t880a  Platform Controller Hub EG20T SDIO Controller #2\n\t880b  Platform Controller Hub EG20T SATA AHCI Controller\n\t880c  Platform Controller Hub EG20T USB OHCI Controller #1\n\t880d  Platform Controller Hub EG20T USB OHCI Controller #2\n\t880e  Platform Controller Hub EG20T USB OHCI Controller #3\n\t880f  Platform Controller Hub EG20T USB2 EHCI Controller #1\n\t8810  Platform Controller Hub EG20T DMA Controller #1\n\t8811  Platform Controller Hub EG20T UART Controller 0\n\t8812  Platform Controller Hub EG20T UART Controller 1\n\t8813  Platform Controller Hub EG20T UART Controller 2\n\t8814  Platform Controller Hub EG20T UART Controller 3\n\t8815  Platform Controller Hub EG20T DMA Controller #2\n\t8816  Platform Controller Hub EG20T Serial Peripheral Interface Bus\n\t8817  Platform Controller Hub EG20T I2C Controller\n\t8818  Platform Controller Hub EG20T Controller Area Network (CAN) Controller\n\t8819  Platform Controller Hub EG20T IEEE 1588 Hardware Assist\n\t8a0d  Ice Lake Thunderbolt 3 NHI #1\n\t8a13  Ice Lake Thunderbolt 3 USB Controller\n\t8a17  Ice Lake Thunderbolt 3 NHI #0\n\t8a1d  Ice Lake Thunderbolt 3 PCI Express Root Port #0\n\t8a1f  Ice Lake Thunderbolt 3 PCI Express Root Port #1\n\t8a21  Ice Lake Thunderbolt 3 PCI Express Root Port #2\n\t8a23  Ice Lake Thunderbolt 3 PCI Express Root Port #3\n\t8a52  Iris Plus Graphics G7\n\t8c00  8 Series/C220 Series Chipset Family 4-port SATA Controller 1 [IDE mode]\n\t8c01  8 Series Chipset Family 4-port SATA Controller 1 [IDE mode] - Mobile\n\t8c02  8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode]\n\t\t17aa 309f  ThinkCentre M83\n\t8c03  8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode]\n\t\t103c 1909  ZBook 15\n\t\t17aa 220e  ThinkPad T440p\n\t8c04  8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode]\n\t8c05  8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode]\n\t8c06  8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode]\n\t8c07  8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode]\n\t8c08  8 Series/C220 Series Chipset Family 2-port SATA Controller 2 [IDE mode]\n\t8c09  8 Series/C220 Series Chipset Family 2-port SATA Controller 2 [IDE mode]\n\t8c0e  8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode]\n\t8c0f  8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode]\n\t8c10  8 Series/C220 Series Chipset Family PCI Express Root Port #1\n\t\t17aa 220e  ThinkPad T440p\n\t8c11  8 Series/C220 Series Chipset Family PCI Express Root Port #1\n\t8c12  8 Series/C220 Series Chipset Family PCI Express Root Port #2\n\t\t17aa 220e  ThinkPad T440p\n\t8c13  8 Series/C220 Series Chipset Family PCI Express Root Port #2\n\t8c14  8 Series/C220 Series Chipset Family PCI Express Root Port #3\n\t8c15  8 Series/C220 Series Chipset Family PCI Express Root Port #3\n\t8c16  8 Series/C220 Series Chipset Family PCI Express Root Port #4\n\t8c17  8 Series/C220 Series Chipset Family PCI Express Root Port #4\n\t8c18  8 Series/C220 Series Chipset Family PCI Express Root Port #5\n\t8c19  8 Series/C220 Series Chipset Family PCI Express Root Port #5\n\t8c1a  8 Series/C220 Series Chipset Family PCI Express Root Port #6\n\t8c1b  8 Series/C220 Series Chipset Family PCI Express Root Port #6\n\t8c1c  8 Series/C220 Series Chipset Family PCI Express Root Port #7\n\t8c1d  8 Series/C220 Series Chipset Family PCI Express Root Port #7\n\t8c1e  8 Series/C220 Series Chipset Family PCI Express Root Port #8\n\t8c1f  8 Series/C220 Series Chipset Family PCI Express Root Port #8\n\t8c20  8 Series/C220 Series Chipset High Definition Audio Controller\n\t\t103c 1909  ZBook 15\n\t\t17aa 220e  ThinkPad T440p\n\t\t17aa 309f  ThinkCentre M83\n\t8c21  8 Series/C220 Series Chipset High Definition Audio Controller\n\t8c22  8 Series/C220 Series Chipset Family SMBus Controller\n\t\t103c 1909  ZBook 15\n\t\t17aa 220e  ThinkPad T440p\n\t\t17aa 309f  ThinkCentre M83\n\t8c23  8 Series Chipset Family CHAP Counters\n\t8c24  8 Series Chipset Family Thermal Management Controller\n\t8c26  8 Series/C220 Series Chipset Family USB EHCI #1\n\t\t103c 1909  ZBook 15\n\t\t17aa 220e  ThinkPad T440p\n\t\t17aa 2210  ThinkPad T540p\n\t\t17aa 309f  ThinkCentre M83\n\t\t2210 17aa  ThinkPad T540p\n\t8c2d  8 Series/C220 Series Chipset Family USB EHCI #2\n\t\t103c 1909  ZBook 15\n\t\t17aa 220e  ThinkPad T440p\n\t\t17aa 309f  ThinkCentre M83\n\t8c31  8 Series/C220 Series Chipset Family USB xHCI\n\t\t103c 1909  ZBook 15\n\t\t17aa 220e  ThinkPad T440p\n\t\t17aa 309f  ThinkCentre M83\n\t8c33  8 Series/C220 Series Chipset Family LAN Controller\n\t8c34  8 Series/C220 Series Chipset Family NAND Controller\n\t8c3a  8 Series/C220 Series Chipset Family MEI Controller #1\n\t\t103c 1909  ZBook 15\n\t\t17aa 220e  ThinkPad T440p\n\t\t17aa 309f  ThinkCentre M83\n\t8c3b  8 Series/C220 Series Chipset Family MEI Controller #2\n\t8c3c  8 Series/C220 Series Chipset Family IDE-r Controller\n\t8c3d  8 Series/C220 Series Chipset Family KT Controller\n\t8c40  8 Series/C220 Series Chipset Family LPC Controller\n\t8c41  8 Series Chipset Family Mobile Super SKU LPC Controller\n\t8c42  8 Series/C220 Series Chipset Family Desktop Super SKU LPC Controller\n\t8c43  8 Series/C220 Series Chipset Family LPC Controller\n\t8c44  Z87 Express LPC Controller\n\t8c45  8 Series/C220 Series Chipset Family LPC Controller\n\t8c46  Z85 Express LPC Controller\n\t8c47  8 Series/C220 Series Chipset Family LPC Controller\n\t8c48  8 Series/C220 Series Chipset Family LPC Controller\n\t8c49  HM86 Express LPC Controller\n\t8c4a  H87 Express LPC Controller\n\t8c4b  HM87 Express LPC Controller\n\t8c4c  Q85 Express LPC Controller\n\t\t17aa 309f  ThinkCentre M83\n\t8c4d  8 Series/C220 Series Chipset Family LPC Controller\n\t8c4e  Q87 Express LPC Controller\n\t8c4f  QM87 Express LPC Controller\n\t\t103c 1909  ZBook 15\n\t\t17aa 220e  ThinkPad T440p\n\t8c50  B85 Express LPC Controller\n\t8c51  8 Series/C220 Series Chipset Family LPC Controller\n\t8c52  C222 Series Chipset Family Server Essential SKU LPC Controller\n\t8c53  8 Series/C220 Series Chipset Family LPC Controller\n\t8c54  C224 Series Chipset Family Server Standard SKU LPC Controller\n\t8c55  8 Series/C220 Series Chipset Family LPC Controller\n\t8c56  C226 Series Chipset Family Server Advanced SKU LPC Controller\n\t8c57  8 Series/C220 Series Chipset Family LPC Controller\n\t8c58  8 Series/C220 Series Chipset Family WS SKU LPC Controller\n\t8c59  8 Series/C220 Series Chipset Family LPC Controller\n\t8c5a  8 Series/C220 Series Chipset Family LPC Controller\n\t8c5b  8 Series/C220 Series Chipset Family LPC Controller\n\t8c5c  H81 Express LPC Controller\n\t8c5d  8 Series/C220 Series Chipset Family LPC Controller\n\t8c5e  8 Series/C220 Series Chipset Family LPC Controller\n\t8c5f  8 Series/C220 Series Chipset Family LPC Controller\n\t8c80  9 Series Chipset Family SATA Controller [IDE Mode]\n\t8c81  9 Series Chipset Family SATA Controller [IDE Mode]\n\t8c82  9 Series Chipset Family SATA Controller [AHCI Mode]\n\t8c83  9 Series Chipset Family SATA Controller [AHCI Mode]\n\t8c84  9 Series Chipset Family SATA Controller [RAID Mode]\n\t8c85  9 Series Chipset Family SATA Controller [RAID Mode]\n\t8c86  9 Series Chipset Family SATA Controller [RAID Mode]\n\t8c87  9 Series Chipset Family SATA Controller [RAID Mode]\n\t8c88  9 Series Chipset Family SATA Controller [IDE Mode]\n\t8c89  9 Series Chipset Family SATA Controller [IDE Mode]\n\t8c8e  9 Series Chipset Family SATA Controller [RAID Mode]\n\t8c8f  9 Series Chipset Family SATA Controller [RAID Mode]\n\t8c90  9 Series Chipset Family PCI Express Root Port 1\n\t8c92  9 Series Chipset Family PCI Express Root Port 2\n\t8c94  9 Series Chipset Family PCI Express Root Port 3\n\t8c96  9 Series Chipset Family PCI Express Root Port 4\n\t8c98  9 Series Chipset Family PCI Express Root Port 5\n\t8c9a  9 Series Chipset Family PCI Express Root Port 6\n\t8c9c  9 Series Chipset Family PCI Express Root Port 7\n\t8c9e  9 Series Chipset Family PCI Express Root Port 8\n\t8ca0  9 Series Chipset Family HD Audio Controller\n\t8ca2  9 Series Chipset Family SMBus Controller\n\t8ca4  9 Series Chipset Family Thermal Controller\n\t8ca6  9 Series Chipset Family USB EHCI Controller #1\n\t8cad  9 Series Chipset Family USB EHCI Controller #2\n\t8cb1  9 Series Chipset Family USB xHCI Controller\n\t8cb3  9 Series Chipset Family LAN Controller\n\t8cba  9 Series Chipset Family ME Interface #1\n\t8cbb  9 Series Chipset Family ME Interface #2\n\t8cbc  9 Series Chipset Family IDE-R Controller\n\t8cbd  9 Series Chipset Family KT Controller\n\t8cc1  9 Series Chipset Family LPC Controller\n\t8cc2  9 Series Chipset Family LPC Controller\n\t8cc3  HM97 Chipset LPC Controller\n\t8cc4  Z97 Chipset LPC Controller\n\t8cc5  QM97 Chipset LPC Controller\n\t8cc6  H97 Chipset LPC Controller\n\t8d00  C610/X99 series chipset 4-port SATA Controller [IDE mode]\n\t8d02  C610/X99 series chipset 6-Port SATA Controller [AHCI mode]\n\t8d04  C610/X99 series chipset SATA Controller [RAID mode]\n\t8d06  C610/X99 series chipset SATA Controller [RAID mode]\n\t\t17aa 1031  ThinkServer RAID 110i\n\t8d08  C610/X99 series chipset 2-port SATA Controller [IDE mode]\n\t8d0e  C610/X99 series chipset SATA Controller [RAID mode]\n\t8d10  C610/X99 series chipset PCI Express Root Port #1\n\t8d11  C610/X99 series chipset PCI Express Root Port #1\n\t8d12  C610/X99 series chipset PCI Express Root Port #2\n\t8d13  C610/X99 series chipset PCI Express Root Port #2\n\t8d14  C610/X99 series chipset PCI Express Root Port #3\n\t8d15  C610/X99 series chipset PCI Express Root Port #3\n\t8d16  C610/X99 series chipset PCI Express Root Port #4\n\t8d17  C610/X99 series chipset PCI Express Root Port #4\n\t8d18  C610/X99 series chipset PCI Express Root Port #5\n\t8d19  C610/X99 series chipset PCI Express Root Port #5\n\t8d1a  C610/X99 series chipset PCI Express Root Port #6\n\t8d1b  C610/X99 series chipset PCI Express Root Port #6\n\t8d1c  C610/X99 series chipset PCI Express Root Port #7\n\t8d1d  C610/X99 series chipset PCI Express Root Port #7\n\t8d1e  C610/X99 series chipset PCI Express Root Port #8\n\t8d1f  C610/X99 series chipset PCI Express Root Port #8\n\t8d20  C610/X99 series chipset HD Audio Controller\n\t8d21  C610/X99 series chipset HD Audio Controller\n\t8d22  C610/X99 series chipset SMBus Controller\n\t\t15d9 0832  X10SRL-F\n\t8d24  C610/X99 series chipset Thermal Subsystem\n\t8d26  C610/X99 series chipset USB Enhanced Host Controller #1\n\t\t15d9 0832  X10SRL-F\n\t8d2d  C610/X99 series chipset USB Enhanced Host Controller #2\n\t\t15d9 0832  X10SRL-F\n\t8d31  C610/X99 series chipset USB xHCI Host Controller\n\t\t15d9 0832  X10SRL-F\n\t8d33  C610/X99 series chipset LAN Controller\n\t8d34  C610/X99 series chipset NAND Controller\n\t8d3a  C610/X99 series chipset MEI Controller #1\n\t\t15d9 0832  X10SRL-F\n\t8d3b  C610/X99 series chipset MEI Controller #2\n\t\t15d9 0832  X10SRL-F\n\t8d3c  C610/X99 series chipset IDE-r Controller\n\t8d3d  C610/X99 series chipset KT Controller\n\t8d40  C610/X99 series chipset LPC Controller\n\t8d41  C610/X99 series chipset LPC Controller\n\t8d42  C610/X99 series chipset LPC Controller\n\t8d43  C610/X99 series chipset LPC Controller\n\t8d44  C610/X99 series chipset LPC Controller\n\t\t15d9 0832  X10SRL-F\n\t8d45  C610/X99 series chipset LPC Controller\n\t8d46  C610/X99 series chipset LPC Controller\n\t8d47  C610/X99 series chipset LPC Controller\n\t8d48  C610/X99 series chipset LPC Controller\n\t8d49  C610/X99 series chipset LPC Controller\n\t8d4a  C610/X99 series chipset LPC Controller\n\t8d4b  C610/X99 series chipset LPC Controller\n\t8d4c  C610/X99 series chipset LPC Controller\n\t8d4d  C610/X99 series chipset LPC Controller\n\t8d4e  C610/X99 series chipset LPC Controller\n\t8d4f  C610/X99 series chipset LPC Controller\n\t8d60  C610/X99 series chipset sSATA Controller [IDE mode]\n\t8d62  C610/X99 series chipset sSATA Controller [AHCI mode]\n\t8d64  C610/X99 series chipset sSATA Controller [RAID mode]\n\t8d66  C610/X99 series chipset sSATA Controller [RAID mode]\n\t8d68  C610/X99 series chipset sSATA Controller [IDE mode]\n\t8d6e  C610/X99 series chipset sSATA Controller [RAID mode]\n\t8d7c  C610/X99 series chipset SPSR\n\t\t15d9 0832  X10SRL-F\n\t8d7d  C610/X99 series chipset MS SMBus 0\n\t8d7e  C610/X99 series chipset MS SMBus 1\n\t8d7f  C610/X99 series chipset MS SMBus 2\n\t9000  IXP2000 Family Network Processor\n\t9001  IXP2400 Network Processor\n\t9002  IXP2300 Network Processor\n\t9004  IXP2800 Network Processor\n\t9621  Integrated RAID\n\t9622  Integrated RAID\n\t9641  Integrated RAID\n\t96a1  Integrated RAID\n\t9b41  UHD Graphics\n\t9c00  8 Series SATA Controller 1 [IDE mode]\n\t9c01  8 Series SATA Controller 1 [IDE mode]\n\t9c02  8 Series SATA Controller 1 [AHCI mode]\n\t9c03  8 Series SATA Controller 1 [AHCI mode]\n\t\t17aa 2214  ThinkPad X240\n\t9c04  8 Series SATA Controller 1 [RAID mode]\n\t9c05  8 Series SATA Controller 1 [RAID mode]\n\t9c06  8 Series SATA Controller 1 [RAID mode]\n\t9c07  8 Series SATA Controller 1 [RAID mode]\n\t9c08  8 Series SATA Controller 2 [IDE mode]\n\t9c09  8 Series SATA Controller 2 [IDE mode]\n\t9c0a  8 Series SATA Controller [Reserved]\n\t9c0b  8 Series SATA Controller [Reserved]\n\t9c0c  8 Series SATA Controller [Reserved]\n\t9c0d  8 Series SATA Controller [Reserved]\n\t9c0e  8 Series SATA Controller 1 [RAID mode]\n\t9c0f  8 Series SATA Controller 1 [RAID mode]\n\t9c10  8 Series PCI Express Root Port 1\n\t9c11  8 Series PCI Express Root Port 1\n\t9c12  8 Series PCI Express Root Port 2\n\t9c13  8 Series PCI Express Root Port 2\n\t9c14  8 Series PCI Express Root Port 3\n\t9c15  8 Series PCI Express Root Port 3\n\t9c16  8 Series PCI Express Root Port 4\n\t9c17  8 Series PCI Express Root Port 4\n\t9c18  8 Series PCI Express Root Port 5\n\t9c19  8 Series PCI Express Root Port 5\n\t9c1a  8 Series PCI Express Root Port 6\n\t9c1b  8 Series PCI Express Root Port 6\n\t9c1c  8 Series PCI Express Root Port 7\n\t9c1d  8 Series PCI Express Root Port 7\n\t9c1e  8 Series PCI Express Root Port 8\n\t9c1f  8 Series PCI Express Root Port 8\n\t9c20  8 Series HD Audio Controller\n\t\t17aa 2214  ThinkPad X240\n\t9c21  8 Series HD Audio Controller\n\t9c22  8 Series SMBus Controller\n\t\t17aa 2214  ThinkPad X240\n\t9c23  8 Series CHAP Counters\n\t9c24  8 Series Thermal\n\t9c26  8 Series USB EHCI #1\n\t\t17aa 220c  T440s\n\t\t17aa 2214  ThinkPad X240\n\t9c2d  8 Series USB EHCI #2\n\t9c31  8 Series USB xHCI HC\n\t\t17aa 2214  ThinkPad X240\n\t\t8086 7270  Apple MacBookAir6,2 / MacBookPro11,1\n\t9c35  8 Series SDIO Controller\n\t9c36  8 Series Audio DSP Controller\n\t9c3a  8 Series HECI #0\n\t\t17aa 2214  ThinkPad X240\n\t9c3b  8 Series HECI #1\n\t9c3c  8 Series HECI IDER\n\t9c3d  8 Series HECI KT\n\t9c40  8 Series LPC Controller\n\t9c41  8 Series LPC Controller\n\t9c42  8 Series LPC Controller\n\t9c43  8 Series LPC Controller\n\t\t17aa 2214  ThinkPad X240\n\t9c44  8 Series LPC Controller\n\t9c45  8 Series LPC Controller\n\t9c46  8 Series LPC Controller\n\t9c47  8 Series LPC Controller\n\t9c60  8 Series Low Power Sub-System DMA\n\t9c61  8 Series I2C Controller #0\n\t9c62  8 Series I2C Controller #1\n\t9c63  8 Series UART Controller #0\n\t9c64  8 Series UART Controller #1\n\t9c65  8 Series SPI Controller #0\n\t9c66  8 Series SPI Controller #1\n\t9c83  Wildcat Point-LP SATA Controller [AHCI Mode]\n\t9c85  Wildcat Point-LP SATA Controller [RAID Mode]\n\t9c87  Wildcat Point-LP SATA Controller [RAID Mode]\n\t9c8f  Wildcat Point-LP SATA Controller [RAID Mode]\n\t9c90  Wildcat Point-LP PCI Express Root Port #1\n\t9c92  Wildcat Point-LP PCI Express Root Port #2\n\t9c94  Wildcat Point-LP PCI Express Root Port #3\n\t9c96  Wildcat Point-LP PCI Express Root Port #4\n\t9c98  Wildcat Point-LP PCI Express Root Port #5\n\t9c9a  Wildcat Point-LP PCI Express Root Port #6\n\t9ca0  Wildcat Point-LP High Definition Audio Controller\n\t9ca2  Wildcat Point-LP SMBus Controller\n\t9ca4  Wildcat Point-LP Thermal Management Controller\n\t9ca6  Wildcat Point-LP USB EHCI Controller\n\t9cb1  Wildcat Point-LP USB xHCI Controller\n\t9cb5  Wildcat Point-LP Secure Digital IO Controller\n\t9cb6  Wildcat Point-LP Smart Sound Technology Controller\n\t9cba  Wildcat Point-LP MEI Controller #1\n\t9cbb  Wildcat Point-LP MEI Controller #2\n\t9cbc  Wildcat Point-LP IDE-r Controller\n\t9cbd  Wildcat Point-LP KT Controller\n\t9cc1  Wildcat Point-LP LPC Controller\n\t9cc2  Wildcat Point-LP LPC Controller\n\t9cc3  Wildcat Point-LP LPC Controller\n\t9cc5  Wildcat Point-LP LPC Controller\n\t9cc6  Wildcat Point-LP LPC Controller\n\t9cc7  Wildcat Point-LP LPC Controller\n\t9cc9  Wildcat Point-LP LPC Controller\n\t9ce0  Wildcat Point-LP Serial IO DMA Controller\n\t9ce1  Wildcat Point-LP Serial IO I2C Controller #0\n\t9ce2  Wildcat Point-LP Serial IO I2C Controller #1\n\t9ce3  Wildcat Point-LP Serial IO UART Controller #0\n\t9ce4  Wildcat Point-LP Serial IO UART Controller #1\n\t9ce5  Wildcat Point-LP Serial IO GSPI Controller #0\n\t9ce6  Wildcat Point-LP Serial IO GSPI Controller #1\n\t9d03  Sunrise Point-LP SATA Controller [AHCI mode]\n\t\t1028 06dc  Latitude E7470\n\t\t1028 06f3  Latitude 3570\n\t\t103c 8079  EliteBook 840 G3\n\t\t17aa 225d  ThinkPad T480\n\t\t17aa 382a  B51-80 Laptop\n\t9d10  Sunrise Point-LP PCI Express Root Port #1\n\t9d11  Sunrise Point-LP PCI Express Root Port #2\n\t9d12  Sunrise Point-LP PCI Express Root Port #3\n\t9d13  Sunrise Point-LP PCI Express Root Port #4\n\t9d14  Sunrise Point-LP PCI Express Root Port #5\n\t\t17aa 382a  B51-80 Laptop\n\t9d15  Sunrise Point-LP PCI Express Root Port #6\n\t\t17aa 382a  B51-80 Laptop\n\t9d16  Sunrise Point-LP PCI Express Root Port #7\n\t9d17  Sunrise Point-LP PCI Express Root Port #8\n\t9d18  Sunrise Point-LP PCI Express Root Port #9\n\t\t17aa 382a  B51-80 Laptop\n\t9d19  Sunrise Point-LP PCI Express Root Port #10\n\t9d1a  Sunrise Point-LP PCI Express Root Port #11\n\t9d21  Sunrise Point-LP PMC\n\t\t1028 06dc  Latitude E7470\n\t\t1028 06f3  Latitude 3570\n\t\t103c 8079  EliteBook 840 G3\n\t\t17aa 224f  ThinkPad X1 Carbon 5th Gen\n\t\t17aa 225d  ThinkPad T480\n\t\t17aa 382a  B51-80 Laptop\n\t9d23  Sunrise Point-LP SMBus\n\t\t1028 06dc  Latitude E7470\n\t\t1028 06f3  Latitude 3570\n\t\t103c 8079  EliteBook 840 G3\n\t\t17aa 2247  ThinkPad T570\n\t\t17aa 224f  ThinkPad X1 Carbon 5th Gen\n\t\t17aa 225d  ThinkPad T480\n\t\t17aa 382a  B51-80 Laptop\n\t9d27  Sunrise Point-LP Serial IO UART Controller #0\n\t9d28  Sunrise Point-LP Serial IO UART Controller #1\n\t9d29  Sunrise Point-LP Serial IO SPI Controller #0\n\t9d2a  Sunrise Point-LP Serial IO SPI Controller #1\n\t9d2d  Sunrise Point-LP Secure Digital IO Controller\n\t9d2f  Sunrise Point-LP USB 3.0 xHCI Controller\n\t\t1028 06dc  Latitude E7470\n\t\t1028 06f3  Latitude 3570\n\t\t103c 8079  EliteBook 840 G3\n\t\t17aa 2247  ThinkPad T570\n\t\t17aa 225d  ThinkPad T480\n\t\t17aa 382a  B51-80 Laptop\n\t9d31  Sunrise Point-LP Thermal subsystem\n\t\t1028 06dc  Latitude E7470\n\t\t1028 06f3  Latitude 3570\n\t\t103c 8079  EliteBook 840 G3\n\t\t17aa 2247  ThinkPad T570\n\t\t17aa 224f  ThinkPad X1 Carbon 5th Gen\n\t\t17aa 225d  ThinkPad T480\n\t\t17aa 382a  B51-80 Laptop\n\t9d35  Sunrise Point-LP Integrated Sensor Hub\n\t9d3a  Sunrise Point-LP CSME HECI #1\n\t\t1028 06dc  Latitude E7470\n\t\t1028 06f3  Latitude 3570\n\t\t103c 8079  EliteBook 840 G3\n\t\t17aa 2247  ThinkPad T570\n\t\t17aa 224f  ThinkPad X1 Carbon 5th Gen\n\t\t17aa 225d  ThinkPad T480\n\t\t17aa 382a  B51-80 Laptop\n\t9d3d  Sunrise Point-LP Active Management Technology - SOL\n\t\t103c 8079  EliteBook 840 G3\n\t9d43  Sunrise Point-LP LPC Controller\n\t\t17aa 382a  B51-80 Laptop\n\t9d48  Sunrise Point-LP LPC Controller\n\t\t1028 06dc  Latitude E7470\n\t\t1028 06f3  Latitude 3570\n\t\t103c 8079  EliteBook 840 G3\n\t9d4e  Sunrise Point LPC Controller/eSPI Controller\n\t\t17aa 225d  ThinkPad T480\n\t9d50  Sunrise Point LPC Controller\n\t9d56  Sunrise Point-LP LPC Controller\n\t9d58  Sunrise Point-LP LPC Controller\n\t\t17aa 2247  ThinkPad T570\n\t\t17aa 224f  ThinkPad X1 Carbon 5th Gen\n\t9d60  Sunrise Point-LP Serial IO I2C Controller #0\n\t\t1028 06f3  Latitude 3570\n\t\t103c 8079  EliteBook 840 G3\n\t\t17aa 225d  ThinkPad T480\n\t\t8086 9d60  100 Series PCH/Sunrise Point PCH I2C0 [Skylake/Kaby Lake LPSS I2C]\n\t9d61  Sunrise Point-LP Serial IO I2C Controller #1\n\t9d62  Sunrise Point-LP Serial IO I2C Controller #2\n\t9d63  Sunrise Point-LP Serial IO I2C Controller #3\n\t9d64  Sunrise Point-LP Serial IO I2C Controller #4\n\t9d65  Sunrise Point-LP Serial IO I2C Controller #5\n\t9d66  Sunrise Point-LP Serial IO UART Controller #2\n\t9d70  Sunrise Point-LP HD Audio\n\t\t1028 06dc  Latitude E7470\n\t\t1028 06f3  Latitude 3570\n\t\t103c 8079  EliteBook 840 G3\n\t\t17aa 382a  B51-80 Laptop\n\t9d71  Sunrise Point-LP HD Audio\n\t\t17aa 224f  ThinkPad X1 Carbon 5th Gen\n\t\t17aa 225d  ThinkPad T480\n\t9d84  Cannon Point-LP LPC Controller\n\t\t1028 089e  Inspiron 5482\n\t9da3  Cannon Point-LP SMBus Controller\n\t9da4  Cannon Point-LP SPI Controller\n\t9db0  Cannon Point-LP PCI Express Root Port #9\n\t9db1  Cannon Point-LP PCI Express Root Port #10\n\t9db2  Cannon Point-LP PCI Express Root Port #1\n\t9db4  Cannon Point-LP PCI Express Root Port #13\n\t\t1028 089e  Inspiron 5482\n\t9db6  Cannon Point-LP PCI Express Root Port #15\n\t9db8  Cannon Point-LP PCI Express Root Port #1\n\t9dbc  Cannon Point-LP PCI Express Root Port #5\n\t9dbe  Cannon Point-LP PCI Express Root Port #7\n\t9dbf  Cannon Point PCI Express Root Port #8\n\t9dc5  Cannon Point-LP Serial IO I2C Host Controller\n\t9dc8  Cannon Point-LP High Definition Audio Controller\n\t\t1028 089e  Inspiron 5482\n\t9dd3  Cannon Point-LP SATA Controller [AHCI Mode]\n\t9de0  Cannon Point-LP MEI Controller #1\n\t9de3  Cannon Point-LP Keyboard and Text (KT) Redirection\n\t9de8  Cannon Point-LP Serial IO I2C Controller #0\n\t\t1028 089e  Inspiron 5482\n\t9de9  Cannon Point-LP Serial IO I2C Controller #1\n\t\t1028 089e  Inspiron 5482\n\t9ded  Cannon Point-LP USB 3.1 xHCI Controller\n\t9def  Cannon Point-LP Shared SRAM\n\t9df0  Cannon Point-LP CNVi [Wireless-AC]\n\t9df5  BayHubTech Integrated SD controller\n\t9df9  Cannon Point-LP Thermal Controller\n\t9dfc  Cannon Point-LP Integrated Sensor Hub\n\ta000  Atom Processor D4xx/D5xx/N4xx/N5xx DMI Bridge\n\t\t1458 5000  GA-D525TUD\n\t\t8086 4f4d  DeskTop Board D510MO\n\t\t8086 544b  Desktop Board D425KT\n\ta001  Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller\n\t\t1458 d000  GA-D525TUD\n\t\t8086 4f4d  DeskTop Board D510MO\n\t\t8086 544b  Desktop Board D425KT\n\ta002  Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller\n\ta003  Atom Processor D4xx/D5xx/N4xx/N5xx CHAPS counter\n\ta010  Atom Processor D4xx/D5xx/N4xx/N5xx DMI Bridge\n\t\t1043 83ac  Eee PC 1015PX\n\t\t144d c072  Notebook N150P\n\ta011  Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller\n\t\t1043 83ac  Eee PC 1015PX\n\t\t144d c072  Notebook N150P\n\ta012  Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller\n\t\t1043 83ac  Eee PC 1015PX\n\t\t144d c072  Notebook N150P\n\ta013  Atom Processor D4xx/D5xx/N4xx/N5xx CHAPS counter\n\ta102  Q170/Q150/B150/H170/H110/Z170/CM236 Chipset SATA Controller [AHCI Mode]\n\ta103  HM170/QM170 Chipset SATA Controller [AHCI Mode]\n\t\t1028 06e4  XPS 15 9550\n\ta105  Sunrise Point-H SATA Controller [RAID mode]\n\ta106  Q170/H170/Z170/CM236 Chipset SATA Controller [RAID Mode]\n\ta107  HM170/QM170 Chipset SATA Controller [RAID Mode]\n\ta10f  Sunrise Point-H SATA Controller [RAID mode]\n\ta110  100 Series/C230 Series Chipset Family PCI Express Root Port #1\n\ta111  100 Series/C230 Series Chipset Family PCI Express Root Port #2\n\ta112  100 Series/C230 Series Chipset Family PCI Express Root Port #3\n\ta113  100 Series/C230 Series Chipset Family PCI Express Root Port #4\n\ta114  100 Series/C230 Series Chipset Family PCI Express Root Port #5\n\ta115  100 Series/C230 Series Chipset Family PCI Express Root Port #6\n\ta116  100 Series/C230 Series Chipset Family PCI Express Root Port #7\n\ta117  100 Series/C230 Series Chipset Family PCI Express Root Port #8\n\ta118  100 Series/C230 Series Chipset Family PCI Express Root Port #9\n\ta119  100 Series/C230 Series Chipset Family PCI Express Root Port #10\n\ta11a  100 Series/C230 Series Chipset Family PCI Express Root Port #11\n\ta11b  100 Series/C230 Series Chipset Family PCI Express Root Port #12\n\ta11c  100 Series/C230 Series Chipset Family PCI Express Root Port #13\n\ta11d  100 Series/C230 Series Chipset Family PCI Express Root Port #14\n\ta11e  100 Series/C230 Series Chipset Family PCI Express Root Port #15\n\ta11f  100 Series/C230 Series Chipset Family PCI Express Root Port #16\n\ta120  100 Series/C230 Series Chipset Family P2SB\n\ta121  100 Series/C230 Series Chipset Family Power Management Controller\n\t\t1028 06e4  XPS 15 9550\n\ta122  Sunrise Point-H cAVS\n\ta123  100 Series/C230 Series Chipset Family SMBus\n\t\t1028 06e4  XPS 15 9550\n\ta124  100 Series/C230 Series Chipset Family SPI Controller\n\ta125  100 Series/C230 Series Chipset Family Gigabit Ethernet Controller\n\ta126  100 Series/C230 Series Chipset Family Trace Hub\n\ta127  100 Series/C230 Series Chipset Family Serial IO UART #0\n\ta128  100 Series/C230 Series Chipset Family Serial IO UART #1\n\ta129  100 Series/C230 Series Chipset Family Serial IO GSPI #0\n\ta12a  100 Series/C230 Series Chipset Family Serial IO GSPI #1\n\ta12f  100 Series/C230 Series Chipset Family USB 3.0 xHCI Controller\n\t\t1028 06e4  XPS 15 9550\n\ta130  100 Series/C230 Series Chipset Family USB Device Controller (OTG)\n\ta131  100 Series/C230 Series Chipset Family Thermal Subsystem\n\t\t1028 06e4  XPS 15 9550\n\ta133  Sunrise Point-H Northpeak ACPI Function\n\ta135  100 Series/C230 Series Chipset Family Integrated Sensor Hub\n\ta13a  100 Series/C230 Series Chipset Family MEI Controller #1\n\t\t1028 06e4  XPS 15 9550\n\ta13b  100 Series/C230 Series Chipset Family MEI Controller #2\n\ta13c  100 Series/C230 Series Chipset Family IDE Redirection\n\ta13d  100 Series/C230 Series Chipset Family KT Redirection\n\ta13e  100 Series/C230 Series Chipset Family MEI Controller #3\n\ta140  Sunrise Point-H LPC Controller\n\ta141  Sunrise Point-H LPC Controller\n\ta142  Sunrise Point-H LPC Controller\n\ta143  H110 Chipset LPC/eSPI Controller\n\ta144  H170 Chipset LPC/eSPI Controller\n\ta145  Z170 Chipset LPC/eSPI Controller\n\ta146  Q170 Chipset LPC/eSPI Controller\n\ta147  Q150 Chipset LPC/eSPI Controller\n\ta148  B150 Chipset LPC/eSPI Controller\n\ta149  C236 Chipset LPC/eSPI Controller\n\ta14a  C232 Chipset LPC/eSPI Controller\n\ta14b  Sunrise Point-H LPC Controller\n\ta14c  Sunrise Point-H LPC Controller\n\ta14d  QM170 Chipset LPC/eSPI Controller\n\ta14e  HM170 Chipset LPC/eSPI Controller\n\t\t1028 06e4  XPS 15 9550\n\ta14f  Sunrise Point-H LPC Controller\n\ta150  CM236 Chipset LPC/eSPI Controller\n\ta151  Sunrise Point-H LPC Controller\n\ta152  HM175 Chipset LPC/eSPI Controller\n\ta153  QM175 Chipset LPC/eSPI Controller\n\ta154  CM238 Chipset LPC/eSPI Controller\n\ta155  Sunrise Point-H LPC Controller\n\ta156  Sunrise Point-H LPC Controller\n\ta157  Sunrise Point-H LPC Controller\n\ta158  Sunrise Point-H LPC Controller\n\ta159  Sunrise Point-H LPC Controller\n\ta15a  Sunrise Point-H LPC Controller\n\ta15b  Sunrise Point-H LPC Controller\n\ta15c  Sunrise Point-H LPC Controller\n\ta15d  Sunrise Point-H LPC Controller\n\ta15e  Sunrise Point-H LPC Controller\n\ta15f  Sunrise Point-H LPC Controller\n\ta160  100 Series/C230 Series Chipset Family Serial IO I2C Controller #0\n\t\t1028 06e4  XPS 15 9550\n\ta161  100 Series/C230 Series Chipset Family Serial IO I2C Controller #1\n\t\t1028 06e4  XPS 15 9550\n\ta162  100 Series/C230 Series Chipset Family Serial IO I2C Controller #2\n\ta163  100 Series/C230 Series Chipset Family Serial IO I2C Controller #3\n\ta166  100 Series/C230 Series Chipset Family Serial IO UART Controller #2\n\ta167  100 Series/C230 Series Chipset Family PCI Express Root Port #17\n\ta168  100 Series/C230 Series Chipset Family PCI Express Root Port #18\n\ta169  100 Series/C230 Series Chipset Family PCI Express Root Port #19\n\ta16a  100 Series/C230 Series Chipset Family PCI Express Root Port #20\n\ta170  100 Series/C230 Series Chipset Family HD Audio Controller\n\t\t1028 06e4  XPS 15 9550\n\ta171  CM238 HD Audio Controller\n\ta182  C620 Series Chipset Family SATA Controller [AHCI mode]\n\ta186  C620 Series Chipset Family SATA Controller [RAID mode]\n\ta190  C620 Series Chipset Family PCI Express Root Port #1\n\ta191  C620 Series Chipset Family PCI Express Root Port #2\n\ta192  C620 Series Chipset Family PCI Express Root Port #3\n\ta193  C620 Series Chipset Family PCI Express Root Port #4\n\ta194  C620 Series Chipset Family PCI Express Root Port #5\n\ta195  C620 Series Chipset Family PCI Express Root Port #6\n\ta196  C620 Series Chipset Family PCI Express Root Port #7\n\ta197  C620 Series Chipset Family PCI Express Root Port #8\n\ta198  C620 Series Chipset Family PCI Express Root Port #9\n\ta199  C620 Series Chipset Family PCI Express Root Port #10\n\ta19a  C620 Series Chipset Family PCI Express Root Port #11\n\ta19b  C620 Series Chipset Family PCI Express Root Port #12\n\ta19c  C620 Series Chipset Family PCI Express Root Port #13\n\ta19d  C620 Series Chipset Family PCI Express Root Port #14\n\ta19e  C620 Series Chipset Family PCI Express Root Port #15\n\ta19f  C620 Series Chipset Family PCI Express Root Port #16\n\ta1a0  C620 Series Chipset Family P2SB\n\ta1a1  C620 Series Chipset Family Power Management Controller\n\t\t15d9 095d  X11SPM-TF\n\ta1a2  C620 Series Chipset Family cAVS\n\ta1a3  C620 Series Chipset Family SMBus\n\t\t15d9 095d  X11SPM-TF\n\ta1a4  C620 Series Chipset Family SPI Controller\n\t\t15d9 095d  X11SPM-TF\n\ta1a6  C620 Series Chipset Family Trace Hub\n\ta1af  C620 Series Chipset Family USB 3.0 xHCI Controller\n\t\t15d9 095d  X11SPM-TF\n\ta1b1  C620 Series Chipset Family Thermal Subsystem\n\t\t15d9 095d  X11SPM-TF\n\ta1ba  C620 Series Chipset Family MEI Controller #1\n\t\t15d9 095d  X11SPM-TF\n\ta1bb  C620 Series Chipset Family MEI Controller #2\n\t\t15d9 095d  X11SPM-TF\n\ta1bc  C620 Series Chipset Family IDE Redirection\n\ta1bd  C620 Series Chipset Family KT Redirection\n\ta1be  C620 Series Chipset Family MEI Controller #3\n\t\t15d9 095d  X11SPM-TF\n\ta1c1  C621 Series Chipset LPC/eSPI Controller\n\ta1c2  C622 Series Chipset LPC/eSPI Controller\n\t\t15d9 095d  X11SPM-TF\n\ta1c3  C624 Series Chipset LPC/eSPI Controller\n\ta1c4  C625 Series Chipset LPC/eSPI Controller\n\ta1c5  C626 Series Chipset LPC/eSPI Controller\n\ta1c6  C627 Series Chipset LPC/eSPI Controller\n\ta1c7  C628 Series Chipset LPC/eSPI Controller\n\ta1d2  C620 Series Chipset Family SSATA Controller [AHCI mode]\n\ta1d6  C620 Series Chipset Family SSATA Controller [RAID mode]\n\ta1e7  C620 Series Chipset Family PCI Express Root Port #17\n\ta1e8  C620 Series Chipset Family PCI Express Root Port #18\n\ta1e9  C620 Series Chipset Family PCI Express Root Port #19\n\ta1ea  C620 Series Chipset Family PCI Express Root Port #20\n\ta1ec  C620 Series Chipset Family MROM 0\n\ta1ed  C620 Series Chipset Family MROM 1\n\ta1f8  Lewisburg IE: HECI #1\n\ta1f9  Lewisburg IE: HECI #2\n\ta1fa  Lewisburg IE: IDE-r\n\ta1fb  Lewisburg IE: KT Controller\n\ta1fc  Lewisburg IE: HECI #3\n\ta202  Lewisburg SATA Controller [AHCI mode]\n\ta206  Lewisburg SATA Controller [RAID mode]\n\ta223  Lewisburg SMBus\n\ta224  Lewisburg SPI Controller\n\ta242  Lewisburg LPC or eSPI Controller\n\ta243  Lewisburg LPC or eSPI Controller\n\ta252  Lewisburg SSATA Controller [AHCI mode]\n\ta256  Lewisburg SSATA Controller [RAID mode]\n\ta282  200 Series PCH SATA controller [AHCI mode]\n\ta286  200 Series PCH SATA controller [RAID mode]\n\ta290  200 Series PCH PCI Express Root Port #1\n\ta291  200 Series PCH PCI Express Root Port #2\n\ta292  200 Series PCH PCI Express Root Port #3\n\ta293  200 Series PCH PCI Express Root Port #4\n\ta294  200 Series PCH PCI Express Root Port #5\n\ta295  200 Series PCH PCI Express Root Port #6\n\ta296  200 Series PCH PCI Express Root Port #7\n\ta297  200 Series PCH PCI Express Root Port #8\n\ta298  200 Series PCH PCI Express Root Port #9\n\ta299  200 Series PCH PCI Express Root Port #10\n\ta29a  200 Series PCH PCI Express Root Port #11\n\ta29b  200 Series PCH PCI Express Root Port #12\n\ta29c  200 Series PCH PCI Express Root Port #13\n\ta29d  200 Series PCH PCI Express Root Port #14\n\ta29e  200 Series PCH PCI Express Root Port #15\n\ta29f  200 Series PCH PCI Express Root Port #16\n\ta2a0  200 Series/Z370 Chipset Family P2SB\n\ta2a1  200 Series/Z370 Chipset Family Power Management Controller\n\ta2a3  200 Series/Z370 Chipset Family SMBus Controller\n\ta2a4  200 Series/Z370 Chipset Family SPI Controller\n\ta2a5  200 Series/Z370 Chipset Family Gigabit Ethernet Controller\n\ta2a6  200 Series/Z370 Chipset Family Trace Hub\n\ta2a7  200 Series/Z370 Chipset Family Serial IO UART Controller #0\n\ta2a8  200 Series/Z370 Chipset Family Serial IO UART Controller #1\n\ta2a9  200 Series/Z370 Chipset Family Serial IO SPI Controller #0\n\ta2aa  200 Series/Z370 Chipset Family Serial IO SPI Controller #1\n\ta2af  200 Series/Z370 Chipset Family USB 3.0 xHCI Controller\n\ta2b1  200 Series PCH Thermal Subsystem\n\ta2ba  200 Series PCH CSME HECI #1\n\ta2bb  200 Series PCH CSME HECI #2\n\ta2c4  200 Series PCH LPC Controller (H270)\n\ta2c5  200 Series PCH LPC Controller (Z270)\n\ta2c6  200 Series PCH LPC Controller (Q270)\n\ta2c7  200 Series PCH LPC Controller (Q250)\n\ta2c8  200 Series PCH LPC Controller (B250)\n\ta2c9  Z370 Chipset LPC/eSPI Controller\n\ta2d2  X299 Chipset LPC/eSPI Controller\n\ta2d3  C422 Chipset LPC/eSPI Controller\n\ta2e0  200 Series PCH Serial IO I2C Controller #0\n\ta2e1  200 Series PCH Serial IO I2C Controller #1\n\ta2e2  200 Series PCH Serial IO I2C Controller #2\n\ta2e3  200 Series PCH Serial IO I2C Controller #3\n\ta2e6  200 Series PCH Serial IO UART Controller #2\n\ta2e7  200 Series PCH PCI Express Root Port #17\n\ta2e8  200 Series PCH PCI Express Root Port #18\n\ta2e9  200 Series PCH PCI Express Root Port #19\n\ta2ea  200 Series PCH PCI Express Root Port #20\n\ta2eb  200 Series PCH PCI Express Root Port #21\n\ta2ec  200 Series PCH PCI Express Root Port #22\n\ta2ed  200 Series PCH PCI Express Root Port #23\n\ta2ee  200 Series PCH PCI Express Root Port #24\n\ta2f0  200 Series PCH HD Audio\n\ta304  H370 Chipset LPC/eSPI Controller\n\ta305  Z390 Chipset LPC/eSPI Controller\n\ta306  Q370 Chipset LPC/eSPI Controller\n\ta309  Cannon Point-LP LPC Controller\n\ta30c  QM370 Chipset LPC/eSPI Controller\n\ta323  Cannon Lake PCH SMBus Controller\n\ta324  Cannon Lake PCH SPI Controller\n\ta328  Cannon Lake PCH Serial IO UART Host Controller\n\ta32c  Cannon Lake PCH PCI Express Root Port #21\n\ta32d  Cannon Lake PCH PCI Express Root Port #22\n\ta32e  Cannon Lake PCH PCI Express Root Port #23\n\ta32f  Cannon Lake PCH PCI Express Root Port #24\n\ta330  Cannon Lake PCH PCI Express Root Port #9\n\ta331  Cannon Lake PCH PCI Express Root Port #10\n\ta332  Cannon Lake PCH PCI Express Root Port #11\n\ta333  Cannon Lake PCH PCI Express Root Port #12\n\ta334  Cannon Lake PCH PCI Express Root Port #13\n\ta335  Cannon Lake PCH PCI Express Root Port #14\n\ta336  Cannon Lake PCH PCI Express Root Port #15\n\ta337  Cannon Lake PCH PCI Express Root Port #16\n\ta338  Cannon Lake PCH PCI Express Root Port #1\n\ta339  Cannon Lake PCH PCI Express Root Port #2\n\ta33a  Cannon Lake PCH PCI Express Root Port #3\n\ta33b  Cannon Lake PCH PCI Express Root Port #4\n\ta33c  Cannon Lake PCH PCI Express Root Port #5\n\ta33d  Cannon Lake PCH PCI Express Root Port #6\n\ta33e  Cannon Lake PCH PCI Express Root Port #7\n\ta33f  Cannon Lake PCH PCI Express Root Port #8\n\ta340  Cannon Lake PCH PCI Express Root Port #17\n\ta341  Cannon Lake PCH PCI Express Root Port #18\n\ta342  Cannon Lake PCH PCI Express Root Port #19\n\ta343  Cannon Lake PCH PCI Express Root Port #20\n\ta348  Cannon Lake PCH cAVS\n\ta352  Cannon Lake PCH SATA AHCI Controller\n\ta353  Cannon Lake Mobile PCH SATA AHCI Controller\n\ta360  Cannon Lake PCH HECI Controller\n\ta363  Cannon Lake PCH Active Management Technology - SOL\n\ta364  Cannon Lake PCH HECI Controller #2\n\ta368  Cannon Lake PCH Serial IO I2C Controller #0\n\ta369  Cannon Lake PCH Serial IO I2C Controller #1\n\ta36a  Cannon Lake PCH Serial IO I2C Controller #2\n\ta36b  Cannon Lake PCH Serial IO I2C Controller #3\n\ta36d  Cannon Lake PCH USB 3.1 xHCI Host Controller\n\ta36f  Cannon Lake PCH Shared SRAM\n\ta370  Wireless-AC 9560 [Jefferson Peak]\n\ta379  Cannon Lake PCH Thermal Controller\n\ta620  6400/6402 Advanced Memory Buffer (AMB)\n\tabc0  Omni-Path Fabric Switch Silicon 100 Series\n\tb152  21152 PCI-to-PCI Bridge\n\t\t8086 b152  21152 PCI-to-PCI Bridge\n# observed, and documented in Intel revision note; new mask of 1011:0026\n\tb154  21154 PCI-to-PCI Bridge\n\tb555  21555 Non transparent PCI-to-PCI Bridge\n\t\t12c7 5005  SS7HD PCI Adaptor Card\n\t\t12c7 5006  SS7HDC cPCI Adaptor Card\n\t\t12d9 000a  PCI VoIP Gateway\n\t\t4c53 1050  CT7 mainboard\n\t\t4c53 1051  CE7 mainboard\n\t\te4bf 1000  CC8-1-BLUES\n\td130  Core Processor DMI\n\t\t15d9 0605  X8SIL\n\td131  Core Processor DMI\n\t\t1028 02da  OptiPlex 980\n\t\t15d9 060d  C7SIM-Q Motherboard\n\td132  Core Processor DMI\n\t\t1028 040b  Latitude E6510\n\td133  Core Processor DMI\n\td134  Core Processor DMI\n\td135  Core Processor DMI\n\td136  Core Processor DMI\n\td137  Core Processor DMI\n\td138  Core Processor PCI Express Root Port 1\n\t\t1028 02da  OptiPlex 980\n\t\t1028 040b  Latitude E6510\n\t\t15d9 060d  C7SIM-Q Motherboard\n\td139  Core Processor PCI Express Root Port 2\n\td13a  Core Processor PCI Express Root Port 3\n\td13b  Core Processor PCI Express Root Port 4\n\td150  Core Processor QPI Link\n\td151  Core Processor QPI Routing and Protocol Registers\n\td155  Core Processor System Management Registers\n\td156  Core Processor Semaphore and Scratchpad Registers\n\td157  Core Processor System Control and Status Registers\n\td158  Core Processor Miscellaneous Registers\n\tf1a5  SSD 600P Series\n\tf1a6  SSD Pro 7600p/760p/E 6100p Series\n\tf1a8  SSD 660P Series\n8088  Beijing Wangxun Technology Co., Ltd.\n\t0101  WX1860A2 Gigabit Ethernet Controller\n\t\t8088 0201  Dual-Port Ethernet Network Adaptor SF200T\n\t0102  WX1860A2S Gigabit Ethernet Controller\n\t\t8088 0210  Dual-Port Ethernet Network Adaptor SF200T-S\n\t0103  WX1860A4 Gigabit Ethernet Controller\n\t\t8088 0401  Qual-Port Ethernet Network Adaptor SF400T\n\t\t8088 0440  Qual-Port Ethernet Network Adaptor SF400-OCP\n\t0104  WX1860A4S Gigabit Ethernet Controller\n\t\t8088 0410  Qual-Port Ethernet Network Adaptor SF400T-S\n\t0105  WX1860AL2 Gigabit Ethernet Controller\n\t\t8088 0202  Dual-Port Ethernet Network Adaptor SF200HT\n\t0106  WX1860AL2S Gigabit Ethernet Controller\n\t\t8088 0220  Dual-Port Ethernet Network Adaptor SF200HT-S\n\t0107  WX1860AL4 Gigabit Ethernet Controller\n\t\t8088 0402  Qual-Port Ethernet Network Adaptor SF400HT\n\t0108  WX1860AL4S Gigabit Ethernet Controller\n\t\t8088 0420  Qual-Port Ethernet Network Adaptor SF400HT-S\n\t1001  Ethernet Controller RP1000 for 10GbE SFP+\n\t\t8088 0000  Ethernet Network Adaptor RP1000 for 10GbE SFP+\n\t2001  Ethernet Controller RP2000 for 10GbE SFP+\n\t\t8088 2000  Ethernet Network Adaptor RP2000 for 10GbE SFP+\n80ee  InnoTek Systemberatung GmbH\n\tbeef  VirtualBox Graphics Adapter\n\tcafe  VirtualBox Guest Service\n8322  Sodick America Corp.\n8384  SigmaTel\n8401  TRENDware International Inc.\n8686  ScaleMP\n\t1010  vSMP Foundation controller [vSMP CTL]\n\t1011  vSMP Foundation MEX/FLX controller [vSMP CTL]\n8800  Trigem Computer Inc.\n\t2008  Video assistant component\n8866  T-Square Design Inc.\n8888  Silicon Magic\n8912  TRX\n# 8c4a is not Winbond but there is a board misprogrammed\n8c4a  Winbond\n\t1980  W89C940 misprogrammed [ne2k]\n8e0e  Computone Corporation\n8e2e  KTI\n\t3000  ET32P2\n9004  Adaptec\n\t0078  AHA-2940U_CN\n\t1078  AIC-7810\n\t1160  AIC-1160 [Family Fibre Channel Adapter]\n\t2178  AIC-7821\n\t3860  AHA-2930CU\n\t3b78  AHA-4844W/4844UW\n\t5075  AIC-755x\n\t5078  AIC-7850T/7856T [AVA-2902/4/6 / AHA-2910]\n\t\t9004 7850  AIC-7850T/7856T [AVA-290x / AHA-2910]\n\t5175  AIC-755x\n\t5178  AIC-7851\n\t5275  AIC-755x\n\t5278  AIC-7852\n\t5375  AIC-755x\n\t5378  AIC-7850\n\t5475  AIC-755x\n\t5478  AIC-7850\n\t5575  AVA-2930\n\t5578  AIC-7855\n\t5647  ANA-7711 TCP Offload Engine\n\t\t9004 7710  ANA-7711F TCP Offload Engine - Optical\n\t\t9004 7711  ANA-7711LP TCP Offload Engine - Copper\n\t5675  AIC-755x\n\t5678  AIC-7856\n\t5775  AIC-755x\n\t5778  AIC-7850\n\t5800  AIC-5800\n\t5900  ANA-5910/5930/5940 ATM155 & 25 LAN Adapter\n\t5905  ANA-5910A/5930A/5940A ATM Adapter\n\t6038  AIC-3860\n\t6075  AIC-1480 / APA-1480\n\t\t9004 7560  AIC-1480 / APA-1480 Cardbus\n\t6078  AIC-7860\n\t6178  AIC-7861\n\t\t9004 7861  AHA-2940AU Single\n\t6278  AIC-7860\n\t6378  AIC-7860\n\t6478  AIC-786x\n\t6578  AIC-786x\n\t6678  AIC-786x\n\t6778  AIC-786x\n\t6915  ANA620xx/ANA69011A\n\t\t9004 0008  ANA69011A/TX 10/100\n\t\t9004 0009  ANA69011A/TX 10/100\n\t\t9004 0010  ANA62022 2-port 10/100\n\t\t9004 0018  ANA62044 4-port 10/100\n\t\t9004 0019  ANA62044 4-port 10/100\n\t\t9004 0020  ANA62022 2-port 10/100\n\t\t9004 0028  ANA69011A/TX 10/100\n\t\t9004 8008  ANA69011A/TX 64 bit 10/100\n\t\t9004 8009  ANA69011A/TX 64 bit 10/100\n\t\t9004 8010  ANA62022 2-port 64 bit 10/100\n\t\t9004 8018  ANA62044 4-port 64 bit 10/100\n\t\t9004 8019  ANA62044 4-port 64 bit 10/100\n\t\t9004 8020  ANA62022 2-port 64 bit 10/100\n\t\t9004 8028  ANA69011A/TX 64 bit 10/100\n\t7078  AHA-294x / AIC-7870\n\t7178  AIC-7870P/7871 [AHA-2940/W/S76]\n\t7278  AHA-3940/3940W / AIC-7872\n\t7378  AHA-3985 / AIC-7873\n\t7478  AHA-2944/2944W / AIC-7874\n\t7578  AHA-3944/3944W / AIC-7875\n\t7678  AHA-4944W/UW / AIC-7876\n\t7710  ANA-7711F Network Accelerator Card (NAC) - Optical\n\t7711  ANA-7711C Network Accelerator Card (NAC) - Copper\n\t7778  AIC-787x\n\t7810  AIC-7810\n\t7815  AIC-7815 RAID+Memory Controller IC\n\t\t9004 7815  ARO-1130U2 RAID Controller\n\t\t9004 7840  AIC-7815 RAID+Memory Controller IC\n\t7850  AIC-7850\n\t7855  AHA-2930\n\t7860  AIC-7860\n\t7870  AIC-7870\n\t7871  AHA-2940\n\t7872  AHA-3940\n\t7873  AHA-3980\n\t7874  AHA-2944\n\t7880  AIC-7880P\n\t7890  AIC-7890\n\t7891  AIC-789x\n\t7892  AIC-789x\n\t7893  AIC-789x\n\t7894  AIC-789x\n\t7895  AHA-2940U/UW / AHA-39xx / AIC-7895\n\t\t9004 7890  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B\n\t\t9004 7891  AHA-2940U/2940UW Dual\n\t\t9004 7892  AHA-3940AU/AUW/AUWD/UWD\n\t\t9004 7894  AHA-3944AUWD\n\t\t9004 7895  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B\n\t\t9004 7896  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B\n\t\t9004 7897  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B\n\t7896  AIC-789x\n\t7897  AIC-789x\n\t8078  AIC-7880U\n\t\t9004 7880  AIC-7880P Ultra/Ultra Wide SCSI Chipset\n\t8178  AIC-7870P/7881U [AHA-2940U/UW/D/S76]\n\t\t9004 7881  AHA-2940UW SCSI Host Adapter\n\t8278  AHA-3940U/UW/UWD / AIC-7882U\n\t8378  AHA-3940U/UW / AIC-7883U\n\t8478  AHA-2944UW / AIC-7884U\n\t8578  AHA-3944U/UWD / AIC-7885\n\t8678  AHA-4944UW / AIC-7886\n\t8778  AHA-2940UW Pro / AIC-788x\n\t\t9004 7887  2940UW Pro Ultra-Wide SCSI Controller\n\t8878  AHA-2930UW / AIC-7888\n\t\t9004 7888  AHA-2930UW SCSI Controller\n\t8b78  ABA-1030\n\tec78  AHA-4944W/UW\n# Acquired by Microchip Technology\n9005  Adaptec\n\t0010  AHA-2940U2/U2W\n\t\t9005 2180  AHA-2940U2 SCSI Controller\n\t\t9005 8100  AHA-2940U2B SCSI Controller\n\t\t9005 a100  AHA-2940U2B SCSI Controller\n\t\t9005 a180  AIC-3860Q [AHA-2940U2W/GE] SCSI Controller\n\t\t9005 e100  AHA-2950U2B SCSI Controller\n\t0011  AHA-2930U2\n\t0013  78902\n\t\t9005 0003  AAA-131U2 Array1000 1 Channel RAID Controller\n\t\t9005 000f  AIC7890_ARO\n\t001f  AHA-2940U2/U2W / 7890/7891\n\t\t9005 000f  2940U2W SCSI Controller\n\t\t9005 a180  2940U2W SCSI Controller\n\t0020  AIC-7890\n\t002f  AIC-7890\n\t0030  AIC-7890\n\t003f  AIC-7890\n\t0050  AHA-3940U2x/395U2x\n\t\t9005 f500  AHA-3950U2B\n\t\t9005 ffff  AHA-3950U2B\n\t0051  AHA-3950U2D\n\t\t9005 b500  AHA-3950U2D\n\t0053  AIC-7896 SCSI Controller\n\t\t9005 ffff  AIC-7896 SCSI Controller mainboard implementation\n\t005f  AIC-7896U2/7897U2\n\t0080  AIC-7892A U160/m\n\t\t0e11 e2a0  Compaq 64-Bit/66MHz Wide Ultra3 SCSI Adapter\n\t\t9005 6220  AHA-29160C\n\t\t9005 62a0  29160N Ultra160 SCSI Controller\n\t\t9005 e220  29160LP Low Profile Ultra160 SCSI Controller\n\t\t9005 e2a0  29160 Ultra160 SCSI Controller\n\t0081  AIC-7892B U160/m\n\t\t9005 62a1  19160 Ultra160 SCSI Controller\n\t0083  AIC-7892D U160/m\n\t008f  AIC-7892P U160/m\n\t\t1179 0001  Magnia Z310\n\t\t15d9 9005  Onboard SCSI Host Adapter\n\t0092  AVC-2010 [VideoH!]\n\t0093  AVC-2410 [VideoH!]\n\t00c0  AHA-3960D / AIC-7899A U160/m\n\t\t0e11 f620  Compaq 64-Bit/66MHz Dual Channel Wide Ultra3 SCSI Adapter\n\t\t9005 f620  AHA-3960D U160/m\n\t00c1  AIC-7899B U160/m\n\t00c3  AIC-7899D U160/m\n\t00c5  RAID subsystem HBA\n\t\t1028 00c5  PowerEdge 2400,2500,2550,4400\n\t00cf  AIC-7899P U160/m\n\t\t1028 00ce  PowerEdge 1400\n\t\t1028 00d1  PowerEdge 2550\n\t\t1028 00d9  PowerEdge 2500\n\t\t10f1 2462  Thunder K7 S2462\n\t\t15d9 9005  Onboard SCSI Host Adapter\n\t\t8086 3411  SDS2 Mainboard\n\t0241  Serial ATA II RAID 1420SA\n\t0242  Serial ATA II RAID 1220SA\n\t0243  Serial ATA II RAID 1430SA\n\t0244  eSATA II RAID 1225SA\n\t0250  ServeRAID Controller\n\t\t1014 0279  ServeRAID 6M\n\t\t1014 028c  ServeRAID 6i/6i+\n\t\t1014 028e  ServeRAID 7k\n\t0279  ServeRAID 6M\n\t0283  AAC-RAID\n\t\t9005 0283  Catapult\n\t0284  AAC-RAID\n\t\t9005 0284  Tomcat\n\t0285  AAC-RAID\n\t\t0e11 0295  SATA 6Ch (Bearcat)\n\t\t1014 02f2  ServeRAID 8i\n\t\t1028 0287  PowerEdge Expandable RAID Controller 320/DC\n\t\t1028 0291  CERC SATA RAID 2 PCI SATA 6ch (DellCorsair)\n\t\t103c 3227  AAR-2610SA\n\t\t108e 0286  Sun StorageTek SAS RAID HBA, Internal\n\t\t108e 0287  STK RAID EXT\n\t\t108e 7aac  STK RAID REM\n\t\t108e 7aae  STK RAID EX\n\t\t15d9 02b5  SMC AOC-USAS-S4i\n\t\t15d9 02b6  SMC AOC-USAS-S8i\n\t\t15d9 02c9  SMC AOC-USAS-S4iR\n\t\t15d9 02ca  SMC AOC-USAS-S8iR\n\t\t15d9 02d2  SMC AOC-USAS-S8i-LP\n\t\t15d9 02d3  SMC AOC-USAS-S8iR-LP\n\t\t17aa 0286  Legend S220 (Legend Crusader)\n\t\t17aa 0287  Legend S230 (Legend Vulcan)\n\t\t9005 0285  2200S (Vulcan)\n\t\t9005 0286  2120S (Crusader)\n\t\t9005 0287  2200S (Vulcan-2m)\n\t\t9005 0288  3230S (Harrier)\n\t\t9005 0289  3240S (Tornado)\n# Some early versions reported 2020S\n\t\t9005 028a  ASR-2020ZCR\n# Some early versions reported 2025S\n\t\t9005 028b  ASR-2025ZCR (Terminator)\n\t\t9005 028e  ASR-2020SA (Skyhawk)\n\t\t9005 028f  ASR-2025SA\n\t\t9005 0290  AAR-2410SA PCI SATA 4ch (Jaguar II)\n\t\t9005 0292  AAR-2810SA PCI SATA 8ch (Corsair-8)\n\t\t9005 0293  AAR-21610SA PCI SATA 16ch (Corsair-16)\n\t\t9005 0294  ESD SO-DIMM PCI-X SATA ZCR (Prowler)\n\t\t9005 0296  ASR-2240S\n\t\t9005 0297  ASR-4005SAS\n\t\t9005 0298  ASR-4000\n\t\t9005 0299  ASR-4800SAS\n\t\t9005 029a  4805SAS\n\t\t9005 02a4  ICP ICP9085LI\n\t\t9005 02a5  ICP ICP5085BR\n\t\t9005 02b5  ASR5800\n\t\t9005 02b6  ASR5805\n\t\t9005 02b7  ASR5808\n\t\t9005 02b8  ICP5445SL\n\t\t9005 02b9  ICP5085SL\n\t\t9005 02ba  ICP5805SL\n\t\t9005 02bb  3405\n\t\t9005 02bc  3805\n\t\t9005 02bd  31205\n\t\t9005 02be  31605\n\t\t9005 02bf  ICP ICP5045BL\n\t\t9005 02c0  ICP ICP5085BL\n\t\t9005 02c1  ICP ICP5125BR\n\t\t9005 02c2  ICP ICP5165BR\n\t\t9005 02c3  51205\n\t\t9005 02c4  51605\n\t\t9005 02c5  ICP ICP5125SL\n\t\t9005 02c6  ICP ICP5165SL\n\t\t9005 02c7  3085\n\t\t9005 02c8  ICP5805BL\n\t\t9005 02ce  51245\n\t\t9005 02cf  51645\n\t\t9005 02d0  52445\n\t\t9005 02d1  5405\n\t\t9005 02d4  ASR-2045\n\t\t9005 02d5  ASR-2405\n\t\t9005 02d6  ASR-2445\n\t\t9005 02d7  ASR-2805\n\t\t9005 02d8  5405G\n\t\t9005 02d9  5445G\n\t\t9005 02da  5805G\n\t\t9005 02db  5085G\n\t\t9005 02dc  51245G\n\t\t9005 02dd  51645G\n\t\t9005 02de  52445G\n\t\t9005 02df  ASR-2045G\n\t\t9005 02e0  ASR-2405G\n\t\t9005 02e1  ASR-2445G\n\t\t9005 02e2  ASR-2805G\n\t0286  AAC-RAID (Rocket)\n\t\t1014 034d  8s\n\t\t1014 9540  ServeRAID 8k/8k-l4\n\t\t1014 9580  ServeRAID 8k/8k-l8\n\t\t9005 028c  ASR-2230S + ASR-2230SLP PCI-X (Lancer)\n\t\t9005 028d  ASR-2130S\n\t\t9005 029b  ASR-2820SA\n\t\t9005 029c  ASR-2620SA\n\t\t9005 029d  ASR-2420SA\n\t\t9005 029e  ICP ICP9024R0\n\t\t9005 029f  ICP ICP9014R0\n\t\t9005 02a0  ICP ICP9047MA\n\t\t9005 02a1  ICP ICP9087MA\n\t\t9005 02a2  3800\n\t\t9005 02a3  ICP ICP5445AU\n\t\t9005 02a4  ICP ICP9085LI\n\t\t9005 02a5  ICP ICP5085BR\n\t\t9005 02a6  ICP9067MA\n\t\t9005 02a7  3805\n\t\t9005 02a8  3400\n\t\t9005 02a9  ICP ICP5085AU\n\t\t9005 02aa  ICP ICP5045AU\n\t\t9005 02ac  1800\n\t\t9005 02b3  2400\n\t\t9005 02b4  ICP ICP5045AL\n\t\t9005 0800  Callisto\n\t028b  Series 6 - 6G SAS/PCIe 2\n\t\t9005 0200  Series 6 Entry Level - ASR-6405E - 4 internal 6G SAS ports\n\t\t9005 0201  Series 6 Entry Level - ASR-6805E - 8 internal 6G SAS ports\n\t\t9005 0300  Series 6 - ASR-6405 - 4 internal 6G SAS ports\n\t\t9005 0301  Series 6 - ASR-6805 - 8 internal 6G SAS ports\n\t\t9005 0302  Series 6 - ASR-6445 - 4 internal and 4 external 6G SAS ports\n\t\t9005 0310  Series 6 Connectors on Top - ASR-6405T - 4 internal 6G SAS ports\n\t\t9005 0311  Series 6 Connectors on Top - ASR-6805T - 8 internal 6G SAS\n\t\t9005 0400  Series 6 - ASR-61205 - 12 internal 6G SAS ports\n\t\t9005 0401  Series 6 - ASR-61605 - 16 internal 6G SAS ports\n\t\t9005 0403  Series 6 - ASR-62405 - 24 internal 6G SAS ports\n\t028c  Series 7 6G SAS/PCIe 3\n\t\t9005 0500  Series 7 - ASR-7805 - 8 internal 6G SAS Port/PCIe 3.0\n\t\t9005 0501  Series 7 - ASR-71605 - 16 internal 6G SAS Port/PCIe 3.0\n\t\t9005 0502  Series 7 - ASR-71685 - 16 internal 8 external 6G SAS Port/PCIe 3.0\n\t\t9005 0503  Series 7 - ASR-72405 - 24 internal 0 external 6G SAS Port/PCIe 3.0\n\t\t9005 0504  Series 7 - ASR-7885 - 8 internal 8 external 6G SAS Port/PCIe 3.0\n\t\t9005 0505  Series 7 Entry Level - ASR-71685E - 16 internal 8 external 6G SAS Port/PCIe 3.0\n\t\t9005 0506  Series 7 Entry Level - ASR-72405E - 24 internal 0 external 6G SAS Port/PCIe 3.0\n\t028d  Series 8 12G SAS/PCIe 3\n\t\t9005 0550  Series 8 - ASR-82405 - 24 internal 0 external 12G SAS Port/PCIe 3.0\n\t\t9005 0551  Series 8 - ASR-81605 - 16 internal 0 external 12G SAS Port/PCIe 3.0\n\t\t9005 0552  Series 8 - ASR-8805 - 8 internal 0 external 12G SAS Port/PCIe 3.0\n\t\t9005 0553  Series 8 - ASR-8085 - 0 internal 8 external 12G SAS Port/PCIe 3.0\n\t\t9005 0554  Series 8 - ASR-8885 - 8 internal 8 external 12G SAS Port/PCIe 3.0\n\t028f  Smart Storage PQI 12G SAS/PCIe 3\n\t\t103c 0600  Smart Array P408i-p SR Gen10\n\t\t103c 0601  Smart Array P408e-p SR Gen10\n\t\t103c 0602  Smart Array P408i-a SR Gen10\n\t\t103c 0603  Smart Array P408i-c SR Gen10\n\t\t103c 0650  Smart Array E208i-p SR Gen10\n\t\t103c 0651  Smart Array E208e-p SR Gen10\n\t\t103c 0652  Smart Array E208i-c SR Gen10\n\t\t103c 0654  Smart Array E208i-a SR Gen10\n\t\t103c 0655  Smart Array P408e-m SR Gen10\n\t\t103c 0700  Smart Array P204i-c SR Gen10\n\t\t103c 0701  Smart Array P204i-b SR Gen10\n\t\t103c 1100  Smart Array P816i-a SR Gen10\n\t\t103c 1101  Smart Array P416ie-m SR G10\n\t\t105b 1211  HBA 8238-16i\n\t\t105b 1321  HBA 8242-24i\n\t\t13fe 8312  SKY-9200 MIC-8312BridgeB\n\t\t152d 8a22  QS-8204-8i\n\t\t152d 8a23  QS-8238-16i\n\t\t152d 8a24  QS-8236-16i\n\t\t152d 8a36  QS-8240-24i\n\t\t152d 8a37  QS-8242-24i\n\t\t193d 8460  HBA H460-M1\n\t\t193d 8461  HBA H460-B1\n\t\t193d c460  RAID P460-M2\n\t\t193d c461  RAID P460-B2\n\t\t193d f460  RAID P460-M4\n\t\t193d f461  RAID P460-B4\n\t\t19e5 d227  SmartROC-HD SR465C-M 4G\n\t\t19e5 d228  SmartROC SR455C-M 2G\n\t\t19e5 d229  SmartIOC SR155-M\n\t\t19e5 d22a  SmartIOC-HD SR765-M\n\t\t19e5 d22b  SmartROC-e SR455C-ME 4G\n\t\t19e5 d22c  SmartROC SR455C-M 4G\n\t\t1bd4 0045  SMART-HBA 8242-24i\n\t\t1bd4 0046  RAID 8236-16i\n\t\t1bd4 0047  RAID 8240-24i\n\t\t1bd4 0048  SMART-HBA 8238-16i\n\t\t1bd4 004a  PM8222-SHBA\n\t\t1bd4 004b  RAID PM8204-2GB\n\t\t1bd4 004c  RAID PM8204-4GB\n\t\t1bd4 004f  PM8222-HBA\n\t\t9005 0608  SmartRAID 3162-8i /e\n\t\t9005 0800  SmartRAID 3154-8i\n\t\t9005 0801  SmartRAID 3152-8i\n\t\t9005 0802  SmartRAID 3151-4i\n\t\t9005 0803  SmartRAID 3101-4i\n\t\t9005 0804  SmartRAID 3154-8e\n\t\t9005 0805  SmartRAID 3102-8i\n\t\t9005 0806  SmartRAID 3100\n\t\t9005 0807  SmartRAID 3162-8i\n\t\t9005 0900  SmartHBA 2100-8i\n\t\t9005 0901  SmartHBA 2100-4i\n\t\t9005 0902  HBA 1100-8i\n\t\t9005 0903  HBA 1100-4i\n\t\t9005 0904  SmartHBA 2100-8e\n\t\t9005 0905  HBA 1100-8e\n\t\t9005 0906  SmartHBA 2100-4i4e\n\t\t9005 0907  HBA 1100\n\t\t9005 0908  SmartHBA 2100\n\t\t9005 090a  SmartHBA 2100A-8i\n\t\t9005 1200  SmartRAID 3154-24i\n\t\t9005 1201  SmartRAID 3154-8i16e\n\t\t9005 1202  SmartRAID 3154-8i8e\n\t\t9005 1280  HBA 1100-16i\n\t\t9005 1281  HBA 1100-16e\n\t\t9005 1300  HBA 1100-8i8e\n\t\t9005 1301  HBA 1100-24i\n\t\t9005 1302  SmartHBA 2100-8i8e\n\t\t9005 1303  SmartHBA 2100-24i\n\t\t9005 1380  SmartRAID 3154-16i\n\t0410  AIC-9410W SAS (Razor HBA RAID)\n\t\t9005 0410  ASC-48300(Spirit RAID)\n\t\t9005 0411  ASC-58300 (Oakmont RAID)\n\t0412  AIC-9410W SAS (Razor HBA non-RAID)\n\t\t9005 0412  ASC-48300 (Spirit non-RAID)\n\t\t9005 0413  ASC-58300 (Oakmont non-RAID)\n\t0415  ASC-58300 SAS (Razor-External HBA RAID)\n\t0416  ASC-58300 SAS (Razor-External HBA non-RAID)\n\t041e  AIC-9410W SAS (Razor ASIC non-RAID)\n\t041f  AIC-9410W SAS (Razor ASIC RAID)\n\t\t9005 041f  AIC-9410W SAS (Razor ASIC RAID)\n\t042f  VSC7250/7251 SAS (Aurora ASIC non-RAID)\n\t0430  AIC-9405W SAS (Razor-Lite HBA RAID)\n\t\t9005 0430  ASC-44300 (Spirit-Lite RAID)\n\t0432  AIC-9405W SAS (Razor-Lite HBA non-RAID)\n\t\t9005 0432  ASC-44300 (Spirit-Lite non-RAID)\n\t043e  AIC-9405W SAS (Razor-Lite ASIC non-RAID)\n\t043f  AIC-9405W SAS (Razor-Lite ASIC RAID)\n\t0450  ASC-1405 Unified Serial HBA\n\t0500  Obsidian chipset SCSI controller\n\t\t1014 02c1  PCI-X DDR 3Gb SAS Adapter (572A/572C)\n\t\t1014 02c2  PCI-X DDR 3Gb SAS RAID Adapter (572B/572D)\n\t0503  Scamp chipset SCSI controller\n\t\t1014 02bf  Quad Channel PCI-X DDR U320 SCSI RAID Adapter (571E)\n\t\t1014 02c3  PCI-X DDR 3Gb SAS RAID Adapter (572F)\n\t\t1014 02d5  Quad Channel PCI-X DDR U320 SCSI RAID Adapter (571F)\n\t0910  AUA-3100B\n\t091e  AUA-3100B\n\t8000  ASC-29320A U320\n\t800f  AIC-7901 U320\n\t8010  ASC-39320 U320\n\t8011  ASC-39320D\n\t\t0e11 00ac  ASC-39320D U320\n\t\t9005 0041  ASC-39320D U320\n\t8012  ASC-29320 U320\n\t8013  ASC-29320B U320\n\t8014  ASC-29320LP U320\n\t8015  ASC-39320B U320\n\t8016  ASC-39320A U320\n\t8017  ASC-29320ALP U320\n\t\t9005 0044  ASC-29320ALP PCIx U320\n\t\t9005 0045  ASC-29320LPE PCIe U320\n\t801c  ASC-39320D U320\n\t801d  AIC-7902B U320\n\t\t1014 02cc  ServeRAID 7e\n\t801e  AIC-7901A U320\n\t801f  AIC-7902 U320\n\t\t1734 1011  PRIMERGY RX300 onboard SCSI\n\t8080  ASC-29320A U320 w/HostRAID\n\t8081  PMC-Sierra PM8001 SAS HBA [Series 6H]\n\t8088  PMC-Sierra PM8018 SAS HBA [Series 7H]\n\t8089  PMC-Sierra PM8019 SAS encryption HBA [Series 7He]\n\t808f  AIC-7901 U320 w/HostRAID\n\t\t1028 0168  Precision Workstation 670 Mainboard\n\t8090  ASC-39320 U320 w/HostRAID\n\t8091  ASC-39320D U320 w/HostRAID\n\t8092  ASC-29320 U320 w/HostRAID\n\t8093  ASC-29320B U320 w/HostRAID\n\t8094  ASC-29320LP U320 w/HostRAID\n\t8095  ASC-39320(B) U320 w/HostRAID\n\t8096  ASC-39320A U320 w/HostRAID\n\t8097  ASC-29320ALP U320 w/HostRAID\n\t809c  ASC-39320D(B) U320 w/HostRAID\n\t809d  AIC-7902(B) U320 w/HostRAID\n\t\t1014 02cc  ServeRAID 7e\n\t809e  AIC-7901A U320 w/HostRAID\n\t809f  AIC-7902 U320 w/HostRAID\n907f  Atronics\n\t2015  IDE-2015PL\n919a  Gigapixel Corp\n9412  Holtek\n\t6565  6565\n9413  Softlogic Co., Ltd.\n\t6010  SOLO6010 MPEG-4 Video encoder/decoder\n\t6110  SOLO6110 H.264 Video encoder/decoder\n9618  JusonTech Corporation\n\t0001  JusonTech Gigabit Ethernet Controller\n9699  Omni Media Technology Inc\n\t6565  6565\n# nee Netmos Technology\n9710  MosChip Semiconductor Technology Ltd.\n\t9250  PCI-to-PCI bridge [MCS9250]\n\t9805  PCI 1 port parallel adapter\n\t9815  PCI 9815 Multi-I/O Controller\n\t\t1000 0020  2P0S (2 port parallel adaptor)\n\t9820  PCI 9820 Multi-I/O Controller\n\t9835  PCI 9835 Multi-I/O Controller\n\t\t1000 0002  2S (16C550 UART)\n\t\t1000 0012  1P2S\n\t9845  PCI 9845 Multi-I/O Controller\n# Serial ports at BAR0-3\n\t\t1000 0004  0P4S (4 port 16550A serial card)\n\t\t1000 0006  0P6S (6 port 16550a serial card)\n# Serial ports at BAR0-3, Parallel port at BAR4\n\t\t1000 0014  1P4S (1 Parallel / 4 16550A Serial Port Adapter)\n\t9855  PCI 9855 Multi-I/O Controller\n# Parallel port at BAR0. Serial ports at BAR2-5\n\t\t1000 0014  1P4S\n# Parallel ports at BAR0,BAR2. Serial ports at BAR4-5\n\t\t1000 0022  2P2S (2 Parallel / 2 16550A Serial Port Adapter)\n\t9865  PCI 9865 Multi-I/O Controller\n\t9900  MCS9900 Multi-I/O Controller\n\t9901  PCIe 9901 Multi-I/O Controller\n\t9904  4-Port PCIe Serial Adapter\n# 2-port Serial 1-port Parallel Adaptor\n\t9912  PCIe 9912 Multi-I/O Controller\n\t9922  MCS9922 PCIe Multi-I/O Controller\n\t9990  MCS9990 PCIe to 4‐Port USB 2.0 Host Controller\n# Subsystem ID on a 3c985B-SX network card\n9850  3Com (wrong ID)\n9902  Stargen Inc.\n\t0001  SG2010 PCI over Starfabric Bridge\n\t0002  SG2010 PCI to Starfabric Gateway\n\t0003  SG1010 Starfabric Switch and PCI Bridge\na0a0  AOPEN Inc.\na0f1  UNISYS Corporation\na200  NEC Corporation\na259  Hewlett Packard\na25b  Hewlett Packard GmbH PL24-MKT\na304  Sony\na727  3Com Corporation\n\t0013  3CRPAG175 Wireless PC Card\n\t6803  3CRDAG675B Wireless 11a/b/g Adapter\naa00  iTuner\naa01  iTuner\naa02  iTuner\naa03  iTuner\naa04  iTuner\naa05  iTuner\naa06  iTuner\naa07  iTuner\naa08  iTuner\naa09  iTuner\naa0a  iTuner\naa0b  iTuner\naa0c  iTuner\naa0d  iTuner\naa0e  iTuner\naa0f  iTuner\naa42  Scitex Digital Video\naa55  Ncomputing X300 PCI-Engine\naaaa  Adnaco Technology Inc.\n\t0001  H1 PCIe over fiber optic host controller\n\t0002  R1BP1 PCIe over fiber optic expansion chassis\nabcd  Vadatech Inc.\nac1e  Digital Receiver Technology Inc\nac3d  Actuality Systems\nad00  Alta Data Technologies LLC\naecb  Adrienne Electronics Corporation\n\t6250  VITC/LTC Timecode Reader card [PCI-VLTC/RDR]\naffe  Sirrix AG security technologies\n\t01e1  PCI1E1 1-port ISDN E1 interface\n\t02e1  PCI2E1 2-port ISDN E1 interface\n\t450e  PCI4S0EC 4-port ISDN S0 interface\n\tdead  Sirrix.PCI4S0 4-port ISDN S0 interface\nb100  OpenVox Communication Co. Ltd.\n# Not registered officially\nb10b  Uakron PCI Project\nb1b3  Shiva Europe Limited\nb1d9  ATCOM Technology co., LTD.\n# Pinnacle should be 11bd, but they got it wrong several times --mj\nbd11  Pinnacle Systems, Inc. (Wrong ID)\nbdbd  Blackmagic Design\n\ta106  Multibridge Extreme\n\ta117  Intensity Pro\n\ta11a  DeckLink HD Extreme 2\n\ta11b  DeckLink SDI/Duo/Quad\n\ta11c  DeckLink HD Extreme 3\n\ta11d  DeckLink Studio\n\ta11e  DeckLink Optical Fibre\n\ta120  Decklink Studio 2\n\ta121  DeckLink HD Extreme 3D/3D+\n\ta124  Intensity Extreme\n\ta126  Intensity Shuttle\n\ta127  UltraStudio Express\n\ta129  UltraStudio Mini Recorder\n\ta12a  UltraStudio Mini Monitor\n\ta12d  UltraStudio 4K\n\ta12e  DeckLink 4K Extreme\n\ta12f  DeckLink Mini Monitor\n\ta130  DeckLink Mini Recorder\n\ta132  UltraStudio 4K\n\ta136  DeckLink 4K Extreme 12G\n\ta137  DeckLink Studio 4K\n\ta138  Decklink SDI 4K\n\ta139  Intensity Pro 4K\n\ta13b  DeckLink Micro Recorder\n\ta13d  DeckLink 4K Pro\n\ta13e  UltraStudio 4K Extreme\n\ta13f  DeckLink Quad 2\n\ta140  DeckLink Duo 2\n\ta141  UltraStudio 4K Extreme 3\n\ta142  UltraStudio HD Mini\n\ta143  DeckLink Mini Recorder 4K\n\ta144  DeckLink Mini Monitor 4K\n\ta148  DeckLink SDI Micro\n\ta14b  DeckLink 8K Pro\n\ta14e  DeckLink Quad HDMI Recorder\n\ta1ff  eGPU RX580\nc001  TSI Telsys\nc0a9  Micron/Crucial Technology\n\t2263  P1 NVMe PCIe SSD\nc0de  Motorola\nc0fe  Motion Engineering, Inc.\nca3b  Cambrionix Ltd.\nca50  Varian Australia Pty Ltd\ncace  CACE Technologies, Inc.\n\t0001  TurboCap Port A\n\t0002  TurboCap Port B\n\t0023  AirPcap N\ncaed  Canny Edge\ncafe  Chrysalis-ITS\n\t0003  Luna K3 Hardware Security Module\n\t0006  Luna PCI-e 3000 Hardware Security Module\n\t0007  Luna K6 Hardware Security Module\n\t0008  Luna K7 Hardware Security Module\ncc53  ScaleFlux Inc.\ncccc  Catapult Communications\nccec  Curtiss-Wright Controls Embedded Computing\ncddd  Tyzx, Inc.\n\t0101  DeepSea 1 High Speed Stereo Vision Frame Grabber\n\t0200  DeepSea 2 High Speed Stereo Vision Frame Grabber\nceba  KEBA AG\nd161  Digium, Inc.\n\t0120  Wildcard TE120P single-span T1/E1/J1 card\n\t0205  Wildcard TE205P/TE207P dual-span T1/E1/J1 card 5.0V\n\t0210  Wildcard TE210P/TE212P dual-span T1/E1/J1 card 3.3V\n\t0220  Wildcard TE220 dual-span T1/E1/J1 card 3.3V (PCI-Express)\n\t0405  Wildcard TE405P/TE407P quad-span T1/E1/J1 card 5.0V\n\t0410  Wildcard TE410P/TE412P quad-span T1/E1/J1 card 3.3V\n\t0420  Wildcard TE420P quad-span T1/E1/J1 card 3.3V (PCI-Express)\n\t0800  Wildcard TDM800P 8-port analog card\n\t1205  Wildcard TE205P/TE207P dual-span T1/E1/J1 card 5.0V (u1)\n\t1220  Wildcard TE220 dual-span T1/E1/J1 card 3.3V (PCI-Express) (5th gen)\n\t1405  Wildcard TE405P/TE407P quad-span T1/E1/J1 card 5.0V (u1)\n\t1410  Wildcard TE410P quad-span T1/E1/J1 card 3.3V (5th Gen)\n\t1420  Wildcard TE420 quad-span T1/E1/J1 card 3.3V (PCI-Express) (5th gen)\n\t1820  Wildcard TE820 octal-span T1/E1/J1 card 3.3V (PCI-Express)\n\t2400  Wildcard TDM2400P 24-port analog card\n\t3400  Wildcard TC400P transcoder base card\n\t8000  Wildcard TE121 single-span T1/E1/J1 card (PCI-Express)\n\t8001  Wildcard TE122 single-span T1/E1/J1 card\n\t8002  Wildcard AEX800 8-port analog card (PCI-Express)\n\t8003  Wildcard AEX2400 24-port analog card (PCI-Express)\n\t8004  Wildcard TCE400P transcoder base card\n\t8005  Wildcard TDM410 4-port analog card\n\t8006  Wildcard AEX410 4-port analog card (PCI-Express)\n\t8007  Hx8 Series 8-port Base Card\n\t8008  Hx8 Series 8-port Base Card (PCI-Express)\n\t800a  Wildcard TE133 single-span T1/E1/J1 card (PCI Express)\n\t800b  Wildcard TE134 single-span T1/E1/J1 card\n\t800c  Wildcard A8A 8-port analog card\n\t800d  Wildcard A8B 8-port analog card (PCI-Express)\n\t800e  Wildcard TE235/TE435 quad-span T1/E1/J1 card (PCI-Express)\n\t800f  Wildcard A4A 4-port analog card\n\t8010  Wildcard A4B 4-port analog card (PCI-Express)\n\t8013  Wildcard TE236/TE436 quad-span T1/E1/J1 card\n\tb410  Wildcard B410 quad-BRI card\nd4d4  Dy4 Systems Inc\n\t0601  PCI Mezzanine Card\nd531  I+ME ACTIA GmbH\nd84d  Exsys\ndada  Datapath Limited\n\t0133  VisionRGB-X2\n\t0139  VisionRGB-E1\n\t0144  VisionSD8\n\t0150  VisionRGB-E2\n\t0151  VisionSD4+1\n\t0159  VisionAV\n\t0161  DGC161\n\t0165  DGC165\n\t0167  DGC167\n\t0168  DGC168\n\t1139  VisionRGB-E1S\n\t1150  VisionRGB-E2S\n\t1151  VisionSD4+1S\n\t1153  VisionDVI-DL\n\t1154  VisionSDI2\ndb10  Diablo Technologies\ndc93  Dawicontrol GmbH\ndcba  Dynamic Engineering\n\t0046  PCIe Altera Cyclone IV\n# VPX format Receiver Controller Board\n\t0047  VPX-RCB\n# PMC Format FPGA design with 8 high speed UART channels\n\t0048  PMC-Biserial-III-BAE9\n\t004e  PC104p-Biserial-III-NVY5\n\t004f  PC104p-Biserial-III-NVY6\n\t0052  PCIeBiSerialDb37 BA22 LVDS IO\n# 8 port 16550 compatible UART, PMC format, RS-232 IO, RTS, CTS, DTR, DSR supported\n\t0066  PMC-OctalUART-232\ndd01  Digital Devices GmbH\n\t0003  Octopus DVB Adapter\n\t\tdd01 0001  Octopus DVB adapter\n\t\tdd01 0002  Octopus LE DVB adapter\n\t\tdd01 0003  Octopus OEM\n\t\tdd01 0004  Octopus V3 DVB adapter\n\t\tdd01 0010  Octopus Mini\n\t\tdd01 0020  Cine S2 V6 DVB adapter\n\t\tdd01 0021  Cine S2 V6.5 DVB adapter\n\t\tdd01 0030  Cine CT V6.1 DVB adapter\n\t\tdd01 db03  Mystique SaTiX-S2 V3 DVB adapter\n\t0006  Cine V7\n\t0007  Max\n\t\tdd01 0023  Max S8 4/8\n\t0011  Octopus CI DVB Adapter\n\t\tdd01 0040  Octopus CI\n\t\tdd01 0041  Octopus CI Single\n\t0201  Resi DVB-C Modulator\n\t\tdd01 0001  Resi DVB-C Modulator\ndead  Indigita Corporation\ndeaf  Middle Digital Inc.\n\t9050  PC Weasel Virtual VGA\n\t9051  PC Weasel Serial Port\n\t9052  PC Weasel Watchdog Timer\n# formerly SoftHard Technology Ltd.\ndeda  XIMEA\n\t4001  CB or MX camera\n\t4021  MT camera\ne000  Winbond\n\te000  W89C940\ne159  Tiger Jet Network Inc.\n\t0001  Tiger3XX Modem/ISDN interface\n\t\t0059 0001  128k ISDN-S/T Adapter\n\t\t0059 0003  128k ISDN-U Adapter\n\t\t00a7 0001  TELES.S0/PCI 2.x ISDN Adapter\n\t\t8086 0003  Digium X100P/X101P analogue PSTN FXO interface\n\t\tb100 0003  OpenVox A400P 4-port analog card\n\t\tb1d9 0003  AX400P 4-port analog card\n\t0002  Tiger100APC ISDN chipset\ne1c5  Elcus\ne4bf  EKF Elektronik GmbH\n\t0ccd  CCD-CALYPSO\n\t0cd1  CD1-OPERA\n\t0cd2  CD2-BEBOP\n\t0cd3  CD3-JIVE\n\t50c1  PC1-GROOVE\n\t50c2  PC2-LIMBO\n\t53c1  SC1-ALLEGRO\n\tcc47  CCG-RUMBA\n\tcc4d  CCM-BOOGIE\ne4e4  Xorcom\ne55e  Essence Technology, Inc.\nea01  Eagle Technology\n\t000a  PCI-773 Temperature Card\n\t0032  PCI-730 & PC104P-30 Card\n\t003e  PCI-762 Opto-Isolator Card\n\t0041  PCI-763 Reed Relay Card\n\t0043  PCI-769 Opto-Isolator Reed Relay Combo Card\n\t0046  PCI-766 Analog Output Card\n\t0052  PCI-703 Analog I/O Card\n\t0800  PCI-800 Digital I/O Card\n# The main chip of all these devices is by Xilinx -> It could also be a Xilinx ID.\nea60  RME\n\t9896  Digi32\n\t9897  Digi32 Pro\n\t9898  Digi32/8\neabb  Aashima Technology B.V.\neace  Endace Measurement Systems, Ltd\n\t3100  DAG 3.10 OC-3/OC-12\n\t3200  DAG 3.2x OC-3/OC-12\n\t320e  DAG 3.2E Fast Ethernet\n\t340e  DAG 3.4E Fast Ethernet\n\t341e  DAG 3.41E Fast Ethernet\n\t3500  DAG 3.5 OC-3/OC-12\n\t351c  DAG 3.5ECM Fast Ethernet\n\t360d  DAG 3.6D DS3\n\t360e  DAG 3.6E Fast Ethernet\n\t368e  DAG 3.6E Gig Ethernet\n\t3707  DAG 3.7T T1/E1/J1\n\t370d  DAG 3.7D DS3/E3\n\t378e  DAG 3.7G Gig Ethernet\n\t3800  DAG 3.8S OC-3/OC-12\n\t4100  DAG 4.10 OC-48\n\t4110  DAG 4.11 OC-48\n\t4220  DAG 4.2 OC-48\n\t422e  DAG 4.2GE Gig Ethernet\n\t4230  DAG 4.2S OC-48\n\t423e  DAG 4.2GE Gig Ethernet\n\t4300  DAG 4.3S OC-48\n\t430e  DAG 4.3GE Gig Ethernet\n\t452e  DAG 4.5G2 Gig Ethernet\n\t454e  DAG 4.5G4 Gig Ethernet\n\t45b8  DAG 4.5Z8 Gig Ethernet\n\t45be  DAG 4.5Z2 Gig Ethernet\n\t520e  DAG 5.2X 10G Ethernet\n\t521a  DAG 5.2SXA 10G Ethernet/OC-192\n\t5400  DAG 5.4S-12 OC-3/OC-12\n\t5401  DAG 5.4SG-48 Gig Ethernet/OC-3/OC-12/OC-48\n\t540a  DAG 5.4GA Gig Ethernet\n\t541a  DAG 5.4SA-12 OC-3/OC-12\n\t542a  DAG 5.4SGA-48 Gig Ethernet/OC-3/OC-12/OC-48\n\t6000  DAG 6.0SE 10G Ethernet/OC-192\n\t6100  DAG 6.1SE 10G Ethernet/OC-192\n\t6200  DAG 6.2SE 10G Ethernet/OC-192\n\t7100  DAG 7.1S OC-3/OC-12\n\t7400  DAG 7.4S OC-3/OC-12\n\t7401  DAG 7.4S48 OC-48\n\t752e  DAG 7.5G2 Gig Ethernet\n\t754e  DAG 7.5G4 Gig Ethernet\n\t8100  DAG 8.1X 10G Ethernet\n\t8101  DAG 8.1SX 10G Ethernet/OC-192\n\t8102  DAG 8.1X 10G Ethernet\n\t820e  DAG 8.2X 10G Ethernet\n\t820f  DAG 8.2X 10G Ethernet (2nd bus)\n\t8400  DAG 8.4I Infiniband x4 SDR\n\t8500  DAG 8.5I Infiniband x4 DDR\n\t9200  DAG 9.2SX2 10G Ethernet\n\t920e  DAG 9.2X2 10G Ethernet\n\t9540  DAG 9.5G4 Gig Ethernet\n\t954f  DAG 9.5G4F Gig Ethernet\n\ta120  DAG 10X2-P 10G Ethernet\n\ta12e  DAG 10X2-S 10G Ethernet\n\ta140  DAG 10X4-P 10/40G Ethernet\n\ta14e  DAG 10X4-S 10/40G Ethernet\n\teace  vDAG virtual device\nec80  Belkin Corporation\n\tec00  F5D6000\necc0  Echo Digital Audio Corporation\nedd8  ARK Logic Inc\n\ta091  1000PV [Stingray]\n\ta099  2000PV [Stingray]\n\ta0a1  2000MT\n\ta0a9  2000MI\n# Found on M2N68-AM Motherboard\nf043  ASUSTeK Computer Inc. (Wrong ID)\nf05b  Foxconn International, Inc. (Wrong ID)\nf15e  SiFive, Inc.\nf1d0  AJA Video\n\tc0fe  Xena HS/HD-R\n\tc0ff  Kona/Xena 2\n\tcafe  Kona SD\n\tcfee  Xena LS/SD-22-DA/SD-DA\n\tdaff  KONA LHi\n\tdb01  Corvid22\n\tdb09  Corvid 24\n\tdcaf  Kona HD\n\tdfee  Xena HD-DA\n\teb0d  Corvid 88\n\teb0e  Corvid 44\n\teb1d  Kona 5\n\tefac  Xena SD-MM/SD-22-MM\n\tfacd  Xena HD-MM\nf5f5  F5 Networks, Inc.\n# Subsystem ID for PATA controller on nForce motherboard\nf849  ASRock Incorporation (Wrong ID)\nfa57  Interagon AS\n\t0001  PMC [Pattern Matching Chip]\nfab7  Fabric7 Systems, Inc.\nfebd  Ultraview Corp.\n# Nee Epigram\nfeda  Broadcom Inc\n\ta0fa  BCM4210 iLine10 HomePNA 2.0\n\ta10e  BCM4230 iLine10 HomePNA 2.0\nfede  Fedetec Inc.\n\t0003  TABIC PCI v3\nfffd  XenSource, Inc.\n\t0101  PCI Event Channel Controller\n# Used in some old VMWare products before they got a real ID assigned\nfffe  VMWare Inc (temporary ID)\n\t0710  Virtual SVGA\nffff  Illegal Vendor ID\n\n\n# List of known device classes, subclasses and programming interfaces\n\n# Syntax:\n# C class\tclass_name\n#\tsubclass\tsubclass_name  \t\t<-- single tab\n#\t\tprog-if  prog-if_name  \t<-- two tabs\n\nC 00  Unclassified device\n\t00  Non-VGA unclassified device\n\t01  VGA compatible unclassified device\nC 01  Mass storage controller\n\t00  SCSI storage controller\n\t01  IDE interface\n\t\t00  ISA Compatibility mode-only controller\n\t\t05  PCI native mode-only controller\n\t\t0a  ISA Compatibility mode controller, supports both channels switched to PCI native mode\n\t\t0f  PCI native mode controller, supports both channels switched to ISA compatibility mode\n\t\t80  ISA Compatibility mode-only controller, supports bus mastering\n\t\t85  PCI native mode-only controller, supports bus mastering\n\t\t8a  ISA Compatibility mode controller, supports both channels switched to PCI native mode, supports bus mastering\n\t\t8f  PCI native mode controller, supports both channels switched to ISA compatibility mode, supports bus mastering\n\t02  Floppy disk controller\n\t03  IPI bus controller\n\t04  RAID bus controller\n\t05  ATA controller\n\t\t20  ADMA single stepping\n\t\t30  ADMA continuous operation\n\t06  SATA controller\n\t\t00  Vendor specific\n\t\t01  AHCI 1.0\n\t\t02  Serial Storage Bus\n\t07  Serial Attached SCSI controller\n\t\t01  Serial Storage Bus\n\t08  Non-Volatile memory controller\n\t\t01  NVMHCI\n\t\t02  NVM Express\n\t80  Mass storage controller\nC 02  Network controller\n\t00  Ethernet controller\n\t01  Token ring network controller\n\t02  FDDI network controller\n\t03  ATM network controller\n\t04  ISDN controller\n\t05  WorldFip controller\n\t06  PICMG controller\n\t07  Infiniband controller\n\t08  Fabric controller\n\t80  Network controller\nC 03  Display controller\n\t00  VGA compatible controller\n\t\t00  VGA controller\n\t\t01  8514 controller\n\t01  XGA compatible controller\n\t02  3D controller\n\t80  Display controller\nC 04  Multimedia controller\n\t00  Multimedia video controller\n\t01  Multimedia audio controller\n\t02  Computer telephony device\n\t03  Audio device\n\t80  Multimedia controller\nC 05  Memory controller\n\t00  RAM memory\n\t01  FLASH memory\n\t80  Memory controller\nC 06  Bridge\n\t00  Host bridge\n\t01  ISA bridge\n\t02  EISA bridge\n\t03  MicroChannel bridge\n\t04  PCI bridge\n\t\t00  Normal decode\n\t\t01  Subtractive decode\n\t05  PCMCIA bridge\n\t06  NuBus bridge\n\t07  CardBus bridge\n\t08  RACEway bridge\n\t\t00  Transparent mode\n\t\t01  Endpoint mode\n\t09  Semi-transparent PCI-to-PCI bridge\n\t\t40  Primary bus towards host CPU\n\t\t80  Secondary bus towards host CPU\n\t0a  InfiniBand to PCI host bridge\n\t80  Bridge\nC 07  Communication controller\n\t00  Serial controller\n\t\t00  8250\n\t\t01  16450\n\t\t02  16550\n\t\t03  16650\n\t\t04  16750\n\t\t05  16850\n\t\t06  16950\n\t01  Parallel controller\n\t\t00  SPP\n\t\t01  BiDir\n\t\t02  ECP\n\t\t03  IEEE1284\n\t\tfe  IEEE1284 Target\n\t02  Multiport serial controller\n\t03  Modem\n\t\t00  Generic\n\t\t01  Hayes/16450\n\t\t02  Hayes/16550\n\t\t03  Hayes/16650\n\t\t04  Hayes/16750\n\t04  GPIB controller\n\t05  Smard Card controller\n\t80  Communication controller\nC 08  Generic system peripheral\n\t00  PIC\n\t\t00  8259\n\t\t01  ISA PIC\n\t\t02  EISA PIC\n\t\t10  IO-APIC\n\t\t20  IO(X)-APIC\n\t01  DMA controller\n\t\t00  8237\n\t\t01  ISA DMA\n\t\t02  EISA DMA\n\t02  Timer\n\t\t00  8254\n\t\t01  ISA Timer\n\t\t02  EISA Timers\n\t\t03  HPET\n\t03  RTC\n\t\t00  Generic\n\t\t01  ISA RTC\n\t04  PCI Hot-plug controller\n\t05  SD Host controller\n\t06  IOMMU\n\t80  System peripheral\nC 09  Input device controller\n\t00  Keyboard controller\n\t01  Digitizer Pen\n\t02  Mouse controller\n\t03  Scanner controller\n\t04  Gameport controller\n\t\t00  Generic\n\t\t10  Extended\n\t80  Input device controller\nC 0a  Docking station\n\t00  Generic Docking Station\n\t80  Docking Station\nC 0b  Processor\n\t00  386\n\t01  486\n\t02  Pentium\n\t10  Alpha\n\t20  Power PC\n\t30  MIPS\n\t40  Co-processor\nC 0c  Serial bus controller\n\t00  FireWire (IEEE 1394)\n\t\t00  Generic\n\t\t10  OHCI\n\t01  ACCESS Bus\n\t02  SSA\n\t03  USB controller\n\t\t00  UHCI\n\t\t10  OHCI\n\t\t20  EHCI\n\t\t30  XHCI\n\t\t80  Unspecified\n\t\tfe  USB Device\n\t04  Fibre Channel\n\t05  SMBus\n\t06  InfiniBand\n\t07  IPMI Interface\n\t\t00  SMIC\n\t\t01  KCS\n\t\t02  BT (Block Transfer)\n\t08  SERCOS interface\n\t09  CANBUS\nC 0d  Wireless controller\n\t00  IRDA controller\n\t01  Consumer IR controller\n\t10  RF controller\n\t11  Bluetooth\n\t12  Broadband\n\t20  802.1a controller\n\t21  802.1b controller\n\t80  Wireless controller\nC 0e  Intelligent controller\n\t00  I2O\nC 0f  Satellite communications controller\n\t01  Satellite TV controller\n\t02  Satellite audio communication controller\n\t03  Satellite voice communication controller\n\t04  Satellite data communication controller\nC 10  Encryption controller\n\t00  Network and computing encryption device\n\t10  Entertainment encryption device\n\t80  Encryption controller\nC 11  Signal processing controller\n\t00  DPIO module\n\t01  Performance counters\n\t10  Communication synchronizer\n\t20  Signal processing management\n\t80  Signal processing controller\nC 12  Processing accelerators\n\t00  Processing accelerators\n# For the class of PCI attached devices which perform a function of Deep Learning Neural Network inference acceleration\n\t01  AI Inference Accelerator\nC 13  Non-Essential Instrumentation\nC 40  Coprocessor\nC ff  Unassigned class\n"
  },
  {
    "path": "programs/pci-printer/build.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse regex::Regex;\nuse std::{env, fs::File, io::Write, path::Path};\n\nfn main() {\n    let out_dir = env::var(\"OUT_DIR\").unwrap();\n    let dest_path = Path::new(&out_dir).join(\"build-pci.rs\");\n    let mut f = File::create(&dest_path).unwrap();\n\n    write!(f, r#\"\n        fn build_pci_info() -> hashbrown::HashMap<(u16, u16), (&'static str, &'static str), fnv::FnvBuildHasher> {{\n            [\n    \"#\n    )\n    .unwrap();\n\n    let mut current_vendor_id = None::<u16>;\n    let mut current_vendor_name = None;\n\n    let vendor_regex = Regex::new(r\"^(\\w{4})  (.*)$\").unwrap();\n    let device_regex = Regex::new(r\"^\\t(\\w{4})  (.*)$\").unwrap();\n\n    for line in include_str!(\"build/pci.ids\").lines() {\n        // Strip comments.\n        let line = if let Some(pos) = line.find('#') {\n            line.split_at(pos).0\n        } else {\n            line\n        };\n\n        if let Some(regex_match) = device_regex.captures(line) {\n            let device_id = u16::from_str_radix(regex_match.get(1).unwrap().as_str(), 16).unwrap();\n            let device_name = regex_match.get(2).unwrap().as_str();\n\n            write!(\n                f,\n                r##\"\n                ((0x{:x}, 0x{:x}), (r#\"{}\"#, r#\"{}\"#)),\n            \"##,\n                current_vendor_id.unwrap(),\n                device_id,\n                current_vendor_name.clone().unwrap(),\n                device_name\n            )\n            .unwrap();\n        } else if let Some(regex_match) = vendor_regex.captures(line) {\n            current_vendor_id =\n                Some(u16::from_str_radix(regex_match.get(1).unwrap().as_str(), 16).unwrap());\n            current_vendor_name = Some(regex_match.get(2).unwrap().as_str().to_string());\n        } else if !line.is_empty() && !line.starts_with(\"\\t\\t\") {\n            write!(\n                f,\n                r##\"\n                // Couldn't parse line: {}\n            \"##,\n                line\n            )\n            .unwrap();\n        }\n    }\n\n    write!(\n        f,\n        r#\"\n            ].iter().cloned().collect()\n        }}\n    \"#\n    )\n    .unwrap();\n}\n"
  },
  {
    "path": "programs/pci-printer/src/main.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Queries the PCI interface for all the devices on the system, and prints them out.\n//!\n//! This program is nothing more than a small debugging utility.\n\nuse fnv::FnvBuildHasher;\nuse std::borrow::Cow;\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/build-pci.rs\"));\n\nfn main() {\n    redshirt_log_interface::init();\n    redshirt_syscalls::block_on(async_main());\n}\n\nasync fn async_main() {\n    let devices = redshirt_pci_interface::get_pci_devices().await;\n\n    for device in devices {\n        let (vendor_name, device_name) =\n            match PCI_DEVICES.get(&(device.vendor_id, device.device_id)) {\n                Some((v, d)) => (Cow::Borrowed(*v), Cow::Borrowed(*d)),\n                None => (\n                    Cow::Owned(format!(\"Unknown <0x{:x}>\", device.vendor_id)),\n                    Cow::Owned(format!(\"Unknown <0x{:x}>\", device.device_id)),\n                ),\n            };\n\n        log::info!(\n            \"PCI device: {} - {}\\nDevice class: {} (prog. if. = 0x{:x}, rev. = 0x{:x})\",\n            vendor_name,\n            device_name,\n            show_class_code(device.class_code, device.subclass),\n            device.prog_if,\n            device.revision_id,\n        );\n    }\n}\n\nlazy_static::lazy_static! {\n    static ref PCI_DEVICES: hashbrown::HashMap<(u16, u16), (&'static str, &'static str), FnvBuildHasher> = build_pci_info();\n}\n\nfn show_class_code(class_code: u8, subclass: u8) -> Cow<'static, str> {\n    match (class_code, subclass) {\n        (0x00, 0x00) => \"Non-VGA-Compatible devices\".into(),\n        (0x00, 0x01) => \"VGA-Compatible Device\".into(),\n\n        (0x01, 0x00) => \"SCSI Bus Controller\".into(),\n        (0x01, 0x01) => \"IDE Controller\".into(),\n        (0x01, 0x02) => \"Floppy Disk Controller\".into(),\n        (0x01, 0x03) => \"IPI Bus Controller\".into(),\n        (0x01, 0x04) => \"RAID Controller\".into(),\n        (0x01, 0x05) => \"ATA Controller\".into(),\n        (0x01, 0x06) => \"Serial ATA\".into(),\n        (0x01, 0x07) => \"Serial Attached SCSI\".into(),\n        (0x01, 0x08) => \"Non-Volatile Memory Controller\".into(),\n        (0x01, 0x80) => \"Other\".into(),\n\n        (0x02, 0x00) => \"Ethernet Controller\".into(),\n        (0x02, 0x01) => \"Token Ring Controller\".into(),\n        (0x02, 0x02) => \"FDDI Controller\".into(),\n        (0x02, 0x03) => \"ATM Controller\".into(),\n        (0x02, 0x04) => \"ISDN Controller\".into(),\n        (0x02, 0x05) => \"WorldFip Controller\".into(),\n        (0x02, 0x06) => \"PICMG 2.14 Multi Computing\".into(),\n        (0x02, 0x07) => \"Infiniband Controller\".into(),\n        (0x02, 0x08) => \"Fabric Controller\".into(),\n        (0x02, 0x80) => \"Other\".into(),\n\n        (0x03, 0x00) => \"VGA Compatible Controller\".into(),\n        (0x03, 0x01) => \"XGA Controller\".into(),\n        (0x03, 0x02) => \"3D Controller (Not VGA-Compatible)\".into(),\n        (0x03, 0x80) => \"Other\".into(),\n\n        (0x04, 0x00) => \"Multimedia Video Controller\".into(),\n        (0x04, 0x01) => \"Multimedia Audio Controller\".into(),\n        (0x04, 0x02) => \"Computer Telephony Device\".into(),\n        (0x04, 0x03) => \"Audio Device\".into(),\n        (0x04, 0x80) => \"Other\".into(),\n\n        (0x05, 0x00) => \"RAM Controller\".into(),\n        (0x05, 0x01) => \"Flash Controller\".into(),\n        (0x05, 0x80) => \"Other\".into(),\n\n        (0x06, 0x00) => \"Host Bridge\".into(),\n        (0x06, 0x01) => \"ISA Bridge\".into(),\n        (0x06, 0x02) => \"EISA Bridge\".into(),\n        (0x06, 0x03) => \"MCA Bridge\".into(),\n        (0x06, 0x04) => \"PCI-to-PCI Bridge\".into(),\n        (0x06, 0x05) => \"PCMCIA Bridge\".into(),\n        (0x06, 0x06) => \"NuBus Bridge\".into(),\n        (0x06, 0x07) => \"CardBus Bridge\".into(),\n        (0x06, 0x08) => \"RACEway Bridge\".into(),\n        (0x06, 0x09) => \"PCI-to-PCI Bridge\".into(),\n        (0x06, 0x0A) => \"InfiniBand-to-PCI Host Bridge\".into(),\n        (0x06, 0x80) => \"Other\".into(),\n\n        (0x07, 0x00) => \"Serial Controller\".into(),\n        (0x07, 0x01) => \"Parallel Controller\".into(),\n        (0x07, 0x02) => \"Multiport Serial Controller\".into(),\n        (0x07, 0x03) => \"Modem\".into(),\n        (0x07, 0x04) => \"IEEE 488.1/2 (GPIB) Controller\".into(),\n        (0x07, 0x05) => \"Smart Card\".into(),\n        (0x07, 0x80) => \"Other\".into(),\n\n        (0x08, 0x00) => \"PIC\".into(),\n        (0x08, 0x01) => \"DMA Controller\".into(),\n        (0x08, 0x02) => \"Timer\".into(),\n        (0x08, 0x03) => \"RTC Controller\".into(),\n        (0x08, 0x04) => \"PCI Hot-Plug Controller\".into(),\n        (0x08, 0x05) => \"SD Host controller\".into(),\n        (0x08, 0x06) => \"IOMMU\".into(),\n        (0x08, 0x80) => \"Other\".into(),\n\n        (0x09, 0x00) => \"Keyboard Controller\".into(),\n        (0x09, 0x01) => \"Digitizer Pen\".into(),\n        (0x09, 0x02) => \"Mouse Controller\".into(),\n        (0x09, 0x03) => \"Scanner Controller\".into(),\n        (0x09, 0x04) => \"Gameport Contro\".into(),\n        (0x09, 0x80) => \"Other\".into(),\n\n        (0x0A, 0x00) => \"Generic\".into(),\n        (0x0A, 0x80) => \"Other\".into(),\n\n        (0x0B, 0x00) => \"386\".into(),\n        (0x0B, 0x01) => \"486\".into(),\n        (0x0B, 0x02) => \"Pentium\".into(),\n        (0x0B, 0x03) => \"Pentium Pro\".into(),\n        (0x0B, 0x10) => \"Alpha\".into(),\n        (0x0B, 0x20) => \"PowerPC\".into(),\n        (0x0B, 0x30) => \"MIPS\".into(),\n        (0x0B, 0x40) => \"Co-Processor\".into(),\n        (0x0B, 0x80) => \"Other\".into(),\n\n        (0x0C, 0x00) => \"FireWire (IEEE 1394) Controller\".into(),\n        (0x0C, 0x01) => \"ACCESS Bus\".into(),\n        (0x0C, 0x02) => \"SSA\".into(),\n        (0x0C, 0x03) => \"USB Controller\".into(),\n        (0x0C, 0x04) => \"Fibre Channel\".into(),\n        (0x0C, 0x05) => \"SMBus\".into(),\n        (0x0C, 0x06) => \"InfiniBand\".into(),\n        (0x0C, 0x07) => \"IPMI Interface\".into(),\n        (0x0C, 0x08) => \"SERCOS Interface (IEC 61491)\".into(),\n        (0x0C, 0x09) => \"CANbus\".into(),\n        (0x0C, 0x80) => \"Other\".into(),\n\n        (0x0D, 0x00) => \"iRDA Compatible Controller\".into(),\n        (0x0D, 0x01) => \"Consumer IR Controller\".into(),\n        (0x0D, 0x10) => \"RF Controller\".into(),\n        (0x0D, 0x11) => \"Bluetooth Controller\".into(),\n        (0x0D, 0x12) => \"Broadband Controller\".into(),\n        (0x0D, 0x20) => \"Ethernet Controller (802.1a)\".into(),\n        (0x0D, 0x21) => \"Ethernet Controller (802.1b)\".into(),\n        (0x0D, 0x80) => \"Other\".into(),\n\n        (0x0E, 0x00) => \"I20\".into(),\n\n        (0x0F, 0x01) => \"Satellite TV Controller\".into(),\n        (0x0F, 0x02) => \"Satellite Audio Controller\".into(),\n        (0x0F, 0x03) => \"Satellite Voice Controller\".into(),\n        (0x0F, 0x04) => \"Satellite Data Controller\".into(),\n\n        (0x10, 0x00) => \"Network and Computing Encrpytion/Decryption\".into(),\n        (0x10, 0x10) => \"Entertainment Encryption/Decryption\".into(),\n        (0x10, 0x80) => \"Other Encryption/Decryption\".into(),\n\n        (0x11, 0x00) => \"DPIO Modules\".into(),\n        (0x11, 0x01) => \"Performance Counters\".into(),\n        (0x11, 0x10) => \"Communication Synchronizer\".into(),\n        (0x11, 0x20) => \"Signal Processing Management\".into(),\n        (0x11, 0x80) => \"Other\".into(),\n\n        (0x12, _) => \"Processing Accelerator\".into(),\n        (0x13, _) => \"Non-Essential Instrumentation\".into(),\n        (0x40, _) => \"Co-Processor\".into(),\n\n        _ => format!(\"unknown ({}-{})\", class_code, subclass).into(),\n    }\n}\n"
  },
  {
    "path": "programs/rpi-framebuffer/Cargo.toml",
    "content": "[package]\nname = \"rpi-framebuffer\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[dependencies]\nredshirt-hardware-interface = { path = \"../../interface-wrappers/hardware\" }\nredshirt-interface-interface = { path = \"../../interface-wrappers/interface\" }\nredshirt-log-interface = { path = \"../../interface-wrappers/log\" }\nredshirt-syscalls = { path = \"../../interface-wrappers/syscalls\" }\nparity-scale-codec = { version = \"1.3.6\", default-features = false }\n"
  },
  {
    "path": "programs/rpi-framebuffer/src/mailbox.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n// TODO: more docs at https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface\n\nuse std::convert::TryFrom as _;\n\n/// Message to write to the mailbox, or read from the mailbox.\n///\n/// A message is composed of a channel number and data.\npub struct Message {\n    /// Raw representation of the message, as written in memory or read from memory.\n    ///\n    /// 4 lowest bits are the channel. 28 highest bits are the data.\n    value: u32,\n}\n\nimpl Message {\n    /// Builds a message from its raw components.\n    ///\n    /// # Panic\n    ///\n    /// Panics if `data` doesn't fit in 28 bits or `channel` doesn't fit in 4 bits.\n    ///\n    pub fn new(channel: u8, data: u32) -> Message {\n        assert!(channel < (1 << 4));\n        assert!(data < (1 << 28));\n        Message {\n            value: (data << 4) | u32::from(channel),\n        }\n    }\n\n    /// Returns the channel of this message.\n    pub fn channel(&self) -> u8 {\n        u8::try_from(self.value & 0xf).unwrap()\n    }\n\n    /// Returns the data of this message.\n    pub fn data(&self) -> u32 {\n        self.value >> 4\n    }\n}\n\nconst BASE_IO_PERIPH: u64 = 0x3f000000; // 0x20000000 for raspi 1\nconst MAILBOX_BASE: u64 = BASE_IO_PERIPH + 0xb880;\n\n/// Reads one message from the mailbox.\npub async fn read_mailbox() -> Message {\n    unsafe {\n        // Wait for status register to indicate a message.\n        loop {\n            let val = redshirt_hardware_interface::read_one_u32(MAILBOX_BASE + 0x18).await;\n            if val & (1 << 30) == 0 {\n                break;\n            }\n        }\n\n        let mut read = redshirt_hardware_interface::HardwareOperationsBuilder::new();\n        let mut out = [0];\n        read.read_u32(MAILBOX_BASE + 0x0, &mut out);\n        read.send().await;\n        Message { value: out[0] }\n    }\n}\n\n/// Writes one message from the mailbox.\npub async fn write_mailbox(message: Message) {\n    unsafe {\n        // Wait for status register to indicate a message.\n        loop {\n            let val = redshirt_hardware_interface::read_one_u32(MAILBOX_BASE + 0x18).await;\n            if val & (1 << 31) == 0 {\n                break;\n            }\n        }\n\n        redshirt_hardware_interface::write_one_u32(MAILBOX_BASE + 0x20, message.value);\n    }\n}\n"
  },
  {
    "path": "programs/rpi-framebuffer/src/main.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n// TODO: doc https://jsandler18.github.io/\n\nuse parity_scale_codec::DecodeAll;\nuse std::{convert::TryFrom as _, fmt};\n\nmod mailbox;\nmod property;\n\nfn main() {\n    redshirt_syscalls::block_on(async_main());\n}\n\nasync fn async_main() {\n    property::init().await;\n}\n"
  },
  {
    "path": "programs/rpi-framebuffer/src/property.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::mailbox;\nuse std::{borrow::Cow, convert::TryFrom as _, iter};\n\n/// Builder for a request on the property interface.\npub struct PropertyMessageBuilder {\n    /// Buffer containing the request.\n    ///\n    /// The first element (the buffer length) is only filled right before we submit the message.\n    buffer: Vec<u32>,\n}\n\nimpl PropertyMessageBuilder {\n    pub fn new() -> PropertyMessageBuilder {\n        PropertyMessageBuilder { buffer: vec![0; 2] }\n    }\n\n    pub fn add_tag(&mut self, tag: u32, value_buffer: &[u8]) {\n        let value_buffer_size_bytes = u32::try_from(value_buffer.len()).unwrap();\n        let value_buffer_num_u32s = value_buffer_size_bytes\n            .checked_sub(1)\n            .map(|v| 4 * (1 + (v / 4)))\n            .unwrap_or(0);\n\n        let buffer_tag_start = self.buffer.len();\n        let new_buffer_len =\n            self.buffer.len() + 3 + usize::try_from(value_buffer_num_u32s).unwrap();\n        self.buffer.resize(new_buffer_len, 0);\n\n        self.buffer[buffer_tag_start] = tag;\n        self.buffer[buffer_tag_start + 1] = value_buffer_size_bytes;\n\n        // Copy `value_buffer` into `self.buffer`.\n        for (byte_index, byte) in value_buffer.iter().enumerate() {\n            self.buffer[buffer_tag_start + 3 + (byte_index / 4)] |=\n                u32::from(*byte) << (8 * (byte_index % 4));\n        }\n    }\n\n    pub fn with_tag(mut self, tag: u32, value_buffer: &[u8]) -> Self {\n        self.add_tag(tag, value_buffer);\n        self\n    }\n\n    pub async fn send(self) {\n        unimplemented!()\n        /*let buffer1 = redshirt_hardware_interface::malloc::PhysicalBuffer::new(Packet1 {\n            data: [\n                80,                             // The whole buffer is 80 bytes\n                0,                              // This is a request, so the request/response code is 0\n                0x00048003, 8, 0, 640, 480,     // This tag sets the screen size to 640x480\n                0x00048004, 8, 0, 640, 480,     // This tag sets the virtual screen size to 640x480\n                0x00048005, 4, 0, 24,           // This tag sets the depth to 24 bits\n                0,                              // This is the end tag\n                0, 0, 0                         // This pads the message to by 16 byte aligned\n            ]\n        }).await;\n\n        assert_eq!(buffer1.pointer() % 16, 0);\n        mailbox::write_mailbox(mailbox::Message::new(8, u32::try_from(buffer1.pointer() >> 4).unwrap())).await;      // TODO: ` | 0x40000000` ?*/\n    }\n}\n\npub struct PropertyMessageParser<'a> {\n    data: Cow<'a, [u32]>,\n}\n\nimpl<'a> PropertyMessageParser<'a> {\n    pub fn from_buffer(buffer: impl Into<Cow<'a, [u32]>>) -> Result<Self, ()> {\n        let buffer = buffer.into();\n        assert!(buffer.len() >= 2);\n        assert_eq!(buffer.len() % 16, 0);\n        assert_eq!(u32::try_from(buffer.len()).unwrap(), buffer[0]);\n        if buffer[1] != 0x80000000 {\n            return Err(());\n        }\n        Ok(PropertyMessageParser { data: buffer })\n    }\n\n    /// Returns an iterator to the list of tags of the message.\n    pub fn tags<'b: 'a>(&'b self) -> impl Iterator<Item = PropertyMessageParserTag<'a>> + 'b {\n        // This is the \"state\" of our iterator. Corresponds to the start index of the next tag\n        // within `self.data`.\n        let mut cursor = 2;\n\n        iter::from_fn(move || {\n            if cursor >= u32::try_from(self.data.len()).unwrap() {\n                return None;\n            }\n\n            let value_buffer_size_bytes = self.data[usize::try_from(cursor).unwrap() + 1];\n            let value_buffer_num_u32s = value_buffer_size_bytes\n                .checked_sub(1)\n                .map(|v| 4 * (1 + (v / 4)))\n                .unwrap_or(0);\n\n            let tag_start = usize::try_from(cursor).unwrap();\n            let tag_total_u32s = 3 + value_buffer_num_u32s;\n            cursor += tag_total_u32s;\n            let tag_end = usize::try_from(cursor).unwrap();\n\n            Some(PropertyMessageParserTag {\n                data: &self.data[tag_start..tag_end],\n            })\n        })\n    }\n}\n\npub struct PropertyMessageParserTag<'a> {\n    data: &'a [u32],\n}\n\n#[repr(align(16))]\nstruct Packet1 {\n    data: [u32; 20],\n}\n\n#[repr(align(16))]\nstruct Packet2 {\n    data: [u32; 8],\n}\n\n// TODO: make more generic and explicit, with tags and all, to be more robust to code changes\npub async fn init() {\n    let buffer1 = redshirt_hardware_interface::malloc::PhysicalBuffer::new(Packet1 {\n        data: [\n            80, // The whole buffer is 80 bytes\n            0,  // This is a request, so the request/response code is 0\n            0x00048003, 8, 0, 640, 480, // This tag sets the screen size to 640x480\n            0x00048004, 8, 0, 640, 480, // This tag sets the virtual screen size to 640x480\n            0x00048005, 4, 0, 24, // This tag sets the depth to 24 bits\n            0,  // This is the end tag\n            0, 0, 0, // This pads the message to by 16 byte aligned\n        ],\n    })\n    .await;\n\n    assert_eq!(buffer1.pointer() % 16, 0);\n    mailbox::write_mailbox(mailbox::Message::new(\n        8,\n        u32::try_from(buffer1.pointer() >> 4).unwrap(),\n    ))\n    .await; // TODO: ` | 0x40000000` ?\n\n    mailbox::read_mailbox().await;\n\n    let data1 = buffer1.take().await;\n    assert_eq!(data1.data[1], 0x80000000);\n\n    let actual_width = data1.data[5];\n    let actual_height = data1.data[6];\n\n    let buffer2 = redshirt_hardware_interface::malloc::PhysicalBuffer::new(Packet2 {\n        data: [\n            32, // The whole buffer is 32 bytes\n            0,  // This is a request, so the request/response code is 0\n            0x00040001, 8, 0, 16, 0, // This tag requests a 16 byte aligned framebuffer\n            0, // This is the end tag\n        ],\n    })\n    .await;\n\n    assert_eq!(buffer2.pointer() % 16, 0);\n    mailbox::write_mailbox(mailbox::Message::new(\n        8,\n        u32::try_from(buffer2.pointer() >> 4).unwrap(),\n    ))\n    .await;\n\n    mailbox::read_mailbox().await;\n\n    let data2 = buffer2.take().await;\n    assert_eq!(data2.data[1], 0x80000000);\n\n    let fb_addr = data2.data[5];\n    let fb_size = data2.data[6];\n    //panic!(\"{:x} size {}\", fb_addr, fb_size);\n\n    let mut op_builder = redshirt_hardware_interface::HardwareWriteOperationsBuilder::new();\n    unsafe {\n        op_builder.memset(\n            u64::from(fb_addr),\n            3 * u64::from(actual_height) * u64::from(actual_width),\n            0xff,\n        );\n    }\n    op_builder.send();\n}\n"
  },
  {
    "path": "programs/stub/Cargo.toml",
    "content": "[package]\nname = \"stub\"\nversion = \"0.1.0\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[dependencies]\nfutures = { version = \"0.3.21\", default-features = false }\nredshirt-syscalls = { path = \"../../interface-wrappers/syscalls\" }\nwee_alloc = \"0.4.5\"\n"
  },
  {
    "path": "programs/stub/src/main.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Draft for a module, with the purpose of inspecting the WASM output.\n//!\n//! This module doesn't do much by itself and isn't meant to be actually executed.\n//! This code exists with the intent of being compiled in release mode so that one can inspect\n//! the WASM output.\n\n#![no_std]\n#![no_main]\n\n#[global_allocator]\nstatic ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;\n\n#[cfg(not(any(test, doc, doctest)))]\n#[panic_handler]\nfn panic(_: &core::panic::PanicInfo) -> ! {\n    unsafe { core::hint::unreachable_unchecked() }\n}\n\nextern crate alloc;\nuse alloc::vec;\nuse futures::prelude::*;\n\n#[no_mangle]\nfn _start(_: isize, _: *const *const u8) -> isize {\n    redshirt_syscalls::block_on(async_main());\n    0\n}\n\nfn async_main() -> impl Future<Output = ()> {\n    let interface = redshirt_syscalls::InterfaceHash::from_raw_hash([\n        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,\n        0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,\n        0x36, 0x37,\n    ]);\n\n    redshirt_syscalls::next_interface_message().then(move |msg| {\n        let msg = match msg {\n            redshirt_syscalls::DecodedInterfaceOrDestroyed::Interface(m) => m,\n            redshirt_syscalls::DecodedInterfaceOrDestroyed::ProcessDestroyed(_) => panic!(),\n        };\n        assert_eq!(msg.interface, interface);\n        assert_eq!(\n            msg.actual_data,\n            redshirt_syscalls::EncodedMessage(vec![1, 2, 3, 4, 5, 6, 7, 8])\n        );\n        future::ready(())\n    })\n}\n"
  },
  {
    "path": "programs/third-party/README.md",
    "content": "Contains libraries that were not written specifically for this OS, but that need some tweaks in\norder to properly run on redshirt.\n"
  },
  {
    "path": "programs/third-party/wasm-timer/Cargo.toml",
    "content": "[package]\nname = \"wasm-timer\"\nversion = \"0.2.4\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\n\n[dependencies]\npin-project = \"1.0.10\"\n\n[target.'cfg(not(target_arch = \"wasm32\"))'.dependencies]\nfutures-timer = \"3.0\"\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nredshirt-time-interface = { path = \"../../../interface-wrappers/time\" }\n"
  },
  {
    "path": "programs/third-party/wasm-timer/src/lib.rs",
    "content": "// Copyright (C) 2019-2020  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n#[cfg(target_arch = \"wasm32\")]\npub use redshirt_time_interface::Instant;\n#[cfg(not(target_arch = \"wasm32\"))]\npub use std::time::Instant;\n\nuse std::{fmt, future::Future, io, pin::Pin, task::Context, task::Poll, time::Duration};\n\n/// Mimics the API of `futures_timer::Delay`.\n#[pin_project::pin_project]\npub struct Delay {\n    #[cfg(not(target_arch = \"wasm32\"))]\n    #[pin]\n    inner: futures_timer::Delay,\n    #[cfg(not(target_arch = \"wasm32\"))]\n    when: Instant,\n    #[cfg(target_arch = \"wasm32\")]\n    #[pin]\n    inner: redshirt_time_interface::Delay,\n}\n\n#[cfg(target_arch = \"wasm32\")]\nimpl Delay {\n    pub fn new(dur: Duration) -> Delay {\n        Delay {\n            inner: redshirt_time_interface::Delay::new(dur),\n        }\n    }\n\n    pub fn new_at(at: Instant) -> Delay {\n        Delay {\n            inner: redshirt_time_interface::Delay::new_at(at),\n        }\n    }\n\n    pub fn when(&self) -> Instant {\n        self.inner.when()\n    }\n\n    pub fn reset(&mut self, dur: Duration) {\n        *self = Delay::new(dur);\n    }\n\n    pub fn reset_at(&mut self, at: Instant) {\n        *self = Delay::new_at(at);\n    }\n}\n\n#[cfg(not(target_arch = \"wasm32\"))]\nimpl Delay {\n    pub fn new(dur: Duration) -> Delay {\n        // Instant is grabbed before creating the future.\n        let when = Instant::now() + dur;\n        Delay {\n            inner: futures_timer::Delay::new(dur),\n            when,\n        }\n    }\n\n    pub fn new_at(at: Instant) -> Delay {\n        let now = Instant::now();\n        Delay {\n            inner: futures_timer::Delay::new({\n                if at > now {\n                    at - now\n                } else {\n                    Duration::new(0, 0)\n                }\n            }),\n            when: at,\n        }\n    }\n\n    pub fn when(&self) -> Instant {\n        self.when\n    }\n\n    pub fn reset(&mut self, dur: Duration) {\n        *self = Delay::new(dur);\n    }\n\n    pub fn reset_at(&mut self, at: Instant) {\n        self.reset({\n            let now = Instant::now();\n            if at > now {\n                at - now\n            } else {\n                Duration::new(0, 0)\n            }\n        });\n    }\n}\n\nimpl fmt::Debug for Delay {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        fmt::Debug::fmt(&self.inner, f)\n    }\n}\n\nimpl Future for Delay {\n    type Output = io::Result<()>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {\n        let mut this = self.project();\n        Future::poll(this.inner.as_mut(), cx).map(Ok)\n    }\n}\n"
  },
  {
    "path": "programs/vga-vbe/Cargo.toml",
    "content": "[package]\nname = \"vga-vbe\"\nversion = \"0.1.0\"\nlicense = \"GPL-3.0-or-later\"\nauthors = [\"Pierre Krieger <pierre.krieger1708@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[dependencies]\nderive_more = \"0.99.17\"\nfnv = { version = \"1.0.7\", default-features = false }\nhashbrown = { version = \"0.12.0\", default-features = false }\niced-x86 = { version = \"1.14.0\", default-features = false, features = [\"decoder\", \"instr_info\", \"op_code_info\", \"std\"] }\nlazy_static = \"1\"\nlog = \"0.4\"\nredshirt-hardware-interface = { path = \"../../interface-wrappers/hardware\" }\nredshirt-interface-interface = { path = \"../../interface-wrappers/interface\" }\nredshirt-kernel-log-interface = { path = \"../../interface-wrappers/kernel-log\" }\nredshirt-log-interface = { path = \"../../interface-wrappers/log\" }\nredshirt-pci-interface = { path = \"../../interface-wrappers/pci\" }\nredshirt-syscalls = { path = \"../../interface-wrappers/syscalls\" }\nredshirt-video-output-interface = { path = \"../../interface-wrappers/video-output\" }\n\n[dev-dependencies]\nfutures = \"0.3.21\"\n"
  },
  {
    "path": "programs/vga-vbe/src/interpreter/tests.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n#![cfg(test)]\n\nuse super::Interpreter;\n\n#[test]\nfn basic_entry_point_works() {\n    futures::executor::block_on(async move {\n        let mut interpreter =\n            Interpreter::from_memory(include_bytes!(\"test-mem.bin\").to_vec()).await;\n        interpreter.disable_io_operations();\n        interpreter.set_ax(0x4f00);\n        interpreter.set_es_di(0x50, 0x0);\n        interpreter.write_memory(0x500, &b\"VBE2\"[..]);\n        interpreter.int10h().unwrap();\n        assert_eq!(interpreter.ax(), 0x4f);\n\n        let mut info_out = [0; 512];\n        interpreter.read_memory(0x500, &mut info_out[..]);\n        assert_eq!(&info_out[0..4], b\"VESA\");\n\n        let video_modes = {\n            let vmodes_seg = interpreter.read_memory_u16(0x510);\n            let vmodes_ptr = interpreter.read_memory_u16(0x50e);\n            let mut vmodes_addr = (u32::from(vmodes_seg) << 4) + u32::from(vmodes_ptr);\n            let mut modes = Vec::new();\n            loop {\n                let mode = interpreter.read_memory_u16(vmodes_addr);\n                if mode == 0xffff {\n                    break modes;\n                }\n                vmodes_addr += 2;\n                modes.push(mode);\n            }\n        };\n        log::info!(\"Video modes = {:?}\", video_modes);\n\n        let total_memory = u32::from(interpreter.read_memory_u16(0x512)) * 64 * 1024;\n        log::info!(\"Total memory = 0x{:x}\", total_memory);\n\n        let oem_string = {\n            let seg = interpreter.read_memory_u16(0x508);\n            let ptr = interpreter.read_memory_u16(0x506);\n            let addr = (u32::from(seg) << 4) + u32::from(ptr);\n            interpreter.read_memory_nul_terminated_str(addr)\n        };\n        log::info!(\"OEM string: {}\", oem_string);\n\n        for mode in video_modes.iter().take(1) {\n            // TODO: remove take(1)\n            interpreter.set_ax(0x4f01);\n            interpreter.set_cx(*mode);\n            interpreter.set_es_di(0x50, 0x0);\n            interpreter.int10h().unwrap();\n            log::error!(\"EAX after call: 0x{:x}\", interpreter.ax());\n\n            let mut info_out = [0; 256];\n            interpreter.read_memory(0x500, &mut info_out[..]);\n            log::debug!(\"Mode info: {:?}\", &info_out[..]);\n        }\n    })\n}\n"
  },
  {
    "path": "programs/vga-vbe/src/interpreter.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse core::{convert::TryFrom, fmt};\n\nmod tests;\n\n/// Intel 80386 real mode interpreter.\npub struct Interpreter {\n    /// State of all the registers of the CPU, including CS and EIP.\n    regs: Registers,\n    /// Cache of the first megabyte of memory.\n    memory_cache: Vec<u8>,\n    /// If true, perform I/O ports operations on the actual machine. Otherwise, reading a port\n    /// returns 0 and writing a port is a no-op.\n    enable_io_operations: bool,\n}\n\n#[derive(Debug, PartialEq, Eq)]\nstruct Registers {\n    eax: u32,\n    ecx: u32,\n    edx: u32,\n    ebx: u32,\n    esp: u32,\n    ebp: u32,\n    esi: u32,\n    edi: u32,\n    eip: u32,\n    cs: u16,\n    ss: u16,\n    ds: u16,\n    es: u16,\n    fs: u16,\n    gs: u16,\n    flags: u16,\n}\n\n#[derive(Debug)]\npub enum Error {\n    InvalidInstruction,\n\n    /// Code has called the `hlt` instruction, which cannot do anything.\n    InterruptNotSupported,\n}\n\nimpl fmt::Display for Error {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            Error::InvalidInstruction => write!(f, \"Invalid instruction\"),\n            Error::InterruptNotSupported => write!(f, \"HLT has been called\"),\n        }\n    }\n}\n\nimpl Interpreter {\n    pub async fn from_real_machine() -> Self {\n        let first_mb = unsafe { redshirt_hardware_interface::read(0x0, 0x100000).await };\n        // Small sanity check.\n        assert!(first_mb.iter().any(|b| *b != 0));\n        Self::from_memory(first_mb).await\n    }\n\n    pub async fn from_memory(first_mb: Vec<u8>) -> Self {\n        assert_eq!(first_mb.len(), 0x100000);\n\n        Interpreter {\n            memory_cache: first_mb,\n            regs: Registers {\n                eax: 0,\n                ecx: 0,\n                edx: 0,\n                ebx: 0,\n                esp: 0xf000, // TODO:\n                ebp: 0,\n                esi: 0,\n                edi: 0,\n                eip: 0,\n                cs: 0,\n                ss: 0x9000, // TODO:\n                ds: 0,\n                es: 0,\n                fs: 0,\n                gs: 0,\n                flags: 0b1011000000000010,\n            },\n            enable_io_operations: true,\n        }\n    }\n\n    /// After this is called, I/O operations will no longer be performed on the actual machine.\n    /// Reading a port now always returns 0, and writing a port becomes a no-op. Reading and\n    /// writing memory is only done on the local cache.\n    ///\n    /// > **Note**: It is intentional that no opposite function is provided, as the memory stops\n    /// >           being in sync with the actual memory, which will likely cause issues.\n    #[cfg_attr(not(test), allow(unused))] // Used only in tests.\n    pub fn disable_io_operations(&mut self) {\n        self.enable_io_operations = false;\n    }\n\n    /// Reads bytes from the physical memory.\n    ///\n    /// This will read the memory of the actual machine.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the memory address and size are out of range.\n    ///\n    pub fn read_memory(&mut self, addr: u32, out: &mut [u8]) {\n        let out_len = u32::try_from(out.len()).unwrap();\n        assert!(addr + out_len <= 0x100000);\n\n        // Perform a cache refresh only if we hit the video memory.\n        if self.enable_io_operations && addr >= 0xa0000 && addr < 0xc0000 {\n            // TODO: asyncify?\n            redshirt_syscalls::block_on(async {\n                unsafe {\n                    redshirt_hardware_interface::read_to(u64::from(addr), out).await;\n                }\n            });\n            self.memory_cache\n                [usize::try_from(addr).unwrap()..usize::try_from(addr + out_len).unwrap()]\n                .copy_from_slice(&out);\n        } else {\n            out.copy_from_slice(\n                &self.memory_cache\n                    [usize::try_from(addr).unwrap()..usize::try_from(addr + out_len).unwrap()],\n            );\n        }\n    }\n\n    pub fn read_memory_nul_terminated_str(&mut self, mut addr: u32) -> String {\n        let mut out = Vec::new();\n        loop {\n            match self.read_memory_u8(addr) {\n                0 => break,\n                b => out.push(b),\n            };\n            addr += 1;\n        }\n        String::from_utf8(out).unwrap()\n    }\n\n    pub fn read_memory_u8(&mut self, addr: u32) -> u8 {\n        let mut out = [0; 1];\n        self.read_memory(addr, &mut out);\n        u8::from_le_bytes(out)\n    }\n\n    pub fn read_memory_u16(&mut self, addr: u32) -> u16 {\n        let mut out = [0; 2];\n        self.read_memory(addr, &mut out);\n        u16::from_le_bytes(out)\n    }\n\n    pub fn write_memory(&mut self, addr: u32, data: &[u8]) {\n        let data_len = u32::try_from(data.len()).unwrap();\n        assert!(addr + data_len <= 0x100000);\n\n        self.memory_cache\n            [usize::try_from(addr).unwrap()..usize::try_from(addr + data_len).unwrap()]\n            .copy_from_slice(data);\n\n        // We only perform the actual write to memory if we hit the video memory.\n        if self.enable_io_operations && addr >= 0xa0000 && addr < 0xc0000 {\n            unsafe {\n                redshirt_hardware_interface::write(u64::from(addr), data);\n            }\n        }\n    }\n\n    pub fn ax(&mut self) -> u16 {\n        u16::try_from(self.regs.eax & 0xffff).unwrap()\n    }\n\n    pub fn set_ax(&mut self, value: u16) {\n        self.regs.eax &= 0xffff0000;\n        self.regs.eax |= u32::from(value);\n    }\n\n    pub fn set_bx(&mut self, value: u16) {\n        self.regs.ebx &= 0xffff0000;\n        self.regs.ebx |= u32::from(value);\n    }\n\n    pub fn cx(&mut self) -> u16 {\n        u16::try_from(self.regs.ecx & 0xffff).unwrap()\n    }\n\n    pub fn set_cx(&mut self, value: u16) {\n        self.regs.ecx &= 0xffff0000;\n        self.regs.ecx |= u32::from(value);\n    }\n\n    pub fn dx(&mut self) -> u16 {\n        u16::try_from(self.regs.edx & 0xffff).unwrap()\n    }\n\n    pub fn set_es_di(&mut self, es: u16, di: u16) {\n        self.regs.es = es;\n        self.regs.edi &= 0xffff0000;\n        self.regs.edi |= u32::from(di);\n    }\n\n    /// Executes the `int 0x10` instruction on the machine, and run until the corresponding `iret`\n    /// instruction is executed.\n    pub fn int10h(&mut self) -> Result<(), Error> {\n        self.run_int_opcode(0x10);\n        self.run_until_iret()\n    }\n\n    /// Runs the machine until the `iret` instruction is executed.\n    ///\n    /// Nested interrupts are accounted for. If an `int` opcode is executed, then the next `iret`\n    /// will not cause this function to finish.\n    fn run_until_iret(&mut self) -> Result<(), Error> {\n        // Counts the number of nested interrupts. Incremented when `int` is called, decremented\n        // when `iret` is called.\n        let mut nested_ints: u32 = 0;\n\n        loop {\n            // Decode instruction and update the IP register.\n            let instruction = {\n                let rip = (u64::from(self.regs.cs) << 4) + u64::from(self.regs.eip);\n                assert!(usize::try_from(rip).unwrap() < self.memory_cache.len());\n\n                // We recreate a `Decoder` at each iteration because we need to be able to modify\n                // the memory during the processing of the instruction. While it is unlikely to\n                // actually happen, we do need to support self-modifying programs.\n                let mut decoder =\n                    iced_x86::Decoder::new(16, &self.memory_cache, iced_x86::DecoderOptions::NONE);\n                decoder.set_position(usize::try_from(rip).unwrap());\n                decoder.set_ip(rip);\n\n                let instruction = decoder.decode();\n                assert!(!instruction.has_xrelease_prefix());\n                self.regs.eip = {\n                    let ip = self.ip();\n                    let new_ip = ip.wrapping_add(u16::try_from(instruction.len()).unwrap());\n                    u32::from(new_ip)\n                };\n\n                instruction\n            };\n\n            self.run_one(&instruction)?;\n\n            match instruction.mnemonic() {\n                iced_x86::Mnemonic::Iret if nested_ints == 0 => break Ok(()),\n                iced_x86::Mnemonic::Iret => nested_ints -= 1,\n                iced_x86::Mnemonic::Int => nested_ints += 1,\n                _ => {}\n            }\n        }\n    }\n\n    /// Apply the given instruction on the current state of the machine.\n    fn run_one(&mut self, instruction: &iced_x86::Instruction) -> Result<(), Error> {\n        if !instruction.has_rep_prefix()\n            && !instruction.has_repe_prefix()\n            && !instruction.has_repne_prefix()\n        {\n            return self.run_one_no_rep(instruction);\n        }\n\n        // At this point we know we have a REP/REPE/REPNE prefix.\n\n        // Determining whether to use CX or ECX is surprinsingly impossible with the iced-x86\n        // library.\n        let use_ecx =\n            (0..instruction.op_count()).any(|op_n| match instruction.try_op_kind(op_n).unwrap() {\n                iced_x86::OpKind::MemorySegEDI => true,\n                iced_x86::OpKind::MemorySegESI => true,\n                iced_x86::OpKind::MemoryESEDI => true,\n                _ => false,\n            });\n\n        loop {\n            if (use_ecx && self.regs.ecx == 0) || (!use_ecx && self.cx() == 0) {\n                break;\n            }\n\n            self.run_one_no_rep(instruction)?;\n\n            if use_ecx {\n                self.regs.ecx = self.regs.ecx.wrapping_sub(1);\n            } else {\n                self.dec_cx();\n            }\n\n            if instruction.has_repne_prefix() && !self.flags_is_zero() {\n                break;\n            }\n\n            // Unfortunately, the REP and REPE prefixes are the same, and which one is which\n            // depends on the mnemonic. This `if` block checks whether we have a REPE prefix, as\n            // opposed to just REP.\n            if let iced_x86::Mnemonic::Cmpsb\n            | iced_x86::Mnemonic::Cmpsd\n            | iced_x86::Mnemonic::Cmpsq\n            | iced_x86::Mnemonic::Cmpss\n            | iced_x86::Mnemonic::Cmpsw\n            | iced_x86::Mnemonic::Scasb\n            | iced_x86::Mnemonic::Scasd\n            | iced_x86::Mnemonic::Scasq\n            | iced_x86::Mnemonic::Scasw = instruction.mnemonic()\n            {\n                if self.flags_is_zero() {\n                    break;\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    /// Same as [`Interpreter::run_one`] but doesn't care about any `REP`/`REPE`/`REPNE` prefix.\n    fn run_one_no_rep(&mut self, instruction: &iced_x86::Instruction) -> Result<(), Error> {\n        if !instruction.op_code().mode16() {\n            return Err(Error::InvalidInstruction);\n        }\n\n        // List here: https://en.wikipedia.org/wiki/X86_instruction_listings#Original_8086/8088_instructions\n        // The objective is to implement up to and including the x386.\n        // TODO: finish implementing all instructions marked as `todo!()`\n        match instruction.mnemonic() {\n            iced_x86::Mnemonic::Aaa => todo!(),\n            iced_x86::Mnemonic::Aad => todo!(),\n            iced_x86::Mnemonic::Aam => todo!(),\n            iced_x86::Mnemonic::Aas => todo!(),\n\n            iced_x86::Mnemonic::Adc | iced_x86::Mnemonic::Add => {\n                let value0 = self.fetch_operand_value(&instruction, 0);\n                let value1 = self.fetch_operand_value(&instruction, 1);\n\n                let carry =\n                    if instruction.mnemonic() == iced_x86::Mnemonic::Adc && self.flags_is_carry() {\n                        1\n                    } else {\n                        0u8\n                    };\n\n                let (temp, overflow) = match (value0, value1) {\n                    (Value::U8(value0), Value::U8(value1)) => {\n                        let (v, o) = value0.overflowing_add(value1);\n                        let (v, o2) = v.overflowing_add(carry);\n                        (Value::U8(v), o || o2)\n                    }\n                    (Value::U16(value0), Value::U16(value1)) => {\n                        let (v, o) = value0.overflowing_add(value1);\n                        let (v, o2) = v.overflowing_add(u16::from(carry));\n                        (Value::U16(v), o || o2)\n                    }\n                    (Value::U32(value0), Value::U32(value1)) => {\n                        let (v, o) = value0.overflowing_add(value1);\n                        let (v, o2) = v.overflowing_add(u32::from(carry));\n                        (Value::U32(v), o || o2)\n                    }\n                    _ => unreachable!(),\n                };\n\n                self.store_in_operand(&instruction, 0, temp);\n\n                self.flags_set_sign_from_val(temp);\n                self.flags_set_zero_from_val(temp);\n                self.flags_set_parity_from_val(temp);\n                self.flags_set_carry(overflow);\n                self.flags_set_overflow(overflow != temp.most_significant_bit());\n                // TODO: the adjust flag\n            }\n\n            iced_x86::Mnemonic::And | iced_x86::Mnemonic::Or | iced_x86::Mnemonic::Xor => {\n                let value0 = self.fetch_operand_value(&instruction, 0);\n                let value1 = self.fetch_operand_value(&instruction, 1);\n\n                let temp = match (value0, value1, instruction.mnemonic()) {\n                    (Value::U8(value0), Value::U8(value1), iced_x86::Mnemonic::And) => {\n                        Value::U8(value0 & value1)\n                    }\n                    (Value::U16(value0), Value::U16(value1), iced_x86::Mnemonic::And) => {\n                        Value::U16(value0 & value1)\n                    }\n                    (Value::U32(value0), Value::U32(value1), iced_x86::Mnemonic::And) => {\n                        Value::U32(value0 & value1)\n                    }\n                    (Value::U8(value0), Value::U8(value1), iced_x86::Mnemonic::Or) => {\n                        Value::U8(value0 | value1)\n                    }\n                    (Value::U16(value0), Value::U16(value1), iced_x86::Mnemonic::Or) => {\n                        Value::U16(value0 | value1)\n                    }\n                    (Value::U32(value0), Value::U32(value1), iced_x86::Mnemonic::Or) => {\n                        Value::U32(value0 | value1)\n                    }\n                    (Value::U8(value0), Value::U8(value1), iced_x86::Mnemonic::Xor) => {\n                        Value::U8(value0 ^ value1)\n                    }\n                    (Value::U16(value0), Value::U16(value1), iced_x86::Mnemonic::Xor) => {\n                        Value::U16(value0 ^ value1)\n                    }\n                    (Value::U32(value0), Value::U32(value1), iced_x86::Mnemonic::Xor) => {\n                        Value::U32(value0 ^ value1)\n                    }\n                    _ => unreachable!(),\n                };\n\n                self.store_in_operand(&instruction, 0, temp);\n\n                self.flags_set_sign_from_val(temp);\n                self.flags_set_zero_from_val(temp);\n                self.flags_set_parity_from_val(temp);\n                self.flags_set_carry(false);\n                self.flags_set_overflow(false);\n                // adjust flag is undefined\n            }\n\n            iced_x86::Mnemonic::Bound => todo!(),\n\n            iced_x86::Mnemonic::Bsf => todo!(),\n            iced_x86::Mnemonic::Bsr => todo!(),\n\n            iced_x86::Mnemonic::Bt => {\n                let value0 = self.fetch_operand_value(&instruction, 0);\n                let value1 = self.fetch_operand_value(&instruction, 1);\n\n                // TODO: might not be correct; there's some weirdness with when it's memory\n                let bit = match (value0, value1) {\n                    (Value::U8(value0), Value::U8(value1)) => {\n                        (value0 & (1u8.wrapping_shl(u32::from(value1)))) != 0\n                    }\n                    (Value::U16(value0), Value::U8(value1)) => {\n                        (value0 & (1u16.wrapping_shl(u32::from(value1)))) != 0\n                    }\n                    (Value::U16(value0), Value::U16(value1)) => {\n                        (value0 & (1u16.wrapping_shl(u32::from(value1)))) != 0\n                    }\n                    (Value::U32(value0), Value::U8(value1)) => {\n                        (value0 & (1u32.wrapping_shl(u32::from(value1)))) != 0\n                    }\n                    (Value::U32(value0), Value::U32(value1)) => {\n                        (value0 & (1u32.wrapping_shl(u32::from(value1)))) != 0\n                    }\n                    _ => unreachable!(),\n                };\n\n                self.flags_set_carry(bit);\n            }\n\n            iced_x86::Mnemonic::Btc => todo!(),\n            iced_x86::Mnemonic::Btr => todo!(),\n            iced_x86::Mnemonic::Bts => todo!(),\n\n            iced_x86::Mnemonic::Call => {\n                match instruction.code() {\n                    iced_x86::Code::Call_ptr1616 | iced_x86::Code::Call_m1616 => {\n                        let ip = self.ip();\n                        self.stack_push_value(Value::U16(self.regs.cs));\n                        self.stack_push_value(Value::U16(ip));\n                    }\n                    iced_x86::Code::Call_rel16 | iced_x86::Code::Call_rm16 => {\n                        let ip = self.ip();\n                        self.stack_push_value(Value::U16(ip));\n                    }\n                    _ => unreachable!(),\n                }\n\n                self.apply_jump(&instruction);\n            }\n\n            iced_x86::Mnemonic::Cbw => {\n                let al = u8::try_from(self.register(iced_x86::Register::AL)).unwrap();\n                let msb = (al & 0x80) != 0;\n                if msb {\n                    self.set_ax(0xff00 | u16::from(al));\n                } else {\n                    self.set_ax(u16::from(al));\n                }\n            }\n\n            iced_x86::Mnemonic::Cwde => {\n                let ax = u16::try_from(self.register(iced_x86::Register::AX)).unwrap();\n                let msb = (ax & 0x8000) != 0;\n                if msb {\n                    self.regs.eax = 0xffff0000 | u32::from(ax);\n                } else {\n                    self.regs.eax = u32::from(ax);\n                }\n            }\n\n            iced_x86::Mnemonic::Cwd => {\n                if self.register(iced_x86::Register::AX).most_significant_bit() {\n                    self.store_in_register(iced_x86::Register::DX, Value::U16(0xffff))\n                } else {\n                    self.store_in_register(iced_x86::Register::DX, Value::U16(0x0000))\n                }\n            }\n\n            iced_x86::Mnemonic::Cdq => {\n                if self\n                    .register(iced_x86::Register::EAX)\n                    .most_significant_bit()\n                {\n                    self.store_in_register(iced_x86::Register::EDX, Value::U32(0xffffffff))\n                } else {\n                    self.store_in_register(iced_x86::Register::EDX, Value::U32(0x00000000))\n                }\n            }\n\n            iced_x86::Mnemonic::Clc => self.flags_set_carry(false),\n            iced_x86::Mnemonic::Cld => self.flags_set_direction(false),\n            iced_x86::Mnemonic::Cli => self.flags_set_interrupt(false),\n            iced_x86::Mnemonic::Cmc => self.flags_set_carry(!self.flags_is_carry()),\n\n            iced_x86::Mnemonic::Cmp => {\n                let value0 = self.fetch_operand_value(&instruction, 0);\n                let value1 = self.fetch_operand_value(&instruction, 1);\n\n                let (temp, overflow) = match (value0, value1) {\n                    (Value::U8(value0), Value::U8(value1)) => {\n                        let (v, o) = value0.overflowing_sub(value1);\n                        (Value::U8(v), o)\n                    }\n                    (Value::U16(value0), Value::U16(value1)) => {\n                        let (v, o) = value0.overflowing_sub(value1);\n                        (Value::U16(v), o)\n                    }\n                    (Value::U32(value0), Value::U32(value1)) => {\n                        let (v, o) = value0.overflowing_sub(value1);\n                        (Value::U32(v), o)\n                    }\n                    _ => unreachable!(),\n                };\n\n                self.flags_set_sign_from_val(temp);\n                self.flags_set_zero_from_val(temp);\n                self.flags_set_parity_from_val(temp);\n                self.flags_set_carry(overflow);\n                self.flags_set_overflow(overflow != temp.most_significant_bit());\n                // TODO: the adjust flag\n            }\n\n            iced_x86::Mnemonic::Cmpsb | iced_x86::Mnemonic::Cmpsw | iced_x86::Mnemonic::Cmpsd => {\n                todo!()\n            }\n\n            iced_x86::Mnemonic::Daa => todo!(),\n            iced_x86::Mnemonic::Das => todo!(),\n\n            iced_x86::Mnemonic::Dec => {\n                let value = self.fetch_operand_value(&instruction, 0);\n                let (temp, overflow) = match value {\n                    Value::U8(value) => {\n                        let (v, o) = value.overflowing_sub(1);\n                        (Value::U8(v), o)\n                    }\n                    Value::U16(value) => {\n                        let (v, o) = value.overflowing_sub(1);\n                        (Value::U16(v), o)\n                    }\n                    Value::U32(value) => {\n                        let (v, o) = value.overflowing_sub(1);\n                        (Value::U32(v), o)\n                    }\n                };\n\n                self.store_in_operand(&instruction, 0, temp);\n\n                self.flags_set_sign_from_val(temp);\n                self.flags_set_zero_from_val(temp);\n                self.flags_set_parity_from_val(temp);\n                self.flags_set_overflow(overflow != temp.most_significant_bit());\n                // TODO: the adjust flag\n                // Carry flag is not affected.\n            }\n\n            iced_x86::Mnemonic::Div => {\n                // TODO: no check for division by zero\n                match self.fetch_operand_value(&instruction, 0) {\n                    Value::U8(divisor) => {\n                        let dividend = u16::try_from(self.regs.eax & 0xffff).unwrap();\n                        let divisor = u16::from(divisor);\n                        let quotient = u8::try_from((dividend / divisor) & 0xff).unwrap();\n                        let remainder = u8::try_from(dividend % divisor).unwrap();\n                        self.store_in_register(iced_x86::Register::AL, Value::U8(quotient));\n                        self.store_in_register(iced_x86::Register::AH, Value::U8(remainder));\n                    }\n                    Value::U16(divisor) => {\n                        let dividend = u32::try_from(\n                            ((self.regs.edx & 0xffff) << 16) | (self.regs.eax & 0xffff),\n                        )\n                        .unwrap();\n                        let divisor = u32::from(divisor);\n                        let quotient = u16::try_from((dividend / divisor) & 0xffff).unwrap();\n                        let remainder = u16::try_from(dividend % divisor).unwrap();\n                        self.store_in_register(iced_x86::Register::AX, Value::U16(quotient));\n                        self.store_in_register(iced_x86::Register::DX, Value::U16(remainder));\n                    }\n                    Value::U32(divisor) => {\n                        let dividend = (u64::from(self.regs.edx) << 32) | u64::from(self.regs.eax);\n                        let divisor = u64::from(divisor);\n                        let quotient = u32::try_from((dividend / divisor) & 0xffffffff).unwrap();\n                        let remainder = u32::try_from(dividend % divisor).unwrap();\n                        self.regs.eax = quotient;\n                        self.regs.edx = remainder;\n                    }\n                }\n            }\n\n            iced_x86::Mnemonic::Enter => todo!(),\n\n            iced_x86::Mnemonic::Hlt => return Err(Error::InterruptNotSupported),\n\n            iced_x86::Mnemonic::Idiv => {\n                // TODO: no check for division by zero\n                match self.fetch_operand_value(&instruction, 0) {\n                    Value::U8(divisor) => {\n                        let dividend = i16::from_ne_bytes(self.ax().to_ne_bytes());\n                        let divisor = i16::from_ne_bytes(\n                            (i16::from(i8::from_ne_bytes(divisor.to_ne_bytes()))).to_ne_bytes(),\n                        );\n                        let quotient = u16::from_ne_bytes((dividend / divisor).to_ne_bytes());\n                        let quotient = u8::try_from(quotient & 0xff).unwrap();\n                        let remainder = u16::from_ne_bytes((dividend % divisor).to_ne_bytes());\n                        let remainder = u8::try_from(remainder & 0xff).unwrap();\n                        self.store_in_register(iced_x86::Register::AL, Value::U8(quotient));\n                        self.store_in_register(iced_x86::Register::AH, Value::U8(remainder));\n                    }\n                    Value::U16(divisor) => {\n                        let dividend = i32::from_ne_bytes(\n                            ((u32::from(self.dx()) << 16) | u32::from(self.ax())).to_ne_bytes(),\n                        );\n                        let divisor = i32::from(i16::from_ne_bytes(divisor.to_ne_bytes()));\n                        let quotient = u32::from_ne_bytes((dividend / divisor).to_ne_bytes());\n                        let quotient = u16::try_from(quotient & 0xffff).unwrap();\n                        let remainder = u32::from_ne_bytes((dividend % divisor).to_ne_bytes());\n                        let remainder = u16::try_from(remainder & 0xffff).unwrap();\n                        self.store_in_register(iced_x86::Register::AX, Value::U16(quotient));\n                        self.store_in_register(iced_x86::Register::DX, Value::U16(remainder));\n                    }\n                    Value::U32(divisor) => {\n                        let dividend = i64::from_ne_bytes(\n                            ((u64::from(self.regs.edx) << 32) | u64::from(self.regs.eax))\n                                .to_ne_bytes(),\n                        );\n                        let divisor = i64::from(i32::from_ne_bytes(divisor.to_ne_bytes()));\n                        let quotient = u64::from_ne_bytes((dividend / divisor).to_ne_bytes());\n                        let quotient = u32::try_from(quotient & 0xffffffff).unwrap();\n                        let remainder = u64::from_ne_bytes((dividend % divisor).to_ne_bytes());\n                        let remainder = u32::try_from(remainder & 0xffffffff).unwrap();\n                        self.regs.eax = quotient;\n                        self.regs.edx = remainder;\n                    }\n                }\n\n                // Flags are undefined.\n            }\n\n            iced_x86::Mnemonic::Imul => {\n                let (to_mul1, to_mul2) = if instruction.op_count() == 3 {\n                    let value1 = self.fetch_operand_value(&instruction, 1);\n                    let value2 = self.fetch_operand_value(&instruction, 2);\n                    (value1, value2)\n                } else {\n                    // TODO: is that correct when op_count() == 1?\n                    let value0 = self.fetch_operand_value(&instruction, 0);\n                    let value1 = self.fetch_operand_value(&instruction, 1);\n                    (value0, value1)\n                };\n\n                // Signed multiplication of `to_mul1` and `to_mul2`. The highest and lowest half\n                // of the result in `result_hi` and `result_lo` are reinterpreted as unsigned\n                // integers.\n                let (result_hi, result_lo) = match (to_mul1, to_mul2) {\n                    (Value::U8(to_mul1), Value::U8(to_mul2)) => {\n                        let to_mul1 = i16::from(i8::from_ne_bytes(to_mul1.to_ne_bytes()));\n                        let to_mul2 = i16::from(i8::from_ne_bytes(to_mul2.to_ne_bytes()));\n                        let result = to_mul1.checked_mul(to_mul2).unwrap();\n                        let result = u16::from_ne_bytes(result.to_ne_bytes());\n                        let result_lo = u8::try_from(result & 0xff).unwrap();\n                        let result_hi = u8::try_from(result >> 8).unwrap();\n                        (Value::U8(result_hi), Value::U8(result_lo))\n                    }\n                    (Value::U16(to_mul1), Value::U16(to_mul2)) => {\n                        let to_mul1 = i32::from(i16::from_ne_bytes(to_mul1.to_ne_bytes()));\n                        let to_mul2 = i32::from(i16::from_ne_bytes(to_mul2.to_ne_bytes()));\n                        let result = to_mul1.checked_mul(to_mul2).unwrap();\n                        let result = u32::from_ne_bytes(result.to_ne_bytes());\n                        let result_lo = u16::try_from(result & 0xffff).unwrap();\n                        let result_hi = u16::try_from(result >> 16).unwrap();\n                        (Value::U16(result_hi), Value::U16(result_lo))\n                    }\n                    (Value::U32(to_mul1), Value::U32(to_mul2)) => {\n                        let to_mul1 = i64::from(i32::from_ne_bytes(to_mul1.to_ne_bytes()));\n                        let to_mul2 = i64::from(i32::from_ne_bytes(to_mul2.to_ne_bytes()));\n                        let result = to_mul1.checked_mul(to_mul2).unwrap();\n                        let result = u64::from_ne_bytes(result.to_ne_bytes());\n                        let result_lo = u32::try_from(result & 0xffffffff).unwrap();\n                        let result_hi = u32::try_from(result >> 32).unwrap();\n                        (Value::U32(result_hi), Value::U32(result_lo))\n                    }\n                    _ => unreachable!(),\n                };\n\n                self.store_in_operand(&instruction, 0, result_lo);\n\n                match instruction.code() {\n                    iced_x86::Code::Imul_rm8 => {\n                        self.store_in_register(iced_x86::Register::AH, result_hi);\n                    }\n                    iced_x86::Code::Imul_rm16 => {\n                        self.store_in_register(iced_x86::Register::DX, result_hi);\n                    }\n                    iced_x86::Code::Imul_rm32 => {\n                        self.store_in_register(iced_x86::Register::EDX, result_hi);\n                    }\n                    _ => {}\n                };\n\n                // \"The CF and OF flags are set when the signed integer value of the intermediate\n                // product differs from the sign extended operand-size-truncated product, otherwise\n                // the CF and OF flags are cleared.\" - Intel manual\n                let overflow = if result_lo.most_significant_bit() {\n                    !result_hi.is_max_value()\n                } else {\n                    !result_hi.is_zero()\n                };\n\n                self.flags_set_carry(overflow);\n                self.flags_set_overflow(overflow);\n                // Sign, zero, parity and adjust flags are undefined.\n            }\n\n            iced_x86::Mnemonic::In => {\n                let port = match self.fetch_operand_value(&instruction, 1) {\n                    Value::U8(p) => u16::from(p),\n                    Value::U16(p) => p,\n                    _ => unreachable!(),\n                };\n\n                let data = if self.enable_io_operations {\n                    match self.fetch_operand_value(&instruction, 0) {\n                        Value::U8(_) => Value::U8(unsafe {\n                            redshirt_syscalls::block_on(redshirt_hardware_interface::port_read_u8(\n                                u32::from(port),\n                            ))\n                        }),\n                        Value::U16(_) => Value::U16(unsafe {\n                            redshirt_syscalls::block_on(redshirt_hardware_interface::port_read_u16(\n                                u32::from(port),\n                            ))\n                        }),\n                        Value::U32(_) => Value::U32(unsafe {\n                            redshirt_syscalls::block_on(redshirt_hardware_interface::port_read_u32(\n                                u32::from(port),\n                            ))\n                        }),\n                    }\n                } else {\n                    match self.fetch_operand_value(&instruction, 0) {\n                        Value::U8(_) => Value::U8(0),\n                        Value::U16(_) => Value::U16(0),\n                        Value::U32(_) => Value::U32(0),\n                    }\n                };\n\n                self.store_in_operand(&instruction, 0, data);\n            }\n\n            iced_x86::Mnemonic::Inc => {\n                let value = self.fetch_operand_value(&instruction, 0);\n                let (temp, overflow) = match value {\n                    Value::U8(value) => {\n                        let (v, o) = value.overflowing_add(1);\n                        (Value::U8(v), o)\n                    }\n                    Value::U16(value) => {\n                        let (v, o) = value.overflowing_add(1);\n                        (Value::U16(v), o)\n                    }\n                    Value::U32(value) => {\n                        let (v, o) = value.overflowing_add(1);\n                        (Value::U32(v), o)\n                    }\n                };\n\n                self.store_in_operand(&instruction, 0, temp);\n\n                self.flags_set_sign_from_val(temp);\n                self.flags_set_zero_from_val(temp);\n                self.flags_set_parity_from_val(temp);\n                self.flags_set_overflow(overflow != temp.most_significant_bit());\n                // TODO: the adjust flag\n                // Carry flag is not affected.\n            }\n\n            iced_x86::Mnemonic::Insb | iced_x86::Mnemonic::Insd | iced_x86::Mnemonic::Insw => {\n                todo!()\n            }\n\n            iced_x86::Mnemonic::Int => {\n                let value = self.fetch_operand_value(&instruction, 0);\n                self.run_int_opcode(u8::try_from(value).unwrap());\n                log::info!(\"Int 0x{:x}\", u8::try_from(value).unwrap());\n            }\n\n            iced_x86::Mnemonic::Into => todo!(),\n\n            iced_x86::Mnemonic::Iret => {\n                let ip = self.stack_pop_u16();\n                self.regs.eip = u32::from(ip);\n                let cs = self.stack_pop_u16();\n                self.regs.cs = cs;\n\n                let val = self.stack_pop_u16();\n                self.regs.flags &= 0b01000000000101010;\n                self.regs.flags |= val & 0b0111111111010101;\n            }\n\n            iced_x86::Mnemonic::Ja\n            | iced_x86::Mnemonic::Jae\n            | iced_x86::Mnemonic::Jb\n            | iced_x86::Mnemonic::Jbe\n            | iced_x86::Mnemonic::Jcxz\n            | iced_x86::Mnemonic::Je\n            | iced_x86::Mnemonic::Jecxz\n            | iced_x86::Mnemonic::Jg\n            | iced_x86::Mnemonic::Jge\n            | iced_x86::Mnemonic::Jl\n            | iced_x86::Mnemonic::Jle\n            | iced_x86::Mnemonic::Jne\n            | iced_x86::Mnemonic::Jno\n            | iced_x86::Mnemonic::Jnp\n            | iced_x86::Mnemonic::Jns\n            | iced_x86::Mnemonic::Jo\n            | iced_x86::Mnemonic::Jp\n            | iced_x86::Mnemonic::Js => {\n                debug_assert!(!matches!(\n                    instruction.condition_code(),\n                    iced_x86::ConditionCode::None\n                ));\n                if self.flags_check_condition(instruction.condition_code()) {\n                    self.apply_jump(&instruction);\n                }\n            }\n\n            iced_x86::Mnemonic::Jmp => {\n                self.apply_jump(&instruction);\n            }\n\n            iced_x86::Mnemonic::Lahf => todo!(),\n            iced_x86::Mnemonic::Lar => todo!(),\n\n            iced_x86::Mnemonic::Lea => {\n                let ptr = self.memory_operand_pointer(&instruction, 1);\n                self.store_in_operand(&instruction, 0, Value::U16(ptr));\n            }\n\n            iced_x86::Mnemonic::Leave => todo!(),\n\n            iced_x86::Mnemonic::Lgs\n            | iced_x86::Mnemonic::Lss\n            | iced_x86::Mnemonic::Lds\n            | iced_x86::Mnemonic::Les\n            | iced_x86::Mnemonic::Lfs => todo!(),\n\n            iced_x86::Mnemonic::Lodsb => {\n                // TODO: review this\n                let val = self.fetch_operand_value(&instruction, 1);\n\n                let use_esi = match instruction.try_op_kind(1).unwrap() {\n                    iced_x86::OpKind::MemorySegSI => false,\n                    iced_x86::OpKind::MemorySegESI => true,\n                    _ => unreachable!(),\n                };\n\n                self.store_in_operand(&instruction, 0, val);\n\n                if use_esi {\n                    if self.flags_is_direction() {\n                        self.regs.esi = self.regs.esi.wrapping_sub(u32::from(val.size()));\n                    } else {\n                        self.regs.esi = self.regs.esi.wrapping_add(u32::from(val.size()));\n                    }\n                } else {\n                    if self.flags_is_direction() {\n                        self.sub_si(u16::from(val.size()));\n                    } else {\n                        self.add_si(u16::from(val.size()));\n                    }\n                }\n            }\n\n            iced_x86::Mnemonic::Lodsw | iced_x86::Mnemonic::Lodsd => todo!(),\n\n            iced_x86::Mnemonic::Loop | iced_x86::Mnemonic::Loope | iced_x86::Mnemonic::Loopne => {\n                let use_ecx = match instruction.code() {\n                    iced_x86::Code::Loop_rel8_16_CX => false,\n                    iced_x86::Code::Loop_rel8_32_CX => false,\n                    iced_x86::Code::Loop_rel8_16_ECX => true,\n                    iced_x86::Code::Loop_rel8_32_ECX => true,\n                    iced_x86::Code::Loop_rel8_64_ECX => true,\n                    iced_x86::Code::Loope_rel8_16_CX => false,\n                    iced_x86::Code::Loope_rel8_32_CX => false,\n                    iced_x86::Code::Loope_rel8_16_ECX => true,\n                    iced_x86::Code::Loope_rel8_32_ECX => true,\n                    iced_x86::Code::Loope_rel8_64_ECX => true,\n                    iced_x86::Code::Loopne_rel8_16_CX => false,\n                    iced_x86::Code::Loopne_rel8_32_CX => false,\n                    iced_x86::Code::Loopne_rel8_16_ECX => true,\n                    iced_x86::Code::Loopne_rel8_32_ECX => true,\n                    iced_x86::Code::Loopne_rel8_64_ECX => true,\n                    _ => false,\n                };\n\n                let is_zero = if use_ecx {\n                    self.regs.ecx = self.regs.ecx.wrapping_sub(1);\n                    self.regs.ecx == 0\n                } else {\n                    let cx = self.cx();\n                    let cx = cx.wrapping_sub(1);\n                    self.set_cx(cx);\n                    cx == 0\n                };\n\n                let could_jump = match instruction.mnemonic() {\n                    iced_x86::Mnemonic::Loop => true,\n                    iced_x86::Mnemonic::Loope => self.flags_is_zero(),\n                    iced_x86::Mnemonic::Loopne => !self.flags_is_zero(),\n                    _ => unreachable!(),\n                };\n\n                if !is_zero && could_jump {\n                    self.apply_jump(&instruction);\n                }\n            }\n\n            iced_x86::Mnemonic::Mov => {\n                // When executing `mov reg, sreg`, the upper bits of `reg` are zeroed on modern\n                // processors.\n                if let iced_x86::OpKind::Register = instruction.try_op_kind(1).unwrap() {\n                    match instruction.try_op_register(1).unwrap() {\n                        iced_x86::Register::ES\n                        | iced_x86::Register::CS\n                        | iced_x86::Register::SS\n                        | iced_x86::Register::DS\n                        | iced_x86::Register::FS\n                        | iced_x86::Register::GS => match self.operand_size(&instruction, 0) {\n                            2 => {}\n                            4 => self.store_in_operand(&instruction, 0, Value::U32(0)),\n                            _ => unreachable!(),\n                        },\n                        _ => {}\n                    }\n                }\n\n                let value = self.fetch_operand_value(&instruction, 1);\n                self.store_in_operand(&instruction, 0, value);\n            }\n\n            iced_x86::Mnemonic::Movsb | iced_x86::Mnemonic::Movsw | iced_x86::Mnemonic::Movsd => {\n                todo!()\n            }\n\n            iced_x86::Mnemonic::Movsx => {\n                let value = self.fetch_operand_value(&instruction, 1);\n                let msb = value.most_significant_bit();\n\n                match (self.operand_size(&instruction, 0), value, msb) {\n                    (2, Value::U8(v), true) => {\n                        self.store_in_operand(&instruction, 0, Value::U16(0xff | u16::from(v)))\n                    }\n                    (2, Value::U8(v), false) => {\n                        self.store_in_operand(&instruction, 0, Value::U16(u16::from(v)))\n                    }\n                    (4, Value::U8(v), true) => {\n                        self.store_in_operand(&instruction, 0, Value::U32(0xffffff | u32::from(v)))\n                    }\n                    (4, Value::U8(v), false) => {\n                        self.store_in_operand(&instruction, 0, Value::U32(u32::from(v)))\n                    }\n                    (4, Value::U16(v), true) => {\n                        self.store_in_operand(&instruction, 0, Value::U32(0xffff | u32::from(v)))\n                    }\n                    (4, Value::U16(v), false) => {\n                        self.store_in_operand(&instruction, 0, Value::U32(u32::from(v)))\n                    }\n                    _ => unreachable!(),\n                }\n            }\n\n            iced_x86::Mnemonic::Movzx => {\n                let value = self.fetch_operand_value(&instruction, 1);\n\n                match (self.operand_size(&instruction, 0), value) {\n                    (2, Value::U8(v)) => {\n                        self.store_in_operand(&instruction, 0, Value::U16(u16::from(v)))\n                    }\n                    (4, Value::U8(v)) => {\n                        self.store_in_operand(&instruction, 0, Value::U32(u32::from(v)))\n                    }\n                    (4, Value::U16(v)) => {\n                        self.store_in_operand(&instruction, 0, Value::U32(u32::from(v)))\n                    }\n                    _ => unreachable!(),\n                }\n            }\n\n            iced_x86::Mnemonic::Mul => {\n                let value = self.fetch_operand_value(&instruction, 0);\n\n                let (result_hi, result_lo) = match value {\n                    Value::U8(to_mul1) => {\n                        let to_mul1 = u16::from(to_mul1);\n                        let to_mul2 =\n                            u16::from(u8::try_from(self.register(iced_x86::Register::AL)).unwrap());\n                        let result = to_mul1.checked_mul(to_mul2).unwrap();\n                        let result_lo = u8::try_from(result & 0xff).unwrap();\n                        let result_hi = u8::try_from(result >> 8).unwrap();\n                        (Value::U8(result_hi), Value::U8(result_lo))\n                    }\n                    Value::U16(to_mul1) => {\n                        let to_mul1 = u32::from(to_mul1);\n                        let to_mul2 = u32::from(self.ax());\n                        let result = to_mul1.checked_mul(to_mul2).unwrap();\n                        let result_lo = u16::try_from(result & 0xffff).unwrap();\n                        let result_hi = u16::try_from(result >> 16).unwrap();\n                        (Value::U16(result_hi), Value::U16(result_lo))\n                    }\n                    Value::U32(to_mul1) => {\n                        let to_mul1 = u64::from(to_mul1);\n                        let to_mul2 = u64::from(self.regs.eax);\n                        let result = to_mul1.checked_mul(to_mul2).unwrap();\n                        let result_lo = u32::try_from(result & 0xffffffff).unwrap();\n                        let result_hi = u32::try_from(result >> 32).unwrap();\n                        (Value::U32(result_hi), Value::U32(result_lo))\n                    }\n                };\n\n                self.store_in_operand(&instruction, 0, result_lo);\n\n                match result_hi {\n                    v @ Value::U8(_) => self.store_in_register(iced_x86::Register::AH, v),\n                    v @ Value::U16(_) => self.store_in_register(iced_x86::Register::DX, v),\n                    v @ Value::U32(_) => self.store_in_register(iced_x86::Register::EDX, v),\n                }\n\n                self.flags_set_carry(!result_hi.is_zero());\n                self.flags_set_overflow(!result_hi.is_zero());\n                // Sign, zero, parity and adjust flags are undefined.\n            }\n\n            iced_x86::Mnemonic::Nop => {}\n\n            iced_x86::Mnemonic::Not => {\n                let value = self.fetch_operand_value(&instruction, 0);\n                let result = match value {\n                    Value::U8(value) => Value::U8(!value),\n                    Value::U16(value) => Value::U16(!value),\n                    Value::U32(value) => Value::U32(!value),\n                };\n                self.store_in_operand(&instruction, 0, result);\n            }\n\n            iced_x86::Mnemonic::Out => {\n                let port = match self.fetch_operand_value(&instruction, 0) {\n                    Value::U8(p) => u16::from(p),\n                    Value::U16(p) => p,\n                    _ => unreachable!(),\n                };\n\n                if self.enable_io_operations {\n                    match self.fetch_operand_value(&instruction, 1) {\n                        Value::U8(data) => unsafe {\n                            redshirt_hardware_interface::port_write_u8(u32::from(port), data);\n                        },\n                        Value::U16(data) => unsafe {\n                            redshirt_hardware_interface::port_write_u16(u32::from(port), data);\n                        },\n                        Value::U32(data) => unsafe {\n                            redshirt_hardware_interface::port_write_u32(u32::from(port), data);\n                        },\n                    }\n                }\n            }\n\n            iced_x86::Mnemonic::Outsb | iced_x86::Mnemonic::Outsw | iced_x86::Mnemonic::Outsd => {\n                todo!()\n            }\n\n            iced_x86::Mnemonic::Pop => match self.operand_size(&instruction, 0) {\n                1 => {\n                    let val = Value::U8(self.stack_pop_u8());\n                    self.store_in_operand(&instruction, 0, val);\n                }\n                2 => {\n                    let val = Value::U16(self.stack_pop_u16());\n                    self.store_in_operand(&instruction, 0, val);\n                }\n                4 => {\n                    let val = Value::U32(self.stack_pop_u32());\n                    self.store_in_operand(&instruction, 0, val);\n                }\n                _ => unreachable!(),\n            },\n\n            iced_x86::Mnemonic::Popa => match instruction.code() {\n                iced_x86::Code::Popaw => {\n                    let val = Value::U16(self.stack_pop_u16());\n                    self.store_in_register(iced_x86::Register::DI, val);\n                    let val = Value::U16(self.stack_pop_u16());\n                    self.store_in_register(iced_x86::Register::SI, val);\n                    let val = Value::U16(self.stack_pop_u16());\n                    self.store_in_register(iced_x86::Register::BP, val);\n                    let _ = self.stack_pop_u16();\n                    let val = Value::U16(self.stack_pop_u16());\n                    self.store_in_register(iced_x86::Register::BX, val);\n                    let val = Value::U16(self.stack_pop_u16());\n                    self.store_in_register(iced_x86::Register::DX, val);\n                    let val = Value::U16(self.stack_pop_u16());\n                    self.store_in_register(iced_x86::Register::CX, val);\n                    let val = Value::U16(self.stack_pop_u16());\n                    self.store_in_register(iced_x86::Register::AX, val);\n                }\n                iced_x86::Code::Popad => {\n                    let val = Value::U32(self.stack_pop_u32());\n                    self.store_in_register(iced_x86::Register::EDI, val);\n                    let val = Value::U32(self.stack_pop_u32());\n                    self.store_in_register(iced_x86::Register::ESI, val);\n                    let val = Value::U32(self.stack_pop_u32());\n                    self.store_in_register(iced_x86::Register::EBP, val);\n                    let _ = self.stack_pop_u32();\n                    let val = Value::U32(self.stack_pop_u32());\n                    self.store_in_register(iced_x86::Register::EBX, val);\n                    let val = Value::U32(self.stack_pop_u32());\n                    self.store_in_register(iced_x86::Register::EDX, val);\n                    let val = Value::U32(self.stack_pop_u32());\n                    self.store_in_register(iced_x86::Register::ECX, val);\n                    let val = Value::U32(self.stack_pop_u32());\n                    self.store_in_register(iced_x86::Register::EAX, val);\n                }\n                _ => unreachable!(),\n            },\n\n            iced_x86::Mnemonic::Popf => match instruction.code() {\n                iced_x86::Code::Popfw => {\n                    let val = self.stack_pop_u16();\n                    self.regs.flags &= 0b01000000000101010;\n                    self.regs.flags |= val & 0b0111111111010101;\n                }\n                iced_x86::Code::Popfd => todo!(),\n                _ => unreachable!(),\n            },\n\n            iced_x86::Mnemonic::Push => {\n                let value = self.fetch_operand_value(&instruction, 0);\n                self.stack_push_value(value);\n            }\n\n            iced_x86::Mnemonic::Pusha => match instruction.code() {\n                iced_x86::Code::Pushaw => {\n                    let sp = self.register(iced_x86::Register::SP);\n                    self.stack_push_value(self.register(iced_x86::Register::AX));\n                    self.stack_push_value(self.register(iced_x86::Register::CX));\n                    self.stack_push_value(self.register(iced_x86::Register::DX));\n                    self.stack_push_value(self.register(iced_x86::Register::BX));\n                    self.stack_push_value(sp);\n                    self.stack_push_value(self.register(iced_x86::Register::BP));\n                    self.stack_push_value(self.register(iced_x86::Register::SI));\n                    self.stack_push_value(self.register(iced_x86::Register::DI));\n                }\n                iced_x86::Code::Pushad => {\n                    let esp = self.register(iced_x86::Register::ESP);\n                    self.stack_push_value(self.register(iced_x86::Register::EAX));\n                    self.stack_push_value(self.register(iced_x86::Register::ECX));\n                    self.stack_push_value(self.register(iced_x86::Register::EDX));\n                    self.stack_push_value(self.register(iced_x86::Register::EBX));\n                    self.stack_push_value(esp);\n                    self.stack_push_value(self.register(iced_x86::Register::EBP));\n                    self.stack_push_value(self.register(iced_x86::Register::ESI));\n                    self.stack_push_value(self.register(iced_x86::Register::EDI));\n                }\n                _ => unreachable!(),\n            },\n\n            iced_x86::Mnemonic::Pushf => match instruction.code() {\n                iced_x86::Code::Pushfw => {\n                    self.stack_push_value(Value::U16(self.regs.flags));\n                }\n                iced_x86::Code::Pushfd => todo!(),\n                _ => unreachable!(),\n            },\n\n            iced_x86::Mnemonic::Rcl\n            | iced_x86::Mnemonic::Rcr\n            | iced_x86::Mnemonic::Rol\n            | iced_x86::Mnemonic::Ror => {\n                let mut value = self.fetch_operand_value(&instruction, 0);\n                let count =\n                    u8::try_from(self.fetch_operand_value(&instruction, 1)).unwrap() & 0b11111;\n                let use_carry = matches!(\n                    instruction.mnemonic(),\n                    iced_x86::Mnemonic::Rcl | iced_x86::Mnemonic::Rcr\n                );\n                let dir_right = matches!(\n                    instruction.mnemonic(),\n                    iced_x86::Mnemonic::Rcr | iced_x86::Mnemonic::Ror\n                );\n\n                for _ in 0..count {\n                    match (&mut value, dir_right) {\n                        (Value::U8(v), false) => {\n                            let bit = (*v >> 7) != 0;\n                            *v = v.wrapping_mul(2);\n                            let rotated = if use_carry {\n                                self.flags_is_carry()\n                            } else {\n                                bit\n                            };\n                            *v |= if rotated { 1 } else { 0 };\n                            self.flags_set_overflow(bit != (((*v >> 7) & 0x1) != 0));\n                            self.flags_set_carry(bit);\n                        }\n                        (Value::U8(v), true) => {\n                            let bit = (*v & 0x1) != 0;\n                            *v = *v / 2;\n                            let rotated = if use_carry {\n                                self.flags_is_carry()\n                            } else {\n                                bit\n                            };\n                            *v |= if rotated { 1 } else { 0 } << 7;\n                            self.flags_set_overflow(if use_carry {\n                                self.flags_is_carry() != bit\n                            } else {\n                                bit != (((*v >> 6) & 0x1) != 0)\n                            });\n                            self.flags_set_carry(bit);\n                        }\n                        (Value::U16(v), false) => {\n                            let bit = (*v >> 15) != 0;\n                            *v = v.wrapping_mul(2);\n                            let rotated = if use_carry {\n                                self.flags_is_carry()\n                            } else {\n                                bit\n                            };\n                            *v |= if rotated { 1 } else { 0 };\n                            self.flags_set_overflow(bit != (((*v >> 15) & 0x1) != 0));\n                            self.flags_set_carry(bit);\n                        }\n                        (Value::U16(v), true) => {\n                            let bit = (*v & 0x1) != 0;\n                            *v = *v / 2;\n                            let rotated = if use_carry {\n                                self.flags_is_carry()\n                            } else {\n                                bit\n                            };\n                            *v |= if rotated { 1 } else { 0 } << 15;\n                            self.flags_set_overflow(if use_carry {\n                                self.flags_is_carry() != bit\n                            } else {\n                                bit != (((*v >> 14) & 0x1) != 0)\n                            });\n                            self.flags_set_carry(bit);\n                        }\n                        (Value::U32(v), false) => {\n                            let bit = (*v >> 31) != 0;\n                            *v = v.wrapping_mul(2);\n                            let rotated = if use_carry {\n                                self.flags_is_carry()\n                            } else {\n                                bit\n                            };\n                            *v |= if rotated { 1 } else { 0 };\n                            self.flags_set_overflow(bit != (((*v >> 31) & 0x1) != 0));\n                            self.flags_set_carry(bit);\n                        }\n                        (Value::U32(v), true) => {\n                            let bit = (*v & 0x1) != 0;\n                            *v = *v / 2;\n                            let rotated = if use_carry {\n                                self.flags_is_carry()\n                            } else {\n                                bit\n                            };\n                            *v |= if rotated { 1 } else { 0 } << 31;\n                            self.flags_set_overflow(if use_carry {\n                                self.flags_is_carry() != bit\n                            } else {\n                                bit != (((*v >> 30) & 0x1) != 0)\n                            });\n                            self.flags_set_carry(bit);\n                        }\n                    }\n                }\n\n                // OF is defined for some variants and undefined for others, so we don't\n                // distinguish between these.\n            }\n\n            iced_x86::Mnemonic::Ret => {\n                // The `ret` opcode can be followed by a number of bytes to pop from the stack\n                // on top of `cs`/`ip`/`eip`.\n                let num_to_pop = if instruction.op_count() == 1 {\n                    self.fetch_operand_value(&instruction, 0)\n                        .zero_extend_to_u32()\n                } else {\n                    0\n                };\n\n                match instruction.code() {\n                    iced_x86::Code::Retnw_imm16 | iced_x86::Code::Retnw => {\n                        let ip = self.stack_pop_u16();\n                        self.regs.eip = u32::from(ip);\n                    }\n                    iced_x86::Code::Retfw_imm16 | iced_x86::Code::Retfw => {\n                        let ip = self.stack_pop_u16();\n                        self.regs.eip = u32::from(ip);\n                        let cs = self.stack_pop_u16();\n                        self.regs.cs = cs;\n                    }\n                    _ => unreachable!(),\n                }\n\n                for _ in 0..num_to_pop {\n                    let _ = self.stack_pop_u8();\n                }\n            }\n\n            iced_x86::Mnemonic::Sahf => {\n                self.flags_set_sign(self.regs.eax & (1 << 7) != 0);\n                self.flags_set_zero(self.regs.eax & (1 << 6) != 0);\n                self.flags_set_adjust(self.regs.eax & (1 << 4) != 0);\n                self.flags_set_parity(self.regs.eax & (1 << 2) != 0);\n                self.flags_set_carry(self.regs.eax & (1 << 0) != 0);\n            }\n\n            iced_x86::Mnemonic::Sal\n            | iced_x86::Mnemonic::Sar\n            | iced_x86::Mnemonic::Shl\n            | iced_x86::Mnemonic::Shr => {\n                assert_eq!(instruction.op_count(), 2);\n                let mut value0 = self.fetch_operand_value(&instruction, 0);\n                let value1 = self.fetch_operand_value(&instruction, 1);\n\n                for _ in 0..value1.zero_extend_to_u32() {\n                    if matches!(\n                        instruction.mnemonic(),\n                        iced_x86::Mnemonic::Sal | iced_x86::Mnemonic::Shl\n                    ) {\n                        self.flags_set_carry(value0.most_significant_bit());\n                    } else {\n                        self.flags_set_carry(value0.least_significant_bit());\n                    }\n\n                    if matches!(\n                        instruction.mnemonic(),\n                        iced_x86::Mnemonic::Sal | iced_x86::Mnemonic::Shl\n                    ) {\n                        value0 = match value0 {\n                            Value::U8(v) => Value::U8(v.wrapping_mul(2)),\n                            Value::U16(v) => Value::U16(v.wrapping_mul(2)),\n                            Value::U32(v) => Value::U32(v.wrapping_mul(2)),\n                        };\n                    } else if matches!(instruction.mnemonic(), iced_x86::Mnemonic::Sar) {\n                        let sign_extension = value0.most_significant_bit();\n                        value0 = match value0 {\n                            Value::U8(v) => {\n                                Value::U8((v / 2) | if sign_extension { 0x80 } else { 0 })\n                            }\n                            Value::U16(v) => {\n                                Value::U16((v / 2) | if sign_extension { 0x8000 } else { 0 })\n                            }\n                            Value::U32(v) => {\n                                Value::U32((v / 2) | if sign_extension { 0x80000000 } else { 0 })\n                            }\n                        };\n                    } else {\n                        value0 = match value0 {\n                            Value::U8(v) => Value::U8(v / 2),\n                            Value::U16(v) => Value::U16(v / 2),\n                            Value::U32(v) => Value::U32(v / 2),\n                        };\n                    }\n                }\n\n                self.store_in_operand(&instruction, 0, value0);\n\n                self.flags_set_sign_from_val(value0);\n                self.flags_set_zero_from_val(value0);\n                self.flags_set_parity_from_val(value0);\n                // The adjust flag is undefined\n\n                if matches!(\n                    instruction.mnemonic(),\n                    iced_x86::Mnemonic::Sal | iced_x86::Mnemonic::Shl\n                ) {\n                    self.flags_set_overflow(self.flags_is_carry() != value0.most_significant_bit());\n                } else if matches!(instruction.mnemonic(), iced_x86::Mnemonic::Sar) {\n                    self.flags_set_overflow(false);\n                } else {\n                    self.flags_set_overflow(value0.most_significant_bit());\n                }\n            }\n\n            iced_x86::Mnemonic::Sbb => {\n                let value0 = self.fetch_operand_value(&instruction, 0);\n                let value1 = self.fetch_operand_value(&instruction, 1);\n\n                let (temp, overflow) = match (value0, value1) {\n                    (Value::U8(value0), Value::U8(value1)) => {\n                        let carry_val = if self.flags_is_carry() { 1 } else { 0 };\n                        let (v, o) = value0.overflowing_sub(value1.wrapping_add(carry_val));\n                        (Value::U8(v), o)\n                    }\n                    (Value::U16(value0), Value::U16(value1)) => {\n                        let carry_val = if self.flags_is_carry() { 1 } else { 0 };\n                        let (v, o) = value0.overflowing_sub(value1.wrapping_add(carry_val));\n                        (Value::U16(v), o)\n                    }\n                    (Value::U32(value0), Value::U32(value1)) => {\n                        let carry_val = if self.flags_is_carry() { 1 } else { 0 };\n                        let (v, o) = value0.overflowing_sub(value1.wrapping_add(carry_val));\n                        (Value::U32(v), o)\n                    }\n                    _ => unreachable!(),\n                };\n\n                self.store_in_operand(&instruction, 0, temp);\n\n                self.flags_set_sign_from_val(temp);\n                self.flags_set_zero_from_val(temp);\n                self.flags_set_parity_from_val(temp);\n                self.flags_set_carry(overflow);\n                self.flags_set_overflow(overflow != temp.most_significant_bit());\n                // TODO: the adjust flag\n            }\n\n            iced_x86::Mnemonic::Scasb | iced_x86::Mnemonic::Scasw | iced_x86::Mnemonic::Scasd => {\n                assert_eq!(instruction.op_count(), 2);\n                let value0 = self.fetch_operand_value(&instruction, 0);\n                let value1 = self.fetch_operand_value(&instruction, 1);\n\n                let (temp, overflow) = match (value0, value1) {\n                    (Value::U8(value0), Value::U8(value1)) => {\n                        let (v, o) = value0.overflowing_sub(value1);\n                        (Value::U8(v), o)\n                    }\n                    (Value::U16(value0), Value::U16(value1)) => {\n                        let (v, o) = value0.overflowing_sub(value1);\n                        (Value::U16(v), o)\n                    }\n                    (Value::U32(value0), Value::U32(value1)) => {\n                        let (v, o) = value0.overflowing_sub(value1);\n                        (Value::U32(v), o)\n                    }\n                    _ => unreachable!(),\n                };\n\n                self.flags_set_sign_from_val(temp);\n                self.flags_set_zero_from_val(temp);\n                self.flags_set_parity_from_val(temp);\n                self.flags_set_carry(overflow);\n                self.flags_set_overflow(overflow != temp.most_significant_bit());\n                // TODO: the adjust flag\n\n                let use_edi = match instruction.try_op_kind(1).unwrap() {\n                    iced_x86::OpKind::MemorySegDI => false,\n                    iced_x86::OpKind::MemorySegEDI => true,\n                    iced_x86::OpKind::MemoryESDI => false,\n                    iced_x86::OpKind::MemoryESEDI => true,\n                    _ => unreachable!(),\n                };\n\n                if use_edi {\n                    if self.flags_is_direction() {\n                        self.regs.edi = self.regs.edi.wrapping_sub(u32::from(temp.size()));\n                    } else {\n                        self.regs.edi = self.regs.edi.wrapping_add(u32::from(temp.size()));\n                    }\n                } else {\n                    if self.flags_is_direction() {\n                        self.sub_di(u16::from(temp.size()));\n                    } else {\n                        self.add_di(u16::from(temp.size()));\n                    }\n                }\n            }\n\n            iced_x86::Mnemonic::Seta\n            | iced_x86::Mnemonic::Setae\n            | iced_x86::Mnemonic::Setb\n            | iced_x86::Mnemonic::Setbe\n            | iced_x86::Mnemonic::Sete\n            | iced_x86::Mnemonic::Setg\n            | iced_x86::Mnemonic::Setge\n            | iced_x86::Mnemonic::Setl\n            | iced_x86::Mnemonic::Setle\n            | iced_x86::Mnemonic::Setne\n            | iced_x86::Mnemonic::Setno\n            | iced_x86::Mnemonic::Setnp\n            | iced_x86::Mnemonic::Setns\n            | iced_x86::Mnemonic::Seto\n            | iced_x86::Mnemonic::Setp\n            | iced_x86::Mnemonic::Sets => {\n                debug_assert!(!matches!(\n                    instruction.condition_code(),\n                    iced_x86::ConditionCode::None\n                ));\n                let cond = self.flags_check_condition(instruction.condition_code());\n                let value = Value::U8(if cond { 1 } else { 0 });\n                self.store_in_operand(&instruction, 0, value);\n            }\n\n            iced_x86::Mnemonic::Shld => todo!(),\n            iced_x86::Mnemonic::Shrd => todo!(),\n\n            iced_x86::Mnemonic::Smsw => todo!(),\n\n            iced_x86::Mnemonic::Stc => self.flags_set_carry(true),\n            iced_x86::Mnemonic::Std => self.flags_set_direction(true),\n            iced_x86::Mnemonic::Sti => self.flags_set_interrupt(true),\n\n            iced_x86::Mnemonic::Stosb | iced_x86::Mnemonic::Stosw | iced_x86::Mnemonic::Stosd => {\n                // TODO: review this\n                let val = self.fetch_operand_value(&instruction, 1);\n\n                let use_edi = match instruction.try_op_kind(0).unwrap() {\n                    iced_x86::OpKind::MemorySegDI => false,\n                    iced_x86::OpKind::MemorySegEDI => true,\n                    iced_x86::OpKind::MemoryESDI => false,\n                    iced_x86::OpKind::MemoryESEDI => true,\n                    _ => unreachable!(),\n                };\n\n                self.store_in_operand(&instruction, 0, val);\n\n                if use_edi {\n                    if self.flags_is_direction() {\n                        self.regs.edi = self.regs.edi.wrapping_sub(u32::from(val.size()));\n                    } else {\n                        self.regs.edi = self.regs.edi.wrapping_add(u32::from(val.size()));\n                    }\n                } else {\n                    if self.flags_is_direction() {\n                        self.sub_di(u16::from(val.size()));\n                    } else {\n                        self.add_di(u16::from(val.size()));\n                    }\n                }\n            }\n\n            iced_x86::Mnemonic::Sub => {\n                let value0 = self.fetch_operand_value(&instruction, 0);\n                let value1 = self.fetch_operand_value(&instruction, 1);\n\n                let (temp, overflow) = match (value0, value1) {\n                    (Value::U8(value0), Value::U8(value1)) => {\n                        let (v, o) = value0.overflowing_sub(value1);\n                        (Value::U8(v), o)\n                    }\n                    (Value::U16(value0), Value::U16(value1)) => {\n                        let (v, o) = value0.overflowing_sub(value1);\n                        (Value::U16(v), o)\n                    }\n                    (Value::U32(value0), Value::U32(value1)) => {\n                        let (v, o) = value0.overflowing_sub(value1);\n                        (Value::U32(v), o)\n                    }\n                    _ => unreachable!(),\n                };\n\n                self.store_in_operand(&instruction, 0, temp);\n\n                self.flags_set_sign_from_val(temp);\n                self.flags_set_zero_from_val(temp);\n                self.flags_set_parity_from_val(temp);\n                self.flags_set_carry(overflow);\n                self.flags_set_overflow(overflow != temp.most_significant_bit());\n                // TODO: the adjust flag\n            }\n\n            iced_x86::Mnemonic::Test => {\n                let value0 = self.fetch_operand_value(&instruction, 0);\n                let value1 = self.fetch_operand_value(&instruction, 1);\n\n                let temp = match (value0, value1) {\n                    (Value::U8(value0), Value::U8(value1)) => Value::U8(value0 & value1),\n                    (Value::U16(value0), Value::U16(value1)) => Value::U16(value0 & value1),\n                    (Value::U32(value0), Value::U32(value1)) => Value::U32(value0 & value1),\n                    _ => unreachable!(),\n                };\n\n                self.flags_set_sign_from_val(temp);\n                self.flags_set_zero_from_val(temp);\n                self.flags_set_parity_from_val(temp);\n                self.flags_set_carry(false);\n                self.flags_set_overflow(false);\n                // adjust flag is undefined\n            }\n\n            iced_x86::Mnemonic::Wait => {}\n\n            iced_x86::Mnemonic::Xchg => {\n                let value0 = self.fetch_operand_value(&instruction, 0);\n                let value1 = self.fetch_operand_value(&instruction, 1);\n                self.store_in_operand(&instruction, 0, value1);\n                self.store_in_operand(&instruction, 1, value0);\n            }\n\n            iced_x86::Mnemonic::Xlatb => todo!(),\n\n            iced_x86::Mnemonic::INVALID => return Err(Error::InvalidInstruction),\n            opcode => {\n                log::error!(\"Unsupported instruction: {:?}\", opcode);\n                return Err(Error::InvalidInstruction);\n            }\n        }\n\n        Ok(())\n    }\n\n    /// Executes the `int` instruction on the current state of the machine.\n    fn run_int_opcode(&mut self, vector: u8) {\n        self.stack_push_value(Value::U16(self.regs.flags));\n        self.stack_push_value(Value::U16(self.regs.cs));\n        self.stack_push_value(Value::U16(self.ip()));\n\n        self.flags_set_interrupt(false);\n        self.flags_set_trap(false);\n\n        let vector = u32::from(vector);\n\n        self.regs.cs = self.read_memory_u16((vector * 4) + 2);\n        self.regs.eip = u32::from(self.read_memory_u16(vector * 4));\n    }\n\n    /// Unconditionally applies the jump instruction passed as parameter.\n    ///\n    /// > **Note**: Does not work with `int` instruction.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the passed instruction is not a jump or a call.\n    ///\n    fn apply_jump(&mut self, instruction: &iced_x86::Instruction) {\n        assert_eq!(instruction.op_count(), 1);\n\n        match instruction.try_op_kind(0).unwrap() {\n            iced_x86::OpKind::NearBranch16 => {\n                self.regs.eip = u32::from(instruction.near_branch16());\n            }\n            iced_x86::OpKind::NearBranch32 => {\n                self.regs.eip = instruction.near_branch32();\n            }\n            iced_x86::OpKind::FarBranch16 => {\n                self.regs.cs = instruction.far_branch_selector();\n                self.regs.eip = u32::from(instruction.far_branch16());\n            }\n            iced_x86::OpKind::FarBranch32 => {\n                self.regs.cs = instruction.far_branch_selector();\n                self.regs.eip = instruction.far_branch32();\n            }\n            _ => {\n                self.regs.eip = match self.fetch_operand_value(instruction, 0) {\n                    Value::U16(v) => u32::from(v),\n                    Value::U32(v) => v,\n                    _ => unreachable!(),\n                };\n            }\n        }\n    }\n\n    /// Pushes data on the stack.\n    fn stack_push(&mut self, data: &[u8]) {\n        // TODO: don't panic; handle overflows by generating a SS exception\n        self.regs.esp = self\n            .regs\n            .esp\n            .checked_sub(u32::try_from(data.len()).unwrap())\n            .unwrap();\n        let addr = (u32::from(self.regs.ss) << 4) + self.regs.esp;\n        self.write_memory(addr, data);\n    }\n\n    /// Pushes a value on the stack.\n    fn stack_push_value(&mut self, value: Value) {\n        match value {\n            Value::U8(v) => {\n                let data = v.to_le_bytes();\n                self.stack_push(&data);\n            }\n            Value::U16(v) => {\n                let data = v.to_le_bytes();\n                self.stack_push(&data);\n            }\n            Value::U32(v) => {\n                let data = v.to_le_bytes();\n                self.stack_push(&data);\n            }\n        }\n    }\n\n    /// Pops data from the stack.\n    fn stack_pop(&mut self, out: &mut [u8]) {\n        let addr = (u32::from(self.regs.ss) << 4) + self.regs.esp;\n        self.read_memory(addr, out);\n        // TODO: don't panic\n        self.regs.esp = self\n            .regs\n            .esp\n            .checked_add(u32::try_from(out.len()).unwrap())\n            .unwrap();\n    }\n\n    fn stack_pop_u8(&mut self) -> u8 {\n        let mut out = [0; 1];\n        self.stack_pop(&mut out);\n        u8::from_le_bytes(out)\n    }\n\n    fn stack_pop_u16(&mut self) -> u16 {\n        let mut out = [0; 2];\n        self.stack_pop(&mut out);\n        u16::from_le_bytes(out)\n    }\n\n    fn stack_pop_u32(&mut self) -> u32 {\n        let mut out = [0; 4];\n        self.stack_pop(&mut out);\n        u32::from_le_bytes(out)\n    }\n\n    fn flags_is_carry(&self) -> bool {\n        (self.regs.flags & 1 << 0) != 0\n    }\n\n    fn flags_set_carry(&mut self, val: bool) {\n        if val {\n            self.regs.flags |= 1 << 0;\n        } else {\n            self.regs.flags &= !(1 << 0);\n        }\n    }\n\n    fn flags_is_parity(&self) -> bool {\n        (self.regs.flags & 1 << 2) != 0\n    }\n\n    fn flags_set_parity(&mut self, val: bool) {\n        if val {\n            self.regs.flags |= 1 << 2;\n        } else {\n            self.regs.flags &= !(1 << 2);\n        }\n    }\n\n    fn flags_set_parity_from_val(&mut self, val: Value) {\n        self.flags_set_parity(match val {\n            Value::U8(val) => (val.count_ones() % 2) == 0,\n            Value::U16(val) => ((val & 0xff).count_ones() % 2) == 0,\n            Value::U32(val) => ((val & 0xff).count_ones() % 2) == 0,\n        });\n    }\n\n    fn flags_is_zero(&self) -> bool {\n        (self.regs.flags & 1 << 6) != 0\n    }\n\n    fn flags_set_zero_from_val(&mut self, val: Value) {\n        self.flags_set_zero(val.is_zero())\n    }\n\n    fn flags_set_zero(&mut self, val: bool) {\n        if val {\n            self.regs.flags |= 1 << 6;\n        } else {\n            self.regs.flags &= !(1 << 6);\n        }\n    }\n\n    fn flags_set_adjust(&mut self, val: bool) {\n        if val {\n            self.regs.flags |= 1 << 4;\n        } else {\n            self.regs.flags &= !(1 << 4);\n        }\n    }\n\n    fn flags_is_sign(&self) -> bool {\n        (self.regs.flags & 1 << 7) != 0\n    }\n\n    fn flags_set_sign_from_val(&mut self, val: Value) {\n        self.flags_set_sign(val.most_significant_bit())\n    }\n\n    fn flags_set_sign(&mut self, val: bool) {\n        if val {\n            self.regs.flags |= 1 << 7;\n        } else {\n            self.regs.flags &= !(1 << 7);\n        }\n    }\n\n    fn flags_set_trap(&mut self, val: bool) {\n        if val {\n            self.regs.flags |= 1 << 8;\n        } else {\n            self.regs.flags &= !(1 << 8);\n        }\n    }\n\n    fn flags_set_interrupt(&mut self, val: bool) {\n        if val {\n            self.regs.flags |= 1 << 9;\n        } else {\n            self.regs.flags &= !(1 << 9);\n        }\n    }\n\n    fn flags_is_direction(&self) -> bool {\n        (self.regs.flags & 1 << 10) != 0\n    }\n\n    fn flags_set_direction(&mut self, val: bool) {\n        if val {\n            self.regs.flags |= 1 << 10;\n        } else {\n            self.regs.flags &= !(1 << 10);\n        }\n    }\n\n    fn flags_is_overflow(&self) -> bool {\n        (self.regs.flags & 1 << 11) != 0\n    }\n\n    fn flags_set_overflow(&mut self, val: bool) {\n        if val {\n            self.regs.flags |= 1 << 11;\n        } else {\n            self.regs.flags &= !(1 << 11);\n        }\n    }\n\n    /// Checks whether the state of the flags matches the given condition. Returns `true` if `None`\n    /// is passed.\n    fn flags_check_condition(&self, condition: iced_x86::ConditionCode) -> bool {\n        match condition {\n            iced_x86::ConditionCode::None => true,\n            iced_x86::ConditionCode::o => self.flags_is_overflow(),\n            iced_x86::ConditionCode::no => !self.flags_is_overflow(),\n            iced_x86::ConditionCode::b => self.flags_is_carry(),\n            iced_x86::ConditionCode::ae => !self.flags_is_carry(),\n            iced_x86::ConditionCode::e => self.flags_is_zero(),\n            iced_x86::ConditionCode::ne => !self.flags_is_zero(),\n            iced_x86::ConditionCode::be => self.flags_is_carry() || self.flags_is_zero(),\n            iced_x86::ConditionCode::a => !self.flags_is_carry() && !self.flags_is_zero(),\n            iced_x86::ConditionCode::s => self.flags_is_sign(),\n            iced_x86::ConditionCode::ns => self.flags_is_sign(),\n            iced_x86::ConditionCode::p => self.flags_is_parity(),\n            iced_x86::ConditionCode::np => self.flags_is_parity(),\n            iced_x86::ConditionCode::l => self.flags_is_sign() != self.flags_is_zero(),\n            iced_x86::ConditionCode::ge => self.flags_is_sign() == self.flags_is_zero(),\n            iced_x86::ConditionCode::le => {\n                self.flags_is_zero() || self.flags_is_sign() != self.flags_is_overflow()\n            }\n            iced_x86::ConditionCode::g => {\n                !self.flags_is_zero() && self.flags_is_sign() == self.flags_is_overflow()\n            }\n        }\n    }\n\n    /// Returns the value of the `IP` register.\n    fn ip(&self) -> u16 {\n        u16::try_from(self.regs.eip & 0xffff).unwrap()\n    }\n\n    fn dec_cx(&mut self) {\n        let cx = u16::try_from(self.regs.ecx & 0xffff).unwrap();\n        let new_cx = cx.wrapping_sub(1);\n        self.regs.ecx &= 0xffff0000;\n        self.regs.ecx |= u32::from(new_cx);\n    }\n\n    fn sub_si(&mut self, n: u16) {\n        let si = u16::try_from(self.regs.esi & 0xffff).unwrap();\n        let new_si = si.wrapping_sub(n);\n        self.regs.esi &= 0xffff0000;\n        self.regs.esi |= u32::from(new_si);\n    }\n\n    fn add_si(&mut self, n: u16) {\n        let si = u16::try_from(self.regs.esi & 0xffff).unwrap();\n        let new_si = si.wrapping_add(n);\n        self.regs.esi &= 0xffff0000;\n        self.regs.esi |= u32::from(new_si);\n    }\n\n    fn sub_di(&mut self, n: u16) {\n        let di = u16::try_from(self.regs.edi & 0xffff).unwrap();\n        let new_di = di.wrapping_sub(n);\n        self.regs.edi &= 0xffff0000;\n        self.regs.edi |= u32::from(new_di);\n    }\n\n    fn add_di(&mut self, n: u16) {\n        let di = u16::try_from(self.regs.edi & 0xffff).unwrap();\n        let new_di = di.wrapping_add(n);\n        self.regs.edi &= 0xffff0000;\n        self.regs.edi |= u32::from(new_di);\n    }\n\n    /// Assumes that operand `op_n` of `instruction` is of type `Memory`, and loads the pointer\n    /// value without the segment.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the operand is not of type `Memory`.\n    ///\n    fn memory_operand_pointer(&self, instruction: &iced_x86::Instruction, op_n: u32) -> u16 {\n        assert!(matches!(\n            instruction.try_op_kind(op_n).unwrap(),\n            iced_x86::OpKind::Memory\n        ));\n\n        let base = match instruction.memory_base() {\n            iced_x86::Register::None => 0,\n            reg => match self.register(reg) {\n                Value::U8(v) => u16::from(v),\n                Value::U16(v) => v,\n                Value::U32(v) => u16::try_from(v).unwrap(), // TODO: is this correct?\n            },\n        };\n\n        let index = match instruction.memory_index() {\n            iced_x86::Register::None => 0,\n            reg => match self.register(reg) {\n                Value::U8(v) => u16::from(v),\n                Value::U16(v) => v,\n                Value::U32(v) => u16::try_from(v).unwrap(), // TODO: is this correct?\n            },\n        };\n\n        let index_scale = u16::try_from(instruction.memory_index_scale()).unwrap();\n\n        let base_and_index = base.wrapping_add(index.wrapping_mul(index_scale));\n        let disp = u16::try_from(instruction.memory_displacement() & 0xffff).unwrap();\n        base_and_index.wrapping_add(disp)\n    }\n\n    /// Returns the size in bytes of the value designated by the given operand of the given\n    /// instruction. This is equal to what [`Interpreter::fetch_operand_value`] would return\n    /// for that operand.\n    ///\n    /// For example if the operand is the register `AX`, returns 2.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the operand index is out of range of the instruction.\n    ///\n    fn operand_size(&mut self, instruction: &iced_x86::Instruction, op_n: u32) -> u8 {\n        match instruction.try_op_kind(op_n).unwrap() {\n            // TODO: lazy way to implement this\n            iced_x86::OpKind::Register => {\n                debug_assert!(!matches!(\n                    instruction.try_op_register(op_n).unwrap(),\n                    iced_x86::Register::None\n                ));\n                self.register(instruction.try_op_register(op_n).unwrap())\n                    .size()\n            }\n            iced_x86::OpKind::Immediate8 => 1,\n            iced_x86::OpKind::Immediate16 => 2,\n            iced_x86::OpKind::Immediate32 => 2,\n            iced_x86::OpKind::Immediate8to16 => 2,\n            iced_x86::OpKind::Immediate8to32 => 4,\n            iced_x86::OpKind::MemorySegSI\n            | iced_x86::OpKind::MemoryESDI\n            | iced_x86::OpKind::Memory => u8::try_from(instruction.memory_size().size()).unwrap(),\n            ty => unimplemented!(\"{:?}\", ty),\n        }\n    }\n\n    /// Returns the value of the given operand of the given instruction.\n    ///\n    /// For example if the operand is the register `AX`, returns the current value of `AX`.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the operand index is out of range of the instruction.\n    ///\n    fn fetch_operand_value(&mut self, instruction: &iced_x86::Instruction, op_n: u32) -> Value {\n        let (segment, pointer) = match instruction.try_op_kind(op_n).unwrap() {\n            iced_x86::OpKind::Register => {\n                debug_assert!(\n                    !matches!(\n                        instruction.try_op_register(op_n).unwrap(),\n                        iced_x86::Register::None\n                    ),\n                    \"{:?} with {:?}\",\n                    instruction.code(),\n                    op_n\n                );\n                return self.register(instruction.try_op_register(op_n).unwrap());\n            }\n            iced_x86::OpKind::Immediate8 => {\n                if (0..op_n)\n                    .any(|n| instruction.try_op_kind(n).unwrap() == iced_x86::OpKind::Immediate8)\n                {\n                    return Value::U8(instruction.immediate8_2nd());\n                } else {\n                    return Value::U8(instruction.immediate8());\n                }\n            }\n            iced_x86::OpKind::Immediate16 => return Value::U16(instruction.immediate16()),\n            iced_x86::OpKind::Immediate32 => return Value::U32(instruction.immediate32()),\n            iced_x86::OpKind::Immediate8to16 => {\n                return Value::U16(u16::from_ne_bytes(\n                    instruction.immediate8to16().to_ne_bytes(),\n                ))\n            }\n            iced_x86::OpKind::Immediate8to32 => {\n                return Value::U32(u32::from_ne_bytes(\n                    instruction.immediate8to32().to_ne_bytes(),\n                ))\n            }\n            iced_x86::OpKind::MemorySegSI => {\n                let segment = {\n                    debug_assert!(!matches!(\n                        instruction.memory_segment(),\n                        iced_x86::Register::None\n                    ));\n                    u16::try_from(self.register(instruction.memory_segment())).unwrap()\n                };\n                let pointer = u16::try_from(self.regs.esi & 0xffff).unwrap();\n                (segment, pointer)\n            }\n            iced_x86::OpKind::MemoryESDI => {\n                let segment = u16::try_from(self.regs.es).unwrap();\n                let pointer = u16::try_from(self.regs.edi & 0xffff).unwrap();\n                (segment, pointer)\n            }\n            iced_x86::OpKind::Memory => {\n                let segment = {\n                    debug_assert!(!matches!(\n                        instruction.memory_segment(),\n                        iced_x86::Register::None\n                    ));\n                    u16::try_from(self.register(instruction.memory_segment())).unwrap()\n                };\n                let pointer = self.memory_operand_pointer(instruction, op_n);\n                (segment, pointer)\n            }\n            ty => unimplemented!(\"{:?}\", ty),\n        };\n\n        // TODO: the memory reads are wrong; should explicitely pass segment and pointer\n        let mem_address = (u32::from(segment) << 4) + u32::from(pointer);\n\n        match instruction.memory_size().size() {\n            1 => {\n                let mut out = [0; 1];\n                self.read_memory(mem_address, &mut out);\n                Value::U8(u8::from_le_bytes(out))\n            }\n            2 => {\n                let mut out = [0; 2];\n                self.read_memory(mem_address, &mut out);\n                Value::U16(u16::from_le_bytes(out))\n            }\n            4 => {\n                let mut out = [0; 4];\n                self.read_memory(mem_address, &mut out);\n                Value::U32(u32::from_le_bytes(out))\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    /// Returns the value of the given register.\n    fn register(&self, register: iced_x86::Register) -> Value {\n        match register {\n            iced_x86::Register::AL => Value::U8(u8::try_from(self.regs.eax & 0xff).unwrap()),\n            iced_x86::Register::CL => Value::U8(u8::try_from(self.regs.ecx & 0xff).unwrap()),\n            iced_x86::Register::DL => Value::U8(u8::try_from(self.regs.edx & 0xff).unwrap()),\n            iced_x86::Register::BL => Value::U8(u8::try_from(self.regs.ebx & 0xff).unwrap()),\n            iced_x86::Register::AH => Value::U8(u8::try_from((self.regs.eax >> 8) & 0xff).unwrap()),\n            iced_x86::Register::CH => Value::U8(u8::try_from((self.regs.ecx >> 8) & 0xff).unwrap()),\n            iced_x86::Register::DH => Value::U8(u8::try_from((self.regs.edx >> 8) & 0xff).unwrap()),\n            iced_x86::Register::BH => Value::U8(u8::try_from((self.regs.ebx >> 8) & 0xff).unwrap()),\n            iced_x86::Register::AX => Value::U16(u16::try_from(self.regs.eax & 0xffff).unwrap()),\n            iced_x86::Register::CX => Value::U16(u16::try_from(self.regs.ecx & 0xffff).unwrap()),\n            iced_x86::Register::DX => Value::U16(u16::try_from(self.regs.edx & 0xffff).unwrap()),\n            iced_x86::Register::BX => Value::U16(u16::try_from(self.regs.ebx & 0xffff).unwrap()),\n            iced_x86::Register::SP => Value::U16(u16::try_from(self.regs.esp & 0xffff).unwrap()),\n            iced_x86::Register::BP => Value::U16(u16::try_from(self.regs.ebp & 0xffff).unwrap()),\n            iced_x86::Register::SI => Value::U16(u16::try_from(self.regs.esi & 0xffff).unwrap()),\n            iced_x86::Register::DI => Value::U16(u16::try_from(self.regs.edi & 0xffff).unwrap()),\n            iced_x86::Register::EAX => Value::U32(self.regs.eax),\n            iced_x86::Register::ECX => Value::U32(self.regs.ecx),\n            iced_x86::Register::EDX => Value::U32(self.regs.edx),\n            iced_x86::Register::EBX => Value::U32(self.regs.ebx),\n            iced_x86::Register::ESP => Value::U32(self.regs.esp),\n            iced_x86::Register::EBP => Value::U32(self.regs.ebp),\n            iced_x86::Register::ESI => Value::U32(self.regs.esi),\n            iced_x86::Register::EDI => Value::U32(self.regs.edi),\n            iced_x86::Register::ES => Value::U16(self.regs.es),\n            iced_x86::Register::CS => Value::U16(self.regs.cs),\n            iced_x86::Register::SS => Value::U16(self.regs.ss),\n            iced_x86::Register::DS => Value::U16(self.regs.ds),\n            iced_x86::Register::FS => Value::U16(self.regs.fs),\n            iced_x86::Register::GS => Value::U16(self.regs.gs),\n            reg => unimplemented!(\"{:?}\", reg),\n        }\n    }\n\n    /// Assumes that the given operand of the given instruction is either a register or a memory\n    /// address, and stores the given value at this location.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the operand index is invalid for this instruction.\n    /// Panics if the operand designates a register and this register is of the wrong size.\n    ///\n    fn store_in_operand(&mut self, instruction: &iced_x86::Instruction, op_n: u32, val: Value) {\n        let (segment, pointer) = match instruction.try_op_kind(op_n).unwrap() {\n            iced_x86::OpKind::Register => {\n                return self.store_in_register(instruction.try_op_register(op_n).unwrap(), val);\n            }\n            iced_x86::OpKind::MemoryESDI => {\n                (self.regs.es, u16::try_from(self.regs.edi & 0xffff).unwrap())\n            }\n            iced_x86::OpKind::Memory => {\n                debug_assert!(!matches!(\n                    instruction.memory_segment(),\n                    iced_x86::Register::None\n                ));\n                let segment = u16::try_from(self.register(instruction.memory_segment())).unwrap();\n                let pointer = self.memory_operand_pointer(instruction, op_n);\n                (segment, pointer)\n            }\n            ty => unimplemented!(\"{:?}\", ty),\n        };\n\n        // TODO: the memory writes are wrong; should explicitely pass segment and pointer\n        let mem_address = (u32::from(segment) << 4) + u32::from(pointer);\n\n        match val {\n            Value::U8(val) => {\n                self.write_memory(mem_address, &val.to_le_bytes());\n            }\n            Value::U16(val) => {\n                self.write_memory(mem_address, &val.to_le_bytes());\n            }\n            Value::U32(val) => {\n                self.write_memory(mem_address, &val.to_le_bytes());\n            }\n        }\n    }\n\n    /// Stores the given value in the given register.\n    ///\n    /// # Panic\n    ///\n    /// Panics if the register and valure are not the same size.\n    /// Panics if `register` is `CS`. Writing in `CS` is explicitly forbidden.\n    ///\n    fn store_in_register(&mut self, register: iced_x86::Register, val: Value) {\n        match (register, val) {\n            (iced_x86::Register::AL, Value::U8(val)) => {\n                self.regs.eax &= 0xffffff00;\n                self.regs.eax |= u32::from(val);\n            }\n            (iced_x86::Register::CL, Value::U8(val)) => {\n                self.regs.ecx &= 0xffffff00;\n                self.regs.ecx |= u32::from(val);\n            }\n            (iced_x86::Register::DL, Value::U8(val)) => {\n                self.regs.edx &= 0xffffff00;\n                self.regs.edx |= u32::from(val);\n            }\n            (iced_x86::Register::BL, Value::U8(val)) => {\n                self.regs.ebx &= 0xffffff00;\n                self.regs.ebx |= u32::from(val);\n            }\n            (iced_x86::Register::AH, Value::U8(val)) => {\n                self.regs.eax &= 0xffff00ff;\n                self.regs.eax |= u32::from(val) << 8;\n            }\n            (iced_x86::Register::CH, Value::U8(val)) => {\n                self.regs.ecx &= 0xffff00ff;\n                self.regs.ecx |= u32::from(val) << 8;\n            }\n            (iced_x86::Register::DH, Value::U8(val)) => {\n                self.regs.edx &= 0xffff00ff;\n                self.regs.edx |= u32::from(val) << 8;\n            }\n            (iced_x86::Register::BH, Value::U8(val)) => {\n                self.regs.ebx &= 0xffff00ff;\n                self.regs.ebx |= u32::from(val) << 8;\n            }\n            (iced_x86::Register::AX, Value::U16(val)) => {\n                self.regs.eax &= 0xffff0000;\n                self.regs.eax |= u32::from(val);\n            }\n            (iced_x86::Register::CX, Value::U16(val)) => {\n                self.regs.ecx &= 0xffff0000;\n                self.regs.ecx |= u32::from(val);\n            }\n            (iced_x86::Register::DX, Value::U16(val)) => {\n                self.regs.edx &= 0xffff0000;\n                self.regs.edx |= u32::from(val);\n            }\n            (iced_x86::Register::BX, Value::U16(val)) => {\n                self.regs.ebx &= 0xffff0000;\n                self.regs.ebx |= u32::from(val);\n            }\n            (iced_x86::Register::SP, Value::U16(val)) => {\n                self.regs.esp &= 0xffff0000;\n                self.regs.esp |= u32::from(val);\n            }\n            (iced_x86::Register::BP, Value::U16(val)) => {\n                self.regs.ebp &= 0xffff0000;\n                self.regs.ebp |= u32::from(val);\n            }\n            (iced_x86::Register::SI, Value::U16(val)) => {\n                self.regs.esi &= 0xffff0000;\n                self.regs.esi |= u32::from(val);\n            }\n            (iced_x86::Register::DI, Value::U16(val)) => {\n                self.regs.edi &= 0xffff0000;\n                self.regs.edi |= u32::from(val);\n            }\n            (iced_x86::Register::EAX, Value::U32(val)) => {\n                self.regs.eax = val;\n            }\n            (iced_x86::Register::ECX, Value::U32(val)) => {\n                self.regs.ecx = val;\n            }\n            (iced_x86::Register::EDX, Value::U32(val)) => {\n                self.regs.edx = val;\n            }\n            (iced_x86::Register::EBX, Value::U32(val)) => {\n                self.regs.ebx = val;\n            }\n            (iced_x86::Register::ESP, Value::U32(val)) => {\n                self.regs.esp = val;\n            }\n            (iced_x86::Register::EBP, Value::U32(val)) => {\n                self.regs.ebp = val;\n            }\n            (iced_x86::Register::ESI, Value::U32(val)) => {\n                self.regs.esi = val;\n            }\n            (iced_x86::Register::EDI, Value::U32(val)) => {\n                self.regs.edi = val;\n            }\n            (iced_x86::Register::ES, Value::U16(val)) => {\n                self.regs.es = val;\n            }\n            (iced_x86::Register::CS, Value::U16(_)) => {\n                // Forbidden.\n                panic!()\n            }\n            (iced_x86::Register::SS, Value::U16(val)) => {\n                self.regs.ss = val;\n            }\n            (iced_x86::Register::DS, Value::U16(val)) => {\n                self.regs.ds = val;\n            }\n            (iced_x86::Register::FS, Value::U16(val)) => {\n                self.regs.fs = val;\n            }\n            (iced_x86::Register::GS, Value::U16(val)) => {\n                self.regs.gs = val;\n            }\n            reg => unimplemented!(\"{:?}\", reg),\n        }\n    }\n}\n\n#[derive(Debug, Copy, Clone)]\nenum Value {\n    U8(u8),\n    U16(u16),\n    U32(u32),\n}\n\nimpl Value {\n    fn size(&self) -> u8 {\n        match *self {\n            Value::U8(_) => 1,\n            Value::U16(_) => 2,\n            Value::U32(_) => 4,\n        }\n    }\n\n    fn most_significant_bit(&self) -> bool {\n        match *self {\n            Value::U8(val) => (val & 0x80) != 0,\n            Value::U16(val) => (val & 0x8000) != 0,\n            Value::U32(val) => (val & 0x80000000) != 0,\n        }\n    }\n\n    fn least_significant_bit(&self) -> bool {\n        match *self {\n            Value::U8(val) => (val & 0x1) != 0,\n            Value::U16(val) => (val & 0x1) != 0,\n            Value::U32(val) => (val & 0x1) != 0,\n        }\n    }\n\n    fn zero_extend_to_u32(&self) -> u32 {\n        match *self {\n            Value::U8(val) => u32::from(val),\n            Value::U16(val) => u32::from(val),\n            Value::U32(val) => val,\n        }\n    }\n\n    fn is_zero(&self) -> bool {\n        match *self {\n            Value::U8(val) => val == 0,\n            Value::U16(val) => val == 0,\n            Value::U32(val) => val == 0,\n        }\n    }\n\n    fn is_max_value(&self) -> bool {\n        match *self {\n            Value::U8(val) => val == 0xff,\n            Value::U16(val) => val == 0xffff,\n            Value::U32(val) => val == 0xffffffff,\n        }\n    }\n}\n\nimpl TryFrom<Value> for u8 {\n    type Error = ();\n    fn try_from(v: Value) -> Result<Self, ()> {\n        if let Value::U8(v) = v {\n            Ok(v)\n        } else {\n            Err(())\n        }\n    }\n}\n\nimpl TryFrom<Value> for u16 {\n    type Error = ();\n    fn try_from(v: Value) -> Result<Self, ()> {\n        if let Value::U16(v) = v {\n            Ok(v)\n        } else {\n            Err(())\n        }\n    }\n}\n\nimpl TryFrom<Value> for u32 {\n    type Error = ();\n    fn try_from(v: Value) -> Result<Self, ()> {\n        if let Value::U32(v) = v {\n            Ok(v)\n        } else {\n            Err(())\n        }\n    }\n}\n"
  },
  {
    "path": "programs/vga-vbe/src/main.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n//! Support for VBE 3.0 and VGA.\n//!\n//! VBE and VGA are two standards specifying a way of interfacing with a video card.\n//!\n//! The VGA standard was created in the 1980 and defines, amongst other things, a list of\n//! I/O registers that the video card must implement.\n//! The VBE standard is more recent and defines a list of functions that the video BIOS must\n//! provide. It is a superset of VGA.\n//!\n//! While these standards are fairly old, they are as of 2020 still the most up-to-date\n//! non-hardware-specific way of interfacing with a video card, and are still almost universally\n//! supported nowadays.\n//!\n//! More modern features, such as 3D acceleration, are not standardized. They are much more\n//! complex to implement and, in practice, require writing a driver specific to each vendor.\n//!\n//! Both VGA and VBE refer to \"the\" video card of the machine. In other words, the motherboard\n//! firmware must either choose a main video card or expose all the video cards together as if it\n//! was a single one, and the VGA and VBE functions apply on it. It is not possible to support\n//! multiple distinct video cards without writing vendor-specific drivers.\n//!\n//! # VESA Bios Extension (VBE)\n//!\n//! When the machine is powered up, if the BIOS/firmware detects a VGA-compatible video card, it\n//! sets up the entry 0x10 of the IVT (interrupt vector table) to point to the entry point of the\n//! video BIOS, mapped somewhere in memory.\n//!\n//! Amongst other things, being \"VGA-compatible\" means that the video BIOS must respond to a\n//! certain standardized list of calls. More details can be found\n//! [here](https://en.wikipedia.org/wiki/INT_10H).\n//!\n//! The VBE standard, whose most recent version is 3.0, extends this list of functions. If the\n//! video BIOS doesn't support the VBE standard, it is assumed to simply do nothing and return\n//! an error code. While the VBE functions are an extension to the VGA functions, they are really\n//! meant to entirely replace the VGA functions.\n//!\n//! VBE-compatible cards, in addition to interruption 0x10, must also provide a protected-mode\n//! (32bits) entry point to their BIOS, which makes it possible to call VBE functions from\n//! protected mode. Unfortunately, the requirements for the protected mode entry point involve\n//! setting up memory segments that point to specific physcial memory locations. Memory segments\n//! are no longer a thing in long mode (64bits).\n//!\n//! Whatever entry point we decide to this, accessing these functions would involve switching the\n//! processor mode from long mode (64bits) to either 16bits or 32bits, which is a hassle.\n//! For this reason, our solution consists in executing the VBE functions through a real mode\n//! (16bits) emulator. In other words, we read the instructions contained in the video BIOS\n//! and interpret them.\n//!\n//! > **Note**: We restrict ourselves to a 16bits emulator as it is considerably more simple to\n//! >           write than a 32bits emulator, but there is no fundamental reason to prefer 16bits\n//! >           over 32bits.\n//!\n\nuse core::convert::TryFrom as _;\n\nmod interpreter;\nmod vbe;\n\nfn main() {\n    redshirt_log_interface::init();\n    redshirt_syscalls::block_on(async_main());\n}\n\nasync fn async_main() {\n    let mut pci_locks = Vec::new();\n\n    let pci_devices = redshirt_pci_interface::get_pci_devices().await;\n    for device in pci_devices {\n        // We match any PCI device that self-describes as VGA-compatible.\n        match (device.class_code, device.subclass, device.prog_if) {\n            (0x03, 0x00, 0x00) => {}\n            _ => continue,\n        };\n\n        let pci_lock = match redshirt_pci_interface::PciDeviceLock::lock(device.location).await {\n            Ok(l) => l,\n            // PCI device is already handled by a different driver.\n            Err(_) => continue,\n        };\n\n        pci_locks.push(pci_lock);\n    }\n\n    if pci_locks.is_empty() {\n        log::info!(\"No VGA/VESA device available. Shutting down driver.\");\n        return;\n    }\n\n    log::info!(\"Initializing VBE BIOS.\");\n    let mut vbe = unsafe { vbe::load_vbe_info().await.unwrap() };\n\n    let (\n        chosen_mode_num,\n        width,\n        height,\n        linear_framebuffer_location,\n        bytes_per_scan_line,\n        red_mask_size,\n        red_mask_pos,\n        green_mask_size,\n        green_mask_pos,\n        blue_mask_size,\n        blue_mask_pos,\n        reserved_mask_size,\n        reserved_mask_pos,\n    ) = {\n        let mut out = None;\n        for mode in vbe.modes() {\n            if mode.pixels_dimensions().0 < 1500 {\n                continue;\n            }\n\n            out = Some((\n                mode.num(),\n                mode.pixels_dimensions().0,\n                mode.pixels_dimensions().1,\n                mode.linear_framebuffer_location(),\n                mode.bytes_per_scan_line(),\n                mode.red_mask_size(),\n                mode.red_mask_pos(),\n                mode.green_mask_size(),\n                mode.green_mask_pos(),\n                mode.blue_mask_size(),\n                mode.blue_mask_pos(),\n                mode.reserved_mask_size(),\n                mode.reserved_mask_pos(),\n            ));\n        }\n        out.unwrap() // TODO: don't unwrap\n    };\n\n    assert_eq!(\n        (red_mask_size + green_mask_size + blue_mask_size + reserved_mask_size) % 8,\n        0\n    );\n    let bytes_per_character =\n        (red_mask_size + green_mask_size + blue_mask_size + reserved_mask_size) / 8;\n\n    log::info!(\n        \"Switching to mode 0x{:x}. Dimensions = {}x{}\",\n        chosen_mode_num,\n        width,\n        height\n    );\n    vbe.set_current_mode(chosen_mode_num).await.unwrap();\n    log::info!(\"Successfully set VESA mode\");\n\n    // Register the framebuffer as a video output.\n    let video_output_registration = redshirt_video_output_interface::video_output::register(\n        redshirt_video_output_interface::video_output::VideoOutputConfig {\n            width: u32::from(width),\n            height: u32::from(height),\n            // TODO: proper format\n            format: redshirt_video_output_interface::ffi::Format::R8G8B8X8,\n        },\n    )\n    .await;\n\n    // TODO: not implemented in the kernel\n    // TODO: should *add* a logging method, rather than set it\n    /*redshirt_kernel_log_interface::configure_kernel(\n        redshirt_kernel_log_interface::KernelLogMethod {\n            enabled: false,\n            framebuffer: Some(redshirt_kernel_log_interface::ffi::FramebufferInfo {\n                address: linear_framebuffer_location,\n                width: width.into(),\n                height: height.into(),\n                pitch: bytes_per_scan_line.into(),\n                bytes_per_character,\n                format: redshirt_kernel_log_interface::ffi::FramebufferFormat::Rgb {\n                    red_size: red_mask_size,\n                    red_position: red_mask_pos,\n                    green_size: green_mask_size,\n                    green_position: green_mask_pos,\n                    blue_size: blue_mask_size,\n                    blue_position: blue_mask_pos,\n                },\n            }),\n            uart: None,\n        },\n    )\n    .await;*/\n\n    loop {\n        let frame = video_output_registration.next_frame().await;\n        if frame.changes.is_empty() {\n            continue;\n        }\n\n        let mut ops = redshirt_hardware_interface::HardwareWriteOperationsBuilder::new();\n\n        for change in frame.changes {\n            for (y, pixels_row) in change.pixels.into_iter().enumerate() {\n                let addr = linear_framebuffer_location\n                    + u64::from(\n                        (change.screen_y_start + u32::try_from(y).unwrap())\n                            * u32::from(bytes_per_scan_line)\n                            + change.screen_x_start * u32::from(bytes_per_character),\n                    );\n                // TODO: check length of pixels_row\n                unsafe { ops.write(addr, pixels_row) };\n            }\n        }\n\n        ops.send();\n    }\n}\n"
  },
  {
    "path": "programs/vga-vbe/src/vbe.rs",
    "content": "// Copyright (C) 2019-2021  Pierre Krieger\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nuse crate::interpreter;\nuse core::convert::TryFrom as _;\n\n/// Access to VBE functions.\npub struct VbeContext {\n    interpreter: interpreter::Interpreter,\n    video_modes: Vec<ModeInfo>,\n}\n\n/// Try to fetch information about the supported video modes from the hardware.\n///\n/// # Safety\n///\n/// Must only ever be called once at a time. No other code should access the VGA BIOS or the video\n/// card while this call is in progress or the returned [`VbeContext`] is in use.\n///\npub async unsafe fn load_vbe_info() -> Result<VbeContext, Error> {\n    let mut interpreter = interpreter::Interpreter::from_real_machine().await;\n\n    // We start by asking the BIOS for general information about the graphics device.\n    interpreter.set_ax(0x4f00);\n    interpreter.set_es_di(0x50, 0x0); // Fill 512 bytes at address 0x500.\n    interpreter.write_memory(0x500, &b\"VBE2\"[..]);\n    interpreter.int10h()?;\n    check_ax(interpreter.ax())?;\n\n    // Read out what the BIOS has written.\n    let mut info_out = [0; 512];\n    interpreter.read_memory(0x500, &mut info_out[..]);\n    if &info_out[0..4] != b\"VESA\" {\n        return Err(Error::BadMagic);\n    }\n\n    // Note that there's a bunch of information we can read from this data, but apart from the\n    // video mode we don't actually care about any of them. For instance, why is the amount of\n    // memory on the video card even reported, other than for showing fancy statistics to the\n    // user?\n\n    // The data structure contains a far pointer to the list of video modes. We now retreive the\n    // content of this list.\n    let video_modes_nums: Vec<u16> = {\n        let vmodes_seg = interpreter.read_memory_u16(0x510);\n        let vmodes_ptr = interpreter.read_memory_u16(0x50e);\n        let mut vmodes_addr = (u32::from(vmodes_seg) << 4) + u32::from(vmodes_ptr);\n        let mut modes = Vec::new();\n        loop {\n            let mode = interpreter.read_memory_u16(vmodes_addr);\n            vmodes_addr += 2;\n            // A `0xffff` value indicates the end of the list of video modes.\n            if mode == 0xffff {\n                break modes;\n            }\n            // Modes are defined to always be only 9bits long.\n            if mode >= (1 << 9) {\n                log::warn!(\"Skipping invalid video mode number: 0x{:x}\", mode);\n                continue;\n            }\n            modes.push(mode);\n        }\n    };\n\n    // For each reported mode, perform an int10h call to retreive information about it and fill\n    // the `video_modes` list.\n    let mut video_modes = Vec::<ModeInfo>::with_capacity(video_modes_nums.len());\n    for mode in video_modes_nums {\n        interpreter.set_ax(0x4f01);\n        interpreter.set_cx(mode);\n        // TODO: better location\n        interpreter.set_es_di(0x50, 0x0);\n\n        // Try to call the VBE function, but ignored that specific mode if the call fails.\n        if interpreter.int10h().is_err() {\n            continue;\n        }\n        if check_ax(interpreter.ax()).is_err() {\n            continue;\n        }\n\n        // The VBE function wrote the information in memory.\n        let mut info_out = [0; 256];\n        interpreter.read_memory(0x500, &mut info_out[..]);\n\n        let mode_attributes = u16::from_le_bytes(<[u8; 2]>::try_from(&info_out[0..2]).unwrap());\n        if mode_attributes & (1 << 0) == 0 {\n            // Skip unsupported video modes.\n            continue;\n        }\n        if mode_attributes & (1 << 4) == 0 {\n            // Skip text modes.\n            continue;\n        }\n        if mode_attributes & (1 << 7) == 0 {\n            // Skip modes that don't support the linear framebuffer.\n            continue;\n        }\n\n        let x_resolution = u16::from_le_bytes(<[u8; 2]>::try_from(&info_out[0x12..0x14]).unwrap());\n        let y_resolution = u16::from_le_bytes(<[u8; 2]>::try_from(&info_out[0x14..0x16]).unwrap());\n        let phys_base = u32::from_le_bytes(<[u8; 4]>::try_from(&info_out[0x28..0x2c]).unwrap());\n        let bytes_per_scan_line =\n            u16::from_le_bytes(<[u8; 2]>::try_from(&info_out[0x32..0x34]).unwrap());\n        let red_mask_size = info_out[0x36];\n        let red_mask_pos = info_out[0x37];\n        let green_mask_size = info_out[0x38];\n        let green_mask_pos = info_out[0x39];\n        let blue_mask_size = info_out[0x3a];\n        let blue_mask_pos = info_out[0x3b];\n        let reserved_mask_size = info_out[0x3c];\n        let reserved_mask_pos = info_out[0x3d];\n\n        video_modes.push(ModeInfo {\n            mode_num: mode,\n            x_resolution,\n            y_resolution,\n            phys_base: u64::from(phys_base),\n            bytes_per_scan_line,\n            red_mask_size,\n            red_mask_pos,\n            green_mask_size,\n            green_mask_pos,\n            blue_mask_size,\n            blue_mask_pos,\n            reserved_mask_size,\n            reserved_mask_pos,\n        });\n    }\n\n    Ok(VbeContext {\n        interpreter,\n        video_modes,\n    })\n}\n\nimpl VbeContext {\n    /// Returns the list of available modes.\n    pub fn modes<'a>(&'a self) -> impl ExactSizeIterator<Item = Mode<'a>> + 'a {\n        self.video_modes.iter().map(|info| Mode { info })\n    }\n\n    /// Try to switch to the given video mode.\n    ///\n    /// > **Note**: As documented in [`load_vbe_info`], no other code should access the video card\n    /// >           or the VGA BIOS while this call is in progress.\n    ///\n    /// # Panic\n    ///\n    /// The mode number must be one of the supported modes.\n    ///\n    pub async fn set_current_mode(&mut self, mode_num: u16) -> Result<(), Error> {\n        assert!(self.video_modes.iter().any(|m| m.mode_num == mode_num));\n\n        self.interpreter.set_ax(0x4f02);\n\n        // Bit 14 requests to use the linear framebuffer.\n        // Note that bit 15 can normally be set in order to ask the BIOS to clear the screen,\n        // but we don't expose this feature as the specifications mention that it is not\n        // actually mandatory for the BIOS to do so.\n        self.interpreter.set_bx((1 << 14) | mode_num);\n\n        // Note that in case of failure such as an unsupported opcode, we might be in the middle\n        // of a mode switch and the video card might be in an inconsistent state. Unfortunately,\n        // there is no way to ask the video card to revert to the previous mode.\n        //\n        // While switching back to the previous mode seems like a legitimate idea, there are two\n        // major obstacles to this:\n        //\n        // - The VBE specs don't give a way to know what the initial mode is. The \"return current\n        //   VBE mode\" (0x3) function is only guaranteed to give a meaningful result if the mode\n        //   was earlier set using the \"set current mode\" function.\n        // - Chances are high that an error that happens when switching mode is a bug that would\n        //   happen as well when switching back to the previous one.\n        //\n\n        self.interpreter.int10h()?;\n        check_ax(self.interpreter.ax())?;\n\n        Ok(())\n    }\n}\n\n/// Access to a single mode within the [`VbeContext`].\n#[derive(Debug)]\npub struct Mode<'a> {\n    info: &'a ModeInfo,\n}\n\n#[derive(Debug)]\nstruct ModeInfo {\n    /// Identifier for this mode.\n    mode_num: u16,\n    /// Number of pixels for the width.\n    x_resolution: u16,\n    /// Number of pixels for the height.\n    y_resolution: u16,\n    /// Base for the physical address of a linear framebuffer for this mode.\n    phys_base: u64,\n    /// Number of bytes per scanline. Also often called the `pitch`.\n    bytes_per_scan_line: u16,\n    /// Size of the red component of the color.\n    red_mask_size: u8,\n    /// Position of the red component of the color.\n    red_mask_pos: u8,\n    /// Size of the green component of the color.\n    green_mask_size: u8,\n    /// Position of the green component of the color.\n    green_mask_pos: u8,\n    /// Size of the blue component of the color.\n    blue_mask_size: u8,\n    /// Position of the blue component of the color.\n    blue_mask_pos: u8,\n    /// Size of the reserved component of the color.\n    reserved_mask_size: u8,\n    /// Position of the reserved component of the color.\n    reserved_mask_pos: u8,\n}\n\nimpl<'a> Mode<'a> {\n    /// Returns the mode number, to pass to [`VbeContext::set_current_mode`].\n    pub fn num(&self) -> u16 {\n        self.info.mode_num\n    }\n\n    /// Get the number of pixels for respectively the width and height.\n    pub fn pixels_dimensions(&self) -> (u16, u16) {\n        (self.info.x_resolution, self.info.y_resolution)\n    }\n\n    /// Returns the physical memory location of the linear framebuffer once we will have switched\n    /// to this mode.\n    pub fn linear_framebuffer_location(&self) -> u64 {\n        self.info.phys_base\n    }\n\n    /// Returns the number of bytes per scan line. Also often called the `pitch`.\n    pub fn bytes_per_scan_line(&self) -> u16 {\n        self.info.bytes_per_scan_line\n    }\n\n    /// Returns the size of the red component of the color.\n    pub fn red_mask_size(&self) -> u8 {\n        self.info.red_mask_size\n    }\n\n    /// Returns the position of the red component of the color.\n    pub fn red_mask_pos(&self) -> u8 {\n        self.info.red_mask_pos\n    }\n\n    /// Returns the size of the green component of the color.\n    pub fn green_mask_size(&self) -> u8 {\n        self.info.green_mask_size\n    }\n\n    /// Returns the position of the green component of the color.\n    pub fn green_mask_pos(&self) -> u8 {\n        self.info.green_mask_pos\n    }\n\n    /// Returns the size of the blue component of the color.\n    pub fn blue_mask_size(&self) -> u8 {\n        self.info.blue_mask_size\n    }\n\n    /// Returns the position of the blue component of the color.\n    pub fn blue_mask_pos(&self) -> u8 {\n        self.info.blue_mask_pos\n    }\n\n    /// Returns the size of the reserved component of the color.\n    pub fn reserved_mask_size(&self) -> u8 {\n        self.info.reserved_mask_size\n    }\n\n    /// Returns the position of the reserved component of the color.\n    pub fn reserved_mask_pos(&self) -> u8 {\n        self.info.reserved_mask_pos\n    }\n}\n\n/// Error while calling VBE functioons.\n#[derive(Debug, derive_more::Display, derive_more::From)]\npub enum Error {\n    /// VBE implementation doesn't support the requested function.\n    #[display(fmt = \"VBE implementation doesn't support requested function\")]\n    #[from(ignore)]\n    NotSupported,\n    /// VBE implementation supports the function, but the call has failed for an undeterminate\n    /// reason.\n    #[display(fmt = \"VBE function call failed. Return code: {}\", ax_value)]\n    #[from(ignore)]\n    FunctionCallFailed {\n        /// Value returned by the VBE function in the `ax` register.\n        ax_value: u16,\n    },\n    /// Magic number produced by the VBE implementation is invalid.\n    #[display(fmt = \"Magic number produced by the VBE implementation is invalid\")]\n    #[from(ignore)]\n    BadMagic,\n    /// An error happened in the real mode interpreter. This indicates either a bug in the VGA\n    /// BIOS or, more likely, a bug in the interpreter itself.\n    #[display(fmt = \"Error in i386 real mode interpreter: {}\", _0)]\n    InterpretationError(interpreter::Error),\n}\n\n/// Check whether the value of `ax` at the end of a VBE function call indicates that the call was\n/// successful.\nfn check_ax(ax: u16) -> Result<(), Error> {\n    if ax == 0x4f {\n        return Ok(());\n    }\n\n    if (ax & 0xf) != 0x4f {\n        return Err(Error::NotSupported);\n    }\n\n    Err(Error::FunctionCallFailed { ax_value: ax })\n}\n"
  },
  {
    "path": "rust-toolchain",
    "content": "[toolchain]\nchannel = \"nightly-2025-03-14\"\ntargets = [\"wasm32-wasip1\"]\n"
  }
]