diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..c9a73b3f8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "arceos"] + path = arceos + url = https://github.com/langqiuyi-77/arceos.git diff --git a/arceos b/arceos new file mode 160000 index 000000000..acbb0d4ba --- /dev/null +++ b/arceos @@ -0,0 +1 @@ +Subproject commit acbb0d4ba9f3d8c983d829988b95446cda433098 diff --git a/arceos/.clang-format b/arceos/.clang-format deleted file mode 100644 index 10aa9f00c..000000000 --- a/arceos/.clang-format +++ /dev/null @@ -1,16 +0,0 @@ ---- -Language: Cpp -BasedOnStyle: LLVM -IndentWidth: 4 -ColumnLimit: 100 -AllowShortBlocksOnASingleLine: Empty -AllowShortFunctionsOnASingleLine: Inline -AllowShortLoopsOnASingleLine: true -AllowShortIfStatementsOnASingleLine: Never -AlignConsecutiveMacros: true -AlignEscapedNewlines: Left -BreakBeforeBraces: Custom -BraceWrapping: - AfterFunction: true -PointerAlignment: Right ---- diff --git a/arceos/.gitignore b/arceos/.gitignore deleted file mode 100644 index 49a19742c..000000000 --- a/arceos/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -/target -/.vscode -.DS_Store -*.asm -*.img -*.o -*.elf -*.bin -qemu.log -rusty-tags.vi -lk_trace.data -tags -*.swp diff --git a/arceos/Cargo.toml b/arceos/Cargo.toml deleted file mode 100644 index 55757f52c..000000000 --- a/arceos/Cargo.toml +++ /dev/null @@ -1,99 +0,0 @@ -[workspace] -resolver = "2" - -members = [ - "modules/axalloc", - "modules/alt_axalloc", - "modules/axconfig", - "modules/axdisplay", - "modules/axdriver", - "modules/axfs", - "modules/axhal", - "modules/axlog", - "modules/axmm", - "modules/axdma", - "modules/axnet", - "modules/axruntime", - "modules/axsync", - "modules/axtask", - "modules/bump_allocator", - "modules/riscv_vcpu", - - "api/axfeat", - "api/arceos_api", - "api/arceos_posix_api", - - "ulib/axstd", - "ulib/axlibc", - - "payload/origin", - "payload/skernel", - "payload/skernel2", - - "tour/u_1_0", - "tour/u_2_0", - "tour/u_3_0", - "tour/u_4_0", - "tour/u_5_0", - "tour/u_6_0", - "tour/u_6_1", - "tour/u_7_0", - "tour/u_8_0", - "tour/m_1_0", - "tour/m_1_1", - "tour/m_2_0", - "tour/m_3_0", - "tour/m_3_1", - "tour/h_1_0", - "tour/h_2_0", - "tour/h_3_0", - "tour/h_4_0", - - "exercises/print_with_color", - "exercises/support_hashmap", - "exercises/alt_alloc", - "exercises/sys_map", - "exercises/simple_hv", - "exercises/ramfs_rename", -] - -[workspace.package] -version = "0.1.0" -authors = ["Yuekai Jia "] -license = "GPL-3.0-or-later OR Apache-2.0 OR MulanPSL-2.0" -homepage = "https://github.com/arceos-org/arceos" -documentation = "https://arceos-org.github.io/arceos" -repository = "https://github.com/arceos-org/arceos" -keywords = ["arceos", "kernel"] -categories = ["os", "no-std"] - -[workspace.dependencies] -axstd = { path = "ulib/axstd" } -axlibc = { path = "ulib/axlibc" } - -arceos_api = { path = "api/arceos_api" } -arceos_posix_api = { path = "api/arceos_posix_api", features = ["fs", "fd"] } -axfeat = { path = "api/axfeat" } - -axalloc = { path = "modules/axalloc" } -alt_axalloc = { path = "modules/alt_axalloc" } -axconfig = { path = "modules/axconfig" } -axdisplay = { path = "modules/axdisplay" } -axdriver = { path = "modules/axdriver" } -axfs = { path = "modules/axfs" } -axhal = { path = "modules/axhal" } -axlog = { path = "modules/axlog" } -axmm = { path = "modules/axmm" } -axnet = { path = "modules/axnet" } -axruntime = { path = "modules/axruntime" } -axsync = { path = "modules/axsync" } -axtask = { path = "modules/axtask" } -axdma = { path = "modules/axdma" } -elf = { path = "modules/elf" } -axfs_ramfs = { path = "./axfs_ramfs" } - -[patch.crates-io] -kernel_guard = { path = "../crates/kernel_guard"} - -[profile.release] -lto = true diff --git a/arceos/LICENSE.Apache2 b/arceos/LICENSE.Apache2 deleted file mode 100644 index 261eeb9e9..000000000 --- a/arceos/LICENSE.Apache2 +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/arceos/LICENSE.GPLv3 b/arceos/LICENSE.GPLv3 deleted file mode 100644 index f288702d2..000000000 --- a/arceos/LICENSE.GPLv3 +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/arceos/LICENSE.MulanPSL2 b/arceos/LICENSE.MulanPSL2 deleted file mode 100644 index 5729580d9..000000000 --- a/arceos/LICENSE.MulanPSL2 +++ /dev/null @@ -1,127 +0,0 @@ - 木兰宽松许可证, 第2版 - - 木兰宽松许可证, 第2版 - 2020年1月 http://license.coscl.org.cn/MulanPSL2 - - - 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: - - 0. 定义 - - “软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 - - “贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 - - “贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 - - “法人实体”是指提交贡献的机构及其“关联实体”。 - - “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 - - 1. 授予版权许可 - - 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 - - 2. 授予专利许可 - - 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 - - 3. 无商标许可 - - “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 - - 4. 分发限制 - - 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 - - 5. 免责声明与责任限制 - - “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 - - 6. 语言 - “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 - - 条款结束 - - 如何将木兰宽松许可证,第2版,应用到您的软件 - - 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: - - 1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; - - 2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; - - 3, 请将如下声明文本放入每个源文件的头部注释中。 - - Copyright (c) [Year] [name of copyright holder] - [Software Name] is licensed under Mulan PSL v2. - You can use this software according to the terms and conditions of the Mulan PSL v2. - You may obtain a copy of Mulan PSL v2 at: - http://license.coscl.org.cn/MulanPSL2 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - See the Mulan PSL v2 for more details. - - - Mulan Permissive Software License,Version 2 - - Mulan Permissive Software License,Version 2 (Mulan PSL v2) - January 2020 http://license.coscl.org.cn/MulanPSL2 - - Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: - - 0. Definition - - Software means the program and related documents which are licensed under this License and comprise all Contribution(s). - - Contribution means the copyrightable work licensed by a particular Contributor under this License. - - Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. - - Legal Entity means the entity making a Contribution and all its Affiliates. - - Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. - - 1. Grant of Copyright License - - Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. - - 2. Grant of Patent License - - Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. - - 3. No Trademark License - - No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. - - 4. Distribution Restriction - - You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. - - 5. Disclaimer of Warranty and Limitation of Liability - - THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - 6. Language - - THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. - - END OF THE TERMS AND CONDITIONS - - How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software - - To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: - - i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; - - ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package; - - iii Attach the statement to the appropriate annotated syntax at the beginning of each source file. - - - Copyright (c) [Year] [name of copyright holder] - [Software Name] is licensed under Mulan PSL v2. - You can use this software according to the terms and conditions of the Mulan PSL v2. - You may obtain a copy of Mulan PSL v2 at: - http://license.coscl.org.cn/MulanPSL2 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - See the Mulan PSL v2 for more details. diff --git a/arceos/LICENSE.MulanPubL2 b/arceos/LICENSE.MulanPubL2 deleted file mode 100644 index 2fcd23f58..000000000 --- a/arceos/LICENSE.MulanPubL2 +++ /dev/null @@ -1,183 +0,0 @@ - 木兰公共许可证, 第2版 - -木兰公共许可证, 第2版 - -2021年5月 http://license.coscl.org.cn/MulanPubL-2.0 - -您对“贡献”的复制、使用、修改及分发受木兰公共许可证,第2版(以下简称“本许可证”)的如下条款的约束: - -0. 定义 - -“贡献” 是指由“贡献者”许可在“本许可证”下的受版权法保护的作品,包括最初“贡献者”许可在“本许可证”下的作品及后续“贡献者”许可在“本许可证”下的“衍生作品”。 - -“贡献者” 是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 - -“法人实体” 是指提交贡献的机构及其“关联实体”。 - -“关联实体” 是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的“控制”是指拥有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 - -“衍生作品” 是指基于“贡献”创作的作品,具体包括对全部或部分“贡献”进行修改、重写、翻译、注释、组合或与之链接(包括动态链接或静态链接)而形成的作品。仅与“贡献”进行进程间通信或系统调用的作品是独立作品,不属于“衍生作品”。 - -“对应源代码” 是指生成、安装和(对于可执行作品)运行目标代码所需的所有源文件和与之关联的接口定义文件,以及控制这些活动的脚本,但不包括编译环境、编译工具、云服务平台(如果有)。 - -“分发” 是指通过任何媒介向他人提供“贡献”或“衍生作品”的行为,以及利用“贡献”或“衍生作品”通过网络远程给用户提供服务的行为,例如:通过利用“贡献”或“衍生作品”搭建的云服务平台提供在线服务的行为。 - -1. 授予版权许可 - -每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、“分发”其“贡献”或“衍生作品”,不论修改与否。 - -2. 授予专利许可 - -每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销的情形除外)专利许可,供您使用、制造、委托制造、销售、许诺销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”中的专利权利要求,而不包括仅因您对“贡献”的修改而将必然会侵犯到的专利权利要求。如果您或您的“关联实体”直接或间接地,就“贡献”对任何人发起专利侵权诉讼(包括在诉讼中提出反诉请求或交叉请求)或发起其他专利维权行动,则“贡献者”根据“本许可证”授予您的专利许可自您发起专利诉讼或专利维权行动之日终止。 - -3. 无商标许可 - -“贡献者”在“本许可证”下不提供对其商品名称、商标、服务标识或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用的情形除外。 - -4. 分发限制 - -您可以将您接收到的“贡献”或您的“衍生作品”以源程序形式或可执行形式重新“分发”,但必须满足下列条件: - -(1)您必须向接收者提供“本许可证”的副本,并保留“贡献”中的版权、商标、专利及免责声明;并且, - -(2)如果您“分发”您接收到的“贡献”,您必须使用“本许可证”提供该“贡献”的源代码副本;如果您 “分发”您的“衍生作品”,您必须: - -(i)随“衍生作品”提供使用“本许可证”“分发”的您的“衍生作品”的“对应源代码”。如果您通过下载链接提供前述“对应源代码”,则您应将下载链接地址置于“衍生作品”或其随附文档中的明显位置,有效期自该“衍生作品”“分发”之日起不少于三年,并确保接收者可以获得“对应源代码”;或者, - -(ii)随“衍生作品”向接收者提供一个书面要约,表明您愿意提供根据“本许可证”“分发”的您“衍生作品”的“对应源代码”。该书面要约应置于“衍生作品”中的明显位置,并确保接收者根据书面要约可获取“对应源代码”的时间从您接到该请求之日起不得超过三个月,且有效期自该“衍生作品”“分发”之日起不少于三年。 - -5. 违约与终止 - -如果您违反“本许可证”,任何“贡献者”有权书面通知您终止其根据“本许可证”授予您的许可。该“贡献者”授予您的许可自您接到其终止通知之日起终止。仅在如下两种情形下,即使您收到“贡献者”的通知也并不终止其授予您的许可: - -(1)您在接到该终止通知之前已停止所有违反行为; - -(2)您是首次收到该“贡献者”根据“本许可证”发出的书面终止通知,并且您在收到该通知后30天内已停止所有违反行为。 - -只要您下游的接收者遵守“本许可证”的相关规定,即使您在“本许可证”下被授予的许可终止,不影响下游的接收者根据“本许可证”享有的权利。 - -6. 例外 - -如果您将“贡献”与采用GNU AFFERO GENERAL PUBLIC LICENSE Version 3(以下简称“AGPLv3”)或其后续版本的作品结合形成新的“衍生作品”,且根据“AGPLv3”或其后续版本的要求您有义务将新形成的“衍生作品”以“AGPLv3”或其后续版本进行许可的,您可以根据“AGPLv3”或其后续版本进行许可,只要您在“分发”该“衍生作品”的同时向接收者提供“本许可证”的副本,并保留“贡献”中的版权、商标、专利及免责声明。但任何“贡献者”不会因您选择“AGPLv3”或其后续版本而授予该“衍生作品”的接收者更多权利。 - -7. 免责声明与责任限制 - -“贡献”在提供时不带有任何明示或默示的担保。在任何情况下,“贡献者”或版权人不对任何人因使用“贡献”而引发的任何直接或间接损失承担任何责任,不论该等损失因何种原因导致或者基于何种法律理论,即使其曾被告知有该等损失的可能性。 - -8. 语言 - -“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何不一致,以中文版为准。 - -条款结束 - -如何将木兰公共许可证,第2版,应用到您的软件 - -如果您希望将木兰公共许可证,第2版,应用到您的软件,为了方便接收者查阅,建议您完成如下三步: - -1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; - -2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; - -3, 请将如下声明文本放入每个源文件的头部注释中。 - -Copyright (c) [Year] [name of copyright holder] -[Software Name] is licensed under Mulan PubL v2. -You can use this software according to the terms and conditions of the Mulan PubL v2. -You may obtain a copy of Mulan PubL v2 at: - http://license.coscl.org.cn/MulanPubL-2.0 -THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -See the Mulan PubL v2 for more details. - - - Mulan Public License,Version 2 - -Mulan Public License,Version 2 (Mulan PubL v2) - -May 2021 http://license.coscl.org.cn/MulanPubL-2.0 - -Your reproduction, use, modification and Distribution of the Contribution shall be subject to Mulan Public License, Version 2 (this License) with following terms and conditions: - -0. Definition - -Contribution means the copyrightable work licensed by a particular Contributor under this License, including the work licensed by the initial Contributor under this License and its Derivative Work licensed by any subsequent Contributor under this License. - -Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. - -Legal Entity means the entity making a Contribution and all its Affiliates. - -Affiliates mmeans entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. - -Derivative Work means works created based on Contribution, specifically including works formed by modifying, rewriting, translating, annotating, combining or linking to all or part of Contribution (including dynamic linking or static linking). Works which only communicate with Contribution through inter-process communication or system call, are independent works, rather than Derivative Work. - -Corresponding Source Code means all the source code needed to generate, install, and (for an executable work) run the object code including the interface definition files associated with source files for the work, and scripts to control those activities, excluding of compilation environment and compilation tools, cloud services platform (if any). - -Distribute (or Distribution) means the act of making the Contribution or Derivative Work available to others through any medium, and using the Contribution or Derivative Work to provide online services to users, such as the act of providing online services through a cloud service platform built using Contributions or Derivative Works. - -1. Grant of Copyright License - -Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or Distribute its Contribution or Derivative Work, with modification or not. - -2. Grant of Patent License - -Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to use, make, have made, sell, offer for sale, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, excluding of any patent claims solely be infringed by your modification. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that any Contribution infringes patents, then any patent license granted to you under this License for the Contribution shall terminate as of the date such litigation or activity is filed or taken. - -3. No Trademark License - -No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. - -4. Distribution Restriction - -You may Distribute the Contribution you received or your Derivative Work, whether in source or executable forms, provided that you meet the following conditions: - -1) You must provide recipients with a copy of this License and retain copyright, trademark, patent and disclaimer statements in the Contribution; and, - -2) If you Distribute the Contribution you received, you must provide copies of the Contribution’s source code under this License; - -If you Distribute your Derivative Work, you have to: - -(i) accompanying the Derivative work, provide recipients with Corresponding Source Code of your Derivative Work under this License. If you provide the Corresponding Source Code through a download link, you should place such link address prominently in the Derivative Work or its accompanying documents, and be valid no less than three years from your Distribution of the particular Derivative Work, and ensure that the recipients can acquire the Corresponding Source Code through the link; or, - -(ii) accompanying the Derivative Work, provide recipients with a written offer indicating your willingness to provide the Corresponding Source Code of the Derivative Work licensed under this License. Such written offer shall be placed prominently in the Derivative Work or its accompanying documents. Without reasonable excuse, the recipient shall be able to acquire the Corresponding Source code of the Derivative work for no more than three months from your receipt of a valid request, and be valid no less than three years from your Distribution of the particular Derivative Work. - -5. Breach and Termination - -If you breach this License, any Contributor has the right to notify you in writing to terminate its license granted to you under this License. The license granted to you by such Contributor terminates upon your receipt of such notice of termination. Notwithstanding the foregoing, your license will not be terminated even if you receive a notice of termination from Contributor, provided that: - -1) you have cured all the breaches prior to receiving such notice of termination; or, - -2) it’s your first time to receive a notice of termination from such Contributor pursuant to this License, and you have cured all the breaches within 30 days of receipt of such notice. - -Termination of your license under this License shall not affect the downstream recipient's rights under this License, provided that the downstream recipient complies with this License. - -6. Exceptions - -If you combine Contribution or your Derivative Work with a work licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (hereinafter referred to as “AGPLv3”) or its subsequent versions, and according to the AGPLv3 or its subsequent versions, you have an obligation to make the combined work to be licensed under the corresponding license, you can license such combined work under the license, provided that when you Distribute the combined work, you also provide a copy of this License to the recipients, and retain copyright, trademarks, patents, and disclaimer statements in the Contribution. No Contributor will grant additional rights to the recipients of the combined work for your license under AGPLv3 or its subsequent versions. - -7. Disclaimer of Warranty and Limitation of liability - -CONTRIBUTION ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE CONTRIBUTION, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -8. Language - -THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. - -END OF THE TERMS AND CONDITIONS - -How to apply the Mulan Public License,Version 2 (Mulan PubL v2), to your software - -To apply the Mulan Public License,Version 2 to your work, for easy identification by recipients, you are suggested to complete following three steps: - -Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; -Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package; -Attach the statement to the appropriate annotated syntax at the beginning of each source file. -Copyright (c) [Year] [name of copyright holder] -[Software Name] is licensed under Mulan PubL v2. -You can use this software according to the terms and conditions of the Mulan PubL v2. -You may obtain a copy of Mulan PubL v2 at: - http://license.coscl.org.cn/MulanPubL-2.0 -THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -See the Mulan PubL v2 for more details. diff --git a/arceos/Makefile b/arceos/Makefile deleted file mode 100644 index ac86cb55d..000000000 --- a/arceos/Makefile +++ /dev/null @@ -1,238 +0,0 @@ -# Available arguments: -# * General options: -# - `ARCH`: Target architecture: x86_64, riscv64, aarch64 -# - `PLATFORM`: Target platform in the `platforms` directory -# - `SMP`: Number of CPUs -# - `MODE`: Build mode: release, debug -# - `LOG:` Logging level: warn, error, info, debug, trace -# - `V`: Verbose level: (empty), 1, 2 -# * App options: -# - `A` or `APP`: Path to the application -# - `FEATURES`: Features os ArceOS modules to be enabled. -# - `APP_FEATURES`: Features of (rust) apps to be enabled. -# * QEMU options: -# - `BLK`: Enable storage devices (virtio-blk) -# - `NET`: Enable network devices (virtio-net) -# - `GRAPHIC`: Enable display devices and graphic output (virtio-gpu) -# - `BUS`: Device bus type: mmio, pci -# - `DISK_IMG`: Path to the virtual disk image -# - `ACCEL`: Enable hardware acceleration (KVM on linux) -# - `QEMU_LOG`: Enable QEMU logging (log file is "qemu.log") -# - `NET_DUMP`: Enable network packet dump (log file is "netdump.pcap") -# - `NET_DEV`: QEMU netdev backend types: user, tap, bridge -# - `VFIO_PCI`: PCI device address in the format "bus:dev.func" to passthrough -# - `VHOST`: Enable vhost-net for tap backend (only for `NET_DEV=tap`) -# * Network options: -# - `IP`: ArceOS IPv4 address (default is 10.0.2.15 for QEMU user netdev) -# - `GW`: Gateway IPv4 address (default is 10.0.2.2 for QEMU user netdev) - -# General options -ARCH ?= riscv64 -PLATFORM ?= -SMP ?= 1 -MODE ?= release -LOG ?= warn -V ?= - -# App options -A ?= tour/u_1_0 -APP ?= $(A) -FEATURES ?= -APP_FEATURES ?= -TARGET_DIR ?= $(PWD)/target - -# QEMU options -BLK ?= n -NET ?= n -GRAPHIC ?= n -BUS ?= pci -PFLASH ?= y -PFLASH_IMG ?= pflash.img - -DISK_IMG ?= disk.img -QEMU_LOG ?= y -NET_DUMP ?= n -NET_DEV ?= user -VFIO_PCI ?= -VHOST ?= n - -# Network options -IP ?= 10.0.2.15 -GW ?= 10.0.2.2 - -# App type -ifeq ($(wildcard $(APP)),) - $(error Application path "$(APP)" is not valid) -endif - -ifneq ($(wildcard $(APP)/Cargo.toml),) - APP_TYPE := rust -else - APP_TYPE := c -endif - -# Architecture and platform -ifneq ($(filter $(MAKECMDGOALS),unittest unittest_no_fail_fast),) - PLATFORM_NAME := -else ifneq ($(PLATFORM),) - # `PLATFORM` is specified, override the `ARCH` variables - builtin_platforms := $(patsubst platforms/%.toml,%,$(wildcard platforms/*)) - ifneq ($(filter $(PLATFORM),$(builtin_platforms)),) - # builtin platform - PLATFORM_NAME := $(PLATFORM) - _arch := $(word 1,$(subst -, ,$(PLATFORM))) - else ifneq ($(wildcard $(PLATFORM)),) - # custom platform, read the "platform" field from the toml file - PLATFORM_NAME := $(shell cat $(PLATFORM) | sed -n 's/^platform = "\([a-z0-9A-Z_\-]*\)"/\1/p') - _arch := $(shell cat $(PLATFORM) | sed -n 's/^arch = "\([a-z0-9A-Z_\-]*\)"/\1/p') - else - $(error "PLATFORM" must be one of "$(builtin_platforms)" or a valid path to a toml file) - endif - ifeq ($(origin ARCH),command line) - ifneq ($(ARCH),$(_arch)) - $(error "ARCH=$(ARCH)" is not compatible with "PLATFORM=$(PLATFORM)") - endif - endif - ARCH := $(_arch) -endif - -ifeq ($(ARCH), x86_64) - # Don't enable kvm for WSL/WSL2. - ACCEL ?= $(if $(findstring -microsoft, $(shell uname -r | tr '[:upper:]' '[:lower:]')),n,y) - PLATFORM_NAME ?= x86_64-qemu-q35 -else ifeq ($(ARCH), riscv64) - ACCEL ?= n - PLATFORM_NAME ?= riscv64-qemu-virt -else ifeq ($(ARCH), aarch64) - ACCEL ?= n - PLATFORM_NAME ?= aarch64-qemu-virt -else - $(error "ARCH" must be one of "x86_64", "riscv64", or "aarch64") -endif - -# Feature parsing -include scripts/make/features.mk - -# Target -ifeq ($(ARCH), x86_64) - TARGET := x86_64-unknown-none -else ifeq ($(ARCH), riscv64) - TARGET := riscv64gc-unknown-none-elf -else ifeq ($(ARCH), aarch64) - ifeq ($(findstring fp_simd,$(FEATURES)),) - TARGET := aarch64-unknown-none-softfloat - else - TARGET := aarch64-unknown-none - endif -endif - -export AX_ARCH=$(ARCH) -export AX_PLATFORM=$(PLATFORM_NAME) -export AX_SMP=$(SMP) -export AX_MODE=$(MODE) -export AX_LOG=$(LOG) -export AX_TARGET=$(TARGET) -export AX_IP=$(IP) -export AX_GW=$(GW) - -# Binutils -CROSS_COMPILE ?= $(ARCH)-linux-musl- -CC := $(CROSS_COMPILE)gcc -AR := $(CROSS_COMPILE)ar -RANLIB := $(CROSS_COMPILE)ranlib -LD := rust-lld -flavor gnu - -OBJDUMP ?= rust-objdump -d --print-imm-hex --x86-asm-syntax=intel -OBJCOPY ?= rust-objcopy --binary-architecture=$(ARCH) -GDB ?= gdb-multiarch - -# Paths -OUT_DIR ?= $(APP) - -APP_NAME := $(shell basename $(APP)) -LD_SCRIPT := $(TARGET_DIR)/$(TARGET)/$(MODE)/linker_$(PLATFORM_NAME).lds -OUT_ELF := $(OUT_DIR)/$(APP_NAME)_$(PLATFORM_NAME).elf -OUT_BIN := $(OUT_DIR)/$(APP_NAME)_$(PLATFORM_NAME).bin - -all: build - -include scripts/make/utils.mk -include scripts/make/build.mk -include scripts/make/qemu.mk -include scripts/make/test.mk -ifeq ($(PLATFORM_NAME), aarch64-raspi4) - include scripts/make/raspi4.mk -else ifeq ($(PLATFORM_NAME), aarch64-bsta1000b) - include scripts/make/bsta1000b-fada.mk -endif - -build: $(OUT_DIR) $(OUT_BIN) - -disasm: - $(OBJDUMP) $(OUT_ELF) | less - -run: build justrun - -justrun: - $(call run_qemu) - -debug: build - $(call run_qemu_debug) & - sleep 1 - $(GDB) $(OUT_ELF) \ - -ex 'target remote localhost:1234' \ - -ex 'b rust_entry' \ - -ex 'continue' \ - -ex 'disp /16i $$pc' - -clippy: -ifeq ($(origin ARCH), command line) - $(call cargo_clippy,--target $(TARGET)) -else - $(call cargo_clippy) -endif - -doc: - $(call cargo_doc) - -doc_check_missing: - $(call cargo_doc) - -fmt: - cargo fmt --all - -fmt_c: - @clang-format --style=file -i $(shell find ulib/axlibc -iname '*.c' -o -iname '*.h') - -unittest: - $(call unit_test) - -unittest_no_fail_fast: - $(call unit_test,--no-fail-fast) - -disk_img: -ifneq ($(wildcard $(DISK_IMG)),) - @printf "$(YELLOW_C)warning$(END_C): disk image \"$(DISK_IMG)\" already exists!\n" -else - $(call make_disk_image,fat32,$(DISK_IMG)) - $(call setup_disk,$(DISK_IMG)) -endif - -pflash_img: - @rm -f $(PFLASH_IMG) - $(call mk_pflash,$(PFLASH_IMG)) - -payload: - @make -C ./payload - -clean: clean_c - rm -rf $(APP)/*.bin $(APP)/*.elf - rm -rf tour/*/*.bin tour/*/*.elf - cargo clean - rm *.img - -clean_c:: - rm -rf ulib/axlibc/build_* - rm -rf $(app-objs) - -.PHONY: all build disasm run justrun debug clippy fmt fmt_c test test_no_fail_fast clean clean_c doc disk_img pflash_img payload diff --git a/arceos/README.md b/arceos/README.md deleted file mode 100644 index b652b0c42..000000000 --- a/arceos/README.md +++ /dev/null @@ -1,200 +0,0 @@ -# ArceOS - -[![CI](https://github.com/arceos-org/arceos/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/arceos-org/arceos/actions/workflows/build.yml) -[![CI](https://github.com/arceos-org/arceos/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/arceos-org/arceos/actions/workflows/test.yml) -[![Docs](https://img.shields.io/badge/docs-pages-green)](https://arceos-org.github.io/arceos/) - -An experimental modular operating system (or unikernel) written in Rust. - -ArceOS was inspired a lot by [Unikraft](https://github.com/unikraft/unikraft). - -🚧 Working In Progress. - -## Features & TODOs - -* [x] Architecture: x86_64, riscv64, aarch64 -* [x] Platform: QEMU pc-q35 (x86_64), virt (riscv64/aarch64) -* [x] Multi-thread -* [x] FIFO/RR/CFS scheduler -* [x] VirtIO net/blk/gpu drivers -* [x] TCP/UDP net stack using [smoltcp](https://github.com/smoltcp-rs/smoltcp) -* [x] Synchronization/Mutex -* [x] SMP scheduling with single run queue -* [x] File system -* [ ] Compatible with Linux apps -* [ ] Interrupt driven device I/O -* [ ] Async I/O - -## Quick Start - -### 1. Install Build Dependencies - -Install [cargo-binutils](https://github.com/rust-embedded/cargo-binutils) to use `rust-objcopy` and `rust-objdump` tools: - -```bash -cargo install cargo-binutils -``` - -#### Dependencies for C apps - -Install `libclang-dev`: - -```bash -sudo apt install libclang-dev -``` - -Download & install [musl](https://musl.cc) toolchains: - -```bash -# download -wget https://musl.cc/aarch64-linux-musl-cross.tgz -wget https://musl.cc/riscv64-linux-musl-cross.tgz -wget https://musl.cc/x86_64-linux-musl-cross.tgz -# install -tar zxf aarch64-linux-musl-cross.tgz -tar zxf riscv64-linux-musl-cross.tgz -tar zxf x86_64-linux-musl-cross.tgz -# exec below command in bash OR add below info in ~/.bashrc -export PATH=`pwd`/x86_64-linux-musl-cross/bin:`pwd`/aarch64-linux-musl-cross/bin:`pwd`/riscv64-linux-musl-cross/bin:$PATH -``` - -#### Dependencies for running apps - -```bash -# for Debian/Ubuntu -sudo apt-get install qemu-system -``` - -```bash -# for macos -brew install qemu -``` - -Other systems and arch please refer to [Qemu Download](https://www.qemu.org/download/#linux) - -### 2. Build & Run - -```bash -# e.g. build app in arceos directory -make A=path/to/app ARCH= LOG= -# e.g. run app in arceos directory -make run A=path/to/app ARCH= LOG= -# e.g. build&run oscamp tour app tour/u_1_0 -make pflash_img -make disk_img -make run A=tour/u_1_0 -# e.g. try to build&run oscamp tour apps -./test_tour.sh -``` - -Where `path/to/app` is the relative path to the application. Examples applications can be found in the [examples](examples/) directory or the [arceos-apps](https://github.com/arceos-org/arceos-apps) repository. - -`` should be one of `riscv64`, `aarch64`, `x86_64`. - -`` should be one of `off`, `error`, `warn`, `info`, `debug`, `trace`. - -More arguments and targets can be found in [Makefile](Makefile). - -For example, to run the [httpserver](examples/httpserver/) on `qemu-system-aarch64` with 4 cores and log level `info`: - -```bash -make A=examples/httpserver ARCH=aarch64 LOG=info SMP=4 run NET=y -``` - -Note that the `NET=y` argument is required to enable the network device in QEMU. These arguments (`BLK`, `GRAPHIC`, etc.) only take effect at runtime not build time. - -## How to write ArceOS apps - -You can write and build your custom applications outside the ArceOS source tree. -Examples are given below and in the [app-helloworld](https://github.com/arceos-org/app-helloworld) and [arceos-apps](https://github.com/arceos-org/arceos-apps) repositories. - -### Rust - -1. Create a new rust package with `no_std` and `no_main` environment. -2. Add `axstd` dependency and features to enable to `Cargo.toml`: - - ```toml - [dependencies] - axstd = { path = "/path/to/arceos/ulib/axstd", features = ["..."] } - # or use git repository: - # axstd = { git = "https://github.com/arceos-org/arceos.git", features = ["..."] } - ``` - -3. Call library functions from `axstd` in your code, just like the Rust [std](https://doc.rust-lang.org/std/) library. - - Remember to annotate the `main` function with `#[no_mangle]` (see this [example](examples/helloworld/src/main.rs)). - -4. Build your application with ArceOS, by running the `make` command in the application directory: - - ```bash - # in app directory - make -C /path/to/arceos A=$(pwd) ARCH= run - # more args: LOG= SMP= NET=[y|n] ... - ``` - - All arguments and targets are the same as above. - -### C - -1. Create `axbuild.mk` and `features.txt` in your project: - - ```bash - app/ - ├── foo.c - ├── bar.c - ├── axbuild.mk # optional, if there is only one `main.c` - └── features.txt # optional, if only use default features - ``` - -2. Add build targets to `axbuild.mk`, add features to enable to `features.txt` (see this [example](examples/httpserver-c/)): - - ```bash - # in axbuild.mk - app-objs := foo.o bar.o - ``` - - ```bash - # in features.txt - alloc - paging - net - ``` - -3. Build your application with ArceOS, by running the `make` command in the application directory: - - ```bash - # in app directory - make -C /path/to/arceos A=$(pwd) ARCH= run - # more args: LOG= SMP= NET=[y|n] ... - ``` - -## How to build ArceOS for specific platforms and devices - -Set the `PLATFORM` variable when run `make`: - -```bash -# Build helloworld for raspi4 -make PLATFORM=aarch64-raspi4 A=examples/helloworld -``` - -You may also need to select the corrsponding device drivers by setting the `FEATURES` variable: - -```bash -# Build the shell app for raspi4, and use the SD card driver -make PLATFORM=aarch64-raspi4 A=examples/shell FEATURES=driver-bcm2835-sdhci -# Build httpserver for the bare-metal x86_64 platform, and use the ixgbe and ramdisk driver -make PLATFORM=x86_64-pc-oslab A=examples/httpserver FEATURES=driver-ixgbe,driver-ramdisk SMP=4 -``` - -## How to reuse ArceOS modules in your own project - -```toml -# In Cargo.toml -[dependencies] -axalloc = { git = "https://github.com/arceos-org/arceos.git", tag = "v0.1.0" } # modules/axalloc -axhal = { git = "https://github.com/arceos-org/arceos.git", tag = "v0.1.0" } # modules/axhal -``` - -## Design - -![](doc/figures/ArceOS.svg) diff --git a/arceos/api/arceos_api/Cargo.toml b/arceos/api/arceos_api/Cargo.toml deleted file mode 100644 index c052aa8a9..000000000 --- a/arceos/api/arceos_api/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[package] -name = "arceos_api" -version.workspace = true -edition = "2021" -authors = ["Yuekai Jia "] -description = "Public APIs and types for ArceOS modules" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/api/arceos_api" -documentation = "https://arceos-org.github.io/arceos/arceos_api/index.html" - -[features] -default = [] - -irq = ["axfeat/irq"] -alloc = ["dep:axalloc", "axfeat/alloc"] -alt_alloc = ["dep:alt_axalloc", "axfeat/alt_alloc"] -paging = ["dep:axmm", "axfeat/paging"] -dma = ["dep:axdma", "axfeat/dma"] -multitask = ["axtask/multitask", "axsync/multitask", "axfeat/multitask"] -fs = ["dep:axfs", "dep:axdriver", "axfeat/fs"] -net = ["dep:axnet", "dep:axdriver", "axfeat/net"] -display = ["dep:axdisplay", "dep:axdriver", "axfeat/display"] - -myfs = ["axfeat/myfs"] - -# Use dummy functions if the feature is not enabled -dummy-if-not-enabled = [] - -[dependencies] -axio = "0.1" -axerrno = "0.1" -axfeat = { workspace = true } -axruntime = { workspace = true } -axconfig = { workspace = true } -axlog = { workspace = true } -axhal = { workspace = true } -axsync = { workspace = true } -axalloc = { workspace = true, optional = true } -alt_axalloc = { workspace = true, optional = true } -axmm = { workspace = true, optional = true } -axdma = { workspace = true, optional = true } -axtask = { workspace = true, optional = true } -axdriver = { workspace = true, optional = true } -axfs = { workspace = true, optional = true } -axnet = { workspace = true, optional = true } -axdisplay = { workspace = true, optional = true } diff --git a/arceos/api/arceos_api/src/imp/display.rs b/arceos/api/arceos_api/src/imp/display.rs deleted file mode 100644 index 1abe25e59..000000000 --- a/arceos/api/arceos_api/src/imp/display.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub use axdisplay::DisplayInfo as AxDisplayInfo; - -/// Gets the framebuffer information. -pub fn ax_framebuffer_info() -> AxDisplayInfo { - axdisplay::framebuffer_info() -} - -/// Flushes the framebuffer, i.e. show on the screen. -pub fn ax_framebuffer_flush() { - axdisplay::framebuffer_flush() -} diff --git a/arceos/api/arceos_api/src/imp/fs.rs b/arceos/api/arceos_api/src/imp/fs.rs deleted file mode 100644 index fd7dac3ed..000000000 --- a/arceos/api/arceos_api/src/imp/fs.rs +++ /dev/null @@ -1,87 +0,0 @@ -use alloc::string::String; -use axerrno::AxResult; -use axfs::fops::{Directory, File}; - -pub use axfs::fops::DirEntry as AxDirEntry; -pub use axfs::fops::FileAttr as AxFileAttr; -pub use axfs::fops::FilePerm as AxFilePerm; -pub use axfs::fops::FileType as AxFileType; -pub use axfs::fops::OpenOptions as AxOpenOptions; -pub use axio::SeekFrom as AxSeekFrom; - -#[cfg(feature = "myfs")] -pub use axfs::fops::{Disk as AxDisk, MyFileSystemIf}; - -/// A handle to an opened file. -pub struct AxFileHandle(File); - -/// A handle to an opened directory. -pub struct AxDirHandle(Directory); - -pub fn ax_open_file(path: &str, opts: &AxOpenOptions) -> AxResult { - Ok(AxFileHandle(File::open(path, opts)?)) -} - -pub fn ax_open_dir(path: &str, opts: &AxOpenOptions) -> AxResult { - Ok(AxDirHandle(Directory::open_dir(path, opts)?)) -} - -pub fn ax_read_file(file: &mut AxFileHandle, buf: &mut [u8]) -> AxResult { - file.0.read(buf) -} - -pub fn ax_read_file_at(file: &AxFileHandle, offset: u64, buf: &mut [u8]) -> AxResult { - file.0.read_at(offset, buf) -} - -pub fn ax_write_file(file: &mut AxFileHandle, buf: &[u8]) -> AxResult { - file.0.write(buf) -} - -pub fn ax_write_file_at(file: &AxFileHandle, offset: u64, buf: &[u8]) -> AxResult { - file.0.write_at(offset, buf) -} - -pub fn ax_truncate_file(file: &AxFileHandle, size: u64) -> AxResult { - file.0.truncate(size) -} - -pub fn ax_flush_file(file: &AxFileHandle) -> AxResult { - file.0.flush() -} - -pub fn ax_seek_file(file: &mut AxFileHandle, pos: AxSeekFrom) -> AxResult { - file.0.seek(pos) -} - -pub fn ax_file_attr(file: &AxFileHandle) -> AxResult { - file.0.get_attr() -} - -pub fn ax_read_dir(dir: &mut AxDirHandle, dirents: &mut [AxDirEntry]) -> AxResult { - dir.0.read_dir(dirents) -} - -pub fn ax_create_dir(path: &str) -> AxResult { - axfs::api::create_dir(path) -} - -pub fn ax_remove_dir(path: &str) -> AxResult { - axfs::api::remove_dir(path) -} - -pub fn ax_remove_file(path: &str) -> AxResult { - axfs::api::remove_file(path) -} - -pub fn ax_rename(old: &str, new: &str) -> AxResult { - axfs::api::rename(old, new) -} - -pub fn ax_current_dir() -> AxResult { - axfs::api::current_dir() -} - -pub fn ax_set_current_dir(path: &str) -> AxResult { - axfs::api::set_current_dir(path) -} diff --git a/arceos/api/arceos_api/src/imp/mem.rs b/arceos/api/arceos_api/src/imp/mem.rs deleted file mode 100644 index d7ba43ffc..000000000 --- a/arceos/api/arceos_api/src/imp/mem.rs +++ /dev/null @@ -1,25 +0,0 @@ -use core::alloc::Layout; - -cfg_alloc! { - use core::ptr::NonNull; - - pub fn ax_alloc(layout: Layout) -> Option> { - axalloc::global_allocator().alloc(layout).ok() - } - - pub fn ax_dealloc(ptr: NonNull, layout: Layout) { - axalloc::global_allocator().dealloc(ptr, layout) - } -} - -cfg_dma! { - pub use axdma::DMAInfo; - - pub unsafe fn ax_alloc_coherent(layout: Layout) -> Option { - axdma::alloc_coherent(layout).ok() - } - - pub unsafe fn ax_dealloc_coherent(dma: DMAInfo, layout: Layout) { - axdma::dealloc_coherent(dma, layout) - } -} diff --git a/arceos/api/arceos_api/src/imp/mod.rs b/arceos/api/arceos_api/src/imp/mod.rs deleted file mode 100644 index 84ec8840d..000000000 --- a/arceos/api/arceos_api/src/imp/mod.rs +++ /dev/null @@ -1,48 +0,0 @@ -mod mem; -mod task; - -cfg_fs! { - mod fs; - pub use fs::*; -} - -cfg_net! { - mod net; - pub use net::*; -} - -cfg_display! { - mod display; - pub use display::*; -} - -mod stdio { - use core::fmt; - - pub fn ax_console_read_byte() -> Option { - axhal::console::getchar().map(|c| if c == b'\r' { b'\n' } else { c }) - } - - pub fn ax_console_write_bytes(buf: &[u8]) -> crate::AxResult { - axhal::console::write_bytes(buf); - Ok(buf.len()) - } - - pub fn ax_console_write_fmt(args: fmt::Arguments) -> fmt::Result { - axlog::print_fmt(args) - } -} - -mod time { - pub use axhal::time::{ - monotonic_time as ax_monotonic_time, wall_time as ax_wall_time, TimeValue as AxTimeValue, - }; -} - -pub use self::mem::*; -pub use self::stdio::*; -pub use self::task::*; -pub use self::time::*; - -pub use axhal::misc::terminate as ax_terminate; -pub use axio::PollState as AxPollState; diff --git a/arceos/api/arceos_api/src/imp/net.rs b/arceos/api/arceos_api/src/imp/net.rs deleted file mode 100644 index 88d4f7722..000000000 --- a/arceos/api/arceos_api/src/imp/net.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::io::AxPollState; -use axerrno::AxResult; -use axnet::{UdpSocket, TcpSocket}; -use core::net::{IpAddr, SocketAddr}; - -/// A handle to a TCP socket. -pub struct AxTcpSocketHandle(TcpSocket); - -/// A handle to a UDP socket. -pub struct AxUdpSocketHandle(UdpSocket); - -//////////////////////////////////////////////////////////////////////////////// -// TCP socket -//////////////////////////////////////////////////////////////////////////////// - -pub fn ax_tcp_socket() -> AxTcpSocketHandle { - AxTcpSocketHandle(TcpSocket::new()) -} - -pub fn ax_tcp_socket_addr(socket: &AxTcpSocketHandle) -> AxResult { - socket.0.local_addr() -} - -pub fn ax_tcp_peer_addr(socket: &AxTcpSocketHandle) -> AxResult { - socket.0.peer_addr() -} - -pub fn ax_tcp_set_nonblocking(socket: &AxTcpSocketHandle, nonblocking: bool) -> AxResult { - socket.0.set_nonblocking(nonblocking); - Ok(()) -} - -pub fn ax_tcp_connect(socket: &AxTcpSocketHandle, addr: SocketAddr) -> AxResult { - socket.0.connect(addr) -} - -pub fn ax_tcp_bind(socket: &AxTcpSocketHandle, addr: SocketAddr) -> AxResult { - socket.0.bind(addr) -} - -pub fn ax_tcp_listen(socket: &AxTcpSocketHandle, _backlog: usize) -> AxResult { - socket.0.listen() -} - -pub fn ax_tcp_accept(socket: &AxTcpSocketHandle) -> AxResult<(AxTcpSocketHandle, SocketAddr)> { - let new_sock = socket.0.accept()?; - let addr = new_sock.peer_addr()?; - Ok((AxTcpSocketHandle(new_sock), addr)) -} - -pub fn ax_tcp_send(socket: &AxTcpSocketHandle, buf: &[u8]) -> AxResult { - socket.0.send(buf) -} - -pub fn ax_tcp_recv(socket: &AxTcpSocketHandle, buf: &mut [u8]) -> AxResult { - socket.0.recv(buf) -} - -pub fn ax_tcp_poll(socket: &AxTcpSocketHandle) -> AxResult { - socket.0.poll() -} - -pub fn ax_tcp_shutdown(socket: &AxTcpSocketHandle) -> AxResult { - socket.0.shutdown() -} - -//////////////////////////////////////////////////////////////////////////////// -// UDP socket -//////////////////////////////////////////////////////////////////////////////// - -pub fn ax_udp_socket() -> AxUdpSocketHandle { - AxUdpSocketHandle(UdpSocket::new()) -} - -pub fn ax_udp_socket_addr(socket: &AxUdpSocketHandle) -> AxResult { - socket.0.local_addr() -} - -pub fn ax_udp_peer_addr(socket: &AxUdpSocketHandle) -> AxResult { - socket.0.peer_addr() -} - -pub fn ax_udp_set_nonblocking(socket: &AxUdpSocketHandle, nonblocking: bool) -> AxResult { - socket.0.set_nonblocking(nonblocking); - Ok(()) -} - -pub fn ax_udp_bind(socket: &AxUdpSocketHandle, addr: SocketAddr) -> AxResult { - socket.0.bind(addr) -} - -pub fn ax_udp_recv_from(socket: &AxUdpSocketHandle, buf: &mut [u8]) -> AxResult<(usize, SocketAddr)> { - socket.0.recv_from(buf) -} - -pub fn ax_udp_peek_from(socket: &AxUdpSocketHandle, buf: &mut [u8]) -> AxResult<(usize, SocketAddr)> { - socket.0.peek_from(buf) -} - -pub fn ax_udp_send_to(socket: &AxUdpSocketHandle, buf: &[u8], addr: SocketAddr) -> AxResult { - socket.0.send_to(buf, addr) -} - -pub fn ax_udp_connect(socket: &AxUdpSocketHandle, addr: SocketAddr) -> AxResult { - socket.0.connect(addr) -} - -pub fn ax_udp_send(socket: &AxUdpSocketHandle, buf: &[u8]) -> AxResult { - socket.0.send(buf) -} - -pub fn ax_udp_recv(socket: &AxUdpSocketHandle, buf: &mut [u8]) -> AxResult { - socket.0.recv(buf) -} - -pub fn ax_udp_poll(socket: &AxUdpSocketHandle) -> AxResult { - socket.0.poll() -} - -//////////////////////////////////////////////////////////////////////////////// -// Miscellaneous -//////////////////////////////////////////////////////////////////////////////// - -pub fn ax_dns_query(domain_name: &str) -> AxResult> { - axnet::dns_query(domain_name) -} - -pub fn ax_poll_interfaces() -> AxResult { - axnet::poll_interfaces(); - Ok(()) -} diff --git a/arceos/api/arceos_api/src/imp/task.rs b/arceos/api/arceos_api/src/imp/task.rs deleted file mode 100644 index e59c48384..000000000 --- a/arceos/api/arceos_api/src/imp/task.rs +++ /dev/null @@ -1,111 +0,0 @@ -pub fn ax_sleep_until(deadline: crate::time::AxTimeValue) { - #[cfg(feature = "multitask")] - axtask::sleep_until(deadline); - #[cfg(not(feature = "multitask"))] - axhal::time::busy_wait_until(deadline); -} - -pub fn ax_yield_now() { - #[cfg(feature = "multitask")] - axtask::yield_now(); - #[cfg(not(feature = "multitask"))] - if cfg!(feature = "irq") { - axhal::arch::wait_for_irqs(); - } else { - core::hint::spin_loop(); - } -} - -pub fn ax_exit(_exit_code: i32) -> ! { - #[cfg(feature = "multitask")] - axtask::exit(_exit_code); - #[cfg(not(feature = "multitask"))] - axhal::misc::terminate(); -} - -cfg_task! { - use core::time::Duration; - - /// A handle to a task. - pub struct AxTaskHandle { - inner: axtask::AxTaskRef, - id: u64, - } - - impl AxTaskHandle { - /// Returns the task ID. - pub fn id(&self) -> u64 { - self.id - } - } - - /// A handle to a wait queue. - /// - /// A wait queue is used to store sleeping tasks waiting for a certain event - /// to happen. - pub struct AxWaitQueueHandle(axtask::WaitQueue); - - impl AxWaitQueueHandle { - /// Creates a new empty wait queue. - pub const fn new() -> Self { - Self(axtask::WaitQueue::new()) - } - } - - pub fn ax_current_task_id() -> u64 { - axtask::current().id().as_u64() - } - - pub fn ax_spawn(f: F, name: alloc::string::String, stack_size: usize) -> AxTaskHandle - where - F: FnOnce() + Send + 'static, - { - let inner = axtask::spawn_raw(f, name, stack_size); - AxTaskHandle { - id: inner.id().as_u64(), - inner, - } - } - - pub fn ax_wait_for_exit(task: AxTaskHandle) -> Option { - task.inner.join() - } - - pub fn ax_set_current_priority(prio: isize) -> crate::AxResult { - if axtask::set_priority(prio) { - Ok(()) - } else { - axerrno::ax_err!( - BadState, - "ax_set_current_priority: failed to set task priority" - ) - } - } - - pub fn ax_wait_queue_wait( - wq: &AxWaitQueueHandle, - until_condition: impl Fn() -> bool, - timeout: Option, - ) -> bool { - #[cfg(feature = "irq")] - if let Some(dur) = timeout { - return wq.0.wait_timeout_until(dur, until_condition); - } - - if timeout.is_some() { - axlog::warn!("ax_wait_queue_wait: the `timeout` argument is ignored without the `irq` feature"); - } - wq.0.wait_until(until_condition); - false - } - - pub fn ax_wait_queue_wake(wq: &AxWaitQueueHandle, count: u32) { - if count == u32::MAX { - wq.0.notify_all(true); - } else { - for _ in 0..count { - wq.0.notify_one(true); - } - } - } -} diff --git a/arceos/api/arceos_api/src/lib.rs b/arceos/api/arceos_api/src/lib.rs deleted file mode 100644 index e63200ebe..000000000 --- a/arceos/api/arceos_api/src/lib.rs +++ /dev/null @@ -1,405 +0,0 @@ -//! Public APIs and types for [ArceOS] modules -//! -//! [ArceOS]: https://github.com/arceos-org/arceos - -#![no_std] -#![feature(doc_auto_cfg)] -#![feature(doc_cfg)] -#![allow(unused_imports)] - -#[cfg(any( - feature = "alloc", - feature = "fs", - feature = "net", - feature = "multitask", - feature = "dummy-if-not-enabled" -))] -extern crate alloc; - -#[macro_use] -mod macros; -mod imp; - -pub use axerrno::{AxError, AxResult}; - -/// Platform-specific constants and parameters. -pub mod config { - pub use axconfig::*; -} - -/// System operations. -pub mod sys { - define_api! { - /// Shutdown the whole system and all CPUs. - pub fn ax_terminate() -> !; - } -} - -/// Time-related operations. -pub mod time { - define_api_type! { - pub type AxTimeValue; - } - - define_api! { - /// Returns the time elapsed since system boot. - pub fn ax_monotonic_time() -> AxTimeValue; - /// Returns the time elapsed since epoch, also known as realtime. - pub fn ax_wall_time() -> AxTimeValue; - } -} - -/// Memory management. -pub mod mem { - use core::{alloc::Layout, ptr::NonNull}; - - define_api! { - @cfg "alloc"; - /// Allocates a continuous memory blocks with the given `layout` in - /// the global allocator. - /// - /// Returns [`None`] if the allocation fails. - /// - /// # Safety - /// - /// This function is unsafe because it requires users to manually manage - /// the buffer life cycle. - pub unsafe fn ax_alloc(layout: Layout) -> Option>; - /// Deallocates the memory block at the given `ptr` pointer with the given - /// `layout`, which should be allocated by [`ax_alloc`]. - /// - /// # Safety - /// - /// This function is unsafe because it requires users to manually manage - /// the buffer life cycle. - pub unsafe fn ax_dealloc(ptr: NonNull, layout: Layout); - } - - define_api_type! { - @cfg "dma"; - pub type DMAInfo; - } - - define_api! { - @cfg "dma"; - /// Allocates **coherent** memory that meets Direct Memory Access (DMA) - /// requirements. - /// - /// Returns [`None`] if the allocation fails. - /// - /// # Safety - /// - /// This function is unsafe because it requires users to manually manage - /// the buffer life cycle. - pub unsafe fn ax_alloc_coherent(layout: Layout) -> Option; - /// Deallocates coherent memory previously allocated. - /// - /// # Safety - /// - /// This function is unsafe because it requires users to manually manage - /// the buffer life cycle. - pub unsafe fn ax_dealloc_coherent(dma: DMAInfo, layout: Layout); - } -} - -/// Standard input and output. -pub mod stdio { - use core::fmt; - define_api! { - /// Reads a byte from the console, or returns [`None`] if no input is available. - pub fn ax_console_read_byte() -> Option; - /// Writes a slice of bytes to the console, returns the number of bytes written. - pub fn ax_console_write_bytes(buf: &[u8]) -> crate::AxResult; - /// Writes a formatted string to the console. - pub fn ax_console_write_fmt(args: fmt::Arguments) -> fmt::Result; - } -} - -/// Multi-threading management. -pub mod task { - define_api_type! { - @cfg "multitask"; - pub type AxTaskHandle; - pub type AxWaitQueueHandle; - } - - define_api! { - /// Current task is going to sleep, it will be woken up at the given deadline. - /// - /// If the feature `multitask` is not enabled, it uses busy-wait instead - pub fn ax_sleep_until(deadline: crate::time::AxTimeValue); - - /// Current task gives up the CPU time voluntarily, and switches to another - /// ready task. - /// - /// If the feature `multitask` is not enabled, it does nothing. - pub fn ax_yield_now(); - - /// Exits the current task with the given exit code. - pub fn ax_exit(exit_code: i32) -> !; - } - - define_api! { - @cfg "multitask"; - - /// Returns the current task's ID. - pub fn ax_current_task_id() -> u64; - /// Spawns a new task with the given entry point and other arguments. - pub fn ax_spawn( - f: impl FnOnce() + Send + 'static, - name: alloc::string::String, - stack_size: usize - ) -> AxTaskHandle; - /// Waits for the given task to exit, and returns its exit code (the - /// argument of [`ax_exit`]). - pub fn ax_wait_for_exit(task: AxTaskHandle) -> Option; - /// Sets the priority of the current task. - pub fn ax_set_current_priority(prio: isize) -> crate::AxResult; - - /// Blocks the current task and put it into the wait queue, until the - /// given condition becomes true, or the the given duration has elapsed - /// (if specified). - pub fn ax_wait_queue_wait( - wq: &AxWaitQueueHandle, - until_condition: impl Fn() -> bool, - timeout: Option, - ) -> bool; - /// Wakes up one or more tasks in the wait queue. - /// - /// The maximum number of tasks to wake up is specified by `count`. If - /// `count` is `u32::MAX`, it will wake up all tasks in the wait queue. - pub fn ax_wait_queue_wake(wq: &AxWaitQueueHandle, count: u32); - } -} - -/// Filesystem manipulation operations. -pub mod fs { - use crate::AxResult; - - define_api_type! { - @cfg "fs"; - pub type AxFileHandle; - pub type AxDirHandle; - pub type AxOpenOptions; - pub type AxFileAttr; - pub type AxFileType; - pub type AxFilePerm; - pub type AxDirEntry; - pub type AxSeekFrom; - #[cfg(feature = "myfs")] - pub type AxDisk; - #[cfg(feature = "myfs")] - pub type MyFileSystemIf; - } - - define_api! { - @cfg "fs"; - - /// Opens a file at the path relative to the current directory with the - /// options specified by `opts`. - pub fn ax_open_file(path: &str, opts: &AxOpenOptions) -> AxResult; - /// Opens a directory at the path relative to the current directory with - /// the options specified by `opts`. - pub fn ax_open_dir(path: &str, opts: &AxOpenOptions) -> AxResult; - - /// Reads the file at the current position, returns the number of bytes read. - /// - /// After the read, the cursor will be advanced by the number of bytes read. - pub fn ax_read_file(file: &mut AxFileHandle, buf: &mut [u8]) -> AxResult; - /// Reads the file at the given position, returns the number of bytes read. - /// - /// It does not update the file cursor. - pub fn ax_read_file_at(file: &AxFileHandle, offset: u64, buf: &mut [u8]) -> AxResult; - /// Writes the file at the current position, returns the number of bytes - /// written. - /// - /// After the write, the cursor will be advanced by the number of bytes - /// written. - pub fn ax_write_file(file: &mut AxFileHandle, buf: &[u8]) -> AxResult; - /// Writes the file at the given position, returns the number of bytes - /// written. - /// - /// It does not update the file cursor. - pub fn ax_write_file_at(file: &AxFileHandle, offset: u64, buf: &[u8]) -> AxResult; - /// Truncates the file to the specified size. - pub fn ax_truncate_file(file: &AxFileHandle, size: u64) -> AxResult; - /// Flushes the file, writes all buffered data to the underlying device. - pub fn ax_flush_file(file: &AxFileHandle) -> AxResult; - /// Sets the cursor of the file to the specified offset. Returns the new - /// position after the seek. - pub fn ax_seek_file(file: &mut AxFileHandle, pos: AxSeekFrom) -> AxResult; - /// Returns attributes of the file. - pub fn ax_file_attr(file: &AxFileHandle) -> AxResult; - - /// Reads directory entries starts from the current position into the - /// given buffer, returns the number of entries read. - /// - /// After the read, the cursor of the directory will be advanced by the - /// number of entries read. - pub fn ax_read_dir(dir: &mut AxDirHandle, dirents: &mut [AxDirEntry]) -> AxResult; - /// Creates a new, empty directory at the provided path. - pub fn ax_create_dir(path: &str) -> AxResult; - /// Removes an empty directory. - /// - /// If the directory is not empty, it will return an error. - pub fn ax_remove_dir(path: &str) -> AxResult; - /// Removes a file from the filesystem. - pub fn ax_remove_file(path: &str) -> AxResult; - /// Rename a file or directory to a new name. - /// - /// It will delete the original file if `old` already exists. - pub fn ax_rename(old: &str, new: &str) -> AxResult; - - /// Returns the current working directory. - pub fn ax_current_dir() -> AxResult; - /// Changes the current working directory to the specified path. - pub fn ax_set_current_dir(path: &str) -> AxResult; - } -} - -/// Networking primitives for TCP/UDP communication. -pub mod net { - use crate::{io::AxPollState, AxResult}; - use core::net::{IpAddr, SocketAddr}; - - define_api_type! { - @cfg "net"; - pub type AxTcpSocketHandle; - pub type AxUdpSocketHandle; - } - - define_api! { - @cfg "net"; - - // TCP socket - - /// Creates a new TCP socket. - pub fn ax_tcp_socket() -> AxTcpSocketHandle; - /// Returns the local address and port of the TCP socket. - pub fn ax_tcp_socket_addr(socket: &AxTcpSocketHandle) -> AxResult; - /// Returns the remote address and port of the TCP socket. - pub fn ax_tcp_peer_addr(socket: &AxTcpSocketHandle) -> AxResult; - /// Moves this TCP socket into or out of nonblocking mode. - pub fn ax_tcp_set_nonblocking(socket: &AxTcpSocketHandle, nonblocking: bool) -> AxResult; - - /// Connects the TCP socket to the given address and port. - pub fn ax_tcp_connect(handle: &AxTcpSocketHandle, addr: SocketAddr) -> AxResult; - /// Binds the TCP socket to the given address and port. - pub fn ax_tcp_bind(socket: &AxTcpSocketHandle, addr: SocketAddr) -> AxResult; - /// Starts listening on the bound address and port. - pub fn ax_tcp_listen(socket: &AxTcpSocketHandle, _backlog: usize) -> AxResult; - /// Accepts a new connection on the TCP socket. - /// - /// This function will block the calling thread until a new TCP connection - /// is established. When established, a new TCP socket is returned. - pub fn ax_tcp_accept(socket: &AxTcpSocketHandle) -> AxResult<(AxTcpSocketHandle, SocketAddr)>; - - /// Transmits data in the given buffer on the TCP socket. - pub fn ax_tcp_send(socket: &AxTcpSocketHandle, buf: &[u8]) -> AxResult; - /// Receives data on the TCP socket, and stores it in the given buffer. - /// On success, returns the number of bytes read. - pub fn ax_tcp_recv(socket: &AxTcpSocketHandle, buf: &mut [u8]) -> AxResult; - /// Returns whether the TCP socket is readable or writable. - pub fn ax_tcp_poll(socket: &AxTcpSocketHandle) -> AxResult; - /// Closes the connection on the TCP socket. - pub fn ax_tcp_shutdown(socket: &AxTcpSocketHandle) -> AxResult; - - // UDP socket - - /// Creates a new UDP socket. - pub fn ax_udp_socket() -> AxUdpSocketHandle; - /// Returns the local address and port of the UDP socket. - pub fn ax_udp_socket_addr(socket: &AxUdpSocketHandle) -> AxResult; - /// Returns the remote address and port of the UDP socket. - pub fn ax_udp_peer_addr(socket: &AxUdpSocketHandle) -> AxResult; - /// Moves this UDP socket into or out of nonblocking mode. - pub fn ax_udp_set_nonblocking(socket: &AxUdpSocketHandle, nonblocking: bool) -> AxResult; - - /// Binds the UDP socket to the given address and port. - pub fn ax_udp_bind(socket: &AxUdpSocketHandle, addr: SocketAddr) -> AxResult; - /// Receives a single datagram message on the UDP socket. - pub fn ax_udp_recv_from(socket: &AxUdpSocketHandle, buf: &mut [u8]) -> AxResult<(usize, SocketAddr)>; - /// Receives a single datagram message on the UDP socket, without - /// removing it from the queue. - pub fn ax_udp_peek_from(socket: &AxUdpSocketHandle, buf: &mut [u8]) -> AxResult<(usize, SocketAddr)>; - /// Sends data on the UDP socket to the given address. On success, - /// returns the number of bytes written. - pub fn ax_udp_send_to(socket: &AxUdpSocketHandle, buf: &[u8], addr: SocketAddr) -> AxResult; - - /// Connects this UDP socket to a remote address, allowing the `send` and - /// `recv` to be used to send data and also applies filters to only receive - /// data from the specified address. - pub fn ax_udp_connect(socket: &AxUdpSocketHandle, addr: SocketAddr) -> AxResult; - /// Sends data on the UDP socket to the remote address to which it is - /// connected. - pub fn ax_udp_send(socket: &AxUdpSocketHandle, buf: &[u8]) -> AxResult; - /// Receives a single datagram message on the UDP socket from the remote - /// address to which it is connected. On success, returns the number of - /// bytes read. - pub fn ax_udp_recv(socket: &AxUdpSocketHandle, buf: &mut [u8]) -> AxResult; - /// Returns whether the UDP socket is readable or writable. - pub fn ax_udp_poll(socket: &AxUdpSocketHandle) -> AxResult; - - // Miscellaneous - - /// Resolves the host name to a list of IP addresses. - pub fn ax_dns_query(domain_name: &str) -> AxResult>; - /// Poll the network stack. - /// - /// It may receive packets from the NIC and process them, and transmit queued - /// packets to the NIC. - pub fn ax_poll_interfaces() -> AxResult; - } -} - -/// Graphics manipulation operations. -pub mod display { - define_api_type! { - @cfg "display"; - pub type AxDisplayInfo; - } - - define_api! { - @cfg "display"; - /// Gets the framebuffer information. - pub fn ax_framebuffer_info() -> AxDisplayInfo; - /// Flushes the framebuffer, i.e. show on the screen. - pub fn ax_framebuffer_flush(); - } -} - -/// Input/output operations. -pub mod io { - define_api_type! { - pub type AxPollState; - } -} - -/// Re-exports of ArceOS modules. -/// -/// You should prefer to use other APIs rather than these modules. The modules -/// here should only be used if other APIs do not meet your requirements. -pub mod modules { - pub use axconfig; - pub use axhal; - pub use axlog; - pub use axruntime; - pub use axsync; - - #[cfg(feature = "alloc")] - pub use axalloc; - #[cfg(feature = "display")] - pub use axdisplay; - #[cfg(feature = "dma")] - pub use axdma; - #[cfg(any(feature = "fs", feature = "net", feature = "display"))] - pub use axdriver; - #[cfg(feature = "fs")] - pub use axfs; - #[cfg(feature = "paging")] - pub use axmm; - #[cfg(feature = "net")] - pub use axnet; - #[cfg(feature = "multitask")] - pub use axtask; -} diff --git a/arceos/api/arceos_api/src/macros.rs b/arceos/api/arceos_api/src/macros.rs deleted file mode 100644 index ae9682596..000000000 --- a/arceos/api/arceos_api/src/macros.rs +++ /dev/null @@ -1,110 +0,0 @@ -#![allow(unused_macros)] - -macro_rules! define_api_type { - ($( $(#[$attr:meta])* $vis:vis type $name:ident; )+) => { - $( - $vis use $crate::imp::$name; - )+ - }; - ( @cfg $feature:literal; $( $(#[$attr:meta])* $vis:vis type $name:ident; )+ ) => { - $( - #[cfg(feature = $feature)] - $(#[$attr])* - $vis use $crate::imp::$name; - - #[cfg(all(feature = "dummy-if-not-enabled", not(feature = $feature)))] - $(#[$attr])* - $vis struct $name; - )+ - }; -} - -macro_rules! define_api { - ($( $(#[$attr:meta])* $vis:vis fn $name:ident( $($arg:ident : $type:ty),* $(,)? ) $( -> $ret:ty )? ; )+) => { - $( - $(#[$attr])* - $vis fn $name( $($arg : $type),* ) $( -> $ret )? { - $crate::imp::$name( $($arg),* ) - } - )+ - }; - ($( $(#[$attr:meta])* $vis:vis unsafe fn $name:ident( $($arg:ident : $type:ty),* $(,)? ) $( -> $ret:ty )? ; )+) => { - $( - $(#[$attr])* - $vis unsafe fn $name( $($arg : $type),* ) $( -> $ret )? { - $crate::imp::$name( $($arg),* ) - } - )+ - }; - ( - @cfg $feature:literal; - $( $(#[$attr:meta])* $vis:vis fn $name:ident( $($arg:ident : $type:ty),* $(,)? ) $( -> $ret:ty )? ; )+ - ) => { - $( - #[cfg(feature = $feature)] - $(#[$attr])* - $vis fn $name( $($arg : $type),* ) $( -> $ret )? { - $crate::imp::$name( $($arg),* ) - } - - #[allow(unused_variables)] - #[cfg(all(feature = "dummy-if-not-enabled", not(feature = $feature)))] - $(#[$attr])* - $vis fn $name( $($arg : $type),* ) $( -> $ret )? { - unimplemented!(stringify!($name)) - } - )+ - }; - ( - @cfg $feature:literal; - $( $(#[$attr:meta])* $vis:vis unsafe fn $name:ident( $($arg:ident : $type:ty),* $(,)? ) $( -> $ret:ty )? ; )+ - ) => { - $( - #[cfg(feature = $feature)] - $(#[$attr])* - $vis unsafe fn $name( $($arg : $type),* ) $( -> $ret )? { - $crate::imp::$name( $($arg),* ) - } - - #[allow(unused_variables)] - #[cfg(all(feature = "dummy-if-not-enabled", not(feature = $feature)))] - $(#[$attr])* - $vis unsafe fn $name( $($arg : $type),* ) $( -> $ret )? { - unimplemented!(stringify!($name)) - } - )+ - }; -} - -macro_rules! _cfg_common { - ( $feature:literal $($item:item)* ) => { - $( - #[cfg(feature = $feature)] - $item - )* - } -} - -macro_rules! cfg_alloc { - ($($item:item)*) => { _cfg_common!{ "alloc" $($item)* } } -} - -macro_rules! cfg_dma { - ($($item:item)*) => { _cfg_common!{ "dma" $($item)* } } -} - -macro_rules! cfg_fs { - ($($item:item)*) => { _cfg_common!{ "fs" $($item)* } } -} - -macro_rules! cfg_net { - ($($item:item)*) => { _cfg_common!{ "net" $($item)* } } -} - -macro_rules! cfg_display { - ($($item:item)*) => { _cfg_common!{ "display" $($item)* } } -} - -macro_rules! cfg_task { - ($($item:item)*) => { _cfg_common!{ "multitask" $($item)* } } -} diff --git a/arceos/api/arceos_posix_api/.gitignore b/arceos/api/arceos_posix_api/.gitignore deleted file mode 100644 index 5e6d7ebe4..000000000 --- a/arceos/api/arceos_posix_api/.gitignore +++ /dev/null @@ -1 +0,0 @@ -ctypes_gen.rs diff --git a/arceos/api/arceos_posix_api/Cargo.toml b/arceos/api/arceos_posix_api/Cargo.toml deleted file mode 100644 index 2de8ccf12..000000000 --- a/arceos/api/arceos_posix_api/Cargo.toml +++ /dev/null @@ -1,55 +0,0 @@ -[package] -name = "arceos_posix_api" -version.workspace = true -edition = "2021" -authors = [ - "Yuekai Jia ", - "yanjuguang ", - "wudashuai ", - "yfblock <321353225@qq.com>", - "scPointer ", - "Shiping Yuan ", -] -description = "POSIX-compatible APIs for ArceOS modules" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/api/arceos_posix_api" -documentation = "https://arceos-org.github.io/arceos/arceos_posix_api/index.html" - -[features] -default = [] - -smp = ["axfeat/smp"] -irq = ["axfeat/irq"] -alloc = ["dep:axalloc", "axfeat/alloc"] -multitask = ["axtask/multitask", "axfeat/multitask", "axsync/multitask"] -fd = ["alloc"] -fs = ["dep:axfs", "axfeat/fs", "fd"] -net = ["dep:axnet", "axfeat/net", "fd"] -pipe = ["fd"] -select = ["fd"] -epoll = ["fd"] - -[dependencies] -# ArceOS modules -axfeat = { workspace = true } -axruntime = { workspace = true } -axconfig = { workspace = true } -axlog = { workspace = true } -axhal = { workspace = true } -axsync = { workspace = true } -axalloc = { workspace = true, optional = true } -axtask = { workspace = true, optional = true } -axfs = { workspace = true, optional = true } -axnet = { workspace = true, optional = true } - -# Other crates -axio = "0.1" -axerrno = "0.1" -flatten_objects = "0.1" -static_assertions = "1.1.0" -spin = { version = "0.9" } -lazy_static = { version = "1.5", features = ["spin_no_std"] } - -[build-dependencies] -bindgen ={ version = "0.69" } diff --git a/arceos/api/arceos_posix_api/build.rs b/arceos/api/arceos_posix_api/build.rs deleted file mode 100644 index bb8368511..000000000 --- a/arceos/api/arceos_posix_api/build.rs +++ /dev/null @@ -1,107 +0,0 @@ -fn main() { - use std::io::Write; - - fn gen_pthread_mutex(out_file: &str) -> std::io::Result<()> { - // TODO: generate size and initial content automatically. - let (mutex_size, mutex_init) = if cfg!(feature = "multitask") { - if cfg!(feature = "smp") { - (6, "{0, 0, 8, 0, 0, 0}") // core::mem::transmute::<_, [usize; 6]>(axsync::Mutex::new(())) - } else { - (5, "{0, 8, 0, 0, 0}") // core::mem::transmute::<_, [usize; 5]>(axsync::Mutex::new(())) - } - } else { - (1, "{0}") - }; - - let mut output = Vec::new(); - writeln!( - output, - "// Generated by arceos_posix_api/build.rs, DO NOT edit!" - )?; - writeln!( - output, - r#" -typedef struct {{ - long __l[{mutex_size}]; -}} pthread_mutex_t; - -#define PTHREAD_MUTEX_INITIALIZER {{ .__l = {mutex_init}}} -"# - )?; - std::fs::write(out_file, output)?; - Ok(()) - } - - fn gen_c_to_rust_bindings(in_file: &str, out_file: &str) { - println!("cargo:rerun-if-changed={in_file}"); - - let allow_types = [ - "stat", - "size_t", - "ssize_t", - "off_t", - "mode_t", - "sock.*", - "fd_set", - "timeval", - "pthread_t", - "pthread_attr_t", - "pthread_mutex_t", - "pthread_mutexattr_t", - "epoll_event", - "iovec", - "clockid_t", - "rlimit", - "aibuf", - ]; - let allow_vars = [ - "CLOCK_.*", - "O_.*", - "AF_.*", - "SOCK_.*", - "IPPROTO_.*", - "FD_.*", - "F_.*", - "_SC_.*", - "EPOLL_CTL_.*", - "EPOLL.*", - "RLIMIT_.*", - "EAI_.*", - "MAXADDRS", - ]; - - #[derive(Debug)] - struct MyCallbacks; - - impl bindgen::callbacks::ParseCallbacks for MyCallbacks { - fn include_file(&self, fname: &str) { - if !fname.contains("ax_pthread_mutex.h") { - println!("cargo:rerun-if-changed={}", fname); - } - } - } - - let mut builder = bindgen::Builder::default() - .header(in_file) - .clang_arg("-I./../../ulib/axlibc/include") - .parse_callbacks(Box::new(MyCallbacks)) - .derive_default(true) - .size_t_is_usize(false) - .use_core(); - for ty in allow_types { - builder = builder.allowlist_type(ty); - } - for var in allow_vars { - builder = builder.allowlist_var(var); - } - - builder - .generate() - .expect("Unable to generate c->rust bindings") - .write_to_file(out_file) - .expect("Couldn't write bindings!"); - } - - gen_pthread_mutex("../../ulib/axlibc/include/ax_pthread_mutex.h").unwrap(); - gen_c_to_rust_bindings("ctypes.h", "src/ctypes_gen.rs"); -} diff --git a/arceos/api/arceos_posix_api/ctypes.h b/arceos/api/arceos_posix_api/ctypes.h deleted file mode 100644 index 1acb87467..000000000 --- a/arceos/api/arceos_posix_api/ctypes.h +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include diff --git a/arceos/api/arceos_posix_api/src/imp/fd_ops.rs b/arceos/api/arceos_posix_api/src/imp/fd_ops.rs deleted file mode 100644 index 926669eca..000000000 --- a/arceos/api/arceos_posix_api/src/imp/fd_ops.rs +++ /dev/null @@ -1,129 +0,0 @@ -use alloc::sync::Arc; -use core::ffi::c_int; - -use axerrno::{LinuxError, LinuxResult}; -use axio::PollState; -use flatten_objects::FlattenObjects; -use spin::RwLock; - -use super::stdio::{stdin, stdout}; -use crate::ctypes; - -pub const AX_FILE_LIMIT: usize = 1024; - -#[allow(dead_code)] -pub trait FileLike: Send + Sync { - fn read(&self, buf: &mut [u8]) -> LinuxResult; - fn write(&self, buf: &[u8]) -> LinuxResult; - fn stat(&self) -> LinuxResult; - fn into_any(self: Arc) -> Arc; - fn poll(&self) -> LinuxResult; - fn set_nonblocking(&self, nonblocking: bool) -> LinuxResult; -} - -lazy_static::lazy_static! { - static ref FD_TABLE: RwLock, AX_FILE_LIMIT>> = { - let mut fd_table = FlattenObjects::new(); - fd_table.add_at(0, Arc::new(stdin()) as _).unwrap(); // stdin - fd_table.add_at(1, Arc::new(stdout()) as _).unwrap(); // stdout - fd_table.add_at(2, Arc::new(stdout()) as _).unwrap(); // stderr - RwLock::new(fd_table) - }; -} - -pub fn get_file_like(fd: c_int) -> LinuxResult> { - FD_TABLE - .read() - .get(fd as usize) - .cloned() - .ok_or(LinuxError::EBADF) -} - -pub fn add_file_like(f: Arc) -> LinuxResult { - Ok(FD_TABLE.write().add(f).ok_or(LinuxError::EMFILE)? as c_int) -} - -pub fn close_file_like(fd: c_int) -> LinuxResult { - let f = FD_TABLE - .write() - .remove(fd as usize) - .ok_or(LinuxError::EBADF)?; - drop(f); - Ok(()) -} - -/// Close a file by `fd`. -pub fn sys_close(fd: c_int) -> c_int { - debug!("sys_close <= {}", fd); - if (0..=2).contains(&fd) { - return 0; // stdin, stdout, stderr - } - syscall_body!(sys_close, close_file_like(fd).map(|_| 0)) -} - -fn dup_fd(old_fd: c_int) -> LinuxResult { - let f = get_file_like(old_fd)?; - let new_fd = add_file_like(f)?; - Ok(new_fd) -} - -/// Duplicate a file descriptor. -pub fn sys_dup(old_fd: c_int) -> c_int { - debug!("sys_dup <= {}", old_fd); - syscall_body!(sys_dup, dup_fd(old_fd)) -} - -/// Duplicate a file descriptor, but it uses the file descriptor number specified in `new_fd`. -/// -/// TODO: `dup2` should forcibly close new_fd if it is already opened. -pub fn sys_dup2(old_fd: c_int, new_fd: c_int) -> c_int { - debug!("sys_dup2 <= old_fd: {}, new_fd: {}", old_fd, new_fd); - syscall_body!(sys_dup2, { - if old_fd == new_fd { - let r = sys_fcntl(old_fd, ctypes::F_GETFD as _, 0); - if r >= 0 { - return Ok(old_fd); - } else { - return Ok(r); - } - } - if new_fd as usize >= AX_FILE_LIMIT { - return Err(LinuxError::EBADF); - } - - let f = get_file_like(old_fd)?; - FD_TABLE - .write() - .add_at(new_fd as usize, f) - .ok_or(LinuxError::EMFILE)?; - - Ok(new_fd) - }) -} - -/// Manipulate file descriptor. -/// -/// TODO: `SET/GET` command is ignored, hard-code stdin/stdout -pub fn sys_fcntl(fd: c_int, cmd: c_int, arg: usize) -> c_int { - debug!("sys_fcntl <= fd: {} cmd: {} arg: {}", fd, cmd, arg); - syscall_body!(sys_fcntl, { - match cmd as u32 { - ctypes::F_DUPFD => dup_fd(fd), - ctypes::F_DUPFD_CLOEXEC => { - // TODO: Change fd flags - dup_fd(fd) - } - ctypes::F_SETFL => { - if fd == 0 || fd == 1 || fd == 2 { - return Ok(0); - } - get_file_like(fd)?.set_nonblocking(arg & (ctypes::O_NONBLOCK as usize) > 0)?; - Ok(0) - } - _ => { - warn!("unsupported fcntl parameters: cmd {}", cmd); - Ok(0) - } - } - }) -} diff --git a/arceos/api/arceos_posix_api/src/imp/fs.rs b/arceos/api/arceos_posix_api/src/imp/fs.rs deleted file mode 100644 index 6c92f2da6..000000000 --- a/arceos/api/arceos_posix_api/src/imp/fs.rs +++ /dev/null @@ -1,217 +0,0 @@ -use alloc::sync::Arc; -use core::ffi::{c_char, c_int}; - -use axerrno::{LinuxError, LinuxResult}; -use axfs::fops::OpenOptions; -use axio::{PollState, SeekFrom}; -use axsync::Mutex; - -use super::fd_ops::{get_file_like, FileLike}; -use crate::{ctypes, utils::char_ptr_to_str}; - -pub struct File { - inner: Mutex, -} - -impl File { - fn new(inner: axfs::fops::File) -> Self { - Self { - inner: Mutex::new(inner), - } - } - - fn add_to_fd_table(self) -> LinuxResult { - super::fd_ops::add_file_like(Arc::new(self)) - } - - fn from_fd(fd: c_int) -> LinuxResult> { - let f = super::fd_ops::get_file_like(fd)?; - f.into_any() - .downcast::() - .map_err(|_| LinuxError::EINVAL) - } -} - -impl FileLike for File { - fn read(&self, buf: &mut [u8]) -> LinuxResult { - Ok(self.inner.lock().read(buf)?) - } - - fn write(&self, buf: &[u8]) -> LinuxResult { - Ok(self.inner.lock().write(buf)?) - } - - fn stat(&self) -> LinuxResult { - let metadata = self.inner.lock().get_attr()?; - let ty = metadata.file_type() as u8; - let perm = metadata.perm().bits() as u32; - let st_mode = ((ty as u32) << 12) | perm; - Ok(ctypes::stat { - st_ino: 1, - st_nlink: 1, - st_mode, - st_uid: 1000, - st_gid: 1000, - st_size: metadata.size() as _, - st_blocks: metadata.blocks() as _, - st_blksize: 512, - ..Default::default() - }) - } - - fn into_any(self: Arc) -> Arc { - self - } - - fn poll(&self) -> LinuxResult { - Ok(PollState { - readable: true, - writable: true, - }) - } - - fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult { - Ok(()) - } -} - -/// Convert open flags to [`OpenOptions`]. -fn flags_to_options(flags: c_int, _mode: ctypes::mode_t) -> OpenOptions { - let flags = flags as u32; - let mut options = OpenOptions::new(); - match flags & 0b11 { - ctypes::O_RDONLY => options.read(true), - ctypes::O_WRONLY => options.write(true), - _ => { - options.read(true); - options.write(true); - } - }; - if flags & ctypes::O_APPEND != 0 { - options.append(true); - } - if flags & ctypes::O_TRUNC != 0 { - options.truncate(true); - } - if flags & ctypes::O_CREAT != 0 { - options.create(true); - } - if flags & ctypes::O_EXEC != 0 { - options.create_new(true); - } - options -} - -/// Open a file by `filename` and insert it into the file descriptor table. -/// -/// Return its index in the file table (`fd`). Return `EMFILE` if it already -/// has the maximum number of files open. -pub fn sys_open(filename: *const c_char, flags: c_int, mode: ctypes::mode_t) -> c_int { - let filename = char_ptr_to_str(filename); - debug!("sys_open <= {:?} {:#o} {:#o}", filename, flags, mode); - syscall_body!(sys_open, { - let options = flags_to_options(flags, mode); - let file = axfs::fops::File::open(filename?, &options)?; - File::new(file).add_to_fd_table() - }) -} - -/// Set the position of the file indicated by `fd`. -/// -/// Return its position after seek. -pub fn sys_lseek(fd: c_int, offset: ctypes::off_t, whence: c_int) -> ctypes::off_t { - debug!("sys_lseek <= {} {} {}", fd, offset, whence); - syscall_body!(sys_lseek, { - let pos = match whence { - 0 => SeekFrom::Start(offset as _), - 1 => SeekFrom::Current(offset as _), - 2 => SeekFrom::End(offset as _), - _ => return Err(LinuxError::EINVAL), - }; - let off = File::from_fd(fd)?.inner.lock().seek(pos)?; - Ok(off) - }) -} - -/// Get the file metadata by `path` and write into `buf`. -/// -/// Return 0 if success. -pub unsafe fn sys_stat(path: *const c_char, buf: *mut ctypes::stat) -> c_int { - let path = char_ptr_to_str(path); - debug!("sys_stat <= {:?} {:#x}", path, buf as usize); - syscall_body!(sys_stat, { - if buf.is_null() { - return Err(LinuxError::EFAULT); - } - let mut options = OpenOptions::new(); - options.read(true); - let file = axfs::fops::File::open(path?, &options)?; - let st = File::new(file).stat()?; - unsafe { *buf = st }; - Ok(0) - }) -} - -/// Get file metadata by `fd` and write into `buf`. -/// -/// Return 0 if success. -pub unsafe fn sys_fstat(fd: c_int, buf: *mut ctypes::stat) -> c_int { - debug!("sys_fstat <= {} {:#x}", fd, buf as usize); - syscall_body!(sys_fstat, { - if buf.is_null() { - return Err(LinuxError::EFAULT); - } - - unsafe { *buf = get_file_like(fd)?.stat()? }; - Ok(0) - }) -} - -/// Get the metadata of the symbolic link and write into `buf`. -/// -/// Return 0 if success. -pub unsafe fn sys_lstat(path: *const c_char, buf: *mut ctypes::stat) -> ctypes::ssize_t { - let path = char_ptr_to_str(path); - debug!("sys_lstat <= {:?} {:#x}", path, buf as usize); - syscall_body!(sys_lstat, { - if buf.is_null() { - return Err(LinuxError::EFAULT); - } - unsafe { *buf = Default::default() }; // TODO - Ok(0) - }) -} - -/// Get the path of the current directory. -pub fn sys_getcwd(buf: *mut c_char, size: usize) -> *mut c_char { - debug!("sys_getcwd <= {:#x} {}", buf as usize, size); - syscall_body!(sys_getcwd, { - if buf.is_null() { - return Ok(core::ptr::null::() as _); - } - let dst = unsafe { core::slice::from_raw_parts_mut(buf as *mut u8, size as _) }; - let cwd = axfs::api::current_dir()?; - let cwd = cwd.as_bytes(); - if cwd.len() < size { - dst[..cwd.len()].copy_from_slice(cwd); - dst[cwd.len()] = 0; - Ok(buf) - } else { - Err(LinuxError::ERANGE) - } - }) -} - -/// Rename `old` to `new` -/// If new exists, it is first removed. -/// -/// Return 0 if the operation succeeds, otherwise return -1. -pub fn sys_rename(old: *const c_char, new: *const c_char) -> c_int { - syscall_body!(sys_rename, { - let old_path = char_ptr_to_str(old)?; - let new_path = char_ptr_to_str(new)?; - debug!("sys_rename <= old: {:?}, new: {:?}", old_path, new_path); - axfs::api::rename(old_path, new_path)?; - Ok(0) - }) -} diff --git a/arceos/api/arceos_posix_api/src/imp/io.rs b/arceos/api/arceos_posix_api/src/imp/io.rs deleted file mode 100644 index 269ce2035..000000000 --- a/arceos/api/arceos_posix_api/src/imp/io.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::ctypes; -use axerrno::LinuxError; -use core::ffi::{c_int, c_void}; - -#[cfg(feature = "fd")] -use crate::imp::fd_ops::get_file_like; -#[cfg(not(feature = "fd"))] -use axio::prelude::*; - -/// Read data from the file indicated by `fd`. -/// -/// Return the read size if success. -pub fn sys_read(fd: c_int, buf: *mut c_void, count: usize) -> ctypes::ssize_t { - debug!("sys_read <= {} {:#x} {}", fd, buf as usize, count); - syscall_body!(sys_read, { - if buf.is_null() { - return Err(LinuxError::EFAULT); - } - let dst = unsafe { core::slice::from_raw_parts_mut(buf as *mut u8, count) }; - #[cfg(feature = "fd")] - { - Ok(get_file_like(fd)?.read(dst)? as ctypes::ssize_t) - } - #[cfg(not(feature = "fd"))] - match fd { - 0 => Ok(super::stdio::stdin().read(dst)? as ctypes::ssize_t), - 1 | 2 => Err(LinuxError::EPERM), - _ => Err(LinuxError::EBADF), - } - }) -} - -/// Write data to the file indicated by `fd`. -/// -/// Return the written size if success. -pub fn sys_write(fd: c_int, buf: *const c_void, count: usize) -> ctypes::ssize_t { - debug!("sys_write <= {} {:#x} {}", fd, buf as usize, count); - syscall_body!(sys_write, { - if buf.is_null() { - return Err(LinuxError::EFAULT); - } - let src = unsafe { core::slice::from_raw_parts(buf as *const u8, count) }; - #[cfg(feature = "fd")] - { - Ok(get_file_like(fd)?.write(src)? as ctypes::ssize_t) - } - #[cfg(not(feature = "fd"))] - match fd { - 0 => Err(LinuxError::EPERM), - 1 | 2 => Ok(super::stdio::stdout().write(src)? as ctypes::ssize_t), - _ => Err(LinuxError::EBADF), - } - }) -} - -/// Write a vector. -pub unsafe fn sys_writev(fd: c_int, iov: *const ctypes::iovec, iocnt: c_int) -> ctypes::ssize_t { - debug!("sys_writev <= fd: {}", fd); - syscall_body!(sys_writev, { - if !(0..=1024).contains(&iocnt) { - return Err(LinuxError::EINVAL); - } - - let iovs = unsafe { core::slice::from_raw_parts(iov, iocnt as usize) }; - let mut ret = 0; - for iov in iovs.iter() { - ret += sys_write(fd, iov.iov_base, iov.iov_len); - } - - Ok(ret) - }) -} diff --git a/arceos/api/arceos_posix_api/src/imp/io_mpx/epoll.rs b/arceos/api/arceos_posix_api/src/imp/io_mpx/epoll.rs deleted file mode 100644 index a53d0d6a0..000000000 --- a/arceos/api/arceos_posix_api/src/imp/io_mpx/epoll.rs +++ /dev/null @@ -1,205 +0,0 @@ -//! `epoll` implementation. -//! -//! TODO: do not support `EPOLLET` flag - -use alloc::collections::btree_map::Entry; -use alloc::collections::BTreeMap; -use alloc::sync::Arc; -use core::{ffi::c_int, time::Duration}; - -use axerrno::{LinuxError, LinuxResult}; -use axhal::time::wall_time; -use axsync::Mutex; - -use crate::ctypes; -use crate::imp::fd_ops::{add_file_like, get_file_like, FileLike}; - -pub struct EpollInstance { - events: Mutex>, -} - -unsafe impl Send for ctypes::epoll_event {} -unsafe impl Sync for ctypes::epoll_event {} - -impl EpollInstance { - // TODO: parse flags - pub fn new(_flags: usize) -> Self { - Self { - events: Mutex::new(BTreeMap::new()), - } - } - - fn from_fd(fd: c_int) -> LinuxResult> { - get_file_like(fd)? - .into_any() - .downcast::() - .map_err(|_| LinuxError::EINVAL) - } - - fn control(&self, op: usize, fd: usize, event: &ctypes::epoll_event) -> LinuxResult { - match get_file_like(fd as c_int) { - Ok(_) => {} - Err(e) => return Err(e), - } - - match op as u32 { - ctypes::EPOLL_CTL_ADD => { - if let Entry::Vacant(e) = self.events.lock().entry(fd) { - e.insert(*event); - } else { - return Err(LinuxError::EEXIST); - } - } - ctypes::EPOLL_CTL_MOD => { - let mut events = self.events.lock(); - if let Entry::Occupied(mut ocp) = events.entry(fd) { - ocp.insert(*event); - } else { - return Err(LinuxError::ENOENT); - } - } - ctypes::EPOLL_CTL_DEL => { - let mut events = self.events.lock(); - if let Entry::Occupied(ocp) = events.entry(fd) { - ocp.remove_entry(); - } else { - return Err(LinuxError::ENOENT); - } - } - _ => { - return Err(LinuxError::EINVAL); - } - } - Ok(0) - } - - fn poll_all(&self, events: &mut [ctypes::epoll_event]) -> LinuxResult { - let ready_list = self.events.lock(); - let mut events_num = 0; - - for (infd, ev) in ready_list.iter() { - match get_file_like(*infd as c_int)?.poll() { - Err(_) => { - if (ev.events & ctypes::EPOLLERR) != 0 { - events[events_num].events = ctypes::EPOLLERR; - events[events_num].data = ev.data; - events_num += 1; - } - } - Ok(state) => { - if state.readable && (ev.events & ctypes::EPOLLIN != 0) { - events[events_num].events = ctypes::EPOLLIN; - events[events_num].data = ev.data; - events_num += 1; - } - - if state.writable && (ev.events & ctypes::EPOLLOUT != 0) { - events[events_num].events = ctypes::EPOLLOUT; - events[events_num].data = ev.data; - events_num += 1; - } - } - } - } - Ok(events_num) - } -} - -impl FileLike for EpollInstance { - fn read(&self, _buf: &mut [u8]) -> LinuxResult { - Err(LinuxError::ENOSYS) - } - - fn write(&self, _buf: &[u8]) -> LinuxResult { - Err(LinuxError::ENOSYS) - } - - fn stat(&self) -> LinuxResult { - let st_mode = 0o600u32; // rw------- - Ok(ctypes::stat { - st_ino: 1, - st_nlink: 1, - st_mode, - ..Default::default() - }) - } - - fn into_any(self: Arc) -> alloc::sync::Arc { - self - } - - fn poll(&self) -> LinuxResult { - Err(LinuxError::ENOSYS) - } - - fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult { - Ok(()) - } -} - -/// Creates a new epoll instance. -/// -/// It returns a file descriptor referring to the new epoll instance. -pub fn sys_epoll_create(size: c_int) -> c_int { - debug!("sys_epoll_create <= {}", size); - syscall_body!(sys_epoll_create, { - if size < 0 { - return Err(LinuxError::EINVAL); - } - let epoll_instance = EpollInstance::new(0); - add_file_like(Arc::new(epoll_instance)) - }) -} - -/// Control interface for an epoll file descriptor -pub unsafe fn sys_epoll_ctl( - epfd: c_int, - op: c_int, - fd: c_int, - event: *mut ctypes::epoll_event, -) -> c_int { - debug!("sys_epoll_ctl <= epfd: {} op: {} fd: {}", epfd, op, fd); - syscall_body!(sys_epoll_ctl, { - let ret = unsafe { - EpollInstance::from_fd(epfd)?.control(op as usize, fd as usize, &(*event))? as c_int - }; - Ok(ret) - }) -} - -/// Waits for events on the epoll instance referred to by the file descriptor epfd. -pub unsafe fn sys_epoll_wait( - epfd: c_int, - events: *mut ctypes::epoll_event, - maxevents: c_int, - timeout: c_int, -) -> c_int { - debug!( - "sys_epoll_wait <= epfd: {}, maxevents: {}, timeout: {}", - epfd, maxevents, timeout - ); - - syscall_body!(sys_epoll_wait, { - if maxevents <= 0 { - return Err(LinuxError::EINVAL); - } - let events = unsafe { core::slice::from_raw_parts_mut(events, maxevents as usize) }; - let deadline = - (!timeout.is_negative()).then(|| wall_time() + Duration::from_millis(timeout as u64)); - let epoll_instance = EpollInstance::from_fd(epfd)?; - loop { - #[cfg(feature = "net")] - axnet::poll_interfaces(); - let events_num = epoll_instance.poll_all(events)?; - if events_num > 0 { - return Ok(events_num as c_int); - } - - if deadline.map_or(false, |ddl| wall_time() >= ddl) { - debug!(" timeout!"); - return Ok(0); - } - crate::sys_sched_yield(); - } - }) -} diff --git a/arceos/api/arceos_posix_api/src/imp/io_mpx/mod.rs b/arceos/api/arceos_posix_api/src/imp/io_mpx/mod.rs deleted file mode 100644 index 397ed44f3..000000000 --- a/arceos/api/arceos_posix_api/src/imp/io_mpx/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! I/O multiplexing: -//! -//! * [`select`](select::sys_select) -//! * [`epoll_create`](epoll::sys_epoll_create) -//! * [`epoll_ctl`](epoll::sys_epoll_ctl) -//! * [`epoll_wait`](epoll::sys_epoll_wait) - -#[cfg(feature = "epoll")] -mod epoll; -#[cfg(feature = "select")] -mod select; - -#[cfg(feature = "epoll")] -pub use self::epoll::{sys_epoll_create, sys_epoll_ctl, sys_epoll_wait}; -#[cfg(feature = "select")] -pub use self::select::sys_select; diff --git a/arceos/api/arceos_posix_api/src/imp/io_mpx/select.rs b/arceos/api/arceos_posix_api/src/imp/io_mpx/select.rs deleted file mode 100644 index 23e85c5cf..000000000 --- a/arceos/api/arceos_posix_api/src/imp/io_mpx/select.rs +++ /dev/null @@ -1,165 +0,0 @@ -use core::ffi::c_int; - -use axerrno::{LinuxError, LinuxResult}; -use axhal::time::wall_time; - -use crate::{ctypes, imp::fd_ops::get_file_like}; - -const FD_SETSIZE: usize = 1024; -const BITS_PER_USIZE: usize = usize::BITS as usize; -const FD_SETSIZE_USIZES: usize = FD_SETSIZE.div_ceil(BITS_PER_USIZE); - -struct FdSets { - nfds: usize, - bits: [usize; FD_SETSIZE_USIZES * 3], -} - -impl FdSets { - fn from( - nfds: usize, - read_fds: *const ctypes::fd_set, - write_fds: *const ctypes::fd_set, - except_fds: *const ctypes::fd_set, - ) -> Self { - let nfds = nfds.min(FD_SETSIZE); - let nfds_usizes = nfds.div_ceil(BITS_PER_USIZE); - let mut bits = core::mem::MaybeUninit::<[usize; FD_SETSIZE_USIZES * 3]>::uninit(); - let bits_ptr: *mut usize = unsafe { core::mem::transmute(bits.as_mut_ptr()) }; - - let copy_from_fd_set = |bits_ptr: *mut usize, fds: *const ctypes::fd_set| unsafe { - let dst = core::slice::from_raw_parts_mut(bits_ptr, nfds_usizes); - if fds.is_null() { - dst.fill(0); - } else { - let fds_ptr = (*fds).fds_bits.as_ptr() as *const usize; - let src = core::slice::from_raw_parts(fds_ptr, nfds_usizes); - dst.copy_from_slice(src); - } - }; - - let bits = unsafe { - copy_from_fd_set(bits_ptr, read_fds); - copy_from_fd_set(bits_ptr.add(FD_SETSIZE_USIZES), write_fds); - copy_from_fd_set(bits_ptr.add(FD_SETSIZE_USIZES * 2), except_fds); - bits.assume_init() - }; - Self { nfds, bits } - } - - fn poll_all( - &self, - res_read_fds: *mut ctypes::fd_set, - res_write_fds: *mut ctypes::fd_set, - res_except_fds: *mut ctypes::fd_set, - ) -> LinuxResult { - let mut read_bits_ptr = self.bits.as_ptr(); - let mut write_bits_ptr = unsafe { read_bits_ptr.add(FD_SETSIZE_USIZES) }; - let mut execpt_bits_ptr = unsafe { read_bits_ptr.add(FD_SETSIZE_USIZES * 2) }; - let mut i = 0; - let mut res_num = 0; - while i < self.nfds { - let read_bits = unsafe { *read_bits_ptr }; - let write_bits = unsafe { *write_bits_ptr }; - let except_bits = unsafe { *execpt_bits_ptr }; - unsafe { - read_bits_ptr = read_bits_ptr.add(1); - write_bits_ptr = write_bits_ptr.add(1); - execpt_bits_ptr = execpt_bits_ptr.add(1); - } - - let all_bits = read_bits | write_bits | except_bits; - if all_bits == 0 { - i += BITS_PER_USIZE; - continue; - } - let mut j = 0; - while j < BITS_PER_USIZE && i + j < self.nfds { - let bit = 1 << j; - if all_bits & bit == 0 { - j += 1; - continue; - } - let fd = i + j; - match get_file_like(fd as _)?.poll() { - Ok(state) => { - if state.readable && read_bits & bit != 0 { - unsafe { set_fd_set(res_read_fds, fd) }; - res_num += 1; - } - if state.writable && write_bits & bit != 0 { - unsafe { set_fd_set(res_write_fds, fd) }; - res_num += 1; - } - } - Err(e) => { - debug!(" except: {} {:?}", fd, e); - if except_bits & bit != 0 { - unsafe { set_fd_set(res_except_fds, fd) }; - res_num += 1; - } - } - } - j += 1; - } - i += BITS_PER_USIZE; - } - Ok(res_num) - } -} - -/// Monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation -pub unsafe fn sys_select( - nfds: c_int, - readfds: *mut ctypes::fd_set, - writefds: *mut ctypes::fd_set, - exceptfds: *mut ctypes::fd_set, - timeout: *mut ctypes::timeval, -) -> c_int { - debug!( - "sys_select <= {} {:#x} {:#x} {:#x}", - nfds, readfds as usize, writefds as usize, exceptfds as usize - ); - syscall_body!(sys_select, { - if nfds < 0 { - return Err(LinuxError::EINVAL); - } - let nfds = (nfds as usize).min(FD_SETSIZE); - let deadline = unsafe { timeout.as_ref().map(|t| wall_time() + (*t).into()) }; - let fd_sets = FdSets::from(nfds, readfds, writefds, exceptfds); - - unsafe { - zero_fd_set(readfds, nfds); - zero_fd_set(writefds, nfds); - zero_fd_set(exceptfds, nfds); - } - - loop { - #[cfg(feature = "net")] - axnet::poll_interfaces(); - let res = fd_sets.poll_all(readfds, writefds, exceptfds)?; - if res > 0 { - return Ok(res); - } - - if deadline.map_or(false, |ddl| wall_time() >= ddl) { - debug!(" timeout!"); - return Ok(0); - } - crate::sys_sched_yield(); - } - }) -} - -unsafe fn zero_fd_set(fds: *mut ctypes::fd_set, nfds: usize) { - if !fds.is_null() { - let nfds_usizes = nfds.div_ceil(BITS_PER_USIZE); - let dst = &mut (*fds).fds_bits[..nfds_usizes]; - dst.fill(0); - } -} - -unsafe fn set_fd_set(fds: *mut ctypes::fd_set, fd: usize) { - if !fds.is_null() { - (*fds).fds_bits[fd / BITS_PER_USIZE] |= 1 << (fd % BITS_PER_USIZE); - } -} diff --git a/arceos/api/arceos_posix_api/src/imp/mod.rs b/arceos/api/arceos_posix_api/src/imp/mod.rs deleted file mode 100644 index 603f934ba..000000000 --- a/arceos/api/arceos_posix_api/src/imp/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -mod stdio; - -pub mod io; -pub mod resources; -pub mod sys; -pub mod task; -pub mod time; - -#[cfg(feature = "fd")] -pub mod fd_ops; -#[cfg(feature = "fs")] -pub mod fs; -#[cfg(any(feature = "select", feature = "epoll"))] -pub mod io_mpx; -#[cfg(feature = "net")] -pub mod net; -#[cfg(feature = "pipe")] -pub mod pipe; -#[cfg(feature = "multitask")] -pub mod pthread; diff --git a/arceos/api/arceos_posix_api/src/imp/net.rs b/arceos/api/arceos_posix_api/src/imp/net.rs deleted file mode 100644 index 861e4737b..000000000 --- a/arceos/api/arceos_posix_api/src/imp/net.rs +++ /dev/null @@ -1,581 +0,0 @@ -use alloc::{sync::Arc, vec, vec::Vec}; -use core::ffi::{c_char, c_int, c_void}; -use core::mem::size_of; -use core::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4}; - -use axerrno::{LinuxError, LinuxResult}; -use axio::PollState; -use axnet::{TcpSocket, UdpSocket}; -use axsync::Mutex; - -use super::fd_ops::FileLike; -use crate::ctypes; -use crate::utils::char_ptr_to_str; - -pub enum Socket { - Udp(Mutex), - Tcp(Mutex), -} - -impl Socket { - fn add_to_fd_table(self) -> LinuxResult { - super::fd_ops::add_file_like(Arc::new(self)) - } - - fn from_fd(fd: c_int) -> LinuxResult> { - let f = super::fd_ops::get_file_like(fd)?; - f.into_any() - .downcast::() - .map_err(|_| LinuxError::EINVAL) - } - - fn send(&self, buf: &[u8]) -> LinuxResult { - match self { - Socket::Udp(udpsocket) => Ok(udpsocket.lock().send(buf)?), - Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().send(buf)?), - } - } - - fn recv(&self, buf: &mut [u8]) -> LinuxResult { - match self { - Socket::Udp(udpsocket) => Ok(udpsocket.lock().recv_from(buf).map(|e| e.0)?), - Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().recv(buf)?), - } - } - - pub fn poll(&self) -> LinuxResult { - match self { - Socket::Udp(udpsocket) => Ok(udpsocket.lock().poll()?), - Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().poll()?), - } - } - - fn local_addr(&self) -> LinuxResult { - match self { - Socket::Udp(udpsocket) => Ok(udpsocket.lock().local_addr()?), - Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().local_addr()?), - } - } - - fn peer_addr(&self) -> LinuxResult { - match self { - Socket::Udp(udpsocket) => Ok(udpsocket.lock().peer_addr()?), - Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().peer_addr()?), - } - } - - fn bind(&self, addr: SocketAddr) -> LinuxResult { - match self { - Socket::Udp(udpsocket) => Ok(udpsocket.lock().bind(addr)?), - Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().bind(addr)?), - } - } - - fn connect(&self, addr: SocketAddr) -> LinuxResult { - match self { - Socket::Udp(udpsocket) => Ok(udpsocket.lock().connect(addr)?), - Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().connect(addr)?), - } - } - - fn sendto(&self, buf: &[u8], addr: SocketAddr) -> LinuxResult { - match self { - // diff: must bind before sendto - Socket::Udp(udpsocket) => Ok(udpsocket.lock().send_to(buf, addr)?), - Socket::Tcp(_) => Err(LinuxError::EISCONN), - } - } - - fn recvfrom(&self, buf: &mut [u8]) -> LinuxResult<(usize, Option)> { - match self { - // diff: must bind before recvfrom - Socket::Udp(udpsocket) => Ok(udpsocket - .lock() - .recv_from(buf) - .map(|res| (res.0, Some(res.1)))?), - Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().recv(buf).map(|res| (res, None))?), - } - } - - fn listen(&self) -> LinuxResult { - match self { - Socket::Udp(_) => Err(LinuxError::EOPNOTSUPP), - Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().listen()?), - } - } - - fn accept(&self) -> LinuxResult { - match self { - Socket::Udp(_) => Err(LinuxError::EOPNOTSUPP), - Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().accept()?), - } - } - - fn shutdown(&self) -> LinuxResult { - match self { - Socket::Udp(udpsocket) => { - let udpsocket = udpsocket.lock(); - udpsocket.peer_addr()?; - udpsocket.shutdown()?; - Ok(()) - } - - Socket::Tcp(tcpsocket) => { - let tcpsocket = tcpsocket.lock(); - tcpsocket.peer_addr()?; - tcpsocket.shutdown()?; - Ok(()) - } - } - } -} - -impl FileLike for Socket { - fn read(&self, buf: &mut [u8]) -> LinuxResult { - self.recv(buf) - } - - fn write(&self, buf: &[u8]) -> LinuxResult { - self.send(buf) - } - - fn stat(&self) -> LinuxResult { - // not really implemented - let st_mode = 0o140000 | 0o777u32; // S_IFSOCK | rwxrwxrwx - Ok(ctypes::stat { - st_ino: 1, - st_nlink: 1, - st_mode, - st_uid: 1000, - st_gid: 1000, - st_blksize: 4096, - ..Default::default() - }) - } - - fn into_any(self: Arc) -> Arc { - self - } - - fn poll(&self) -> LinuxResult { - self.poll() - } - - fn set_nonblocking(&self, nonblock: bool) -> LinuxResult { - match self { - Socket::Udp(udpsocket) => udpsocket.lock().set_nonblocking(nonblock), - Socket::Tcp(tcpsocket) => tcpsocket.lock().set_nonblocking(nonblock), - } - Ok(()) - } -} - -impl From for ctypes::sockaddr_in { - fn from(addr: SocketAddrV4) -> ctypes::sockaddr_in { - ctypes::sockaddr_in { - sin_family: ctypes::AF_INET as u16, - sin_port: addr.port().to_be(), - sin_addr: ctypes::in_addr { - // `s_addr` is stored as BE on all machines and the array is in BE order. - // So the native endian conversion method is used so that it's never swapped. - s_addr: u32::from_ne_bytes(addr.ip().octets()), - }, - sin_zero: [0; 8], - } - } -} - -impl From for SocketAddrV4 { - fn from(addr: ctypes::sockaddr_in) -> SocketAddrV4 { - SocketAddrV4::new( - Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes()), - u16::from_be(addr.sin_port), - ) - } -} - -fn into_sockaddr(addr: SocketAddr) -> (ctypes::sockaddr, ctypes::socklen_t) { - debug!(" Sockaddr: {}", addr); - match addr { - SocketAddr::V4(addr) => ( - unsafe { *(&ctypes::sockaddr_in::from(addr) as *const _ as *const ctypes::sockaddr) }, - size_of::() as _, - ), - SocketAddr::V6(_) => panic!("IPv6 is not supported"), - } -} - -fn from_sockaddr( - addr: *const ctypes::sockaddr, - addrlen: ctypes::socklen_t, -) -> LinuxResult { - if addr.is_null() { - return Err(LinuxError::EFAULT); - } - if addrlen != size_of::() as _ { - return Err(LinuxError::EINVAL); - } - - let mid = unsafe { *(addr as *const ctypes::sockaddr_in) }; - if mid.sin_family != ctypes::AF_INET as u16 { - return Err(LinuxError::EINVAL); - } - - let res = SocketAddr::V4(mid.into()); - debug!(" load sockaddr:{:#x} => {:?}", addr as usize, res); - Ok(res) -} - -/// Create an socket for communication. -/// -/// Return the socket file descriptor. -pub fn sys_socket(domain: c_int, socktype: c_int, protocol: c_int) -> c_int { - debug!("sys_socket <= {} {} {}", domain, socktype, protocol); - let (domain, socktype, protocol) = (domain as u32, socktype as u32, protocol as u32); - syscall_body!(sys_socket, { - match (domain, socktype, protocol) { - (ctypes::AF_INET, ctypes::SOCK_STREAM, ctypes::IPPROTO_TCP) - | (ctypes::AF_INET, ctypes::SOCK_STREAM, 0) => { - Socket::Tcp(Mutex::new(TcpSocket::new())).add_to_fd_table() - } - (ctypes::AF_INET, ctypes::SOCK_DGRAM, ctypes::IPPROTO_UDP) - | (ctypes::AF_INET, ctypes::SOCK_DGRAM, 0) => { - Socket::Udp(Mutex::new(UdpSocket::new())).add_to_fd_table() - } - _ => Err(LinuxError::EINVAL), - } - }) -} - -/// Bind a address to a socket. -/// -/// Return 0 if success. -pub fn sys_bind( - socket_fd: c_int, - socket_addr: *const ctypes::sockaddr, - addrlen: ctypes::socklen_t, -) -> c_int { - debug!( - "sys_bind <= {} {:#x} {}", - socket_fd, socket_addr as usize, addrlen - ); - syscall_body!(sys_bind, { - let addr = from_sockaddr(socket_addr, addrlen)?; - Socket::from_fd(socket_fd)?.bind(addr)?; - Ok(0) - }) -} - -/// Connects the socket to the address specified. -/// -/// Return 0 if success. -pub fn sys_connect( - socket_fd: c_int, - socket_addr: *const ctypes::sockaddr, - addrlen: ctypes::socklen_t, -) -> c_int { - debug!( - "sys_connect <= {} {:#x} {}", - socket_fd, socket_addr as usize, addrlen - ); - syscall_body!(sys_connect, { - let addr = from_sockaddr(socket_addr, addrlen)?; - Socket::from_fd(socket_fd)?.connect(addr)?; - Ok(0) - }) -} - -/// Send a message on a socket to the address specified. -/// -/// Return the number of bytes sent if success. -pub fn sys_sendto( - socket_fd: c_int, - buf_ptr: *const c_void, - len: ctypes::size_t, - flag: c_int, // currently not used - socket_addr: *const ctypes::sockaddr, - addrlen: ctypes::socklen_t, -) -> ctypes::ssize_t { - debug!( - "sys_sendto <= {} {:#x} {} {} {:#x} {}", - socket_fd, buf_ptr as usize, len, flag, socket_addr as usize, addrlen - ); - syscall_body!(sys_sendto, { - if buf_ptr.is_null() { - return Err(LinuxError::EFAULT); - } - let addr = from_sockaddr(socket_addr, addrlen)?; - let buf = unsafe { core::slice::from_raw_parts(buf_ptr as *const u8, len) }; - Socket::from_fd(socket_fd)?.sendto(buf, addr) - }) -} - -/// Send a message on a socket to the address connected. -/// -/// Return the number of bytes sent if success. -pub fn sys_send( - socket_fd: c_int, - buf_ptr: *const c_void, - len: ctypes::size_t, - flag: c_int, // currently not used -) -> ctypes::ssize_t { - debug!( - "sys_sendto <= {} {:#x} {} {}", - socket_fd, buf_ptr as usize, len, flag - ); - syscall_body!(sys_send, { - if buf_ptr.is_null() { - return Err(LinuxError::EFAULT); - } - let buf = unsafe { core::slice::from_raw_parts(buf_ptr as *const u8, len) }; - Socket::from_fd(socket_fd)?.send(buf) - }) -} - -/// Receive a message on a socket and get its source address. -/// -/// Return the number of bytes received if success. -pub unsafe fn sys_recvfrom( - socket_fd: c_int, - buf_ptr: *mut c_void, - len: ctypes::size_t, - flag: c_int, // currently not used - socket_addr: *mut ctypes::sockaddr, - addrlen: *mut ctypes::socklen_t, -) -> ctypes::ssize_t { - debug!( - "sys_recvfrom <= {} {:#x} {} {} {:#x} {:#x}", - socket_fd, buf_ptr as usize, len, flag, socket_addr as usize, addrlen as usize - ); - syscall_body!(sys_recvfrom, { - if buf_ptr.is_null() || socket_addr.is_null() || addrlen.is_null() { - return Err(LinuxError::EFAULT); - } - let socket = Socket::from_fd(socket_fd)?; - let buf = unsafe { core::slice::from_raw_parts_mut(buf_ptr as *mut u8, len) }; - - let res = socket.recvfrom(buf)?; - if let Some(addr) = res.1 { - unsafe { - (*socket_addr, *addrlen) = into_sockaddr(addr); - } - } - Ok(res.0) - }) -} - -/// Receive a message on a socket. -/// -/// Return the number of bytes received if success. -pub fn sys_recv( - socket_fd: c_int, - buf_ptr: *mut c_void, - len: ctypes::size_t, - flag: c_int, // currently not used -) -> ctypes::ssize_t { - debug!( - "sys_recv <= {} {:#x} {} {}", - socket_fd, buf_ptr as usize, len, flag - ); - syscall_body!(sys_recv, { - if buf_ptr.is_null() { - return Err(LinuxError::EFAULT); - } - let buf = unsafe { core::slice::from_raw_parts_mut(buf_ptr as *mut u8, len) }; - Socket::from_fd(socket_fd)?.recv(buf) - }) -} - -/// Listen for connections on a socket -/// -/// Return 0 if success. -pub fn sys_listen( - socket_fd: c_int, - backlog: c_int, // currently not used -) -> c_int { - debug!("sys_listen <= {} {}", socket_fd, backlog); - syscall_body!(sys_listen, { - Socket::from_fd(socket_fd)?.listen()?; - Ok(0) - }) -} - -/// Accept for connections on a socket -/// -/// Return file descriptor for the accepted socket if success. -pub unsafe fn sys_accept( - socket_fd: c_int, - socket_addr: *mut ctypes::sockaddr, - socket_len: *mut ctypes::socklen_t, -) -> c_int { - debug!( - "sys_accept <= {} {:#x} {:#x}", - socket_fd, socket_addr as usize, socket_len as usize - ); - syscall_body!(sys_accept, { - if socket_addr.is_null() || socket_len.is_null() { - return Err(LinuxError::EFAULT); - } - let socket = Socket::from_fd(socket_fd)?; - let new_socket = socket.accept()?; - let addr = new_socket.peer_addr()?; - let new_fd = Socket::add_to_fd_table(Socket::Tcp(Mutex::new(new_socket)))?; - unsafe { - (*socket_addr, *socket_len) = into_sockaddr(addr); - } - Ok(new_fd) - }) -} - -/// Shut down a full-duplex connection. -/// -/// Return 0 if success. -pub fn sys_shutdown( - socket_fd: c_int, - flag: c_int, // currently not used -) -> c_int { - debug!("sys_shutdown <= {} {}", socket_fd, flag); - syscall_body!(sys_shutdown, { - Socket::from_fd(socket_fd)?.shutdown()?; - Ok(0) - }) -} - -/// Query addresses for a domain name. -/// -/// Only IPv4. Ports are always 0. Ignore servname and hint. -/// Results' ai_flags and ai_canonname are 0 or NULL. -/// -/// Return address number if success. -pub unsafe fn sys_getaddrinfo( - nodename: *const c_char, - servname: *const c_char, - _hints: *const ctypes::addrinfo, - res: *mut *mut ctypes::addrinfo, -) -> c_int { - let name = char_ptr_to_str(nodename); - let port = char_ptr_to_str(servname); - debug!("sys_getaddrinfo <= {:?} {:?}", name, port); - syscall_body!(sys_getaddrinfo, { - if nodename.is_null() && servname.is_null() { - return Ok(0); - } - if res.is_null() { - return Err(LinuxError::EFAULT); - } - - let port = port.map_or(0, |p| p.parse::().unwrap_or(0)); - let ip_addrs = if let Ok(domain) = name { - if let Ok(a) = domain.parse::() { - vec![a] - } else { - axnet::dns_query(domain)? - } - } else { - vec![Ipv4Addr::LOCALHOST.into()] - }; - - let len = ip_addrs.len().min(ctypes::MAXADDRS as usize); - if len == 0 { - return Ok(0); - } - - let mut out: Vec = Vec::with_capacity(len); - for (i, &ip) in ip_addrs.iter().enumerate().take(len) { - let buf = match ip { - IpAddr::V4(ip) => ctypes::aibuf { - ai: ctypes::addrinfo { - ai_family: ctypes::AF_INET as _, - // TODO: This is a hard-code part, only return TCP parameters - ai_socktype: ctypes::SOCK_STREAM as _, - ai_protocol: ctypes::IPPROTO_TCP as _, - ai_addrlen: size_of::() as _, - ai_addr: core::ptr::null_mut(), - ai_canonname: core::ptr::null_mut(), - ai_next: core::ptr::null_mut(), - ai_flags: 0, - }, - sa: ctypes::aibuf_sa { - sin: SocketAddrV4::new(ip, port).into(), - }, - slot: i as i16, - lock: [0], - ref_: 0, - }, - _ => panic!("IPv6 is not supported"), - }; - out.push(buf); - out[i].ai.ai_addr = - unsafe { core::ptr::addr_of_mut!(out[i].sa.sin) as *mut ctypes::sockaddr }; - if i > 0 { - out[i - 1].ai.ai_next = core::ptr::addr_of_mut!(out[i].ai); - } - } - - out[0].ref_ = len as i16; - unsafe { *res = core::ptr::addr_of_mut!(out[0].ai) }; - core::mem::forget(out); // drop in `sys_freeaddrinfo` - Ok(len) - }) -} - -/// Free queried `addrinfo` struct -pub unsafe fn sys_freeaddrinfo(res: *mut ctypes::addrinfo) { - if res.is_null() { - return; - } - let aibuf_ptr = res as *mut ctypes::aibuf; - let len = (*aibuf_ptr).ref_ as usize; - assert!((*aibuf_ptr).slot == 0); - assert!(len > 0); - let vec = Vec::from_raw_parts(aibuf_ptr, len, len); // TODO: lock - drop(vec); -} - -/// Get current address to which the socket sockfd is bound. -pub unsafe fn sys_getsockname( - sock_fd: c_int, - addr: *mut ctypes::sockaddr, - addrlen: *mut ctypes::socklen_t, -) -> c_int { - debug!( - "sys_getsockname <= {} {:#x} {:#x}", - sock_fd, addr as usize, addrlen as usize - ); - syscall_body!(sys_getsockname, { - if addr.is_null() || addrlen.is_null() { - return Err(LinuxError::EFAULT); - } - if unsafe { *addrlen } < size_of::() as u32 { - return Err(LinuxError::EINVAL); - } - unsafe { - (*addr, *addrlen) = into_sockaddr(Socket::from_fd(sock_fd)?.local_addr()?); - } - Ok(0) - }) -} - -/// Get peer address to which the socket sockfd is connected. -pub unsafe fn sys_getpeername( - sock_fd: c_int, - addr: *mut ctypes::sockaddr, - addrlen: *mut ctypes::socklen_t, -) -> c_int { - debug!( - "sys_getpeername <= {} {:#x} {:#x}", - sock_fd, addr as usize, addrlen as usize - ); - syscall_body!(sys_getpeername, { - if addr.is_null() || addrlen.is_null() { - return Err(LinuxError::EFAULT); - } - if unsafe { *addrlen } < size_of::() as u32 { - return Err(LinuxError::EINVAL); - } - unsafe { - (*addr, *addrlen) = into_sockaddr(Socket::from_fd(sock_fd)?.peer_addr()?); - } - Ok(0) - }) -} diff --git a/arceos/api/arceos_posix_api/src/imp/pipe.rs b/arceos/api/arceos_posix_api/src/imp/pipe.rs deleted file mode 100644 index 17a9b248b..000000000 --- a/arceos/api/arceos_posix_api/src/imp/pipe.rs +++ /dev/null @@ -1,214 +0,0 @@ -use alloc::sync::Arc; -use core::ffi::c_int; - -use axerrno::{LinuxError, LinuxResult}; -use axio::PollState; -use axsync::Mutex; - -use super::fd_ops::{add_file_like, close_file_like, FileLike}; -use crate::ctypes; - -#[derive(Copy, Clone, PartialEq)] -enum RingBufferStatus { - Full, - Empty, - Normal, -} - -const RING_BUFFER_SIZE: usize = 256; - -pub struct PipeRingBuffer { - arr: [u8; RING_BUFFER_SIZE], - head: usize, - tail: usize, - status: RingBufferStatus, -} - -impl PipeRingBuffer { - pub const fn new() -> Self { - Self { - arr: [0; RING_BUFFER_SIZE], - head: 0, - tail: 0, - status: RingBufferStatus::Empty, - } - } - - pub fn write_byte(&mut self, byte: u8) { - self.status = RingBufferStatus::Normal; - self.arr[self.tail] = byte; - self.tail = (self.tail + 1) % RING_BUFFER_SIZE; - if self.tail == self.head { - self.status = RingBufferStatus::Full; - } - } - - pub fn read_byte(&mut self) -> u8 { - self.status = RingBufferStatus::Normal; - let c = self.arr[self.head]; - self.head = (self.head + 1) % RING_BUFFER_SIZE; - if self.head == self.tail { - self.status = RingBufferStatus::Empty; - } - c - } - - /// Get the length of remaining data in the buffer - pub const fn available_read(&self) -> usize { - if matches!(self.status, RingBufferStatus::Empty) { - 0 - } else if self.tail > self.head { - self.tail - self.head - } else { - self.tail + RING_BUFFER_SIZE - self.head - } - } - - /// Get the length of remaining space in the buffer - pub const fn available_write(&self) -> usize { - if matches!(self.status, RingBufferStatus::Full) { - 0 - } else { - RING_BUFFER_SIZE - self.available_read() - } - } -} - -pub struct Pipe { - readable: bool, - buffer: Arc>, -} - -impl Pipe { - pub fn new() -> (Pipe, Pipe) { - let buffer = Arc::new(Mutex::new(PipeRingBuffer::new())); - let read_end = Pipe { - readable: true, - buffer: buffer.clone(), - }; - let write_end = Pipe { - readable: false, - buffer, - }; - (read_end, write_end) - } - - pub const fn readable(&self) -> bool { - self.readable - } - - pub const fn writable(&self) -> bool { - !self.readable - } - - pub fn write_end_close(&self) -> bool { - Arc::strong_count(&self.buffer) == 1 - } -} - -impl FileLike for Pipe { - fn read(&self, buf: &mut [u8]) -> LinuxResult { - if !self.readable() { - return Err(LinuxError::EPERM); - } - let mut read_size = 0usize; - let max_len = buf.len(); - loop { - let mut ring_buffer = self.buffer.lock(); - let loop_read = ring_buffer.available_read(); - if loop_read == 0 { - if self.write_end_close() { - return Ok(read_size); - } - drop(ring_buffer); - // Data not ready, wait for write end - crate::sys_sched_yield(); // TODO: use synconize primitive - continue; - } - for _ in 0..loop_read { - if read_size == max_len { - return Ok(read_size); - } - buf[read_size] = ring_buffer.read_byte(); - read_size += 1; - } - } - } - - fn write(&self, buf: &[u8]) -> LinuxResult { - if !self.writable() { - return Err(LinuxError::EPERM); - } - let mut write_size = 0usize; - let max_len = buf.len(); - loop { - let mut ring_buffer = self.buffer.lock(); - let loop_write = ring_buffer.available_write(); - if loop_write == 0 { - drop(ring_buffer); - // Buffer is full, wait for read end to consume - crate::sys_sched_yield(); // TODO: use synconize primitive - continue; - } - for _ in 0..loop_write { - if write_size == max_len { - return Ok(write_size); - } - ring_buffer.write_byte(buf[write_size]); - write_size += 1; - } - } - } - - fn stat(&self) -> LinuxResult { - let st_mode = 0o10000 | 0o600u32; // S_IFIFO | rw------- - Ok(ctypes::stat { - st_ino: 1, - st_nlink: 1, - st_mode, - st_uid: 1000, - st_gid: 1000, - st_blksize: 4096, - ..Default::default() - }) - } - - fn into_any(self: Arc) -> Arc { - self - } - - fn poll(&self) -> LinuxResult { - let buf = self.buffer.lock(); - Ok(PollState { - readable: self.readable() && buf.available_read() > 0, - writable: self.writable() && buf.available_write() > 0, - }) - } - - fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult { - Ok(()) - } -} - -/// Create a pipe -/// -/// Return 0 if succeed -pub fn sys_pipe(fds: &mut [c_int]) -> c_int { - debug!("sys_pipe <= {:#x}", fds.as_ptr() as usize); - syscall_body!(sys_pipe, { - if fds.len() != 2 { - return Err(LinuxError::EFAULT); - } - - let (read_end, write_end) = Pipe::new(); - let read_fd = add_file_like(Arc::new(read_end))?; - let write_fd = add_file_like(Arc::new(write_end)).inspect_err(|_| { - close_file_like(read_fd).ok(); - })?; - - fds[0] = read_fd as c_int; - fds[1] = write_fd as c_int; - - Ok(0) - }) -} diff --git a/arceos/api/arceos_posix_api/src/imp/pthread/mod.rs b/arceos/api/arceos_posix_api/src/imp/pthread/mod.rs deleted file mode 100644 index bcf12fff8..000000000 --- a/arceos/api/arceos_posix_api/src/imp/pthread/mod.rs +++ /dev/null @@ -1,154 +0,0 @@ -use alloc::{boxed::Box, collections::BTreeMap, sync::Arc}; -use core::cell::UnsafeCell; -use core::ffi::{c_int, c_void}; - -use axerrno::{LinuxError, LinuxResult}; -use axtask::AxTaskRef; -use spin::RwLock; - -use crate::ctypes; - -pub mod mutex; - -lazy_static::lazy_static! { - static ref TID_TO_PTHREAD: RwLock>> = { - let mut map = BTreeMap::new(); - let main_task = axtask::current(); - let main_tid = main_task.id().as_u64(); - let main_thread = Pthread { - inner: main_task.as_task_ref().clone(), - retval: Arc::new(Packet { - result: UnsafeCell::new(core::ptr::null_mut()), - }), - }; - let ptr = Box::into_raw(Box::new(main_thread)) as *mut c_void; - map.insert(main_tid, ForceSendSync(ptr)); - RwLock::new(map) - }; -} - -struct Packet { - result: UnsafeCell, -} - -unsafe impl Send for Packet {} -unsafe impl Sync for Packet {} - -pub struct Pthread { - inner: AxTaskRef, - retval: Arc>, -} - -impl Pthread { - fn create( - _attr: *const ctypes::pthread_attr_t, - start_routine: extern "C" fn(arg: *mut c_void) -> *mut c_void, - arg: *mut c_void, - ) -> LinuxResult { - let arg_wrapper = ForceSendSync(arg); - - let my_packet: Arc> = Arc::new(Packet { - result: UnsafeCell::new(core::ptr::null_mut()), - }); - let their_packet = my_packet.clone(); - - let main = move || { - let arg = arg_wrapper; - let ret = start_routine(arg.0); - unsafe { *their_packet.result.get() = ret }; - drop(their_packet); - }; - - let task_inner = axtask::spawn(main); - let tid = task_inner.id().as_u64(); - let thread = Pthread { - inner: task_inner, - retval: my_packet, - }; - let ptr = Box::into_raw(Box::new(thread)) as *mut c_void; - TID_TO_PTHREAD.write().insert(tid, ForceSendSync(ptr)); - Ok(ptr) - } - - fn current_ptr() -> *mut Pthread { - let tid = axtask::current().id().as_u64(); - match TID_TO_PTHREAD.read().get(&tid) { - None => core::ptr::null_mut(), - Some(ptr) => ptr.0 as *mut Pthread, - } - } - - fn current() -> Option<&'static Pthread> { - unsafe { core::ptr::NonNull::new(Self::current_ptr()).map(|ptr| ptr.as_ref()) } - } - - fn exit_current(retval: *mut c_void) -> ! { - let thread = Self::current().expect("fail to get current thread"); - unsafe { *thread.retval.result.get() = retval }; - axtask::exit(0); - } - - fn join(ptr: ctypes::pthread_t) -> LinuxResult<*mut c_void> { - if core::ptr::eq(ptr, Self::current_ptr() as _) { - return Err(LinuxError::EDEADLK); - } - - let thread = unsafe { Box::from_raw(ptr as *mut Pthread) }; - thread.inner.join(); - let tid = thread.inner.id().as_u64(); - let retval = unsafe { *thread.retval.result.get() }; - TID_TO_PTHREAD.write().remove(&tid); - drop(thread); - Ok(retval) - } -} - -/// Returns the `pthread` struct of current thread. -pub fn sys_pthread_self() -> ctypes::pthread_t { - Pthread::current().expect("fail to get current thread") as *const Pthread as _ -} - -/// Create a new thread with the given entry point and argument. -/// -/// If successful, it stores the pointer to the newly created `struct __pthread` -/// in `res` and returns 0. -pub unsafe fn sys_pthread_create( - res: *mut ctypes::pthread_t, - attr: *const ctypes::pthread_attr_t, - start_routine: extern "C" fn(arg: *mut c_void) -> *mut c_void, - arg: *mut c_void, -) -> c_int { - debug!( - "sys_pthread_create <= {:#x}, {:#x}", - start_routine as usize, arg as usize - ); - syscall_body!(sys_pthread_create, { - let ptr = Pthread::create(attr, start_routine, arg)?; - unsafe { core::ptr::write(res, ptr) }; - Ok(0) - }) -} - -/// Exits the current thread. The value `retval` will be returned to the joiner. -pub fn sys_pthread_exit(retval: *mut c_void) -> ! { - debug!("sys_pthread_exit <= {:#x}", retval as usize); - Pthread::exit_current(retval); -} - -/// Waits for the given thread to exit, and stores the return value in `retval`. -pub unsafe fn sys_pthread_join(thread: ctypes::pthread_t, retval: *mut *mut c_void) -> c_int { - debug!("sys_pthread_join <= {:#x}", retval as usize); - syscall_body!(sys_pthread_join, { - let ret = Pthread::join(thread)?; - if !retval.is_null() { - unsafe { core::ptr::write(retval, ret) }; - } - Ok(0) - }) -} - -#[derive(Clone, Copy)] -struct ForceSendSync(T); - -unsafe impl Send for ForceSendSync {} -unsafe impl Sync for ForceSendSync {} diff --git a/arceos/api/arceos_posix_api/src/imp/pthread/mutex.rs b/arceos/api/arceos_posix_api/src/imp/pthread/mutex.rs deleted file mode 100644 index 528779a09..000000000 --- a/arceos/api/arceos_posix_api/src/imp/pthread/mutex.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::{ctypes, utils::check_null_mut_ptr}; - -use axerrno::LinuxResult; -use axsync::Mutex; - -use core::ffi::c_int; -use core::mem::{size_of, ManuallyDrop}; - -static_assertions::const_assert_eq!( - size_of::(), - size_of::() -); - -#[repr(C)] -pub struct PthreadMutex(Mutex<()>); - -impl PthreadMutex { - const fn new() -> Self { - Self(Mutex::new(())) - } - - fn lock(&self) -> LinuxResult { - let _guard = ManuallyDrop::new(self.0.lock()); - Ok(()) - } - - fn unlock(&self) -> LinuxResult { - unsafe { self.0.force_unlock() }; - Ok(()) - } -} - -/// Initialize a mutex. -pub fn sys_pthread_mutex_init( - mutex: *mut ctypes::pthread_mutex_t, - _attr: *const ctypes::pthread_mutexattr_t, -) -> c_int { - debug!("sys_pthread_mutex_init <= {:#x}", mutex as usize); - syscall_body!(sys_pthread_mutex_init, { - check_null_mut_ptr(mutex)?; - unsafe { - mutex.cast::().write(PthreadMutex::new()); - } - Ok(0) - }) -} - -/// Lock the given mutex. -pub fn sys_pthread_mutex_lock(mutex: *mut ctypes::pthread_mutex_t) -> c_int { - debug!("sys_pthread_mutex_lock <= {:#x}", mutex as usize); - syscall_body!(sys_pthread_mutex_lock, { - check_null_mut_ptr(mutex)?; - unsafe { - (*mutex.cast::()).lock()?; - } - Ok(0) - }) -} - -/// Unlock the given mutex. -pub fn sys_pthread_mutex_unlock(mutex: *mut ctypes::pthread_mutex_t) -> c_int { - debug!("sys_pthread_mutex_unlock <= {:#x}", mutex as usize); - syscall_body!(sys_pthread_mutex_unlock, { - check_null_mut_ptr(mutex)?; - unsafe { - (*mutex.cast::()).unlock()?; - } - Ok(0) - }) -} diff --git a/arceos/api/arceos_posix_api/src/imp/resources.rs b/arceos/api/arceos_posix_api/src/imp/resources.rs deleted file mode 100644 index 16956ae83..000000000 --- a/arceos/api/arceos_posix_api/src/imp/resources.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::ctypes; -use axerrno::LinuxError; -use core::ffi::c_int; - -/// Get resource limitations -/// -/// TODO: support more resource types -pub unsafe fn sys_getrlimit(resource: c_int, rlimits: *mut ctypes::rlimit) -> c_int { - debug!("sys_getrlimit <= {} {:#x}", resource, rlimits as usize); - syscall_body!(sys_getrlimit, { - match resource as u32 { - ctypes::RLIMIT_DATA => {} - ctypes::RLIMIT_STACK => {} - ctypes::RLIMIT_NOFILE => {} - _ => return Err(LinuxError::EINVAL), - } - if rlimits.is_null() { - return Ok(0); - } - match resource as u32 { - ctypes::RLIMIT_STACK => unsafe { - (*rlimits).rlim_cur = axconfig::TASK_STACK_SIZE as _; - (*rlimits).rlim_max = axconfig::TASK_STACK_SIZE as _; - }, - #[cfg(feature = "fd")] - ctypes::RLIMIT_NOFILE => unsafe { - (*rlimits).rlim_cur = super::fd_ops::AX_FILE_LIMIT as _; - (*rlimits).rlim_max = super::fd_ops::AX_FILE_LIMIT as _; - }, - _ => {} - } - Ok(0) - }) -} - -/// Set resource limitations -/// -/// TODO: support more resource types -pub unsafe fn sys_setrlimit(resource: c_int, rlimits: *mut crate::ctypes::rlimit) -> c_int { - debug!("sys_setrlimit <= {} {:#x}", resource, rlimits as usize); - syscall_body!(sys_setrlimit, { - match resource as u32 { - crate::ctypes::RLIMIT_DATA => {} - crate::ctypes::RLIMIT_STACK => {} - crate::ctypes::RLIMIT_NOFILE => {} - _ => return Err(LinuxError::EINVAL), - } - // Currently do not support set resources - Ok(0) - }) -} diff --git a/arceos/api/arceos_posix_api/src/imp/stdio.rs b/arceos/api/arceos_posix_api/src/imp/stdio.rs deleted file mode 100644 index ded9c3333..000000000 --- a/arceos/api/arceos_posix_api/src/imp/stdio.rs +++ /dev/null @@ -1,170 +0,0 @@ -use axerrno::AxResult; -use axio::{prelude::*, BufReader}; -use axsync::Mutex; - -#[cfg(feature = "fd")] -use {alloc::sync::Arc, axerrno::LinuxError, axerrno::LinuxResult, axio::PollState}; - -fn console_read_bytes() -> Option { - axhal::console::getchar().map(|c| if c == b'\r' { b'\n' } else { c }) -} - -fn console_write_bytes(buf: &[u8]) -> AxResult { - axhal::console::write_bytes(buf); - Ok(buf.len()) -} - -struct StdinRaw; -struct StdoutRaw; - -impl Read for StdinRaw { - // Non-blocking read, returns number of bytes read. - fn read(&mut self, buf: &mut [u8]) -> AxResult { - let mut read_len = 0; - while read_len < buf.len() { - if let Some(c) = console_read_bytes() { - buf[read_len] = c; - read_len += 1; - } else { - break; - } - } - Ok(read_len) - } -} - -impl Write for StdoutRaw { - fn write(&mut self, buf: &[u8]) -> AxResult { - console_write_bytes(buf) - } - - fn flush(&mut self) -> AxResult { - Ok(()) - } -} - -pub struct Stdin { - inner: &'static Mutex>, -} - -impl Stdin { - // Block until at least one byte is read. - fn read_blocked(&self, buf: &mut [u8]) -> AxResult { - let read_len = self.inner.lock().read(buf)?; - if buf.is_empty() || read_len > 0 { - return Ok(read_len); - } - // try again until we get something - loop { - let read_len = self.inner.lock().read(buf)?; - if read_len > 0 { - return Ok(read_len); - } - crate::sys_sched_yield(); - } - } -} - -impl Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> AxResult { - self.read_blocked(buf) - } -} - -pub struct Stdout { - inner: &'static Mutex, -} - -impl Write for Stdout { - fn write(&mut self, buf: &[u8]) -> AxResult { - self.inner.lock().write(buf) - } - - fn flush(&mut self) -> AxResult { - self.inner.lock().flush() - } -} - -/// Constructs a new handle to the standard input of the current process. -pub fn stdin() -> Stdin { - static INSTANCE: Mutex> = Mutex::new(BufReader::new(StdinRaw)); - Stdin { inner: &INSTANCE } -} - -/// Constructs a new handle to the standard output of the current process. -pub fn stdout() -> Stdout { - static INSTANCE: Mutex = Mutex::new(StdoutRaw); - Stdout { inner: &INSTANCE } -} - -#[cfg(feature = "fd")] -impl super::fd_ops::FileLike for Stdin { - fn read(&self, buf: &mut [u8]) -> LinuxResult { - Ok(self.read_blocked(buf)?) - } - - fn write(&self, _buf: &[u8]) -> LinuxResult { - Err(LinuxError::EPERM) - } - - fn stat(&self) -> LinuxResult { - let st_mode = 0o20000 | 0o440u32; // S_IFCHR | r--r----- - Ok(crate::ctypes::stat { - st_ino: 1, - st_nlink: 1, - st_mode, - ..Default::default() - }) - } - - fn into_any(self: Arc) -> Arc { - self - } - - fn poll(&self) -> LinuxResult { - Ok(PollState { - readable: true, - writable: true, - }) - } - - fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult { - Ok(()) - } -} - -#[cfg(feature = "fd")] -impl super::fd_ops::FileLike for Stdout { - fn read(&self, _buf: &mut [u8]) -> LinuxResult { - Err(LinuxError::EPERM) - } - - fn write(&self, buf: &[u8]) -> LinuxResult { - Ok(self.inner.lock().write(buf)?) - } - - fn stat(&self) -> LinuxResult { - let st_mode = 0o20000 | 0o220u32; // S_IFCHR | -w--w---- - Ok(crate::ctypes::stat { - st_ino: 1, - st_nlink: 1, - st_mode, - ..Default::default() - }) - } - - fn into_any(self: Arc) -> Arc { - self - } - - fn poll(&self) -> LinuxResult { - Ok(PollState { - readable: true, - writable: true, - }) - } - - fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult { - Ok(()) - } -} diff --git a/arceos/api/arceos_posix_api/src/imp/sys.rs b/arceos/api/arceos_posix_api/src/imp/sys.rs deleted file mode 100644 index 0e7a43292..000000000 --- a/arceos/api/arceos_posix_api/src/imp/sys.rs +++ /dev/null @@ -1,29 +0,0 @@ -use core::ffi::{c_int, c_long}; - -use crate::ctypes; - -const PAGE_SIZE_4K: usize = 4096; - -/// Return system configuration infomation -/// -/// Notice: currently only support what unikraft covers -pub fn sys_sysconf(name: c_int) -> c_long { - debug!("sys_sysconf <= {}", name); - syscall_body!(sys_sysconf, { - match name as u32 { - // Page size - ctypes::_SC_PAGE_SIZE => Ok(PAGE_SIZE_4K), - // Total physical pages - ctypes::_SC_PHYS_PAGES => Ok(axconfig::PHYS_MEMORY_SIZE / PAGE_SIZE_4K), - // Number of processors in use - ctypes::_SC_NPROCESSORS_ONLN => Ok(axconfig::SMP), - // Avaliable physical pages - #[cfg(feature = "alloc")] - ctypes::_SC_AVPHYS_PAGES => Ok(axalloc::global_allocator().available_pages()), - // Maximum number of files per process - #[cfg(feature = "fd")] - ctypes::_SC_OPEN_MAX => Ok(super::fd_ops::AX_FILE_LIMIT), - _ => Ok(0), - } - }) -} diff --git a/arceos/api/arceos_posix_api/src/imp/task.rs b/arceos/api/arceos_posix_api/src/imp/task.rs deleted file mode 100644 index 5ba05feef..000000000 --- a/arceos/api/arceos_posix_api/src/imp/task.rs +++ /dev/null @@ -1,40 +0,0 @@ -use core::ffi::c_int; - -/// Relinquish the CPU, and switches to another task. -/// -/// For single-threaded configuration (`multitask` feature is disabled), we just -/// relax the CPU and wait for incoming interrupts. -pub fn sys_sched_yield() -> c_int { - #[cfg(feature = "multitask")] - axtask::yield_now(); - #[cfg(not(feature = "multitask"))] - if cfg!(feature = "irq") { - axhal::arch::wait_for_irqs(); - } else { - core::hint::spin_loop(); - } - 0 -} - -/// Get current thread ID. -pub fn sys_getpid() -> c_int { - syscall_body!(sys_getpid, - #[cfg(feature = "multitask")] - { - Ok(axtask::current().id().as_u64() as c_int) - } - #[cfg(not(feature = "multitask"))] - { - Ok(2) // `main` task ID - } - ) -} - -/// Exit current task -pub fn sys_exit(exit_code: c_int) -> ! { - debug!("sys_exit <= {}", exit_code); - #[cfg(feature = "multitask")] - axtask::exit(exit_code); - #[cfg(not(feature = "multitask"))] - axhal::misc::terminate(); -} diff --git a/arceos/api/arceos_posix_api/src/imp/time.rs b/arceos/api/arceos_posix_api/src/imp/time.rs deleted file mode 100644 index 62458f489..000000000 --- a/arceos/api/arceos_posix_api/src/imp/time.rs +++ /dev/null @@ -1,92 +0,0 @@ -use axerrno::LinuxError; -use core::ffi::{c_int, c_long}; -use core::time::Duration; - -use crate::ctypes; -use crate::ctypes::{CLOCK_MONOTONIC, CLOCK_REALTIME}; - -impl From for Duration { - fn from(ts: ctypes::timespec) -> Self { - Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32) - } -} - -impl From for Duration { - fn from(tv: ctypes::timeval) -> Self { - Duration::new(tv.tv_sec as u64, tv.tv_usec as u32 * 1000) - } -} - -impl From for ctypes::timespec { - fn from(d: Duration) -> Self { - ctypes::timespec { - tv_sec: d.as_secs() as c_long, - tv_nsec: d.subsec_nanos() as c_long, - } - } -} - -impl From for ctypes::timeval { - fn from(d: Duration) -> Self { - ctypes::timeval { - tv_sec: d.as_secs() as c_long, - tv_usec: d.subsec_micros() as c_long, - } - } -} - -/// Get clock time since booting -pub unsafe fn sys_clock_gettime(clk: ctypes::clockid_t, ts: *mut ctypes::timespec) -> c_int { - syscall_body!(sys_clock_gettime, { - if ts.is_null() { - return Err(LinuxError::EFAULT); - } - let now = match clk as u32 { - CLOCK_REALTIME => axhal::time::wall_time().into(), - CLOCK_MONOTONIC => axhal::time::monotonic_time().into(), - _ => { - warn!("Called sys_clock_gettime for unsupported clock {}", clk); - return Err(LinuxError::EINVAL); - } - }; - unsafe { *ts = now }; - debug!("sys_clock_gettime: {}.{:09}s", now.tv_sec, now.tv_nsec); - Ok(0) - }) -} - -/// Sleep some nanoseconds -/// -/// TODO: should be woken by signals, and set errno -pub unsafe fn sys_nanosleep(req: *const ctypes::timespec, rem: *mut ctypes::timespec) -> c_int { - syscall_body!(sys_nanosleep, { - unsafe { - if req.is_null() || (*req).tv_nsec < 0 || (*req).tv_nsec > 999999999 { - return Err(LinuxError::EINVAL); - } - } - - let dur = unsafe { - debug!("sys_nanosleep <= {}.{:09}s", (*req).tv_sec, (*req).tv_nsec); - Duration::from(*req) - }; - - let now = axhal::time::monotonic_time(); - - #[cfg(feature = "multitask")] - axtask::sleep(dur); - #[cfg(not(feature = "multitask"))] - axhal::time::busy_wait(dur); - - let after = axhal::time::monotonic_time(); - let actual = after - now; - - if let Some(diff) = dur.checked_sub(actual) { - if !rem.is_null() { - unsafe { (*rem) = diff.into() }; - } - return Err(LinuxError::EINTR); - } - Ok(0) - }) -} diff --git a/arceos/api/arceos_posix_api/src/lib.rs b/arceos/api/arceos_posix_api/src/lib.rs deleted file mode 100644 index ef6c7a11d..000000000 --- a/arceos/api/arceos_posix_api/src/lib.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! POSIX-compatible APIs for [ArceOS] modules -//! -//! [ArceOS]: https://github.com/arceos-org/arceos - -#![cfg_attr(all(not(test), not(doc)), no_std)] -#![feature(doc_cfg)] -#![feature(doc_auto_cfg)] -#![allow(clippy::missing_safety_doc)] - -#[macro_use] -extern crate axlog; -extern crate axruntime; - -#[cfg(feature = "alloc")] -extern crate alloc; - -#[macro_use] -mod utils; - -mod imp; - -/// Platform-specific constants and parameters. -pub mod config { - pub use axconfig::*; -} - -/// POSIX C types. -#[rustfmt::skip] -#[path = "./ctypes_gen.rs"] -#[allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals, clippy::upper_case_acronyms, missing_docs)] -pub mod ctypes; - -pub use imp::io::{sys_read, sys_write, sys_writev}; -pub use imp::resources::{sys_getrlimit, sys_setrlimit}; -pub use imp::sys::sys_sysconf; -pub use imp::task::{sys_exit, sys_getpid, sys_sched_yield}; -pub use imp::time::{sys_clock_gettime, sys_nanosleep}; - -#[cfg(feature = "fd")] -pub use imp::fd_ops::{sys_close, sys_dup, sys_dup2, sys_fcntl, get_file_like}; -#[cfg(feature = "fs")] -pub use imp::fs::{sys_fstat, sys_getcwd, sys_lseek, sys_lstat, sys_open, sys_rename, sys_stat}; -#[cfg(feature = "select")] -pub use imp::io_mpx::sys_select; -#[cfg(feature = "epoll")] -pub use imp::io_mpx::{sys_epoll_create, sys_epoll_ctl, sys_epoll_wait}; -#[cfg(feature = "net")] -pub use imp::net::{ - sys_accept, sys_bind, sys_connect, sys_freeaddrinfo, sys_getaddrinfo, sys_getpeername, - sys_getsockname, sys_listen, sys_recv, sys_recvfrom, sys_send, sys_sendto, sys_shutdown, - sys_socket, -}; -#[cfg(feature = "pipe")] -pub use imp::pipe::sys_pipe; -#[cfg(feature = "multitask")] -pub use imp::pthread::mutex::{ - sys_pthread_mutex_init, sys_pthread_mutex_lock, sys_pthread_mutex_unlock, -}; -#[cfg(feature = "multitask")] -pub use imp::pthread::{sys_pthread_create, sys_pthread_exit, sys_pthread_join, sys_pthread_self}; diff --git a/arceos/api/arceos_posix_api/src/utils.rs b/arceos/api/arceos_posix_api/src/utils.rs deleted file mode 100644 index 664bf5231..000000000 --- a/arceos/api/arceos_posix_api/src/utils.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![allow(dead_code)] -#![allow(unused_macros)] - -use axerrno::{LinuxError, LinuxResult}; -use core::ffi::{c_char, CStr}; - -pub fn char_ptr_to_str<'a>(str: *const c_char) -> LinuxResult<&'a str> { - if str.is_null() { - Err(LinuxError::EFAULT) - } else { - unsafe { CStr::from_ptr(str) } - .to_str() - .map_err(|_| LinuxError::EINVAL) - } -} - -pub fn check_null_ptr(ptr: *const T) -> LinuxResult { - if ptr.is_null() { - Err(LinuxError::EFAULT) - } else { - Ok(()) - } -} - -pub fn check_null_mut_ptr(ptr: *mut T) -> LinuxResult { - if ptr.is_null() { - Err(LinuxError::EFAULT) - } else { - Ok(()) - } -} - -macro_rules! syscall_body { - ($fn: ident, $($stmt: tt)*) => {{ - #[allow(clippy::redundant_closure_call)] - let res = (|| -> axerrno::LinuxResult<_> { $($stmt)* })(); - match res { - Ok(_) | Err(axerrno::LinuxError::EAGAIN) => debug!(concat!(stringify!($fn), " => {:?}"), res), - Err(_) => info!(concat!(stringify!($fn), " => {:?}"), res), - } - match res { - Ok(v) => v as _, - Err(e) => { - -e.code() as _ - } - } - }}; -} - -macro_rules! syscall_body_no_debug { - ($($stmt: tt)*) => {{ - #[allow(clippy::redundant_closure_call)] - let res = (|| -> axerrno::LinuxResult<_> { $($stmt)* })(); - match res { - Ok(v) => v as _, - Err(e) => { - -e.code() as _ - } - } - }}; -} diff --git a/arceos/api/axfeat/Cargo.toml b/arceos/api/axfeat/Cargo.toml deleted file mode 100644 index a4d7c3327..000000000 --- a/arceos/api/axfeat/Cargo.toml +++ /dev/null @@ -1,81 +0,0 @@ -[package] -name = "axfeat" -version.workspace = true -edition = "2021" -authors = ["Yuekai Jia "] -description = "Top-level feature selection for ArceOS" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/api/axfeat" -documentation = "https://arceos-org.github.io/arceos/axfeat/index.html" - -[features] -default = [] - -# Multicore -smp = ["axhal/smp", "axruntime/smp", "kspin/smp"] - -# Floating point/SIMD -fp_simd = ["axhal/fp_simd"] - -# Interrupts -irq = ["axhal/irq", "axruntime/irq", "axtask?/irq"] - -# Memory -alloc = ["axalloc", "axruntime/alloc"] -alloc-tlsf = ["axalloc/tlsf"] -alloc-slab = ["axalloc/slab"] -alloc-buddy = ["axalloc/buddy"] -paging = ["alloc", "axhal/paging", "axruntime/paging"] -tls = ["alloc", "axhal/tls", "axruntime/tls", "axtask?/tls"] -dma = ["alloc", "paging"] - -alt_alloc = ["alt_axalloc", "axruntime/alt_alloc"] - -# Multi-threading and scheduler -multitask = ["alloc", "axtask/multitask", "axsync/multitask", "axruntime/multitask"] -sched_fifo = ["axtask/sched_fifo"] -sched_rr = ["axtask/sched_rr", "irq"] -sched_cfs = ["axtask/sched_cfs", "irq"] - -# File system -fs = ["alloc", "paging", "axdriver/virtio-blk", "dep:axfs", "axruntime/fs"] # TODO: try to remove "paging" -myfs = ["axfs?/myfs"] - -# Networking -net = ["alloc", "paging", "axdriver/virtio-net", "dep:axnet", "axruntime/net"] - -# Display -display = ["alloc", "paging", "axdriver/virtio-gpu", "dep:axdisplay", "axruntime/display"] - -# Real Time Clock (RTC) Driver. -rtc = ["axhal/rtc", "axruntime/rtc"] - -# Device drivers -bus-mmio = ["axdriver?/bus-mmio"] -bus-pci = ["axdriver?/bus-pci"] -driver-ramdisk = ["axdriver?/ramdisk", "axfs?/use-ramdisk"] -driver-ixgbe = ["axdriver?/ixgbe"] -driver-bcm2835-sdhci = ["axdriver?/bcm2835-sdhci"] - -# Logging -log-level-off = ["axlog/log-level-off"] -log-level-error = ["axlog/log-level-error"] -log-level-warn = ["axlog/log-level-warn"] -log-level-info = ["axlog/log-level-info"] -log-level-debug = ["axlog/log-level-debug"] -log-level-trace = ["axlog/log-level-trace"] - -[dependencies] -axruntime = { workspace = true } -axhal = { workspace = true } -axlog = { workspace = true } -axalloc = { workspace = true, optional = true } -alt_axalloc = { workspace = true, optional = true } -axdriver = { workspace = true, optional = true } -axfs = { workspace = true, optional = true } -axnet = { workspace = true, optional = true } -axdisplay = { workspace = true, optional = true } -axsync = { workspace = true, optional = true } -axtask = { workspace = true, optional = true } -kspin = { version = "0.1", optional = true } diff --git a/arceos/api/axfeat/src/lib.rs b/arceos/api/axfeat/src/lib.rs deleted file mode 100644 index 85fc2abb2..000000000 --- a/arceos/api/axfeat/src/lib.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! Top-level feature selection for [ArceOS]. -//! -//! # Cargo Features -//! -//! - CPU -//! - `smp`: Enable SMP (symmetric multiprocessing) support. -//! - `fp_simd`: Enable floating point and SIMD support. -//! - Interrupts: -//! - `irq`: Enable interrupt handling support. -//! - Memory -//! - `alloc`: Enable dynamic memory allocation. -//! - `alloc-tlsf`: Use the TLSF allocator. -//! - `alloc-slab`: Use the slab allocator. -//! - `alloc-buddy`: Use the buddy system allocator. -//! - `paging`: Enable page table manipulation. -//! - `tls`: Enable thread-local storage. -//! - Task management -//! - `multitask`: Enable multi-threading support. -//! - `sched_fifo`: Use the FIFO cooperative scheduler. -//! - `sched_rr`: Use the Round-robin preemptive scheduler. -//! - `sched_cfs`: Use the Completely Fair Scheduler (CFS) preemptive scheduler. -//! - Upperlayer stacks (fs, net, display) -//! - `fs`: Enable file system support. -//! - `myfs`: Allow users to define their custom filesystems to override the default. -//! - `net`: Enable networking support. -//! - `display`: Enable graphics support. -//! - Device drivers -//! - `bus-mmio`: Use device tree to probe all MMIO devices. -//! - `bus-pci`: Use PCI bus to probe all PCI devices. -//! - `driver-ramdisk`: Use the RAM disk to emulate the block device. -//! - `driver-ixgbe`: Enable the Intel 82599 10Gbit NIC driver. -//! - `driver-bcm2835-sdhci`: Enable the BCM2835 SDHCI driver (Raspberry Pi SD card). -//! - Logging -//! - `log-level-off`: Disable all logging. -//! - `log-level-error`, `log-level-warn`, `log-level-info`, `log-level-debug`, -//! `log-level-trace`: Keep logging only at the specified level or higher. -//! -//! [ArceOS]: https://github.com/arceos-org/arceos - -#![no_std] diff --git a/arceos/axfs_ramfs/.cargo-ok b/arceos/axfs_ramfs/.cargo-ok deleted file mode 100644 index 5f8b79583..000000000 --- a/arceos/axfs_ramfs/.cargo-ok +++ /dev/null @@ -1 +0,0 @@ -{"v":1} \ No newline at end of file diff --git a/arceos/axfs_ramfs/.cargo_vcs_info.json b/arceos/axfs_ramfs/.cargo_vcs_info.json deleted file mode 100644 index ab8f240b7..000000000 --- a/arceos/axfs_ramfs/.cargo_vcs_info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "git": { - "sha1": "0b21a163b5fde021d7f5b96e57a46f0e1aa7a756" - }, - "path_in_vcs": "axfs_ramfs" -} \ No newline at end of file diff --git a/arceos/axfs_ramfs/Cargo.toml b/arceos/axfs_ramfs/Cargo.toml deleted file mode 100644 index bb42bd0b8..000000000 --- a/arceos/axfs_ramfs/Cargo.toml +++ /dev/null @@ -1,50 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -name = "axfs_ramfs" -version = "0.1.1" -authors = ["Yuekai Jia "] -build = false -autobins = false -autoexamples = false -autotests = false -autobenches = false -description = "RAM filesystem used by ArceOS" -homepage = "https://github.com/arceos-org/arceos" -documentation = "https://docs.rs/axfs_ramfs" -readme = "README.md" -keywords = [ - "arceos", - "filesystem", - "ramfs", -] -categories = [ - "os", - "no-std", - "filesystem", -] -license = "GPL-3.0-or-later OR Apache-2.0 OR MulanPSL-2.0" -repository = "https://github.com/arceos-org/axfs_crates" - -[lib] -name = "axfs_ramfs" -path = "src/lib.rs" - -[dependencies.axfs_vfs] -version = "0.1" - -[dependencies.log] -version = "0.4" - -[dependencies.spin] -version = "0.9" diff --git a/arceos/axfs_ramfs/Cargo.toml.orig b/arceos/axfs_ramfs/Cargo.toml.orig deleted file mode 100644 index 8cb1a5183..000000000 --- a/arceos/axfs_ramfs/Cargo.toml.orig +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "axfs_ramfs" -edition = "2021" -description = "RAM filesystem used by ArceOS" -documentation = "https://docs.rs/axfs_ramfs" -keywords = ["arceos", "filesystem", "ramfs"] -version.workspace = true -authors.workspace = true -license.workspace = true -homepage.workspace = true -repository.workspace = true -categories.workspace = true - -[dependencies] -axfs_vfs.workspace = true -spin = "0.9" -log = "0.4" diff --git a/arceos/axfs_ramfs/README.md b/arceos/axfs_ramfs/README.md deleted file mode 100644 index 792dca5e5..000000000 --- a/arceos/axfs_ramfs/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# axfs_crates - -[![CI](https://github.com/arceos-org/axfs_crates/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/arceos-org/axfs_crates/actions/workflows/ci.yml) - -Crates for building filesystems: - -* [axfs_vfs](https://github.com/arceos-org/axfs_crates/tree/main/axfs_vfs): Virtual filesystem interfaces. [![Crates.io](https://img.shields.io/crates/v/axfs_vfs)](https://crates.io/crates/axfs_vfs) -* [axfs_devfs](https://github.com/arceos-org/axfs_crates/tree/main/axfs_devfs): Device filesystem. [![Crates.io](https://img.shields.io/crates/v/axfs_devfs)](https://crates.io/crates/axfs_devfs) -* [axfs_ramfs](https://github.com/arceos-org/axfs_crates/tree/main/axfs_ramfs): RAM filesystem. [![Crates.io](https://img.shields.io/crates/v/axfs_ramfs)](https://crates.io/crates/axfs_ramfs) diff --git a/arceos/axfs_ramfs/src/dir.rs b/arceos/axfs_ramfs/src/dir.rs deleted file mode 100644 index b64707e84..000000000 --- a/arceos/axfs_ramfs/src/dir.rs +++ /dev/null @@ -1,176 +0,0 @@ -use alloc::collections::BTreeMap; -use alloc::sync::{Arc, Weak}; -use alloc::{string::String, vec::Vec}; - -use axfs_vfs::{VfsDirEntry, VfsNodeAttr, VfsNodeOps, VfsNodeRef, VfsNodeType}; -use axfs_vfs::{VfsError, VfsResult}; -use spin::RwLock; - -use crate::file::FileNode; - -/// The directory node in the RAM filesystem. -/// -/// It implements [`axfs_vfs::VfsNodeOps`]. -pub struct DirNode { - this: Weak, - parent: RwLock>, - children: RwLock>, -} - -impl DirNode { - pub(super) fn new(parent: Option>) -> Arc { - Arc::new_cyclic(|this| Self { - this: this.clone(), - parent: RwLock::new(parent.unwrap_or_else(|| Weak::::new())), - children: RwLock::new(BTreeMap::new()), - }) - } - - pub(super) fn set_parent(&self, parent: Option<&VfsNodeRef>) { - *self.parent.write() = parent.map_or(Weak::::new() as _, Arc::downgrade); - } - - /// Returns a string list of all entries in this directory. - pub fn get_entries(&self) -> Vec { - self.children.read().keys().cloned().collect() - } - - /// Checks whether a node with the given name exists in this directory. - pub fn exist(&self, name: &str) -> bool { - self.children.read().contains_key(name) - } - - /// Creates a new node with the given name and type in this directory. - pub fn create_node(&self, name: &str, ty: VfsNodeType) -> VfsResult { - if self.exist(name) { - log::error!("AlreadyExists {}", name); - return Err(VfsError::AlreadyExists); - } - let node: VfsNodeRef = match ty { - VfsNodeType::File => Arc::new(FileNode::new()), - VfsNodeType::Dir => Self::new(Some(self.this.clone())), - _ => return Err(VfsError::Unsupported), - }; - self.children.write().insert(name.into(), node); - Ok(()) - } - - /// Removes a node by the given name in this directory. - pub fn remove_node(&self, name: &str) -> VfsResult { - let mut children = self.children.write(); - let node = children.get(name).ok_or(VfsError::NotFound)?; - if let Some(dir) = node.as_any().downcast_ref::() { - if !dir.children.read().is_empty() { - return Err(VfsError::DirectoryNotEmpty); - } - } - children.remove(name); - Ok(()) - } -} - -impl VfsNodeOps for DirNode { - fn get_attr(&self) -> VfsResult { - Ok(VfsNodeAttr::new_dir(4096, 0)) - } - - fn parent(&self) -> Option { - self.parent.read().upgrade() - } - - fn lookup(self: Arc, path: &str) -> VfsResult { - let (name, rest) = split_path(path); - let node = match name { - "" | "." => Ok(self.clone() as VfsNodeRef), - ".." => self.parent().ok_or(VfsError::NotFound), - _ => self - .children - .read() - .get(name) - .cloned() - .ok_or(VfsError::NotFound), - }?; - - if let Some(rest) = rest { - node.lookup(rest) - } else { - Ok(node) - } - } - - fn read_dir(&self, start_idx: usize, dirents: &mut [VfsDirEntry]) -> VfsResult { - let children = self.children.read(); - let mut children = children.iter().skip(start_idx.max(2) - 2); - for (i, ent) in dirents.iter_mut().enumerate() { - match i + start_idx { - 0 => *ent = VfsDirEntry::new(".", VfsNodeType::Dir), - 1 => *ent = VfsDirEntry::new("..", VfsNodeType::Dir), - _ => { - if let Some((name, node)) = children.next() { - *ent = VfsDirEntry::new(name, node.get_attr().unwrap().file_type()); - } else { - return Ok(i); - } - } - } - } - Ok(dirents.len()) - } - - fn create(&self, path: &str, ty: VfsNodeType) -> VfsResult { - log::debug!("create {:?} at ramfs: {}", ty, path); - let (name, rest) = split_path(path); - if let Some(rest) = rest { - match name { - "" | "." => self.create(rest, ty), - ".." => self.parent().ok_or(VfsError::NotFound)?.create(rest, ty), - _ => { - let subdir = self - .children - .read() - .get(name) - .ok_or(VfsError::NotFound)? - .clone(); - subdir.create(rest, ty) - } - } - } else if name.is_empty() || name == "." || name == ".." { - Ok(()) // already exists - } else { - self.create_node(name, ty) - } - } - - fn remove(&self, path: &str) -> VfsResult { - log::debug!("remove at ramfs: {}", path); - let (name, rest) = split_path(path); - if let Some(rest) = rest { - match name { - "" | "." => self.remove(rest), - ".." => self.parent().ok_or(VfsError::NotFound)?.remove(rest), - _ => { - let subdir = self - .children - .read() - .get(name) - .ok_or(VfsError::NotFound)? - .clone(); - subdir.remove(rest) - } - } - } else if name.is_empty() || name == "." || name == ".." { - Err(VfsError::InvalidInput) // remove '.' or '.. - } else { - self.remove_node(name) - } - } - - axfs_vfs::impl_vfs_dir_default! {} -} - -fn split_path(path: &str) -> (&str, Option<&str>) { - let trimmed_path = path.trim_start_matches('/'); - trimmed_path.find('/').map_or((trimmed_path, None), |n| { - (&trimmed_path[..n], Some(&trimmed_path[n + 1..])) - }) -} diff --git a/arceos/axfs_ramfs/src/file.rs b/arceos/axfs_ramfs/src/file.rs deleted file mode 100644 index b378ee7cf..000000000 --- a/arceos/axfs_ramfs/src/file.rs +++ /dev/null @@ -1,56 +0,0 @@ -use alloc::vec::Vec; -use axfs_vfs::{impl_vfs_non_dir_default, VfsNodeAttr, VfsNodeOps, VfsResult}; -use spin::RwLock; - -/// The file node in the RAM filesystem. -/// -/// It implements [`axfs_vfs::VfsNodeOps`]. -pub struct FileNode { - content: RwLock>, -} - -impl FileNode { - pub(super) const fn new() -> Self { - Self { - content: RwLock::new(Vec::new()), - } - } -} - -impl VfsNodeOps for FileNode { - fn get_attr(&self) -> VfsResult { - Ok(VfsNodeAttr::new_file(self.content.read().len() as _, 0)) - } - - fn truncate(&self, size: u64) -> VfsResult { - let mut content = self.content.write(); - if size < content.len() as u64 { - content.truncate(size as _); - } else { - content.resize(size as _, 0); - } - Ok(()) - } - - fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { - let content = self.content.read(); - let start = content.len().min(offset as usize); - let end = content.len().min(offset as usize + buf.len()); - let src = &content[start..end]; - buf[..src.len()].copy_from_slice(src); - Ok(src.len()) - } - - fn write_at(&self, offset: u64, buf: &[u8]) -> VfsResult { - let offset = offset as usize; - let mut content = self.content.write(); - if offset + buf.len() > content.len() { - content.resize(offset + buf.len(), 0); - } - let dst = &mut content[offset..offset + buf.len()]; - dst.copy_from_slice(&buf[..dst.len()]); - Ok(buf.len()) - } - - impl_vfs_non_dir_default! {} -} diff --git a/arceos/axfs_ramfs/src/lib.rs b/arceos/axfs_ramfs/src/lib.rs deleted file mode 100644 index 44bc1f3e9..000000000 --- a/arceos/axfs_ramfs/src/lib.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! RAM filesystem used by [ArceOS](https://github.com/arceos-org/arceos). -//! -//! The implementation is based on [`axfs_vfs`]. - -#![cfg_attr(not(test), no_std)] - -extern crate alloc; - -mod dir; -mod file; - -#[cfg(test)] -mod tests; - -pub use self::dir::DirNode; -pub use self::file::FileNode; - -use alloc::sync::Arc; -use axfs_vfs::{VfsNodeRef, VfsOps, VfsResult}; -use spin::once::Once; - -/// A RAM filesystem that implements [`axfs_vfs::VfsOps`]. -pub struct RamFileSystem { - parent: Once, - root: Arc, -} - -impl RamFileSystem { - /// Create a new instance. - pub fn new() -> Self { - Self { - parent: Once::new(), - root: DirNode::new(None), - } - } - - /// Returns the root directory node in [`Arc`](DirNode). - pub fn root_dir_node(&self) -> Arc { - self.root.clone() - } -} - -impl VfsOps for RamFileSystem { - fn mount(&self, _path: &str, mount_point: VfsNodeRef) -> VfsResult { - if let Some(parent) = mount_point.parent() { - self.root.set_parent(Some(self.parent.call_once(|| parent))); - } else { - self.root.set_parent(None); - } - Ok(()) - } - - fn root_dir(&self) -> VfsNodeRef { - self.root.clone() - } -} - -impl Default for RamFileSystem { - fn default() -> Self { - Self::new() - } -} diff --git a/arceos/axfs_ramfs/src/tests.rs b/arceos/axfs_ramfs/src/tests.rs deleted file mode 100644 index fda7001d5..000000000 --- a/arceos/axfs_ramfs/src/tests.rs +++ /dev/null @@ -1,136 +0,0 @@ -use std::sync::Arc; - -use axfs_vfs::{VfsError, VfsNodeType, VfsResult}; - -use crate::*; - -fn test_ramfs_ops(devfs: &RamFileSystem) -> VfsResult { - const N: usize = 32; - const N_HALF: usize = N / 2; - let mut buf = [1; N]; - - let root = devfs.root_dir(); - assert!(root.get_attr()?.is_dir()); - assert_eq!(root.get_attr()?.file_type(), VfsNodeType::Dir); - assert_eq!( - root.clone().lookup("urandom").err(), - Some(VfsError::NotFound) - ); - assert_eq!( - root.clone().lookup("f1/").err(), - Some(VfsError::NotADirectory) - ); - - let node = root.lookup("////f1")?; - assert_eq!(node.get_attr()?.file_type(), VfsNodeType::File); - assert!(!node.get_attr()?.is_dir()); - assert_eq!(node.get_attr()?.size(), 0); - assert_eq!(node.read_at(0, &mut buf)?, 0); - assert_eq!(buf, [1; N]); - - assert_eq!(node.write_at(N_HALF as _, &buf[..N_HALF])?, N_HALF); - assert_eq!(node.read_at(0, &mut buf)?, N); - assert_eq!(buf[..N_HALF], [0; N_HALF]); - assert_eq!(buf[N_HALF..], [1; N_HALF]); - assert_eq!(node.lookup("/").err(), Some(VfsError::NotADirectory)); - - let foo = devfs.root_dir().lookup(".///.//././/.////foo")?; - assert!(foo.get_attr()?.is_dir()); - assert_eq!( - foo.read_at(10, &mut buf).err(), - Some(VfsError::IsADirectory) - ); - assert!(Arc::ptr_eq( - &foo.clone().lookup("/f3")?, - &devfs.root_dir().lookup(".//./foo///f3")?, - )); - assert_eq!( - foo.clone().lookup("/bar//f4")?.get_attr()?.file_type(), - VfsNodeType::File - ); - assert_eq!( - foo.lookup("/bar///")?.get_attr()?.file_type(), - VfsNodeType::Dir - ); - - Ok(()) -} - -fn test_get_parent(devfs: &RamFileSystem) -> VfsResult { - let root = devfs.root_dir(); - assert!(root.parent().is_none()); - - let node = root.clone().lookup("f1")?; - assert!(node.parent().is_none()); - - let node = root.clone().lookup(".//foo/bar")?; - assert!(node.parent().is_some()); - let parent = node.parent().unwrap(); - assert!(Arc::ptr_eq(&parent, &root.clone().lookup("foo")?)); - assert!(parent.lookup("bar").is_ok()); - - let node = root.clone().lookup("foo/..")?; - assert!(Arc::ptr_eq(&node, &root.clone().lookup(".")?)); - - assert!(Arc::ptr_eq( - &root.clone().lookup("/foo/..")?, - &devfs.root_dir().lookup(".//./foo/././bar/../..")?, - )); - assert!(Arc::ptr_eq( - &root.clone().lookup("././/foo//./../foo//bar///..//././")?, - &devfs.root_dir().lookup(".//./foo/")?, - )); - assert!(Arc::ptr_eq( - &root.clone().lookup("///foo//bar///../f3")?, - &root.lookup("foo/.//f3")?, - )); - - Ok(()) -} - -#[test] -fn test_ramfs() { - // . - // ├── foo - // │   ├── bar - // │   │   └── f4 - // │   └── f3 - // ├── f1 - // └── f2 - - let ramfs = RamFileSystem::new(); - let root = ramfs.root_dir(); - root.create("f1", VfsNodeType::File).unwrap(); - root.create("f2", VfsNodeType::File).unwrap(); - root.create("foo", VfsNodeType::Dir).unwrap(); - - let dir_foo = root.lookup("foo").unwrap(); - dir_foo.create("f3", VfsNodeType::File).unwrap(); - dir_foo.create("bar", VfsNodeType::Dir).unwrap(); - - let dir_bar = dir_foo.lookup("bar").unwrap(); - dir_bar.create("f4", VfsNodeType::File).unwrap(); - - let mut entries = ramfs.root_dir_node().get_entries(); - entries.sort(); - assert_eq!(entries, ["f1", "f2", "foo"]); - - test_ramfs_ops(&ramfs).unwrap(); - test_get_parent(&ramfs).unwrap(); - - let root = ramfs.root_dir(); - assert_eq!(root.remove("f1"), Ok(())); - assert_eq!(root.remove("//f2"), Ok(())); - assert_eq!(root.remove("f3").err(), Some(VfsError::NotFound)); - assert_eq!(root.remove("foo").err(), Some(VfsError::DirectoryNotEmpty)); - assert_eq!(root.remove("foo/..").err(), Some(VfsError::InvalidInput)); - assert_eq!( - root.remove("foo/./bar").err(), - Some(VfsError::DirectoryNotEmpty) - ); - assert_eq!(root.remove("foo/bar/f4"), Ok(())); - assert_eq!(root.remove("foo/bar"), Ok(())); - assert_eq!(root.remove("./foo//.//f3"), Ok(())); - assert_eq!(root.remove("./foo"), Ok(())); - assert!(ramfs.root_dir_node().get_entries().is_empty()); -} diff --git a/arceos/doc/README.md b/arceos/doc/README.md deleted file mode 100644 index b3f7d2d5b..000000000 --- a/arceos/doc/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# ArceOS Architecture Overview - -The key design principle of ArceOS is to divide components based on their **relevance to the OS design concept**, in order to reduce component coupling and improving reusability. - -## Crates - -Crates are **OS-agnostic** components that can be reused in other OS or system software projects with almost no modification, providing the most reusability. For example, the basic data structures, algorithms, and utilities. - -See [arceos-crates](https://github.com/arceos-org/arceos-crates) for crates used by ArceOS. - -## Modules - -Modules are **OS-related** components that are tightly bound to the design principles of a specific OS and have relatively poor reusability. It may need to be redesigned when it is ported to another OS. - -Most of the modules are optional, depending on the features enabled by the application. A few modules are required by all applications, as shown below: - -* [axruntime](modules/axruntime/): Bootstrapping from the bare-metal environment, and initialization. -* [axhal](modules/axhal/): Hardware abstraction layer, provides unified APIs for cross-platform. -* [axconfig](modules/axconfig/): Platform constants and kernel parameters, such as physical memory base, kernel load addresses, stack size, etc. -* [axlog](modules/axlog/): Multi-level formatted logging. - -Other optional modules and their corresponding features are as follows: - -| Modules | Dependent features | Description | -|-|-|-| -| [axalloc](../modules/axalloc) | alloc | ArceOS global memory allocator. | -| [axdisplay](../modules/axdisplay) | display | ArceOS graphics module. | -| [axfs](../modules/axfs) | fs | ArceOS filesystem module. | -| [axnet](../modules/axnet) | net | ArceOS network module. | -| [axdriver](../modules/axdriver) | driver-*, fs, net, display | ArceOS device drivers. | -| [axtask](../modules/axtask) | multitask | ArceOS task management module. | -| [axsync](../modules/axsync) | multitask | ArceOS synchronization primitives. | - -See [arceos-apps](https://github.com/arceos-org/arceos-apps) for example applications and their required modules and features. - -## Rustdoc - -Documentation of ArceOS [modules](../modules), [api](../api), and [ulib](../ulib) are generated by [`rustdoc`](https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html) and hosted on GitHub Pages: - -* https://arceos-org.github.io/arceos/ diff --git a/arceos/doc/build.md b/arceos/doc/build.md deleted file mode 100644 index 8cc302a65..000000000 --- a/arceos/doc/build.md +++ /dev/null @@ -1,91 +0,0 @@ -# ArceOS Build Flow - -We will provide an example to illustrate the process of building and running ArceOS: - -**Examples:** - -What happens when "make A=apps/net/httpserver ARCH=aarch64 LOG=info NET=y SMP=1 run" is executed? - -- How ArceOS build? - - Firstly check Makefile: Based on different parameters, select whether FS/NET/GRAPHIC param is yes or not. If it is y, it will be compiled in conditional compilation. - - `cargo.mk` determines whether to add the corresponding feature based on whether FS/NET/GRAPHIC is set to y. - ``` - features-$(FS) += libax/fs - features-$(NET) += libax/net - features-$(GRAPHIC) += libax/display - ``` - - - `_cargo_build`: The `_cargo_build` method is defined in cargo.mk. Different compilation methods are selected based on the language. For example, for Rust, when `cargo_build,--manifest-path $(APP)/Cargo.toml` is called, where $(APP) represents the current application to be run. - - Taking httpserver as an example, let's see how ArceOS are conditionally compiled. First, in the `Cargo.toml` file of httpserver, the dependency is specified as: `libax = { path = "../../../ulib/libax", features = ["paging", "multitask", "net"] }`. This indicates that libax needs to be compiled and has the three features mentioned above. - - After checking libax, the following three features were found: - - `paging = ["axruntime/paging"]` - - `multitask = ["axruntime/multitask", "axtask/multitask", "axsync/multitask"]` - - `net = ["axruntime/net", "dep:axnet"]` - - This involves modules such as axruntime, axtask, axsync, etc., and conditional compilation is performed on these modules. - - The above are some modules required for compilation, next we will look at how to perform conditional compilation. The `cargo.mk` file describes how to use the cargo method for conditional compilation, with the following build parameters: - ``` - build_args := \ - -Zbuild-std=core,alloc -Zbuild-std-features=compiler-builtins-mem \ - --config "build.rustflags='-Clink-arg=-T$(LD_SCRIPT)'" \ - --target $(TARGET) \ - --target-dir $(CURDIR)/target \ - --features "$(features-y)" \ - ``` - Note that the -Zbuild-std option is mentioned here, indicating the replacement of the standard library for the application and the use of libraries provided by ArceOS. - - - Therefore, to summarize: choose conditions in Makefile and select the corresponding app directory for conditional compilation in `cargo.mk`. -- Next, describe how ArceOS run: - - Firstly, examining the Makefile reveals that in addition to building, running an application also requires `justrun`. - - Following this, it was found that the `qemu.mk` file would call run_qemu. Similar to the build process, the execution process would also use conditional selection and run. - - At runtime, Arceos first performs some boot operations, such as executing in the riscv64 environment: - ```rust - #[naked] - #[no_mangle] - #[link_section = ".text.boot"] - unsafe extern "C" fn _start() -> ! { - extern "C" { - fn rust_main(); - } - // PC = 0x8020_0000 - // a0 = hartid - // a1 = dtb - core::arch::asm!(" - mv s0, a0 // save hartid - mv s1, a1 // save DTB pointer - la sp, {boot_stack} - li t0, {boot_stack_size} - add sp, sp, t0 // setup boot stack - - call {init_boot_page_table} - call {init_mmu} // setup boot page table and enabel MMU - - li s2, {phys_virt_offset} // fix up virtual high address - add sp, sp, s2 - - mv a0, s0 - mv a1, s1 - la a2, {platform_init} - add a2, a2, s2 - jalr a2 // call platform_init(hartid, dtb) - - mv a0, s0 - mv a1, s1 - la a2, {rust_main} - add a2, a2, s2 - jalr a2 // call rust_main(hartid, dtb) - j .", - phys_virt_offset = const PHYS_VIRT_OFFSET, - boot_stack_size = const TASK_STACK_SIZE, - boot_stack = sym BOOT_STACK, - init_boot_page_table = sym init_boot_page_table, - init_mmu = sym init_mmu, - platform_init = sym super::platform_init, - rust_main = sym rust_main, - options(noreturn), - ) - } - ``` - - Later, it jumps to `rust_main` in `axruntime` to run. After some conditional initialization, `rust_main` executes `main()`. Since this main is defined by the application, symbol linkage should be established and jumped to (no context switch is needed since it's a single address space). - - - Then, the user program begins executing through `libax`'s API. The application runs in kernel mode, without the need for syscall and context switching, resulting in higher efficiency. diff --git a/arceos/doc/figures/ArceOS.svg b/arceos/doc/figures/ArceOS.svg deleted file mode 100644 index a5d2b1c64..000000000 --- a/arceos/doc/figures/ArceOS.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - -
ArceOS modules
ArceOS modules
ArceOS crates
ArceOS crates
User Apps
User Apps
Hypervisor
Hypervisor
axnet
axnet
axtask
axtask
axconfig
axconfig
axruntime
axruntime
axhal
axhal
axdriver
axdriver
allocator
allocator
axalloc
axalloc
scheduler
scheduler
page_table
page_table
linked_list
linked_list
driver_blk
driver_blk
axasync
axasync
smoltcp
smoltcp
buddy
buddy
slab
slab
FIFO
FIFO
CFS
CFS
ixgbe
ixgbe
lwip_rust
lwip_rust
driver_virtio
driver_virtio
driver_net
driver_net
axfs
axfs
page_table_entry
page_table_entry
ArceOS API
ArceOS API
arceos_posix_api
arceos_posix_api
arceos_rust_api
arceos_rust_api
ArceOS ulib
ArceOS ulib
axstd
axstd
axlibc
axlibc
rust std
rust std
Rust App
Rust App
C App
C App
Rust std App
Rust std App
C App
C App
musl libc
musl libc
axfeat
axfeat
feature selection
feature selection
Text is not SVG - cannot display
\ No newline at end of file diff --git a/arceos/doc/figures/draw_jtag_connected.jpg b/arceos/doc/figures/draw_jtag_connected.jpg deleted file mode 100644 index 0a3e0db2f..000000000 Binary files a/arceos/doc/figures/draw_jtag_connected.jpg and /dev/null differ diff --git a/arceos/doc/figures/image_jtag_connected.jpg b/arceos/doc/figures/image_jtag_connected.jpg deleted file mode 100644 index 43075cee8..000000000 Binary files a/arceos/doc/figures/image_jtag_connected.jpg and /dev/null differ diff --git a/arceos/doc/grub_boot.md b/arceos/doc/grub_boot.md deleted file mode 100644 index 1809344c3..000000000 --- a/arceos/doc/grub_boot.md +++ /dev/null @@ -1,50 +0,0 @@ -# Boot ArceOS on the x86 PC with GRUB - -## 1. Build ArceOS and generate the kernel image - -Assume the application is located at `path/to/awesomeapp`, and the target platform is `x86_64-pc-oslab` (the configuration file is located at [platforms/x86_64-pc-oslab.toml](../platforms/x86_64-pc-oslab.toml)): - -```shell -make A=path/to/awesomeapp ARCH=x86_64 PLATFORM=x86_64-pc-oslab -``` - -The ELF format kernel image will be generated at `path/to/awesomeapp/awesomeapp-x86_64-pc-oslab.elf`. - -## 2. Copy the kernel image to the `/boot` directory on the target machine - -```shell -sudo cp path/to/awesomeapp/awesomeapp-x86_64-pc-oslab.elf /boot -``` - -## 3. Add boot entry to GRUB - -Append the following lines to the `/etc/grub.d/40_custom` file on the target machine: - -```shell -submenu 'Boot ArceOS with multiboot' { - menuentry 'Boot ArceOS awesomeapp' { - echo 'ArceOS awesomeapp is booting...' - multiboot /boot/awesomeapp-x86_64-pc-oslab.elf - } -} -``` - -## 4. Update GRUB configuration and reboot the machine - -```shell -sudo update-grub2 -sudo reboot -``` - -After rebooting, select the corresponding entry in the GRUB menu to boot ArceOS. - -## 5. View the console output - -ArceOS will print the log via the serial port. -You need to use a [USB-to-serial adapter](https://en.wikipedia.org/wiki/USB-to-serial_adapter) to connect the serial port of the target machine to another machine. -After that, a character device file will be created on that machine, such as `/dev/ttyUSB0`. -Then you can use the `screen` command to view the output and send commands to ArceOS: - -```shell -screen /dev/ttyUSB0 115200 -``` diff --git a/arceos/doc/ixgbe.md b/arceos/doc/ixgbe.md deleted file mode 100644 index ac93e3e9a..000000000 --- a/arceos/doc/ixgbe.md +++ /dev/null @@ -1,49 +0,0 @@ -# How to run arceos with ixgbe NIC? - -You need to specify the platform that owns this network card. For example, we defined a toml file named `x86_64-pc-oslab`` under the platforms directory to describe the platform characteristics. - -You can use the following command to compile an 'httpserver' app application: - -```shell -make A=apps/net/httpserver PLATFORM=x86_64-pc-oslab FEATURES=driver-ixgbe -``` - -You can also use the following command to start the iperf application: - -```shell -make A=apps/c/iperf PLATFORM=x86_64-pc-oslab FEATURES=driver-ixgbe,driver-ramdisk -``` - -## Use ixgbe NIC in QEMU with PCI passthrough - -1. Install the `vfio-pci` driver in the host: - - ```shell - sudo modprobe vfio-pci - ``` - -2. Bind the NIC to the `vfio-pci` driver (assume the PCI address is `02:00.0`): - - ```shell - sudo ./scripts/net/pci-bind.sh vfio-pci 02:00.0 - # Equivalent to: - # echo 0000:02:00.0 > /sys/bus/pci/drivers/ixgbe/unbind - # echo vfio-pci > /sys/bus/pci/devices/0000:02:00.0/driver_override - # echo 0000:02:00.0 > /sys/bus/pci/drivers/vfio-pci/bind - ``` - -3. Build and run ArceOS: - - ```shell - make A=apps/net/httpserver FEATURES=driver-ixgbe VFIO_PCI=02:00.0 IP=x.x.x.x GW=x.x.x.x run - ``` - -4. If no longer in use, bind the NIC back to the `ixgbe` driver: - - ```shell - sudo ./scripts/net/pci-bind.sh ixgbe 02:00.0 - # Equivalent to: - # echo 0000:02:00.0 > /sys/bus/pci/drivers/vfio-pci/unbind - # echo ixgbe > /sys/bus/pci/devices/0000:02:00.0/driver_override - # echo 0000:02:00.0 > /sys/bus/pci/drivers/ixgbe/bind - ``` diff --git a/arceos/doc/jtag_debug_in_raspi4.md b/arceos/doc/jtag_debug_in_raspi4.md deleted file mode 100644 index f732a59b1..000000000 --- a/arceos/doc/jtag_debug_in_raspi4.md +++ /dev/null @@ -1,276 +0,0 @@ -# Introduction - -This article describes a way to debug jtags via openocd, gdb, jlink debugger. - -## Requirement - -### Resources - -1. Authors using [H-JLINK v9 type c Universal ARM Downloader](https://m.tb.cn/h.5FpduM7jUbbFlzo?tk=Z6t5WlsfPtl), -but theoretically, you can use whatever you want. - -2. [Serial USB to TTL CH340 Module](https://www.amazon.com/HiLetgo-Module-Microcontroller-Download-Serial/dp/B00LZV1G6K/ref=sr_1_3?dib=eyJ2IjoiMSJ9.EVDg6VSjpenXHkAOIddkejC8NrNLBaiI9YKosxxcvxsvWHCkJuYWT97oslmx7iE-il7I7ilkI07pfXYrJnjb0-gM8hu4y8_hMEVA7hiUtPZtjhovoAeF0-L7rM0xTe-hdNscYjbIspct3yjOtYSF9QPNFmr9XmeC5Os2gCQxZihglIJJDxUWWAhJL_MNl06dDKZnk82pkR_p09laqdfg0nFMwJwdxLDObHv3gzDHWNk.pvOBDJ9aVLFwecXlCYuMONK54Z_7sxnzAvdO71qkHWI&dib_tag=se&keywords=CH340&qid=1709218438&sr=8-3) - -3. Some Female to Female [Dupont Wire](https://www.amazon.com/Elegoo-EL-CP-004-Multicolored-Breadboard-arduino/dp/B01EV70C78/ref=sr_1_3?dib=eyJ2IjoiMSJ9.OCLDs3D5By4QvSSJfVxcRa7LFdoHpv56YLqS9wbJRIGaY_r5UKFkopHdBRu0aVmyYfSaH77oX0ure59RTu2R0GWeOUm8DEzRUHiLTYnKqPa02peSrC0JWZMUQPaErE40BeYQpDl0ywu9vg7zI1gHJWxdYtOgrehyUhiT9G9657pN73jvrY3Vd5RrBH9-5aAYEDKpN_P1gS48Yqv9n7S3efD7AKdAsgYsLsN1QLBFeyI.VxVp4ZfND0S73SSXYiJlh6KJD8GRdD2Pn2LHUrCHSj4&dib_tag=se&keywords=DuPont+line&qid=1709218493&sr=8-3) - -4. A laptop - -### Preliminary preparation - -1. Connect CH304 from [bcm2711 pin 8,10,12](https://datasheets.raspberrypi.com/rpi4/raspberry-pi-4-reduced-schematics.pdf) (Rx to Tx, Tx to Rx, GND to GND). - By the ways, power indicator closest to 1. - -2. Connect H-JLINK based on the picture below: - -![connect_jtag_debugger](./figures/image_jtag_connected.jpg) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GPIO # Name JTAG # Note Diagram
VTREF1to 3.3V
GND4to GND
22TRST3
26TDI5
27TMS7
25TCK9
23RTCK11
24TDO13
-

-*thanks for andre-richter provide this sections.* - -3. Try to test whether chainboot works properly - 1. go to tools/raspi4/chainloader - 2. run `make clean && make`, it should generate a kernel8.img under this directory. - if everything right, the image file should be 8576 via `ls -al`. - 3. move this image into your sd card. - 4. check if your sd card has contians following file - [start4.elf](https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/start4.elf), - [fixup4.dat](https://github.com/raspberrypi/firmware/raw/master/boot/fixup4.dat), - [bcm2711-rpi-4-b.dtb](https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/bcm2711-rpi-4-b.dtb) - 5. just run `make A=apps/helloworld PLATFORM=aarch64-raspi4 chainboot`, then should display this image. - - - - - - - - - - - - - - - - - - -
Minipush 1.0





[MP] ⏳ Waiting for /dev/ttyUSB0
[MP] ✅ Serial connected


[MP]  Please power the target now
This means that CH340 is not connected or connected in some other wayconnection is successful
maybe /dev/ttyUSB1 or something else
- - After power up the board: - - ``` - - __ __ _ _ _ _ - | \/ (_)_ _ (_) | ___ __ _ __| | - | |\/| | | ' \| | |__/ _ \/ _` / _` | - |_| |_|_|_||_|_|____\___/\__,_\__,_| - - Raspberry Pi 4 - - [ML] Requesting binary - [MP] ⏩ Pushing 36 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 - [ML] Loaded! Executing the payload now - - @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - @ You're using chainboot image . @ - @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - - d8888 .d88888b. .d8888b. - d88888 d88P" "Y88b d88P Y88b - d88P888 888 888 Y88b. - d88P 888 888d888 .d8888b .d88b. 888 888 "Y888b. - d88P 888 888P" d88P" d8P Y8b 888 888 "Y88b. - d88P 888 888 888 88888888 888 888 "888 - d8888888888 888 Y88b. Y8b. Y88b. .d88P Y88b d88P - d88P 888 888 "Y8888P "Y8888 "Y88888P" "Y8888P" - - arch = aarch64 - platform = aarch64-raspi4 - target = aarch64-unknown-none-softfloat - smp = 1 - build_mode = release - log_level = warn - - Hello, world! - ``` - -## Run - -### Preliminary preparation - - 1. go to tools/raspi4/chainloader - 2. run `make clean && make JTAG=y`, it should generate a kernel8.img under this directory. - if everything right, the image file should be 8576 via `ls -al`. - 3. move this image into your sd card. - 4. check if your sd card has contians following file - [start4.elf](https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/start4.elf), - [fixup4.dat](https://github.com/raspberrypi/firmware/raw/master/boot/fixup4.dat), - [bcm2711-rpi-4-b.dtb](https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/bcm2711-rpi-4-b.dtb) - -### Start Debugging - - 1. just run `make A=apps/helloworld PLATFORM=aarch64-raspi4 chainboot` and Power up the board., then should display this image. - - ``` - Minipush 1.0 - - [MP] ✅ Serial connected - [MP] 🔌 Please power the target now - - __ __ _ _ _ _ - | \/ (_)_ _ (_) | ___ __ _ __| | - | |\/| | | ' \| | |__/ _ \/ _` / _` | - |_| |_|_|_||_|_|____\___/\__,_\__,_| - - Raspberry Pi 4 - - [ML] Requesting binary - [MP] ⏩ Pushing 36 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 - [ML] Loaded! Executing the payload now - - @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - @ You're using a JTAG debug image. @ - @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - @ 1. open openocd, gdb @ - @ 2. target extended-remote :3333; @ - @ 3. set $pc=0x80000 @ - @ 4. break rust_entry/others @ - @ 5. break $previous_addr @ - @ 6. delete 1 @ - @ 7. load @ - @ 8. continue @ - @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - - ``` - - *the following guidelines is basically like previous datasheets, In fact, if you're a senior developer, skip the following. XD* - 3. My personal suggestions is using zellij, but you could choice what ever you want. - 4. A: Keeping this miniload running (just don't terminate it) in terminal A. - 5. B: run `make A=apps/helloworld PLATFORM=aarch64-raspi4 openocd`, - the windows should display following, but it doesn't matter, we don't need to care about this. - - ``` - $ make A=apps/helloworld PLATFORM=aarch64-raspi4 openocd - - Launching OpenOCD - [sudo] password for jacky: - Open On-Chip Debugger 0.11.0+dev-g1ad6ed3 (2021-12-02-20:10) - Licensed under GNU GPL v2 - For bug reports, read - http://openocd.org/doc/doxygen/bugs.html - DEPRECATED! use 'adapter speed' not 'adapter_khz' - Warn : DEPRECATED! use '-baseaddr' not '-ctibase' - Warn : DEPRECATED! use '-baseaddr' not '-ctibase' - Warn : DEPRECATED! use '-baseaddr' not '-ctibase' - Warn : DEPRECATED! use '-baseaddr' not '-ctibase' - Info : Listening on port 6666 for tcl connections - Info : Listening on port 4444 for telnet connections - Info : J-Link V9 compiled May 7 2021 16:26:12 - Info : Hardware version: 9.60 - Info : VTarget = 3.311 V - Info : clock speed 1000 kHz - Info : JTAG tap: rpi4.tap tap/device found: 0x4ba00477 (mfg: 0x23b (ARM Ltd), part: 0xba00, ver: 0x4) - Info : rpi4.core0: hardware has 6 breakpoints, 4 watchpoints - Info : rpi4.core1: hardware has 6 breakpoints, 4 watchpoints - Info : rpi4.core2: hardware has 6 breakpoints, 4 watchpoints - Info : rpi4.core3: hardware has 6 breakpoints, 4 watchpoints - Info : starting gdb server for rpi4.core0 on 3333 - Info : Listening on port 3333 for gdb connections - Info : starting gdb server for rpi4.core1 on 3334 - Info : Listening on port 3334 for gdb connections - Info : starting gdb server for rpi4.core2 on 3335 - Info : Listening on port 3335 for gdb connections - Info : starting gdb server for rpi4.core3 on 3336 - Info : Listening on port 3336 for gdb connections - - ``` - - 6. C: run `make A=apps/helloworld PLATFORM=aarch64-raspi4 gdb` in terminal C. - 7. You are now in GDB, but just don't start your debug immediately. - Because the use of minipush script, we could simple push our image to board before power up the board. - Like a double-edged sword. It also constrains our behavior, - which it's incapable for us to power up the board then use some kinds like halt command to halt the CPU. - (I think it can be done through script modification, but now there is no time to study and change ruby for a trivial upgrade.) - So we add a dead loop at the end of the image we generate lastest. - - ```gdb - (gdb) target extended-remote :3333 // connect to openocd gdb serve - // you should see $pc=0x2080db4 - (gdb) set $pc=0x80000 // The following behavior is unnecessary and can be debugged normally. - (gdb) monitor poll // MMU disable - (gdb) break rust_entry // Start debug module/axhal/ ... the location is VADDR will case error, - // you should use b *0x81a90 (manally remove 0xffff ... from output) - (gdb) b *0x81a90 - (gdb) break rust_main // as previous - (gdb) b *0x82888 - (gdb) delete 1 3 - (gdb) continue // first stop at rust_entry - (gdb) continue // second stop at rust_main - (gdb) monitor poll // MMU enable (in rust_entry) - ``` - -## Reference - -1. [rust-embedded/rust-raspberrypi-OS-tutorials](https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials) -2. [Raspberry Pi 4をJTAGデバッグしてみる(FTDI C232HM-DDHSL-0使用)](https://hikalium.hatenablog.jp/entry/2021/07/18/214013) -3. [Rust Raspberry Pi OS tutorials 08 HW debug JTAG by hikalium 2021-09-20](https://www.youtube.com/watch?v=6ULvzK1Drgo&t=21s) -4. [my record](https://bitbucket.org/jackyliu16/blog/src/master/content/jtag-load-failure-debug.cn.md) -4. openocd docs, bcm2711 docs, gdb docs ... etc. - - diff --git a/arceos/doc/platform_raspi4.md b/arceos/doc/platform_raspi4.md deleted file mode 100644 index 88f1a8166..000000000 --- a/arceos/doc/platform_raspi4.md +++ /dev/null @@ -1,28 +0,0 @@ -# How to run ArceOS on raspi4 - -Recommand you download this tutorial first: - -https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials - -And follow this tutorial to run the 06_uart_chainloader chapter. -It will help you to connect your raspi4 to your computer and it will also teach you how to use `make chainboot` to run your code on raspi4. - -Then run with features `ARCH=aarch64 PLATFORM = raspi4-aarch64` and use the command `make chainboot` to transmit the xxxx_raspi4-aarch64.bin to your raspi4. - -# How to debug ArceOS on raspi4 - -Recommand you download this tutorial first: - -https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials - -And follow this tutorial to run the 08_hw_debug_JTAG chapter. -It will help you to connect your raspi4 to the JTAG and connect your JTAG to your computer and it will also teach you how to use `make jtagboot` to debug your raspi4. - -Because the JTAG only support the first line of code be loaded at `0x80000` and only support single core, so you have to -1. Change the file: /modules/axconfig/src/platform/raspi4_aarch64, replace the "kernel-base-vaddr" with "0x8_0000" and replace the "phys-virt-offset" with "0x0" -2. set the feature `SMP=1` - -Then run with features `ARCH=aarch64 PLATFORM = raspi4-aarch64` and -1. use the command `make jtagboot` to run a halt program on your raspi4 -2. start a new terminal, and run `make openocd` to connect your PC with the JTAG -3. start a new terminal, and run `make gdb` to start a gdb, and type `target remote :3333` to connect with your openocd, and type `load` to load the xxxx_raspi4-aarch64.bin to your raspi4 and start to debug. diff --git a/arceos/examples/helloworld-c/main.c b/arceos/examples/helloworld-c/main.c deleted file mode 100644 index 0e5e7a80f..000000000 --- a/arceos/examples/helloworld-c/main.c +++ /dev/null @@ -1,7 +0,0 @@ -#include - -int main() -{ - printf("Hello, %c app!\n", 'C'); - return 0; -} diff --git a/arceos/examples/helloworld/Cargo.toml b/arceos/examples/helloworld/Cargo.toml deleted file mode 100644 index 67f5f358e..000000000 --- a/arceos/examples/helloworld/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "arceos-helloworld" -version = "0.1.0" -edition = "2021" -authors = ["Yuekai Jia "] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -axstd = { workspace = true, optional = true } diff --git a/arceos/examples/helloworld/src/main.rs b/arceos/examples/helloworld/src/main.rs deleted file mode 100644 index 97161c866..000000000 --- a/arceos/examples/helloworld/src/main.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[cfg(feature = "axstd")] -use axstd::println; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - println!("Hello, world!"); -} diff --git a/arceos/examples/httpclient-c/axbuild.mk b/arceos/examples/httpclient-c/axbuild.mk deleted file mode 100644 index 633789c4b..000000000 --- a/arceos/examples/httpclient-c/axbuild.mk +++ /dev/null @@ -1 +0,0 @@ -app-objs := httpclient.o diff --git a/arceos/examples/httpclient-c/features.txt b/arceos/examples/httpclient-c/features.txt deleted file mode 100644 index 25ca64f38..000000000 --- a/arceos/examples/httpclient-c/features.txt +++ /dev/null @@ -1,3 +0,0 @@ -alloc -paging -net diff --git a/arceos/examples/httpclient-c/httpclient.c b/arceos/examples/httpclient-c/httpclient.c deleted file mode 100644 index 32ec77b58..000000000 --- a/arceos/examples/httpclient-c/httpclient.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include -#include -#include -#include - -const char request[] = "\ -GET / HTTP/1.1\r\n\ -Host: ident.me\r\n\ -Accept: */*\r\n\ -\r\n"; - -int main() -{ - puts("Hello, ArceOS C HTTP client!"); - int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock == -1) { - perror("socket() error"); - return -1; - } - struct addrinfo *res; - - if (getaddrinfo("ident.me", NULL, NULL, &res) != 0) { - perror("getaddrinfo() error"); - return -1; - } - char str[INET_ADDRSTRLEN]; - if (inet_ntop(AF_INET, &(((struct sockaddr_in *)(res->ai_addr))->sin_addr), str, - INET_ADDRSTRLEN) == NULL) { - perror("inet_ntop() error"); - return -1; - } - printf("IP: %s\n", str); - ((struct sockaddr_in *)(res->ai_addr))->sin_port = htons(80); - if (connect(sock, res->ai_addr, sizeof(*(res->ai_addr))) != 0) { - perror("connect() error"); - return -1; - } - char rebuf[2000] = {}; - if (send(sock, request, strlen(request), 0) == -1) { - perror("send() error"); - return -1; - } - ssize_t l = recv(sock, rebuf, 2000, 0); - if (l == -1) { - perror("recv() error"); - return -1; - } - rebuf[l] = '\0'; - printf("%s\n", rebuf); - - freeaddrinfo(res); - - return 0; -} diff --git a/arceos/examples/httpclient/Cargo.toml b/arceos/examples/httpclient/Cargo.toml deleted file mode 100644 index bce4bc026..000000000 --- a/arceos/examples/httpclient/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "arceos-httpclient" -version = "0.1.0" -edition = "2021" -authors = ["Yuekai Jia ", "Dashuai Wu "] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -axstd = { workspace = true, features = ["net"], optional = true } - -[features] -default = [] -dns = ["axstd?/dns"] diff --git a/arceos/examples/httpclient/src/main.rs b/arceos/examples/httpclient/src/main.rs deleted file mode 100644 index 6c81a5da0..000000000 --- a/arceos/examples/httpclient/src/main.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; - -use std::io::{self, prelude::*}; -use std::net::{TcpStream, ToSocketAddrs}; - -#[cfg(feature = "dns")] -const DEST: &str = "ident.me:80"; -#[cfg(not(feature = "dns"))] -const DEST: &str = "49.12.234.183:80"; - -const REQUEST: &str = "\ -GET / HTTP/1.1\r\n\ -Host: ident.me\r\n\ -Accept: */*\r\n\ -\r\n"; - -fn client() -> io::Result<()> { - for addr in DEST.to_socket_addrs()? { - println!("dest: {} ({})", DEST, addr); - } - - let mut stream = TcpStream::connect(DEST)?; - stream.write_all(REQUEST.as_bytes())?; - let mut buf = [0; 2048]; - let n = stream.read(&mut buf)?; - let response = core::str::from_utf8(&buf[..n]).unwrap(); - println!("{}", response); // longer response need to handle tcp package problems. - Ok(()) -} - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - println!("Hello, simple http client!"); - client().expect("test http client failed"); -} diff --git a/arceos/examples/httpserver-c/axbuild.mk b/arceos/examples/httpserver-c/axbuild.mk deleted file mode 100644 index c30772479..000000000 --- a/arceos/examples/httpserver-c/axbuild.mk +++ /dev/null @@ -1 +0,0 @@ -app-objs := httpserver.o diff --git a/arceos/examples/httpserver-c/features.txt b/arceos/examples/httpserver-c/features.txt deleted file mode 100644 index 25ca64f38..000000000 --- a/arceos/examples/httpserver-c/features.txt +++ /dev/null @@ -1,3 +0,0 @@ -alloc -paging -net diff --git a/arceos/examples/httpserver-c/httpserver.c b/arceos/examples/httpserver-c/httpserver.c deleted file mode 100644 index 68dcbed0d..000000000 --- a/arceos/examples/httpserver-c/httpserver.c +++ /dev/null @@ -1,90 +0,0 @@ - -#include -#include -#include -#include -#include -#include - -const char header[] = "\ -HTTP/1.1 200 OK\r\n\ -Content-Type: text/html\r\n\ -Content-Length: %u\r\n\ -Connection: close\r\n\ -\r\n\ -"; - -const char content[] = "\n\ -\n\ - Hello, ArceOS\n\ -\n\ -\n\ -
\n\ -

Hello, ArceOS

\n\ -
\n\ -
\n\ -
\n\ - Powered by ArceOS example HTTP server v0.1.0\n\ -
\n\ -\n\ -\n\ -"; - -int main() -{ - puts("Hello, ArceOS C HTTP server!"); - struct sockaddr_in local, remote; - int addr_len = sizeof(remote); - local.sin_family = AF_INET; - if (inet_pton(AF_INET, "0.0.0.0", &(local.sin_addr)) != 1) { - perror("inet_pton() error"); - return -1; - } - local.sin_port = htons(5555); - int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock == -1) { - perror("socket() error"); - return -1; - } - if (bind(sock, (struct sockaddr *)&local, sizeof(local)) != 0) { - perror("bind() error"); - return -1; - } - if (listen(sock, 0) != 0) { - perror("listen() error"); - return -1; - } - puts("listen on: http://0.0.0.0:5555/"); - char buf[1024] = {}; - int client; - char response[1024] = {}; - snprintf(response, 1024, header, strlen(content)); - strcat(response, content); - for (;;) { - client = accept(sock, (struct sockaddr *)&remote, (socklen_t *)&addr_len); - if (client == -1) { - perror("accept() error"); - return -1; - } - printf("new client %d\n", client); - if (recv(client, buf, 1024, 0) == -1) { - perror("recv() error"); - return -1; - } - ssize_t l = send(client, response, strlen(response), 0); - if (l == -1) { - perror("send() error"); - return -1; - } - if (close(client) == -1) { - perror("close() error"); - return -1; - } - printf("client %d close: %ld bytes sent\n", client, l); - } - if (close(sock) == -1) { - perror("close() error"); - return -1; - } - return 0; -} diff --git a/arceos/examples/httpserver/Cargo.toml b/arceos/examples/httpserver/Cargo.toml deleted file mode 100644 index 081c05ecd..000000000 --- a/arceos/examples/httpserver/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "arceos-httpserver" -version = "0.1.0" -edition = "2021" -authors = ["Yuekai Jia "] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -axstd = { workspace = true, features = ["alloc", "multitask", "net"], optional = true } diff --git a/arceos/examples/httpserver/src/main.rs b/arceos/examples/httpserver/src/main.rs deleted file mode 100644 index 0cadc40f2..000000000 --- a/arceos/examples/httpserver/src/main.rs +++ /dev/null @@ -1,96 +0,0 @@ -//! Simple HTTP server. -//! -//! Benchmark with [Apache HTTP server benchmarking tool](https://httpd.apache.org/docs/2.4/programs/ab.html): -//! -//! ``` -//! ab -n 5000 -c 20 http://X.X.X.X:5555/ -//! ``` - -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; - -use std::io::{self, prelude::*}; -use std::net::{TcpListener, TcpStream}; -use std::thread; - -const LOCAL_IP: &str = "0.0.0.0"; -const LOCAL_PORT: u16 = 5555; - -macro_rules! header { - () => { - "\ -HTTP/1.1 200 OK\r\n\ -Content-Type: text/html\r\n\ -Content-Length: {}\r\n\ -Connection: close\r\n\ -\r\n\ -{}" - }; -} - -const CONTENT: &str = r#" - - Hello, ArceOS - - -
-

Hello, ArceOS

-
-
-
- Powered by ArceOS example HTTP server v0.1.0 -
- - -"#; - -macro_rules! info { - ($($arg:tt)*) => { - match option_env!("LOG") { - Some("info") | Some("debug") | Some("trace") => { - print!("[INFO] {}\n", format_args!($($arg)*)); - } - _ => {} - } - }; -} - -fn http_server(mut stream: TcpStream) -> io::Result<()> { - let mut buf = [0u8; 4096]; - let _len = stream.read(&mut buf)?; - - let response = format!(header!(), CONTENT.len(), CONTENT); - stream.write_all(response.as_bytes())?; - - Ok(()) -} - -fn accept_loop() -> io::Result<()> { - let listener = TcpListener::bind((LOCAL_IP, LOCAL_PORT))?; - println!("listen on: http://{}/", listener.local_addr().unwrap()); - - let mut i = 0; - loop { - match listener.accept() { - Ok((stream, addr)) => { - info!("new client {}: {}", i, addr); - thread::spawn(move || match http_server(stream) { - Err(e) => info!("client connection error: {:?}", e), - Ok(()) => info!("client {} closed successfully", i), - }); - } - Err(e) => return Err(e), - } - i += 1; - } -} - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - println!("Hello, ArceOS HTTP server!"); - accept_loop().expect("test HTTP server failed"); -} diff --git a/arceos/examples/shell/Cargo.toml b/arceos/examples/shell/Cargo.toml deleted file mode 100644 index 5c9342fdb..000000000 --- a/arceos/examples/shell/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "arceos-shell" -version = "0.1.0" -edition = "2021" -authors = ["Yuekai Jia "] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[features] -use-ramfs = ["axstd/myfs", "dep:axfs_vfs", "dep:axfs_ramfs", "dep:crate_interface"] -default = [] - -[dependencies] -axfs_vfs = { version = "0.1", optional = true } -axfs_ramfs = { version = "0.1", optional = true } -crate_interface = { version = "0.1", optional = true } -axstd = { workspace = true, features = ["alloc", "fs"], optional = true } diff --git a/arceos/examples/shell/src/cmd.rs b/arceos/examples/shell/src/cmd.rs deleted file mode 100644 index 23f087fe3..000000000 --- a/arceos/examples/shell/src/cmd.rs +++ /dev/null @@ -1,293 +0,0 @@ -use std::fs::{self, File, FileType}; -use std::io::{self, prelude::*}; -use std::{string::String, vec::Vec}; - -#[cfg(all(not(feature = "axstd"), unix))] -use std::os::unix::fs::{FileTypeExt, PermissionsExt}; - -macro_rules! print_err { - ($cmd: literal, $msg: expr) => { - println!("{}: {}", $cmd, $msg); - }; - ($cmd: literal, $arg: expr, $err: expr) => { - println!("{}: {}: {}", $cmd, $arg, $err); - }; -} - -type CmdHandler = fn(&str); - -const CMD_TABLE: &[(&str, CmdHandler)] = &[ - ("cat", do_cat), - ("cd", do_cd), - ("echo", do_echo), - ("exit", do_exit), - ("help", do_help), - ("ls", do_ls), - ("mkdir", do_mkdir), - ("pwd", do_pwd), - ("rm", do_rm), - ("uname", do_uname), -]; - -fn file_type_to_char(ty: FileType) -> char { - if ty.is_char_device() { - 'c' - } else if ty.is_block_device() { - 'b' - } else if ty.is_socket() { - 's' - } else if ty.is_fifo() { - 'p' - } else if ty.is_symlink() { - 'l' - } else if ty.is_dir() { - 'd' - } else if ty.is_file() { - '-' - } else { - '?' - } -} - -#[rustfmt::skip] -const fn file_perm_to_rwx(mode: u32) -> [u8; 9] { - let mut perm = [b'-'; 9]; - macro_rules! set { - ($bit:literal, $rwx:literal) => { - if mode & (1 << $bit) != 0 { - perm[8 - $bit] = $rwx - } - }; - } - - set!(2, b'r'); set!(1, b'w'); set!(0, b'x'); - set!(5, b'r'); set!(4, b'w'); set!(3, b'x'); - set!(8, b'r'); set!(7, b'w'); set!(6, b'x'); - perm -} - -fn do_ls(args: &str) { - let current_dir = std::env::current_dir().unwrap(); - let args = if args.is_empty() { - path_to_str!(current_dir) - } else { - args - }; - let name_count = args.split_whitespace().count(); - - fn show_entry_info(path: &str, entry: &str) -> io::Result<()> { - let metadata = fs::metadata(path)?; - let size = metadata.len(); - let file_type = metadata.file_type(); - let file_type_char = file_type_to_char(file_type); - let rwx = file_perm_to_rwx(metadata.permissions().mode()); - let rwx = unsafe { core::str::from_utf8_unchecked(&rwx) }; - println!("{}{} {:>8} {}", file_type_char, rwx, size, entry); - Ok(()) - } - - fn list_one(name: &str, print_name: bool) -> io::Result<()> { - let is_dir = fs::metadata(name)?.is_dir(); - if !is_dir { - return show_entry_info(name, name); - } - - if print_name { - println!("{}:", name); - } - let mut entries = fs::read_dir(name)? - .filter_map(|e| e.ok()) - .map(|e| e.file_name()) - .collect::>(); - entries.sort(); - - for entry in entries { - let entry = path_to_str!(entry); - let path = String::from(name) + "/" + entry; - if let Err(e) = show_entry_info(&path, entry) { - print_err!("ls", path, e); - } - } - Ok(()) - } - - for (i, name) in args.split_whitespace().enumerate() { - if i > 0 { - println!(); - } - if let Err(e) = list_one(name, name_count > 1) { - print_err!("ls", name, e); - } - } -} - -fn do_cat(args: &str) { - if args.is_empty() { - print_err!("cat", "no file specified"); - return; - } - - fn cat_one(fname: &str) -> io::Result<()> { - let mut buf = [0; 1024]; - let mut file = File::open(fname)?; - loop { - let n = file.read(&mut buf)?; - if n > 0 { - io::stdout().write_all(&buf[..n])?; - } else { - return Ok(()); - } - } - } - - for fname in args.split_whitespace() { - if let Err(e) = cat_one(fname) { - print_err!("cat", fname, e); - } - } -} - -fn do_echo(args: &str) { - fn echo_file(fname: &str, text_list: &[&str]) -> io::Result<()> { - let mut file = File::create(fname)?; - for text in text_list { - file.write_all(text.as_bytes())?; - } - Ok(()) - } - - if let Some(pos) = args.rfind('>') { - let text_before = args[..pos].trim(); - let (fname, text_after) = split_whitespace(&args[pos + 1..]); - if fname.is_empty() { - print_err!("echo", "no file specified"); - return; - }; - - let text_list = [ - text_before, - if !text_after.is_empty() { " " } else { "" }, - text_after, - "\n", - ]; - if let Err(e) = echo_file(fname, &text_list) { - print_err!("echo", fname, e); - } - } else { - println!("{}", args) - } -} - -fn do_mkdir(args: &str) { - if args.is_empty() { - print_err!("mkdir", "missing operand"); - return; - } - - fn mkdir_one(path: &str) -> io::Result<()> { - fs::create_dir(path) - } - - for path in args.split_whitespace() { - if let Err(e) = mkdir_one(path) { - print_err!("mkdir", format_args!("cannot create directory '{path}'"), e); - } - } -} - -fn do_rm(args: &str) { - if args.is_empty() { - print_err!("rm", "missing operand"); - return; - } - let mut rm_dir = false; - for arg in args.split_whitespace() { - if arg == "-d" { - rm_dir = true; - } - } - - fn rm_one(path: &str, rm_dir: bool) -> io::Result<()> { - if rm_dir && fs::metadata(path)?.is_dir() { - fs::remove_dir(path) - } else { - fs::remove_file(path) - } - } - - for path in args.split_whitespace() { - if path == "-d" { - continue; - } - if let Err(e) = rm_one(path, rm_dir) { - print_err!("rm", format_args!("cannot remove '{path}'"), e); - } - } -} - -fn do_cd(mut args: &str) { - if args.is_empty() { - args = "/"; - } - if !args.contains(char::is_whitespace) { - if let Err(e) = std::env::set_current_dir(args) { - print_err!("cd", args, e); - } - } else { - print_err!("cd", "too many arguments"); - } -} - -fn do_pwd(_args: &str) { - let pwd = std::env::current_dir().unwrap(); - println!("{}", path_to_str!(pwd)); -} - -fn do_uname(_args: &str) { - let arch = option_env!("AX_ARCH").unwrap_or(""); - let platform = option_env!("AX_PLATFORM").unwrap_or(""); - let smp = match option_env!("AX_SMP") { - None | Some("1") => "", - _ => " SMP", - }; - let version = option_env!("CARGO_PKG_VERSION").unwrap_or("0.1.0"); - println!( - "ArceOS {ver}{smp} {arch} {plat}", - ver = version, - smp = smp, - arch = arch, - plat = platform, - ); -} - -fn do_help(_args: &str) { - println!("Available commands:"); - for (name, _) in CMD_TABLE { - println!(" {}", name); - } -} - -fn do_exit(_args: &str) { - println!("Bye~"); - std::process::exit(0); -} - -pub fn run_cmd(line: &[u8]) { - let line_str = unsafe { core::str::from_utf8_unchecked(line) }; - let (cmd, args) = split_whitespace(line_str); - if !cmd.is_empty() { - for (name, func) in CMD_TABLE { - if cmd == *name { - func(args); - return; - } - } - println!("{}: command not found", cmd); - } -} - -fn split_whitespace(str: &str) -> (&str, &str) { - let str = str.trim(); - str.find(char::is_whitespace) - .map_or((str, ""), |n| (&str[..n], str[n + 1..].trim())) -} diff --git a/arceos/examples/shell/src/main.rs b/arceos/examples/shell/src/main.rs deleted file mode 100644 index 1e2875aad..000000000 --- a/arceos/examples/shell/src/main.rs +++ /dev/null @@ -1,85 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; - -macro_rules! path_to_str { - ($path:expr) => {{ - #[cfg(not(feature = "axstd"))] - { - $path.to_str().unwrap() // Path/OsString -> &str - } - #[cfg(feature = "axstd")] - { - $path.as_str() // String -> &str - } - }}; -} - -mod cmd; - -#[cfg(feature = "use-ramfs")] -mod ramfs; - -use std::io::prelude::*; - -const LF: u8 = b'\n'; -const CR: u8 = b'\r'; -const DL: u8 = b'\x7f'; -const BS: u8 = b'\x08'; -const SPACE: u8 = b' '; - -const MAX_CMD_LEN: usize = 256; - -fn print_prompt() { - print!( - "arceos:{}$ ", - path_to_str!(std::env::current_dir().unwrap()) - ); - std::io::stdout().flush().unwrap(); -} - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - let mut stdin = std::io::stdin(); - let mut stdout = std::io::stdout(); - - let mut buf = [0; MAX_CMD_LEN]; - let mut cursor = 0; - cmd::run_cmd("help".as_bytes()); - print_prompt(); - - loop { - if stdin.read(&mut buf[cursor..cursor + 1]).ok() != Some(1) { - continue; - } - if buf[cursor] == b'\x1b' { - buf[cursor] = b'^'; - } - match buf[cursor] { - CR | LF => { - println!(); - if cursor > 0 { - cmd::run_cmd(&buf[..cursor]); - cursor = 0; - } - print_prompt(); - } - BS | DL => { - if cursor > 0 { - stdout.write_all(&[BS, SPACE, BS]).unwrap(); - cursor -= 1; - } - } - 0..=31 => {} - c => { - if cursor < MAX_CMD_LEN - 1 { - stdout.write_all(&[c]).unwrap(); - cursor += 1; - } - } - } - } -} diff --git a/arceos/examples/shell/src/ramfs.rs b/arceos/examples/shell/src/ramfs.rs deleted file mode 100644 index 450cafaeb..000000000 --- a/arceos/examples/shell/src/ramfs.rs +++ /dev/null @@ -1,15 +0,0 @@ -extern crate alloc; - -use alloc::sync::Arc; -use axfs_ramfs::RamFileSystem; -use axfs_vfs::VfsOps; -use std::os::arceos::api::fs::{AxDisk, MyFileSystemIf}; - -struct MyFileSystemIfImpl; - -#[crate_interface::impl_interface] -impl MyFileSystemIf for MyFileSystemIfImpl { - fn new_myfs(_disk: AxDisk) -> Arc { - Arc::new(RamFileSystem::new()) - } -} diff --git a/arceos/exercises/alt_alloc/Cargo.toml b/arceos/exercises/alt_alloc/Cargo.toml deleted file mode 100644 index 8d84985ee..000000000 --- a/arceos/exercises/alt_alloc/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "alt_alloc" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -axstd = { workspace = true, features = ["alt_alloc"], optional = true } diff --git a/arceos/exercises/alt_alloc/src/main.rs b/arceos/exercises/alt_alloc/src/main.rs deleted file mode 100644 index 74ab66e4b..000000000 --- a/arceos/exercises/alt_alloc/src/main.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; -extern crate alloc; - -use alloc::vec::Vec; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - println!("Running bump tests..."); - - const N: usize = 3_000_000; - let mut v = Vec::with_capacity(N); - for i in 0..N { - v.push(i); - } - v.sort(); - for i in 0..N - 1 { - assert!(v[i] <= v[i + 1]); - } - - println!("Bump tests run OK!"); -} diff --git a/arceos/exercises/print_with_color/Cargo.toml b/arceos/exercises/print_with_color/Cargo.toml deleted file mode 100644 index e36fc9eed..000000000 --- a/arceos/exercises/print_with_color/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "print_with_colord" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, optional = true } diff --git a/arceos/exercises/print_with_color/src/main.rs b/arceos/exercises/print_with_color/src/main.rs deleted file mode 100644 index 69f34d7a2..000000000 --- a/arceos/exercises/print_with_color/src/main.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[cfg(feature = "axstd")] -use axstd::println; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - println!("[WithColor]: Hello, Arceos!"); -} diff --git a/arceos/exercises/ramfs_rename/Cargo.toml b/arceos/exercises/ramfs_rename/Cargo.toml deleted file mode 100644 index c828061b7..000000000 --- a/arceos/exercises/ramfs_rename/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "ramfs_rename" -version = "0.1.0" -edition = "2021" -authors = ["Yuekai Jia "] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[features] -default = ["axstd/myfs", "dep:axfs_vfs", "dep:axfs_ramfs", "dep:crate_interface"] - -[dependencies] -axfs_vfs = { version = "0.1", optional = true } -axfs_ramfs = { version = "0.1", optional = true } -crate_interface = { version = "0.1", optional = true } -axstd = { workspace = true, features = ["alloc", "fs"], optional = true } diff --git a/arceos/exercises/ramfs_rename/src/main.rs b/arceos/exercises/ramfs_rename/src/main.rs deleted file mode 100644 index c2d29af83..000000000 --- a/arceos/exercises/ramfs_rename/src/main.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; - -mod ramfs; - -use std::io::{self, prelude::*}; -use std::fs::{self, File}; - -fn create_file(fname: &str, text: &str) -> io::Result<()> { - println!("Create '{}' and write [{}] ...", fname, text); - let mut file = File::create(fname)?; - file.write_all(text.as_bytes()) -} - -// Only support rename, NOT move. -fn rename_file(src: &str, dst: &str) -> io::Result<()> { - println!("Rename '{}' to '{}' ...", src, dst); - fs::rename(src, dst) -} - -fn print_file(fname: &str) -> io::Result<()> { - let mut buf = [0; 1024]; - let mut file = File::open(fname)?; - loop { - let n = file.read(&mut buf)?; - if n > 0 { - print!("Read '{}' content: [", fname); - io::stdout().write_all(&buf[..n])?; - println!("] ok!"); - } else { - return Ok(()); - } - } -} - -fn process() -> io::Result<()> { - create_file("/tmp/f1", "hello")?; - // Just rename, NOT move. - // So this must happen in the same directory. - rename_file("/tmp/f1", "/tmp/f2")?; - print_file("/tmp/f2") -} - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - if let Err(e) = process() { - panic!("Error: {}", e); - } - println!("\n[Ramfs-Rename]: ok!"); -} diff --git a/arceos/exercises/ramfs_rename/src/ramfs.rs b/arceos/exercises/ramfs_rename/src/ramfs.rs deleted file mode 100644 index 450cafaeb..000000000 --- a/arceos/exercises/ramfs_rename/src/ramfs.rs +++ /dev/null @@ -1,15 +0,0 @@ -extern crate alloc; - -use alloc::sync::Arc; -use axfs_ramfs::RamFileSystem; -use axfs_vfs::VfsOps; -use std::os::arceos::api::fs::{AxDisk, MyFileSystemIf}; - -struct MyFileSystemIfImpl; - -#[crate_interface::impl_interface] -impl MyFileSystemIf for MyFileSystemIfImpl { - fn new_myfs(_disk: AxDisk) -> Arc { - Arc::new(RamFileSystem::new()) - } -} diff --git a/arceos/exercises/simple_hv/Cargo.toml b/arceos/exercises/simple_hv/Cargo.toml deleted file mode 100644 index a38c7cc22..000000000 --- a/arceos/exercises/simple_hv/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "simple_hv" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask", "sched_cfs", "fs"], optional = true } -axhal = { workspace = true } -axmm = { workspace = true } -axtask = { workspace = true } -axsync = { workspace = true } -axerrno = "0.1" -sbi-spec = { version = "0.0.6", features = ["legacy"] } -riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } -sbi-rt = { version = "0.0.2", features = ["integer-impls", "legacy"] } -tock-registers = "0.8.1" -memoffset = { version = ">=0.6.5", features = ["unstable_const"] } -axlog = { workspace = true } diff --git a/arceos/exercises/simple_hv/src/csrs.rs b/arceos/exercises/simple_hv/src/csrs.rs deleted file mode 100644 index 6053f7881..000000000 --- a/arceos/exercises/simple_hv/src/csrs.rs +++ /dev/null @@ -1,312 +0,0 @@ -#![allow(dead_code)] - -use defs::*; -use tock_registers::interfaces::{Readable, Writeable}; -use tock_registers::RegisterLongName; - -/// Define each registers of hypervisor using. -pub struct CSR { - pub sie: ReadWriteCsr, - pub hstatus: ReadWriteCsr, - pub hedeleg: ReadWriteCsr, - pub hideleg: ReadWriteCsr, - pub hcounteren: ReadWriteCsr, - pub hvip: ReadWriteCsr, -} - -#[allow(clippy::identity_op, clippy::erasing_op)] -pub const CSR: &CSR = &CSR { - sie: ReadWriteCsr::new(), - hstatus: ReadWriteCsr::new(), - hedeleg: ReadWriteCsr::new(), - hideleg: ReadWriteCsr::new(), - hcounteren: ReadWriteCsr::new(), - hvip: ReadWriteCsr::new(), -}; - -/// Trait defining the possible operations on a RISC-V CSR. -pub trait RiscvCsrTrait { - type R: RegisterLongName; - /// Reads the value of the CSR. - fn get_value(&self) -> usize; - - /// Writes the value of the CSR. - fn write_value(&self, value: usize); - - /// Atomicllt swaps the value of CSRs. - fn atomic_replace(&self, value: usize) -> usize; - - /// Atomically read a CSR and set bits specified in a bitmask - fn read_and_set_bits(&self, bitmasks: usize) -> usize; - - /// Atomically read a CSR and set bits specified in a bitmask - fn read_and_clear_bits(&self, bitmasks: usize) -> usize; -} - -/// Read/Write register. -pub struct ReadWriteCsr { - associated_register: core::marker::PhantomData, -} - -impl ReadWriteCsr { - pub const fn new() -> Self { - Self { - associated_register: core::marker::PhantomData, - } - } -} - -impl RiscvCsrTrait for ReadWriteCsr { - type R = R; - - fn get_value(&self) -> usize { - let r: usize; - unsafe { - core::arch::asm!("csrr {rd}, {csr}", rd = out(reg) r, csr = const V); - } - r - } - - fn write_value(&self, value: usize) { - unsafe { - core::arch::asm!("csrw {csr}, {rs}", csr = const V, rs = in(reg) value); - } - } - - fn atomic_replace(&self, value: usize) -> usize { - let r: usize; - unsafe { - core::arch::asm!("csrrw {rd}, {csr}, {rs}", rd = out(reg) r, csr = const V, rs = in(reg) value); - } - r - } - - fn read_and_set_bits(&self, bitmask: usize) -> usize { - let r: usize; - unsafe { - core::arch::asm!("csrrs {rd}, {csr}, {rs}", rd = out(reg) r, csr = const V, rs = in(reg) bitmask); - } - r - } - - fn read_and_clear_bits(&self, bitmask: usize) -> usize { - let r: usize; - unsafe { - core::arch::asm!("csrrc {rd}, {csr}, {rs}", rd = out(reg) r, csr = const V, rs = in(reg) bitmask); - } - r - } -} - -// The Readable and Writeable traits aren't object-safe so unfortunately we can't implement them -// for RiscvCsrInterface. -impl Readable for ReadWriteCsr { - type T = usize; - type R = R; - - fn get(&self) -> usize { - self.get_value() - } -} - -impl Writeable for ReadWriteCsr { - type T = usize; - type R = R; - - fn set(&self, val_to_set: usize) { - self.write_value(val_to_set); - } -} - -pub mod defs { - use tock_registers::register_bitfields; - pub const CSR_SSTATUS: u16 = 0x100; - pub const CSR_SEDELEG: u16 = 0x102; - pub const CSR_SIDELEG: u16 = 0x103; - pub const CSR_SIE: u16 = 0x104; - pub const CSR_STVEC: u16 = 0x105; - pub const CSR_SCOUNTEREN: u16 = 0x106; - pub const CSR_SENVCFG: u16 = 0x10a; - pub const CSR_SSCRATCH: u16 = 0x140; - pub const CSR_SEPC: u16 = 0x141; - pub const CSR_SCAUSE: u16 = 0x142; - pub const CSR_STVAL: u16 = 0x143; - pub const CSR_SIP: u16 = 0x144; - pub const CSR_STIMECMP: u16 = 0x14d; - pub const CSR_SISELECT: u16 = 0x150; - pub const CSR_SIREG: u16 = 0x151; - pub const CSR_STOPEI: u16 = 0x15c; - pub const CSR_SATP: u16 = 0x180; - pub const CSR_STOPI: u16 = 0xdb0; - pub const CSR_SCONTEXT: u16 = 0x5a8; - pub const CSR_VSSTATUS: u16 = 0x200; - pub const CSR_VSIE: u16 = 0x204; - pub const CSR_VSTVEC: u16 = 0x205; - pub const CSR_VSSCRATCH: u16 = 0x240; - pub const CSR_VSEPC: u16 = 0x241; - pub const CSR_VSCAUSE: u16 = 0x242; - pub const CSR_VSTVAL: u16 = 0x243; - pub const CSR_VSIP: u16 = 0x244; - pub const CSR_VSTIMECMP: u16 = 0x24d; - pub const CSR_VSISELECT: u16 = 0x250; - pub const CSR_VSIREG: u16 = 0x251; - pub const CSR_VSTOPEI: u16 = 0x25c; - pub const CSR_VSATP: u16 = 0x280; - pub const CSR_VSTOPI: u16 = 0xeb0; - pub const CSR_HSTATUS: u16 = 0x600; - pub const CSR_HEDELEG: u16 = 0x602; - pub const CSR_HIDELEG: u16 = 0x603; - pub const CSR_HIE: u16 = 0x604; - pub const CSR_HTIMEDELTA: u16 = 0x605; - pub const CSR_HCOUNTEREN: u16 = 0x606; - pub const CSR_HGEIE: u16 = 0x607; - pub const CSR_HVICTL: u16 = 0x609; - pub const CSR_HENVCFG: u16 = 0x60a; - pub const CSR_HTVAL: u16 = 0x643; - pub const CSR_HIP: u16 = 0x644; - pub const CSR_HVIP: u16 = 0x645; - pub const CSR_HTINST: u16 = 0x64a; - pub const CSR_HGATP: u16 = 0x680; - pub const CSR_HCONTEXT: u16 = 0x6a8; - pub const CSR_HGEIP: u16 = 0xe12; - - // Hypervisor exception delegation register. - register_bitfields![usize, - pub hedeleg [ - instr_misaligned OFFSET(0) NUMBITS(1) [], - instr_fault OFFSET(1) NUMBITS(1) [], - illegal_instr OFFSET(2) NUMBITS(1) [], - breakpoint OFFSET(3) NUMBITS(1) [], - load_misaligned OFFSET(4) NUMBITS(1) [], - load_fault OFFSET(5) NUMBITS(1) [], - store_misaligned OFFSET(6) NUMBITS(1) [], - store_fault OFFSET(7) NUMBITS(1) [], - u_ecall OFFSET(8) NUMBITS(1) [], - instr_page_fault OFFSET(12) NUMBITS(1) [], - load_page_fault OFFSET(13) NUMBITS(1) [], - store_page_fault OFFSET(15) NUMBITS(1) [], - ] - ]; - - // Supervisor interrupt enable register. - register_bitfields![usize, - pub sie [ - ssoft OFFSET(1) NUMBITS(1) [], - stimer OFFSET(5) NUMBITS(1) [], - sext OFFSET(9) NUMBITS(1) [], - ] - ]; - - // Hypervisor status register. - register_bitfields![usize, - pub hstatus [ - // VS mode endianness control. - vsbe OFFSET(6) NUMBITS(1) [], - // A guest virtual address was written to stval as a result of the trap. - gva OFFSET(6) NUMBITS(1) [], - // Virtualization mode at time of trap. - spv OFFSET(7) NUMBITS(1) [ - Host = 0, - Guest = 1, - ], - // Privilege level the virtual hart was executing before entering HS-mode. - spvp OFFSET(8) NUMBITS(1) [ - User = 0, - Supervisor = 1, - ], - // Allow hypervisor instructions in U-mode. - hu OFFSET(9) NUMBITS(1) [], - // Selects the guest external interrupt source for VS external interrupts. - vgein OFFSET(12) NUMBITS(6) [], - // Trap on SFENCE, SINVAL, or changes to vsatp. - vtvm OFFSET(20) NUMBITS(1) [], - // Trap on WFI timeout. - vtw OFFSET(21) NUMBITS(1) [], - // Trap SRET instruction. - vtsr OFFSET(22) NUMBITS(1) [], - // Native base integer ISA width for VS-mode. - vsxl OFFSET(32) NUMBITS(2) [ - Xlen32 = 1, - Xlen64 = 2, - ], - ] - ]; - - // Hypervisor interrupt delegation register. - register_bitfields![usize, - pub hideleg [ - vssoft OFFSET(2) NUMBITS(1) [], - vstimer OFFSET(6) NUMBITS(1) [], - vsext OFFSET(10) NUMBITS(1) [], - ] - ]; - - // Hypervisor interrupt enable register. - register_bitfields![usize, - pub hie [ - vssoft OFFSET(2) NUMBITS(1) [], - vstimer OFFSET(6) NUMBITS(1) [], - vsext OFFSET(10) NUMBITS(1) [], - sgext OFFSET(12) NUMBITS(1) [], - ] - ]; - - // VS-mode counter availability control. - register_bitfields![usize, - pub hcounteren [ - cycle OFFSET(0) NUMBITS(1) [], - time OFFSET(1) NUMBITS(1) [], - instret OFFSET(2) NUMBITS(1) [], - hpm OFFSET(3) NUMBITS(29) [], - ] - ]; - - // Hypervisor virtual interrupt pending. - register_bitfields![usize, - pub hvip [ - vssoft OFFSET(2) NUMBITS(1) [], - vstimer OFFSET(6) NUMBITS(1) [], - vsext OFFSET(10) NUMBITS(1) [], - ] - ]; -} - -pub mod traps { - pub mod interrupt { - pub const USER_SOFT: usize = 1 << 0; - pub const SUPERVISOR_SOFT: usize = 1 << 1; - pub const VIRTUAL_SUPERVISOR_SOFT: usize = 1 << 2; - pub const MACHINE_SOFT: usize = 1 << 3; - pub const USER_TIMER: usize = 1 << 4; - pub const SUPERVISOR_TIMER: usize = 1 << 5; - pub const VIRTUAL_SUPERVISOR_TIMER: usize = 1 << 6; - pub const MACHINE_TIMER: usize = 1 << 7; - pub const USER_EXTERNAL: usize = 1 << 8; - pub const SUPERVISOR_EXTERNAL: usize = 1 << 9; - pub const VIRTUAL_SUPERVISOR_EXTERNAL: usize = 1 << 10; - pub const MACHINEL_EXTERNAL: usize = 1 << 11; - pub const SUPERVISOR_GUEST_EXTERNEL: usize = 1 << 12; - } - - pub mod exception { - pub const INST_ADDR_MISALIGN: usize = 1 << 0; - pub const INST_ACCESSS_FAULT: usize = 1 << 1; - pub const ILLEGAL_INST: usize = 1 << 2; - pub const BREAKPOINT: usize = 1 << 3; - pub const LOAD_ADDR_MISALIGNED: usize = 1 << 4; - pub const LOAD_ACCESS_FAULT: usize = 1 << 5; - pub const STORE_ADDR_MISALIGNED: usize = 1 << 6; - pub const STORE_ACCESS_FAULT: usize = 1 << 7; - pub const ENV_CALL_FROM_U_OR_VU: usize = 1 << 8; - pub const ENV_CALL_FROM_HS: usize = 1 << 9; - pub const ENV_CALL_FROM_VS: usize = 1 << 10; - pub const ENV_CALL_FROM_M: usize = 1 << 11; - pub const INST_PAGE_FAULT: usize = 1 << 12; - pub const LOAD_PAGE_FAULT: usize = 1 << 13; - pub const STORE_PAGE_FAULT: usize = 1 << 15; - pub const INST_GUEST_PAGE_FAULT: usize = 1 << 20; - pub const LOAD_GUEST_PAGE_FAULT: usize = 1 << 21; - pub const VIRTUAL_INST: usize = 1 << 22; - pub const STORE_GUEST_PAGE_FAULT: usize = 1 << 23; - } -} diff --git a/arceos/exercises/simple_hv/src/guest.S b/arceos/exercises/simple_hv/src/guest.S deleted file mode 100644 index 60ab203fa..000000000 --- a/arceos/exercises/simple_hv/src/guest.S +++ /dev/null @@ -1,181 +0,0 @@ - -/// Enter the guest given in `VmCpuRegisters` from `a0` -.global _run_guest -_run_guest: - /* Save hypervisor state */ - - /* Save hypervisor GPRs (except T0-T6 and a0, which is GuestInfo and stashed in sscratch) */ - sd ra, ({hyp_ra})(a0) - sd gp, ({hyp_gp})(a0) - sd tp, ({hyp_tp})(a0) - sd s0, ({hyp_s0})(a0) - sd s1, ({hyp_s1})(a0) - sd a1, ({hyp_a1})(a0) - sd a2, ({hyp_a2})(a0) - sd a3, ({hyp_a3})(a0) - sd a4, ({hyp_a4})(a0) - sd a5, ({hyp_a5})(a0) - sd a6, ({hyp_a6})(a0) - sd a7, ({hyp_a7})(a0) - sd s2, ({hyp_s2})(a0) - sd s3, ({hyp_s3})(a0) - sd s4, ({hyp_s4})(a0) - sd s5, ({hyp_s5})(a0) - sd s6, ({hyp_s6})(a0) - sd s7, ({hyp_s7})(a0) - sd s8, ({hyp_s8})(a0) - sd s9, ({hyp_s9})(a0) - sd s10, ({hyp_s10})(a0) - sd s11, ({hyp_s11})(a0) - sd sp, ({hyp_sp})(a0) - - /* Swap in guest CSRs. */ - ld t1, ({guest_sstatus})(a0) - csrrw t1, sstatus, t1 - sd t1, ({hyp_sstatus})(a0) - - ld t1, ({guest_hstatus})(a0) - csrrw t1, hstatus, t1 - - ld t1, ({guest_scounteren})(a0) - csrrw t1, scounteren, t1 - sd t1, ({hyp_scounteren})(a0) - - ld t1, ({guest_sepc})(a0) - csrw sepc, t1 - - /* Set stvec so that hypervisor resumes after the sret when the guest exits. */ - la t1, _guest_exit - csrrw t1, stvec, t1 - sd t1, ({hyp_stvec})(a0) - - /* Save sscratch and replace with pointer to GuestInfo. */ - csrrw t1, sscratch, a0 - sd t1, ({hyp_sscratch})(a0) - - /* Restore the gprs from this GuestInfo */ - ld ra, ({guest_ra})(a0) - ld gp, ({guest_gp})(a0) - ld tp, ({guest_tp})(a0) - ld s0, ({guest_s0})(a0) - ld s1, ({guest_s1})(a0) - ld a1, ({guest_a1})(a0) - ld a2, ({guest_a2})(a0) - ld a3, ({guest_a3})(a0) - ld a4, ({guest_a4})(a0) - ld a5, ({guest_a5})(a0) - ld a6, ({guest_a6})(a0) - ld a7, ({guest_a7})(a0) - ld s2, ({guest_s2})(a0) - ld s3, ({guest_s3})(a0) - ld s4, ({guest_s4})(a0) - ld s5, ({guest_s5})(a0) - ld s6, ({guest_s6})(a0) - ld s7, ({guest_s7})(a0) - ld s8, ({guest_s8})(a0) - ld s9, ({guest_s9})(a0) - ld s10, ({guest_s10})(a0) - ld s11, ({guest_s11})(a0) - ld t0, ({guest_t0})(a0) - ld t1, ({guest_t1})(a0) - ld t2, ({guest_t2})(a0) - ld t3, ({guest_t3})(a0) - ld t4, ({guest_t4})(a0) - ld t5, ({guest_t5})(a0) - ld t6, ({guest_t6})(a0) - ld sp, ({guest_sp})(a0) - ld a0, ({guest_a0})(a0) - - sret - -.align 2 -_guest_exit: - /* Pull GuestInfo out of sscratch, swapping with guest's a0 */ - csrrw a0, sscratch, a0 - - /* Save guest GPRs. */ - sd ra, ({guest_ra})(a0) - sd gp, ({guest_gp})(a0) - sd tp, ({guest_tp})(a0) - sd s0, ({guest_s0})(a0) - sd s1, ({guest_s1})(a0) - sd a1, ({guest_a1})(a0) - sd a2, ({guest_a2})(a0) - sd a3, ({guest_a3})(a0) - sd a4, ({guest_a4})(a0) - sd a5, ({guest_a5})(a0) - sd a6, ({guest_a6})(a0) - sd a7, ({guest_a7})(a0) - sd s2, ({guest_s2})(a0) - sd s3, ({guest_s3})(a0) - sd s4, ({guest_s4})(a0) - sd s5, ({guest_s5})(a0) - sd s6, ({guest_s6})(a0) - sd s7, ({guest_s7})(a0) - sd s8, ({guest_s8})(a0) - sd s9, ({guest_s9})(a0) - sd s10, ({guest_s10})(a0) - sd s11, ({guest_s11})(a0) - sd t0, ({guest_t0})(a0) - sd t1, ({guest_t1})(a0) - sd t2, ({guest_t2})(a0) - sd t3, ({guest_t3})(a0) - sd t4, ({guest_t4})(a0) - sd t5, ({guest_t5})(a0) - sd t6, ({guest_t6})(a0) - sd sp, ({guest_sp})(a0) - - /* Save Guest a0 after recovering from sscratch. */ - csrr t0, sscratch - sd t0, ({guest_a0})(a0) - -_restore_csrs: - /* Swap in hypervisor CSRs. */ - ld t1, ({hyp_sstatus})(a0) - csrrw t1, sstatus, t1 - sd t1, ({guest_sstatus})(a0) - - csrr t1, hstatus - sd t1, ({guest_hstatus})(a0) - - ld t1, ({hyp_scounteren})(a0) - csrrw t1, scounteren, t1 - sd t1, ({guest_scounteren})(a0) - - ld t1, ({hyp_stvec})(a0) - csrw stvec, t1 - - ld t1, ({hyp_sscratch})(a0) - csrw sscratch, t1 - - /* Save guest EPC. */ - csrr t1, sepc - sd t1, ({guest_sepc})(a0) - - - /* Restore hypervisor GPRs. */ - ld ra, ({hyp_ra})(a0) - ld gp, ({hyp_gp})(a0) - ld tp, ({hyp_tp})(a0) - ld s0, ({hyp_s0})(a0) - ld s1, ({hyp_s1})(a0) - ld a1, ({hyp_a1})(a0) - ld a2, ({hyp_a2})(a0) - ld a3, ({hyp_a3})(a0) - ld a4, ({hyp_a4})(a0) - ld a5, ({hyp_a5})(a0) - ld a6, ({hyp_a6})(a0) - ld a7, ({hyp_a7})(a0) - ld s2, ({hyp_s2})(a0) - ld s3, ({hyp_s3})(a0) - ld s4, ({hyp_s4})(a0) - ld s5, ({hyp_s5})(a0) - ld s6, ({hyp_s6})(a0) - ld s7, ({hyp_s7})(a0) - ld s8, ({hyp_s8})(a0) - ld s9, ({hyp_s9})(a0) - ld s10, ({hyp_s10})(a0) - ld s11, ({hyp_s11})(a0) - ld sp, ({hyp_sp})(a0) - - ret diff --git a/arceos/exercises/simple_hv/src/loader.rs b/arceos/exercises/simple_hv/src/loader.rs deleted file mode 100644 index 0721fbfaa..000000000 --- a/arceos/exercises/simple_hv/src/loader.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::io::{self, Read}; -use std::fs::File; -use axhal::paging::MappingFlags; -use axhal::mem::{PAGE_SIZE_4K, phys_to_virt}; -use axmm::AddrSpace; -use crate::VM_ENTRY; - -pub fn load_vm_image(fname: &str, uspace: &mut AddrSpace) -> io::Result<()> { - let mut buf = [0u8; 64]; - load_file(fname, &mut buf)?; - - uspace.map_alloc(VM_ENTRY.into(), PAGE_SIZE_4K, MappingFlags::READ|MappingFlags::WRITE|MappingFlags::EXECUTE|MappingFlags::USER, true).unwrap(); - - let (paddr, _, _) = uspace - .page_table() - .query(VM_ENTRY.into()) - .unwrap_or_else(|_| panic!("Mapping failed for segment: {:#x}", VM_ENTRY)); - - ax_println!("paddr: {:#x}", paddr); - - unsafe { - core::ptr::copy_nonoverlapping( - buf.as_ptr(), - phys_to_virt(paddr).as_mut_ptr(), - PAGE_SIZE_4K, - ); - } - - Ok(()) -} - -fn load_file(fname: &str, buf: &mut [u8]) -> io::Result { - ax_println!("app: {}", fname); - let mut file = File::open(fname)?; - let n = file.read(buf)?; - Ok(n) -} diff --git a/arceos/exercises/simple_hv/src/main.rs b/arceos/exercises/simple_hv/src/main.rs deleted file mode 100644 index 788ad8ecf..000000000 --- a/arceos/exercises/simple_hv/src/main.rs +++ /dev/null @@ -1,146 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] -#![feature(asm_const)] -#![feature(riscv_ext_intrinsics)] - -#[cfg(feature = "axstd")] -extern crate axstd as std; -extern crate alloc; -#[macro_use] -extern crate axlog; - -mod task; -mod vcpu; -mod regs; -mod csrs; -mod sbi; -mod loader; - -use vcpu::VmCpuRegisters; -use riscv::register::{scause, sstatus, stval}; -use csrs::defs::hstatus; -use tock_registers::LocalRegisterCopy; -use csrs::{RiscvCsrTrait, CSR}; -use vcpu::_run_guest; -use sbi::SbiMessage; -use loader::load_vm_image; -use axhal::mem::PhysAddr; -use crate::regs::GprIndex::{A0, A1}; - -const VM_ENTRY: usize = 0x8020_0000; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - ax_println!("Hypervisor ..."); - - // A new address space for vm. - let mut uspace = axmm::new_user_aspace().unwrap(); - - // Load vm binary file into address space. - if let Err(e) = load_vm_image("/sbin/skernel2", &mut uspace) { - panic!("Cannot load app! {:?}", e); - } - - // Setup context to prepare to enter guest mode. - let mut ctx = VmCpuRegisters::default(); - prepare_guest_context(&mut ctx); - - // Setup pagetable for 2nd address mapping. - let ept_root = uspace.page_table_root(); - prepare_vm_pgtable(ept_root); - - // Kick off vm and wait for it to exit. - while !run_guest(&mut ctx) { - } - - panic!("Hypervisor ok!"); -} - -fn prepare_vm_pgtable(ept_root: PhysAddr) { - let hgatp = 8usize << 60 | usize::from(ept_root) >> 12; - unsafe { - core::arch::asm!( - "csrw hgatp, {hgatp}", - hgatp = in(reg) hgatp, - ); - core::arch::riscv64::hfence_gvma_all(); - } -} - -fn run_guest(ctx: &mut VmCpuRegisters) -> bool { - unsafe { - _run_guest(ctx); - } - - vmexit_handler(ctx) -} - -#[allow(unreachable_code)] -fn vmexit_handler(ctx: &mut VmCpuRegisters) -> bool { - use scause::{Exception, Trap}; - - let scause = scause::read(); - match scause.cause() { - Trap::Exception(Exception::VirtualSupervisorEnvCall) => { - let sbi_msg = SbiMessage::from_regs(ctx.guest_regs.gprs.a_regs()).ok(); - ax_println!("VmExit Reason: VSuperEcall: {:?}", sbi_msg); - if let Some(msg) = sbi_msg { - match msg { - SbiMessage::Reset(_) => { - let a0 = ctx.guest_regs.gprs.reg(A0); - let a1 = ctx.guest_regs.gprs.reg(A1); - ax_println!("a0 = {:#x}, a1 = {:#x}", a0, a1); - assert_eq!(a0, 0x6688); - assert_eq!(a1, 0x1234); - ax_println!("Shutdown vm normally!"); - return true; - }, - _ => todo!(), - } - } else { - panic!("bad sbi message! "); - } - }, - Trap::Exception(Exception::IllegalInstruction) => { - panic!("Bad instruction: {:#x} sepc: {:#x}", - stval::read(), - ctx.guest_regs.sepc - ); - }, - Trap::Exception(Exception::LoadGuestPageFault) => { - panic!("LoadGuestPageFault: stval{:#x} sepc: {:#x}", - stval::read(), - ctx.guest_regs.sepc - ); - }, - _ => { - panic!( - "Unhandled trap: {:?}, sepc: {:#x}, stval: {:#x}", - scause.cause(), - ctx.guest_regs.sepc, - stval::read() - ); - } - } - false -} - -fn prepare_guest_context(ctx: &mut VmCpuRegisters) { - // Set hstatus - let mut hstatus = LocalRegisterCopy::::new( - riscv::register::hstatus::read().bits(), - ); - // Set Guest bit in order to return to guest mode. - hstatus.modify(hstatus::spv::Guest); - // Set SPVP bit in order to accessing VS-mode memory from HS-mode. - hstatus.modify(hstatus::spvp::Supervisor); - CSR.hstatus.write_value(hstatus.get()); - ctx.guest_regs.hstatus = hstatus.get(); - - // Set sstatus in guest mode. - let mut sstatus = sstatus::read(); - sstatus.set_spp(sstatus::SPP::Supervisor); - ctx.guest_regs.sstatus = sstatus.bits(); - // Return to entry to start vm. - ctx.guest_regs.sepc = VM_ENTRY; -} diff --git a/arceos/exercises/simple_hv/src/regs.rs b/arceos/exercises/simple_hv/src/regs.rs deleted file mode 100644 index 5d7aadccc..000000000 --- a/arceos/exercises/simple_hv/src/regs.rs +++ /dev/null @@ -1,114 +0,0 @@ -#[derive(Default)] -#[repr(C)] -pub struct GeneralPurposeRegisters([usize; 32]); - -/// Index of risc-v general purpose registers in `GeneralPurposeRegisters`. -#[allow(missing_docs)] -#[repr(u32)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum GprIndex { - Zero = 0, - RA, - SP, - GP, - TP, - T0, - T1, - T2, - S0, - S1, - A0, - A1, - A2, - A3, - A4, - A5, - A6, - A7, - S2, - S3, - S4, - S5, - S6, - S7, - S8, - S9, - S10, - S11, - T3, - T4, - T5, - T6, -} - -impl GprIndex { - /// Get register index from raw value. - pub fn from_raw(raw: u32) -> Option { - use GprIndex::*; - let index = match raw { - 0 => Zero, - 1 => RA, - 2 => SP, - 3 => GP, - 4 => TP, - 5 => T0, - 6 => T1, - 7 => T2, - 8 => S0, - 9 => S1, - 10 => A0, - 11 => A1, - 12 => A2, - 13 => A3, - 14 => A4, - 15 => A5, - 16 => A6, - 17 => A7, - 18 => S2, - 19 => S3, - 20 => S4, - 21 => S5, - 22 => S6, - 23 => S7, - 24 => S8, - 25 => S9, - 26 => S10, - 27 => S11, - 28 => T3, - 29 => T4, - 30 => T5, - 31 => T6, - _ => { - return None; - } - }; - Some(index) - } -} - -impl GeneralPurposeRegisters { - /// Returns the value of the given register. - pub fn reg(&self, reg_index: GprIndex) -> usize { - self.0[reg_index as usize] - } - - /// Sets the value of the given register. - pub fn set_reg(&mut self, reg_index: GprIndex, val: usize) { - if reg_index == GprIndex::Zero { - return; - } - - self.0[reg_index as usize] = val; - } - - /// Returns the argument registers. - /// This is avoids many calls when an SBI handler needs all of the argmuent regs. - pub fn a_regs(&self) -> &[usize] { - &self.0[GprIndex::A0 as usize..=GprIndex::A7 as usize] - } - - /// Returns the arguments register as a mutable. - pub fn a_regs_mut(&mut self) -> &mut [usize] { - &mut self.0[GprIndex::A0 as usize..=GprIndex::A7 as usize] - } -} diff --git a/arceos/exercises/simple_hv/src/sbi/base.rs b/arceos/exercises/simple_hv/src/sbi/base.rs deleted file mode 100644 index 4fe4ba931..000000000 --- a/arceos/exercises/simple_hv/src/sbi/base.rs +++ /dev/null @@ -1,35 +0,0 @@ -use axerrno::{AxError, AxResult}; - -/// Functions defined for the Base extension -#[derive(Clone, Copy, Debug)] -pub enum BaseFunction { - /// Returns the implemented version of the SBI standard. - GetSepcificationVersion, - /// Returns the ID of the SBI implementation. - GetImplementationID, - /// Returns the version of the SBI implementation. - GetImplementationVersion, - /// Checks if the given SBI extension is supported. - ProbeSbiExtension(u64), - /// Returns the vendor that produced this machine(`mvendorid`). - GetMachineVendorID, - /// Returns the architecture implementation ID of this machine(`marchid`). - GetMachineArchitectureID, - /// Returns the ID of this machine(`mimpid`). - GetMachineImplementationID, -} - -impl BaseFunction { - pub(crate) fn from_regs(args: &[usize]) -> AxResult { - match args[6] { - 0 => Ok(BaseFunction::GetSepcificationVersion), - 1 => Ok(BaseFunction::GetImplementationID), - 2 => Ok(BaseFunction::GetImplementationVersion), - 3 => Ok(BaseFunction::ProbeSbiExtension(args[0] as u64)), - 4 => Ok(BaseFunction::GetMachineVendorID), - 5 => Ok(BaseFunction::GetMachineArchitectureID), - 6 => Ok(BaseFunction::GetMachineImplementationID), - _ => Err(AxError::NotFound), - } - } -} diff --git a/arceos/exercises/simple_hv/src/sbi/dbcn.rs b/arceos/exercises/simple_hv/src/sbi/dbcn.rs deleted file mode 100644 index cde124639..000000000 --- a/arceos/exercises/simple_hv/src/sbi/dbcn.rs +++ /dev/null @@ -1,11 +0,0 @@ -/// Functions for the Debug Console extension -#[derive(Copy, Clone, Debug)] -pub enum DebugConsoleFunction { - /// Prints the given string to the system console. - PutString { - /// The length of the string to print. - len: u64, - /// The address of the string. - addr: u64, - }, -} diff --git a/arceos/exercises/simple_hv/src/sbi/mod.rs b/arceos/exercises/simple_hv/src/sbi/mod.rs deleted file mode 100644 index 0e377e045..000000000 --- a/arceos/exercises/simple_hv/src/sbi/mod.rs +++ /dev/null @@ -1,90 +0,0 @@ -#![allow(dead_code)] - -mod base; -mod dbcn; -mod pmu; -mod rfnc; -mod srst; - -use axerrno::{AxError, AxResult}; -pub use base::BaseFunction; -use dbcn::DebugConsoleFunction; -pub use pmu::PmuFunction; -pub use rfnc::RemoteFenceFunction; -use sbi_spec; -pub use srst::ResetFunction; - -pub const SBI_SUCCESS: usize = 0; -pub const SBI_ERR_FAILUER: isize = -1; -pub const SBI_ERR_NOT_SUPPORTED: isize = -2; -pub const SBI_ERR_INAVLID_PARAM: isize = -3; -pub const SBI_ERR_DENIED: isize = -4; -pub const SBI_ERR_INVALID_ADDRESS: isize = -5; -pub const SBI_ERR_ALREADY_AVAILABLE: isize = -6; - -/// The values returned from an SBI function call. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct SbiReturn { - /// The error code(0 for success) - pub error_code: i64, - /// The return value if the operation is successful - pub return_value: i64, -} - -/// SBI return value conventions -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum SbiReturnTyoe { - /// Legacy(v0.1) extensions return a single value in A0, usually with the convention that 0 - /// is success and < 0 is an implementation defined error code. - Legacy(u64), - /// Modern extensions use the standard error code values enumerated above. - Standard(SbiReturn), -} - -/// SBI Message used to invoke the specfified SBI extension in the firmware. -#[derive(Clone, Copy, Debug)] -pub enum SbiMessage { - /// The base SBI extension functions. - Base(BaseFunction), - /// The legacy GetChar extension. - GetChar, - /// The legacy PutChar extension. - PutChar(usize), - /// The SetTimer Extension - SetTimer(usize), - /// Handles output to the console for debug - DebugConsole(DebugConsoleFunction), - /// Handles system reset - Reset(ResetFunction), - /// The RemoteFence Extension. - RemoteFence(RemoteFenceFunction), - /// The PMU Extension - PMU(PmuFunction), -} - -impl SbiMessage { - /// Creates an SbiMessage struct from the given GPRs. Intended for use from the ECALL handler - /// and passed the saved register state from the calling OS. A7 must contain a valid SBI - /// extension and the other A* registers will be interpreted based on the extension A7 selects. - pub fn from_regs(args: &[usize]) -> AxResult { - match args[7] { - sbi_spec::base::EID_BASE => BaseFunction::from_regs(args).map(SbiMessage::Base), - sbi_spec::legacy::LEGACY_CONSOLE_PUTCHAR => Ok(SbiMessage::PutChar(args[0])), - sbi_spec::legacy::LEGACY_CONSOLE_GETCHAR => Ok(SbiMessage::GetChar), - sbi_spec::legacy::LEGACY_SET_TIMER => Ok(SbiMessage::SetTimer(args[0])), - sbi_spec::legacy::LEGACY_SHUTDOWN => Ok(SbiMessage::Reset(ResetFunction::shutdown())), - sbi_spec::time::EID_TIME => Ok(SbiMessage::SetTimer(args[0])), - sbi_spec::srst::EID_SRST => ResetFunction::from_regs(args).map(SbiMessage::Reset), - sbi_spec::rfnc::EID_RFNC => { - RemoteFenceFunction::from_args(args).map(SbiMessage::RemoteFence) - } - sbi_spec::pmu::EID_PMU => PmuFunction::from_regs(args).map(SbiMessage::PMU), - _ => { - error!("args: {:?}", args); - error!("args[7]: {:#x}", args[7]); - error!("EID_RFENCE: {:#x}", sbi_spec::rfnc::EID_RFNC); - Err(AxError::NotFound) - } - } - } -} diff --git a/arceos/exercises/simple_hv/src/sbi/pmu.rs b/arceos/exercises/simple_hv/src/sbi/pmu.rs deleted file mode 100644 index 990d2780e..000000000 --- a/arceos/exercises/simple_hv/src/sbi/pmu.rs +++ /dev/null @@ -1,34 +0,0 @@ -use axerrno::AxResult; - -#[derive(Clone, Copy, Debug)] -pub enum PmuFunction { - /// Returns the total of performance counters (hardware and fireware). - GetNumCounters, - /// Returns information about hardware counter specified by the inner value. - GetCounterInfo(u64), - /// Stops the couters selected by counter_index and counter_mask. - /// See the sbi_pmu_counter_stop documentation for details. - StopCounter { - /// Countert index base. - counter_index: u64, - /// Counter index mask. - counter_mask: u64, - /// Counter stop flags. - stop_flags: u64, - }, -} - -impl PmuFunction { - pub(crate) fn from_regs(args: &[usize]) -> AxResult { - match args[6] { - 0 => Ok(Self::GetNumCounters), - 1 => Ok(Self::GetCounterInfo(args[0] as u64)), - 4 => Ok(Self::StopCounter { - counter_index: args[0] as u64, - counter_mask: args[1] as u64, - stop_flags: args[2] as u64, - }), - _ => panic!("Unsupported yet!"), - } - } -} diff --git a/arceos/exercises/simple_hv/src/sbi/rfnc.rs b/arceos/exercises/simple_hv/src/sbi/rfnc.rs deleted file mode 100644 index 249803462..000000000 --- a/arceos/exercises/simple_hv/src/sbi/rfnc.rs +++ /dev/null @@ -1,35 +0,0 @@ -use sbi_spec::rfnc::{REMOTE_FENCE_I, REMOTE_SFENCE_VMA}; - -use axerrno::AxResult; - -#[derive(Clone, Copy, Debug)] -pub enum RemoteFenceFunction { - FenceI { - hart_mask: u64, - hart_mask_base: u64, - }, - RemoteSFenceVMA { - hart_mask: u64, - hart_mask_base: u64, - start_addr: u64, - size: u64, - }, -} - -impl RemoteFenceFunction { - pub fn from_args(args: &[usize]) -> AxResult { - match args[6] { - REMOTE_FENCE_I => Ok(Self::FenceI { - hart_mask: args[0] as u64, - hart_mask_base: args[1] as u64, - }), - REMOTE_SFENCE_VMA => Ok(Self::RemoteSFenceVMA { - hart_mask: args[0] as u64, - hart_mask_base: args[1] as u64, - start_addr: args[2] as u64, - size: args[3] as u64, - }), - _ => panic!("Unsupported yet!"), - } - } -} diff --git a/arceos/exercises/simple_hv/src/sbi/srst.rs b/arceos/exercises/simple_hv/src/sbi/srst.rs deleted file mode 100644 index d6512ae93..000000000 --- a/arceos/exercises/simple_hv/src/sbi/srst.rs +++ /dev/null @@ -1,84 +0,0 @@ -use axerrno::{AxError, AxResult}; - -/// Functions for the Reset extension -#[derive(Copy, Clone, Debug)] -pub enum ResetFunction { - /// Performs a system reset. - Reset { - /// Determines the type of reset to perform. - reset_type: ResetType, - /// Represents the reason for system reset. - reason: ResetReason, - }, -} - -/// The types of reset a supervisor can request. -#[repr(usize)] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum ResetType { - /// Powers down the system. - Shutdown = 0, - /// Powers down, then reboots. - ColdReset = 1, - /// Reboots, doesn't power down. - WarmReset = 2, -} - -impl ResetType { - // Creates a reset type from the a0 register value or returns an error if no mapping is - // known for the given value. - fn from_reg(a0: usize) -> AxResult { - use ResetType::*; - Ok(match a0 { - 0 => Shutdown, - 1 => ColdReset, - 2 => WarmReset, - _ => return Err(AxError::InvalidInput), - }) - } -} - -/// Reasons why a supervisor requests a reset. -#[repr(u64)] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum ResetReason { - /// Used for normal resets. - NoReason = 0, - /// Used when the system has failed. - SystemFailure = 1, -} - -impl ResetReason { - // Creates a reset reason from the a1 register value or returns an error if no mapping is - // known for the given value. - fn from_reg(a1: usize) -> AxResult { - use ResetReason::*; - Ok(match a1 { - 0 => NoReason, - 1 => SystemFailure, - _ => return Err(AxError::InvalidInput), - }) - } -} -impl ResetFunction { - /// Attempts to parse `Self` from the passed in `a0-a7`. - pub(crate) fn from_regs(args: &[usize]) -> AxResult { - use ResetFunction::*; - - Ok(match args[6] { - 0 => Reset { - reset_type: ResetType::from_reg(args[0])?, - reason: ResetReason::from_reg(args[1])?, - }, - _ => return Err(AxError::InvalidInput), - }) - } - - /// Creates an operation to shutdown the machine. - pub fn shutdown() -> Self { - ResetFunction::Reset { - reset_type: ResetType::Shutdown, - reason: ResetReason::NoReason, - } - } -} diff --git a/arceos/exercises/simple_hv/src/task.rs b/arceos/exercises/simple_hv/src/task.rs deleted file mode 100644 index 8374f4fea..000000000 --- a/arceos/exercises/simple_hv/src/task.rs +++ /dev/null @@ -1,24 +0,0 @@ -use alloc::sync::Arc; - -use axmm::AddrSpace; -use axsync::Mutex; -use crate::vcpu::VmCpuRegisters; - -/// Task extended data for the monolithic kernel. -pub struct TaskExt { - /// The vcpu. - pub vcpu: VmCpuRegisters, - /// The virtual memory address space. - pub aspace: Arc>, -} - -impl TaskExt { - pub const fn new(vcpu: VmCpuRegisters, aspace: Arc>) -> Self { - Self { - vcpu, - aspace, - } - } -} - -axtask::def_task_ext!(TaskExt); diff --git a/arceos/exercises/simple_hv/src/vcpu.rs b/arceos/exercises/simple_hv/src/vcpu.rs deleted file mode 100644 index 6cdbe5cc1..000000000 --- a/arceos/exercises/simple_hv/src/vcpu.rs +++ /dev/null @@ -1,186 +0,0 @@ -use core::arch::global_asm; -use core::mem::size_of; - -use memoffset::offset_of; -use super::regs::{GeneralPurposeRegisters, GprIndex}; - -/// Hypervisor GPR and CSR state which must be saved/restored when entering/exiting virtualization. -#[derive(Default)] -#[repr(C)] -struct HypervisorCpuState { - gprs: GeneralPurposeRegisters, - sstatus: usize, - scounteren: usize, - stvec: usize, - sscratch: usize, -} - -/// Guest GPR and CSR state which must be saved/restored when exiting/entering virtualization. -#[derive(Default)] -#[repr(C)] -pub struct GuestCpuState { - pub gprs: GeneralPurposeRegisters, - pub sstatus: usize, - pub hstatus: usize, - pub scounteren: usize, - pub sepc: usize, -} - -/// The CSRs that are only in effect when virtualization is enabled (V=1) and must be saved and -/// restored whenever we switch between VMs. -#[derive(Default)] -#[repr(C)] -pub struct GuestVsCsrs { - htimedelta: usize, - vsstatus: usize, - vsie: usize, - vstvec: usize, - vsscratch: usize, - vsepc: usize, - vscause: usize, - vstval: usize, - vsatp: usize, - vstimecmp: usize, -} - -/// Virtualized HS-level CSRs that are used to emulate (part of) the hypervisor extension for the -/// guest. -#[derive(Default)] -#[repr(C)] -pub struct GuestVirtualHsCsrs { - hie: usize, - hgeie: usize, - hgatp: usize, -} - -/// CSRs written on an exit from virtualization that are used by the hypervisor to determine the cause -/// of the trap. -#[derive(Default, Clone)] -#[repr(C)] -pub struct VmCpuTrapState { - pub scause: usize, - pub stval: usize, - pub htval: usize, - pub htinst: usize, -} - -/// (v)CPU register state that must be saved or restored when entering/exiting a VM or switching -/// between VMs. -#[derive(Default)] -#[repr(C)] -pub struct VmCpuRegisters { - // CPU state that's shared between our's and the guest's execution environment. Saved/restored - // when entering/exiting a VM. - hyp_regs: HypervisorCpuState, - pub guest_regs: GuestCpuState, - - // CPU state that only applies when V=1, e.g. the VS-level CSRs. Saved/restored on activation of - // the vCPU. - vs_csrs: GuestVsCsrs, - - // Virtualized HS-level CPU state. - virtual_hs_csrs: GuestVirtualHsCsrs, - - // Read on VM exit. - pub trap_csrs: VmCpuTrapState, -} - -#[allow(dead_code)] -const fn hyp_gpr_offset(index: GprIndex) -> usize { - offset_of!(VmCpuRegisters, hyp_regs) - + offset_of!(HypervisorCpuState, gprs) - + (index as usize) * size_of::() -} - -#[allow(dead_code)] -const fn guest_gpr_offset(index: GprIndex) -> usize { - offset_of!(VmCpuRegisters, guest_regs) - + offset_of!(GuestCpuState, gprs) - + (index as usize) * size_of::() -} - -#[allow(unused_macros)] -macro_rules! hyp_csr_offset { - ($reg:tt) => { - offset_of!(VmCpuRegisters, hyp_regs) + offset_of!(HypervisorCpuState, $reg) - }; -} - -#[allow(unused_macros)] -macro_rules! guest_csr_offset { - ($reg:tt) => { - offset_of!(VmCpuRegisters, guest_regs) + offset_of!(GuestCpuState, $reg) - }; -} - -global_asm!( - include_str!("guest.S"), - hyp_ra = const hyp_gpr_offset(GprIndex::RA), - hyp_gp = const hyp_gpr_offset(GprIndex::GP), - hyp_tp = const hyp_gpr_offset(GprIndex::TP), - hyp_s0 = const hyp_gpr_offset(GprIndex::S0), - hyp_s1 = const hyp_gpr_offset(GprIndex::S1), - hyp_a1 = const hyp_gpr_offset(GprIndex::A1), - hyp_a2 = const hyp_gpr_offset(GprIndex::A2), - hyp_a3 = const hyp_gpr_offset(GprIndex::A3), - hyp_a4 = const hyp_gpr_offset(GprIndex::A4), - hyp_a5 = const hyp_gpr_offset(GprIndex::A5), - hyp_a6 = const hyp_gpr_offset(GprIndex::A6), - hyp_a7 = const hyp_gpr_offset(GprIndex::A7), - hyp_s2 = const hyp_gpr_offset(GprIndex::S2), - hyp_s3 = const hyp_gpr_offset(GprIndex::S3), - hyp_s4 = const hyp_gpr_offset(GprIndex::S4), - hyp_s5 = const hyp_gpr_offset(GprIndex::S5), - hyp_s6 = const hyp_gpr_offset(GprIndex::S6), - hyp_s7 = const hyp_gpr_offset(GprIndex::S7), - hyp_s8 = const hyp_gpr_offset(GprIndex::S8), - hyp_s9 = const hyp_gpr_offset(GprIndex::S9), - hyp_s10 = const hyp_gpr_offset(GprIndex::S10), - hyp_s11 = const hyp_gpr_offset(GprIndex::S11), - hyp_sp = const hyp_gpr_offset(GprIndex::SP), - hyp_sstatus = const hyp_csr_offset!(sstatus), - hyp_scounteren = const hyp_csr_offset!(scounteren), - hyp_stvec = const hyp_csr_offset!(stvec), - hyp_sscratch = const hyp_csr_offset!(sscratch), - guest_ra = const guest_gpr_offset(GprIndex::RA), - guest_gp = const guest_gpr_offset(GprIndex::GP), - guest_tp = const guest_gpr_offset(GprIndex::TP), - guest_s0 = const guest_gpr_offset(GprIndex::S0), - guest_s1 = const guest_gpr_offset(GprIndex::S1), - guest_a0 = const guest_gpr_offset(GprIndex::A0), - guest_a1 = const guest_gpr_offset(GprIndex::A1), - guest_a2 = const guest_gpr_offset(GprIndex::A2), - guest_a3 = const guest_gpr_offset(GprIndex::A3), - guest_a4 = const guest_gpr_offset(GprIndex::A4), - guest_a5 = const guest_gpr_offset(GprIndex::A5), - guest_a6 = const guest_gpr_offset(GprIndex::A6), - guest_a7 = const guest_gpr_offset(GprIndex::A7), - guest_s2 = const guest_gpr_offset(GprIndex::S2), - guest_s3 = const guest_gpr_offset(GprIndex::S3), - guest_s4 = const guest_gpr_offset(GprIndex::S4), - guest_s5 = const guest_gpr_offset(GprIndex::S5), - guest_s6 = const guest_gpr_offset(GprIndex::S6), - guest_s7 = const guest_gpr_offset(GprIndex::S7), - guest_s8 = const guest_gpr_offset(GprIndex::S8), - guest_s9 = const guest_gpr_offset(GprIndex::S9), - guest_s10 = const guest_gpr_offset(GprIndex::S10), - guest_s11 = const guest_gpr_offset(GprIndex::S11), - guest_t0 = const guest_gpr_offset(GprIndex::T0), - guest_t1 = const guest_gpr_offset(GprIndex::T1), - guest_t2 = const guest_gpr_offset(GprIndex::T2), - guest_t3 = const guest_gpr_offset(GprIndex::T3), - guest_t4 = const guest_gpr_offset(GprIndex::T4), - guest_t5 = const guest_gpr_offset(GprIndex::T5), - guest_t6 = const guest_gpr_offset(GprIndex::T6), - guest_sp = const guest_gpr_offset(GprIndex::SP), - - guest_sstatus = const guest_csr_offset!(sstatus), - guest_hstatus = const guest_csr_offset!(hstatus), - guest_scounteren = const guest_csr_offset!(scounteren), - guest_sepc = const guest_csr_offset!(sepc), - -); - -extern "C" { - pub fn _run_guest(state: *mut VmCpuRegisters); -} diff --git a/arceos/exercises/support_hashmap/Cargo.toml b/arceos/exercises/support_hashmap/Cargo.toml deleted file mode 100644 index 62d5a0727..000000000 --- a/arceos/exercises/support_hashmap/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "support_hashmap" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc"], optional = true } diff --git a/arceos/exercises/support_hashmap/src/main.rs b/arceos/exercises/support_hashmap/src/main.rs deleted file mode 100644 index 4c19a3602..000000000 --- a/arceos/exercises/support_hashmap/src/main.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; - -use std::collections::HashMap; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - println!("Running memory tests..."); - test_hashmap(); - println!("Memory tests run OK!"); -} - -fn test_hashmap() { - const N: u32 = 50_000; - let mut m = HashMap::new(); - for value in 0..N { - let key = format!("key_{value}"); - m.insert(key, value); - } - for (k, v) in m.iter() { - if let Some(k) = k.strip_prefix("key_") { - assert_eq!(k.parse::().unwrap(), *v); - } - } - println!("test_hashmap() OK!"); -} diff --git a/arceos/exercises/sys_map/Cargo.toml b/arceos/exercises/sys_map/Cargo.toml deleted file mode 100644 index 0ea968b75..000000000 --- a/arceos/exercises/sys_map/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "sys_map" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask", "sched_cfs", "fs"], optional = true } -axmm = { workspace = true } -axhal = { workspace = true, features = ["uspace"] } -axsync = { workspace = true } -axtask = { workspace = true } -axlog = { workspace = true } -elf = { workspace = true } -axerrno = "0.1" -linkme = "0.3" -kernel-elf-parser = "0.1.0" -arceos_posix_api = { workspace = true } -bitflags = "2.6" -memory_addr = "0.3" diff --git a/arceos/exercises/sys_map/src/loader.rs b/arceos/exercises/sys_map/src/loader.rs deleted file mode 100644 index f95f8f5f8..000000000 --- a/arceos/exercises/sys_map/src/loader.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::io::{self, Read}; -use std::io::SeekFrom; -use std::io::Seek; -use std::fs::File; -use alloc::vec::Vec; -use alloc::vec; -use axhal::paging::MappingFlags; -use axhal::mem::{PAGE_SIZE_4K, VirtAddr, MemoryAddr}; -use axmm::AddrSpace; - -use elf::abi::{PT_INTERP, PT_LOAD}; -use elf::endian::AnyEndian; -use elf::parse::ParseAt; -use elf::segment::ProgramHeader; -use elf::segment::SegmentTable; -use elf::ElfBytes; - -const ELF_HEAD_BUF_SIZE: usize = 256; - -pub fn load_user_app(fname: &str, uspace: &mut AddrSpace) -> io::Result { - let mut file = File::open(fname)?; - let (phdrs, entry, _, _) = load_elf_phdrs(&mut file)?; - - for phdr in &phdrs { - ax_println!( - "phdr: offset: {:#X}=>{:#X} size: {:#X}=>{:#X}", - phdr.p_offset, phdr.p_vaddr, phdr.p_filesz, phdr.p_memsz - ); - - let vaddr = VirtAddr::from(phdr.p_vaddr as usize).align_down_4k(); - let vaddr_end = VirtAddr::from((phdr.p_vaddr+phdr.p_memsz) as usize) - .align_up_4k(); - - ax_println!("{:#x} - {:#x}", vaddr, vaddr_end); - uspace.map_alloc(vaddr, vaddr_end-vaddr, MappingFlags::READ|MappingFlags::WRITE|MappingFlags::EXECUTE|MappingFlags::USER, true)?; - - let mut data = vec![0u8; phdr.p_memsz as usize]; - file.seek(SeekFrom::Start(phdr.p_offset))?; - - let filesz = phdr.p_filesz as usize; - let mut index = 0; - while index < filesz { - let n = file.read(&mut data[index..filesz])?; - index += n; - } - assert_eq!(index, filesz); - uspace.write(VirtAddr::from(phdr.p_vaddr as usize), &data)?; - } - - Ok(entry) -} - -fn load_elf_phdrs(file: &mut File) -> io::Result<(Vec, usize, usize, usize)> { - let mut buf: [u8; ELF_HEAD_BUF_SIZE] = [0; ELF_HEAD_BUF_SIZE]; - file.read(&mut buf)?; - - let ehdr = ElfBytes::::parse_elf_header(&buf[..]).unwrap(); - info!("e_entry: {:#X}", ehdr.e_entry); - - let phnum = ehdr.e_phnum as usize; - // Validate phentsize before trying to read the table so that we can error early for corrupted files - let entsize = ProgramHeader::validate_entsize(ehdr.class, ehdr.e_phentsize as usize).unwrap(); - let size = entsize.checked_mul(phnum).unwrap(); - assert!(size > 0 && size <= PAGE_SIZE_4K); - let phoff = ehdr.e_phoff; - let mut buf = alloc::vec![0u8; size]; - let _ = file.seek(SeekFrom::Start(phoff)); - file.read(&mut buf)?; - let phdrs = SegmentTable::new(ehdr.endianness, ehdr.class, &buf[..]); - - let phdrs: Vec = phdrs - .iter() - .filter(|phdr| phdr.p_type == PT_LOAD || phdr.p_type == PT_INTERP) - .collect(); - Ok((phdrs, ehdr.e_entry as usize, ehdr.e_phoff as usize, ehdr.e_phnum as usize)) -} diff --git a/arceos/exercises/sys_map/src/main.rs b/arceos/exercises/sys_map/src/main.rs deleted file mode 100644 index 18614ea0c..000000000 --- a/arceos/exercises/sys_map/src/main.rs +++ /dev/null @@ -1,82 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[cfg(feature = "axstd")] -extern crate axstd as std; -extern crate alloc; - -#[macro_use] -extern crate axlog; - -mod task; -mod syscall; -mod loader; - -use axstd::io; -use axhal::paging::MappingFlags; -use axhal::arch::UspaceContext; -use axhal::mem::VirtAddr; -use axsync::Mutex; -use alloc::sync::Arc; -use alloc::string::String; -use alloc::collections::BTreeMap; -use axmm::AddrSpace; -use loader::load_user_app; - -const USER_STACK_SIZE: usize = 0x10000; -const KERNEL_STACK_SIZE: usize = 0x40000; // 256 KiB - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - // A new address space for user app. - let mut uspace = axmm::new_user_aspace().unwrap(); - - // Load user app binary file into address space. - let entry = match load_user_app("/sbin/mapfile", &mut uspace) { - Ok(e) => e, - Err(err) => panic!("Cannot load app! {:?}", err), - }; - ax_println!("entry: {:#x}", entry); - - // Init user stack. - let ustack_top = init_user_stack(&mut uspace, true).unwrap(); - ax_println!("New user address space: {:#x?}", uspace); - - // Let's kick off the user process. - let user_task = task::spawn_user_task( - Arc::new(Mutex::new(uspace)), - UspaceContext::new(entry, ustack_top), - ); - - // Wait for user process to exit ... - let exit_code = user_task.join(); - ax_println!("monolithic kernel exit [{:?}] normally!", exit_code); -} - -fn init_user_stack(uspace: &mut AddrSpace, populating: bool) -> io::Result { - let ustack_top = uspace.end(); - let ustack_vaddr = ustack_top - crate::USER_STACK_SIZE; - ax_println!( - "Mapping user stack: {:#x?} -> {:#x?}", - ustack_vaddr, ustack_top - ); - uspace.map_alloc( - ustack_vaddr, - crate::USER_STACK_SIZE, - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER, - populating, - ).unwrap(); - - let app_name = "hello"; - let av = BTreeMap::new(); - let (stack_data, ustack_pointer) = kernel_elf_parser::get_app_stack_region( - &[String::from(app_name)], - &[], - &av, - ustack_vaddr, - crate::USER_STACK_SIZE, - ); - uspace.write(VirtAddr::from_usize(ustack_pointer), stack_data.as_slice())?; - - Ok(ustack_pointer.into()) -} diff --git a/arceos/exercises/sys_map/src/syscall.rs b/arceos/exercises/sys_map/src/syscall.rs deleted file mode 100644 index 83b98d5e7..000000000 --- a/arceos/exercises/sys_map/src/syscall.rs +++ /dev/null @@ -1,176 +0,0 @@ -#![allow(dead_code)] - -use core::ffi::{c_void, c_char, c_int}; -use axhal::arch::TrapFrame; -use axhal::trap::{register_trap_handler, SYSCALL}; -use axerrno::LinuxError; -use axtask::current; -use axtask::TaskExtRef; -use axhal::paging::MappingFlags; -use arceos_posix_api as api; - -const SYS_IOCTL: usize = 29; -const SYS_OPENAT: usize = 56; -const SYS_CLOSE: usize = 57; -const SYS_READ: usize = 63; -const SYS_WRITE: usize = 64; -const SYS_WRITEV: usize = 66; -const SYS_EXIT: usize = 93; -const SYS_EXIT_GROUP: usize = 94; -const SYS_SET_TID_ADDRESS: usize = 96; -const SYS_MMAP: usize = 222; - -const AT_FDCWD: i32 = -100; - -/// Macro to generate syscall body -/// -/// It will receive a function which return Result<_, LinuxError> and convert it to -/// the type which is specified by the caller. -#[macro_export] -macro_rules! syscall_body { - ($fn: ident, $($stmt: tt)*) => {{ - #[allow(clippy::redundant_closure_call)] - let res = (|| -> axerrno::LinuxResult<_> { $($stmt)* })(); - match res { - Ok(_) | Err(axerrno::LinuxError::EAGAIN) => debug!(concat!(stringify!($fn), " => {:?}"), res), - Err(_) => info!(concat!(stringify!($fn), " => {:?}"), res), - } - match res { - Ok(v) => v as _, - Err(e) => { - -e.code() as _ - } - } - }}; -} - -bitflags::bitflags! { - #[derive(Debug)] - /// permissions for sys_mmap - /// - /// See - struct MmapProt: i32 { - /// Page can be read. - const PROT_READ = 1 << 0; - /// Page can be written. - const PROT_WRITE = 1 << 1; - /// Page can be executed. - const PROT_EXEC = 1 << 2; - } -} - -impl From for MappingFlags { - fn from(value: MmapProt) -> Self { - let mut flags = MappingFlags::USER; - if value.contains(MmapProt::PROT_READ) { - flags |= MappingFlags::READ; - } - if value.contains(MmapProt::PROT_WRITE) { - flags |= MappingFlags::WRITE; - } - if value.contains(MmapProt::PROT_EXEC) { - flags |= MappingFlags::EXECUTE; - } - flags - } -} - -bitflags::bitflags! { - #[derive(Debug)] - /// flags for sys_mmap - /// - /// See - struct MmapFlags: i32 { - /// Share changes - const MAP_SHARED = 1 << 0; - /// Changes private; copy pages on write. - const MAP_PRIVATE = 1 << 1; - /// Map address must be exactly as requested, no matter whether it is available. - const MAP_FIXED = 1 << 4; - /// Don't use a file. - const MAP_ANONYMOUS = 1 << 5; - /// Don't check for reservations. - const MAP_NORESERVE = 1 << 14; - /// Allocation is for a stack. - const MAP_STACK = 0x20000; - } -} - -#[register_trap_handler(SYSCALL)] -fn handle_syscall(tf: &TrapFrame, syscall_num: usize) -> isize { - ax_println!("handle_syscall [{}] ...", syscall_num); - let ret = match syscall_num { - SYS_IOCTL => sys_ioctl(tf.arg0() as _, tf.arg1() as _, tf.arg2() as _) as _, - SYS_SET_TID_ADDRESS => sys_set_tid_address(tf.arg0() as _), - SYS_OPENAT => sys_openat(tf.arg0() as _, tf.arg1() as _, tf.arg2() as _, tf.arg3() as _), - SYS_CLOSE => sys_close(tf.arg0() as _), - SYS_READ => sys_read(tf.arg0() as _, tf.arg1() as _, tf.arg2() as _), - SYS_WRITE => sys_write(tf.arg0() as _, tf.arg1() as _, tf.arg2() as _), - SYS_WRITEV => sys_writev(tf.arg0() as _, tf.arg1() as _, tf.arg2() as _), - SYS_EXIT_GROUP => { - ax_println!("[SYS_EXIT_GROUP]: system is exiting .."); - axtask::exit(tf.arg0() as _) - }, - SYS_EXIT => { - ax_println!("[SYS_EXIT]: system is exiting .."); - axtask::exit(tf.arg0() as _) - }, - SYS_MMAP => sys_mmap( - tf.arg0() as _, - tf.arg1() as _, - tf.arg2() as _, - tf.arg3() as _, - tf.arg4() as _, - tf.arg5() as _, - ), - _ => { - ax_println!("Unimplemented syscall: {}", syscall_num); - -LinuxError::ENOSYS.code() as _ - } - }; - ret -} - -#[allow(unused_variables)] -fn sys_mmap( - addr: *mut usize, - length: usize, - prot: i32, - flags: i32, - fd: i32, - _offset: isize, -) -> isize { - unimplemented!("no sys_mmap!"); -} - -fn sys_openat(dfd: c_int, fname: *const c_char, flags: c_int, mode: api::ctypes::mode_t) -> isize { - assert_eq!(dfd, AT_FDCWD); - api::sys_open(fname, flags, mode) as isize -} - -fn sys_close(fd: i32) -> isize { - api::sys_close(fd) as isize -} - -fn sys_read(fd: i32, buf: *mut c_void, count: usize) -> isize { - api::sys_read(fd, buf, count) -} - -fn sys_write(fd: i32, buf: *const c_void, count: usize) -> isize { - api::sys_write(fd, buf, count) -} - -fn sys_writev(fd: i32, iov: *const api::ctypes::iovec, iocnt: i32) -> isize { - unsafe { api::sys_writev(fd, iov, iocnt) } -} - -fn sys_set_tid_address(tid_ptd: *const i32) -> isize { - let curr = current(); - curr.task_ext().set_clear_child_tid(tid_ptd as _); - curr.id().as_u64() as isize -} - -fn sys_ioctl(_fd: i32, _op: usize, _argp: *mut c_void) -> i32 { - ax_println!("Ignore SYS_IOCTL"); - 0 -} diff --git a/arceos/exercises/sys_map/src/task.rs b/arceos/exercises/sys_map/src/task.rs deleted file mode 100644 index d5372dd6a..000000000 --- a/arceos/exercises/sys_map/src/task.rs +++ /dev/null @@ -1,71 +0,0 @@ -#![allow(dead_code)] - -use core::sync::atomic::AtomicU64; - -use alloc::sync::Arc; - -use axhal::arch::UspaceContext; -use axmm::AddrSpace; -use axsync::Mutex; -use axtask::{AxTaskRef, TaskExtRef, TaskInner}; - -/// Task extended data for the monolithic kernel. -pub struct TaskExt { - /// The process ID. - pub proc_id: usize, - /// The clear thread tid field - /// - /// See - /// - /// When the thread exits, the kernel clears the word at this address if it is not NULL. - clear_child_tid: AtomicU64, - /// The user space context. - pub uctx: UspaceContext, - /// The virtual memory address space. - pub aspace: Arc>, -} - -impl TaskExt { - pub const fn new(uctx: UspaceContext, aspace: Arc>) -> Self { - Self { - proc_id: 233, - uctx, - clear_child_tid: AtomicU64::new(0), - aspace, - } - } - - pub(crate) fn clear_child_tid(&self) -> u64 { - self.clear_child_tid - .load(core::sync::atomic::Ordering::Relaxed) - } - - pub(crate) fn set_clear_child_tid(&self, clear_child_tid: u64) { - self.clear_child_tid - .store(clear_child_tid, core::sync::atomic::Ordering::Relaxed); - } -} - -axtask::def_task_ext!(TaskExt); - -pub fn spawn_user_task(aspace: Arc>, uctx: UspaceContext) -> AxTaskRef { - let mut task = TaskInner::new( - || { - let curr = axtask::current(); - let kstack_top = curr.kernel_stack_top().unwrap(); - info!( - "Enter user space: entry={:#x}, ustack={:#x}, kstack={:#x}", - curr.task_ext().uctx.get_ip(), - curr.task_ext().uctx.get_sp(), - kstack_top, - ); - unsafe { curr.task_ext().uctx.enter_uspace(kstack_top) }; - }, - "userboot".into(), - crate::KERNEL_STACK_SIZE, - ); - task.ctx_mut() - .set_page_table_root(aspace.lock().page_table_root()); - task.init_task_ext(TaskExt::new(uctx, aspace)); - axtask::spawn_task(task) -} diff --git a/arceos/modules/alt_axalloc/Cargo.toml b/arceos/modules/alt_axalloc/Cargo.toml deleted file mode 100644 index 5ca6594d8..000000000 --- a/arceos/modules/alt_axalloc/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "alt_axalloc" -version.workspace = true -edition = "2021" - -[features] -default = [] - -[dependencies] -log = "0.4.21" -cfg-if = "1.0" -kspin = "0.1" -memory_addr = "0.3" -axerrno = "0.1" -allocator = { git = "https://github.com/arceos-org/allocator.git", tag ="v0.1.0", features = ["bitmap"] } -bump_allocator = { path = "../bump_allocator" } diff --git a/arceos/modules/alt_axalloc/src/lib.rs b/arceos/modules/alt_axalloc/src/lib.rs deleted file mode 100644 index a33d4e051..000000000 --- a/arceos/modules/alt_axalloc/src/lib.rs +++ /dev/null @@ -1,121 +0,0 @@ -#![no_std] - -#[macro_use] -extern crate log; -extern crate alloc; - -use allocator::{AllocResult, BaseAllocator, ByteAllocator, PageAllocator}; -use bump_allocator::EarlyAllocator; -use core::alloc::{GlobalAlloc, Layout}; -use core::ptr::NonNull; -use kspin::SpinNoIrq; - -const PAGE_SIZE: usize = 0x1000; - -/// The global allocator used by ArceOS. -pub struct GlobalAllocator { - inner: SpinNoIrq>, -} - -impl GlobalAllocator { - /// Creates an empty [`GlobalAllocator`]. - pub const fn new() -> Self { - Self { - inner: SpinNoIrq::new(EarlyAllocator::new()), - } - } - - /// Returns the name of the allocator. - pub const fn name(&self) -> &'static str { - "early" - } - - /// Initializes the allocator with the given region. - pub fn init(&self, start_vaddr: usize, size: usize) { - self.inner.lock().init(start_vaddr, size); - } - - /// Add the given region to the allocator. - pub fn add_memory(&self, _start_vaddr: usize, _size: usize) -> AllocResult { - unimplemented!() - } - - /// Allocate arbitrary number of bytes. Returns the left bound of the - /// allocated region. - pub fn alloc(&self, layout: Layout) -> AllocResult> { - self.inner.lock().alloc(layout) - } - - /// Gives back the allocated region to the byte allocator. - pub fn dealloc(&self, pos: NonNull, layout: Layout) { - self.inner.lock().dealloc(pos, layout) - } - - /// Allocates contiguous pages. - pub fn alloc_pages(&self, num_pages: usize, align_pow2: usize) -> AllocResult { - self.inner.lock().alloc_pages(num_pages, align_pow2) - } - - /// Gives back the allocated pages starts from `pos` to the page allocator. - /// [`alloc_pages`]: GlobalAllocator::alloc_pages - pub fn dealloc_pages(&self, pos: usize, num_pages: usize) { - self.inner.lock().dealloc_pages(pos, num_pages) - } - - /// Returns the number of allocated bytes in the byte allocator. - pub fn used_bytes(&self) -> usize { - self.inner.lock().used_bytes() - } - - /// Returns the number of available bytes in the byte allocator. - pub fn available_bytes(&self) -> usize { - self.inner.lock().available_bytes() - } - - /// Returns the number of allocated pages in the page allocator. - pub fn used_pages(&self) -> usize { - self.inner.lock().used_pages() - } - - /// Returns the number of available pages in the page allocator. - pub fn available_pages(&self) -> usize { - self.inner.lock().available_pages() - } -} - -unsafe impl GlobalAlloc for GlobalAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - if let Ok(ptr) = GlobalAllocator::alloc(self, layout) { - ptr.as_ptr() - } else { - alloc::alloc::handle_alloc_error(layout) - } - } - - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - GlobalAllocator::dealloc(self, NonNull::new(ptr).expect("dealloc null ptr"), layout) - } -} - -#[cfg_attr(all(target_os = "none", not(test)), global_allocator)] -static GLOBAL_ALLOCATOR: GlobalAllocator = GlobalAllocator::new(); - -/// Returns the reference to the global allocator. -pub fn global_allocator() -> &'static GlobalAllocator { - &GLOBAL_ALLOCATOR -} - -/// Initializes the global allocator with the given memory region. -pub fn global_init(start_vaddr: usize, size: usize) { - debug!( - "initialize global allocator at: [{:#x}, {:#x})", - start_vaddr, - start_vaddr + size - ); - GLOBAL_ALLOCATOR.init(start_vaddr, size); -} - -/// Add the given memory region to the global allocator. -pub fn global_add_memory(_start_vaddr: usize, _size: usize) -> AllocResult { - unimplemented!() -} diff --git a/arceos/modules/axalloc/Cargo.toml b/arceos/modules/axalloc/Cargo.toml deleted file mode 100644 index 2402d425f..000000000 --- a/arceos/modules/axalloc/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "axalloc" -version.workspace = true -edition = "2021" -authors = ["Yuekai Jia "] -description = "ArceOS global memory allocator" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/modules/axalloc" -documentation = "https://arceos-org.github.io/arceos/axalloc/index.html" - -[features] -default = ["tlsf"] -tlsf = ["allocator/tlsf"] -slab = ["allocator/slab"] -buddy = ["allocator/buddy"] - -[dependencies] -log = "0.4.21" -cfg-if = "1.0" -kspin = "0.1" -memory_addr = "0.3" -axerrno = "0.1" -allocator = { git = "https://github.com/arceos-org/allocator.git", tag ="v0.1.0", features = ["bitmap"] } diff --git a/arceos/modules/axalloc/src/lib.rs b/arceos/modules/axalloc/src/lib.rs deleted file mode 100644 index ef6f0f6c9..000000000 --- a/arceos/modules/axalloc/src/lib.rs +++ /dev/null @@ -1,233 +0,0 @@ -//! [ArceOS](https://github.com/arceos-org/arceos) global memory allocator. -//! -//! It provides [`GlobalAllocator`], which implements the trait -//! [`core::alloc::GlobalAlloc`]. A static global variable of type -//! [`GlobalAllocator`] is defined with the `#[global_allocator]` attribute, to -//! be registered as the standard library’s default allocator. - -#![no_std] - -#[macro_use] -extern crate log; -extern crate alloc; - -mod page; - -use allocator::{AllocResult, BaseAllocator, BitmapPageAllocator, ByteAllocator, PageAllocator}; -use core::alloc::{GlobalAlloc, Layout}; -use core::ptr::NonNull; -use kspin::SpinNoIrq; - -const PAGE_SIZE: usize = 0x1000; -const MIN_HEAP_SIZE: usize = 0x8000; // 32 K - -pub use page::GlobalPage; - -cfg_if::cfg_if! { - if #[cfg(feature = "slab")] { - /// The default byte allocator. - pub type DefaultByteAllocator = allocator::SlabByteAllocator; - } else if #[cfg(feature = "buddy")] { - /// The default byte allocator. - pub type DefaultByteAllocator = allocator::BuddyByteAllocator; - } else if #[cfg(feature = "tlsf")] { - /// The default byte allocator. - pub type DefaultByteAllocator = allocator::TlsfByteAllocator; - } -} - -/// The global allocator used by ArceOS. -/// -/// It combines a [`ByteAllocator`] and a [`PageAllocator`] into a simple -/// two-level allocator: firstly tries allocate from the byte allocator, if -/// there is no memory, asks the page allocator for more memory and adds it to -/// the byte allocator. -/// -/// Currently, [`TlsfByteAllocator`] is used as the byte allocator, while -/// [`BitmapPageAllocator`] is used as the page allocator. -/// -/// [`TlsfByteAllocator`]: allocator::TlsfByteAllocator -pub struct GlobalAllocator { - balloc: SpinNoIrq, - palloc: SpinNoIrq>, -} - -impl GlobalAllocator { - /// Creates an empty [`GlobalAllocator`]. - pub const fn new() -> Self { - Self { - balloc: SpinNoIrq::new(DefaultByteAllocator::new()), - palloc: SpinNoIrq::new(BitmapPageAllocator::new()), - } - } - - /// Returns the name of the allocator. - pub const fn name(&self) -> &'static str { - cfg_if::cfg_if! { - if #[cfg(feature = "slab")] { - "slab" - } else if #[cfg(feature = "buddy")] { - "buddy" - } else if #[cfg(feature = "tlsf")] { - "TLSF" - } - } - } - - /// Initializes the allocator with the given region. - /// - /// It firstly adds the whole region to the page allocator, then allocates - /// a small region (32 KB) to initialize the byte allocator. Therefore, - /// the given region must be larger than 32 KB. - pub fn init(&self, start_vaddr: usize, size: usize) { - assert!(size > MIN_HEAP_SIZE); - let init_heap_size = MIN_HEAP_SIZE; - self.palloc.lock().init(start_vaddr, size); - let heap_ptr = self - .alloc_pages(init_heap_size / PAGE_SIZE, PAGE_SIZE) - .unwrap(); - self.balloc.lock().init(heap_ptr, init_heap_size); - } - - /// Add the given region to the allocator. - /// - /// It will add the whole region to the byte allocator. - pub fn add_memory(&self, start_vaddr: usize, size: usize) -> AllocResult { - self.balloc.lock().add_memory(start_vaddr, size) - } - - /// Allocate arbitrary number of bytes. Returns the left bound of the - /// allocated region. - /// - /// It firstly tries to allocate from the byte allocator. If there is no - /// memory, it asks the page allocator for more memory and adds it to the - /// byte allocator. - pub fn alloc(&self, layout: Layout) -> AllocResult> { - // simple two-level allocator: if no heap memory, allocate from the page allocator. - let mut balloc = self.balloc.lock(); - loop { - if let Ok(ptr) = balloc.alloc(layout) { - return Ok(ptr); - } else { - let old_size = balloc.total_bytes(); - let expand_size = old_size - .max(layout.size()) - .next_power_of_two() - .max(PAGE_SIZE); - let heap_ptr = self.alloc_pages(expand_size / PAGE_SIZE, PAGE_SIZE)?; - debug!( - "expand heap memory: [{:#x}, {:#x})", - heap_ptr, - heap_ptr + expand_size - ); - balloc.add_memory(heap_ptr, expand_size)?; - } - } - } - - /// Gives back the allocated region to the byte allocator. - /// - /// The region should be allocated by [`alloc`], and `align_pow2` should be - /// the same as the one used in [`alloc`]. Otherwise, the behavior is - /// undefined. - /// - /// [`alloc`]: GlobalAllocator::alloc - pub fn dealloc(&self, pos: NonNull, layout: Layout) { - self.balloc.lock().dealloc(pos, layout) - } - - /// Allocates contiguous pages. - /// - /// It allocates `num_pages` pages from the page allocator. - /// - /// `align_pow2` must be a power of 2, and the returned region bound will be - /// aligned to it. - pub fn alloc_pages(&self, num_pages: usize, align_pow2: usize) -> AllocResult { - self.palloc.lock().alloc_pages(num_pages, align_pow2) - } - - /// Gives back the allocated pages starts from `pos` to the page allocator. - /// - /// The pages should be allocated by [`alloc_pages`], and `align_pow2` - /// should be the same as the one used in [`alloc_pages`]. Otherwise, the - /// behavior is undefined. - /// - /// [`alloc_pages`]: GlobalAllocator::alloc_pages - pub fn dealloc_pages(&self, pos: usize, num_pages: usize) { - self.palloc.lock().dealloc_pages(pos, num_pages) - } - - /// Returns the number of allocated bytes in the byte allocator. - pub fn used_bytes(&self) -> usize { - self.balloc.lock().used_bytes() - } - - /// Returns the number of available bytes in the byte allocator. - pub fn available_bytes(&self) -> usize { - self.balloc.lock().available_bytes() - } - - /// Returns the number of allocated pages in the page allocator. - pub fn used_pages(&self) -> usize { - self.palloc.lock().used_pages() - } - - /// Returns the number of available pages in the page allocator. - pub fn available_pages(&self) -> usize { - self.palloc.lock().available_pages() - } -} - -unsafe impl GlobalAlloc for GlobalAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - if let Ok(ptr) = GlobalAllocator::alloc(self, layout) { - ptr.as_ptr() - } else { - alloc::alloc::handle_alloc_error(layout) - } - } - - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - GlobalAllocator::dealloc(self, NonNull::new(ptr).expect("dealloc null ptr"), layout) - } -} - -#[cfg_attr(all(target_os = "none", not(test)), global_allocator)] -static GLOBAL_ALLOCATOR: GlobalAllocator = GlobalAllocator::new(); - -/// Returns the reference to the global allocator. -pub fn global_allocator() -> &'static GlobalAllocator { - &GLOBAL_ALLOCATOR -} - -/// Initializes the global allocator with the given memory region. -/// -/// Note that the memory region bounds are just numbers, and the allocator -/// does not actually access the region. Users should ensure that the region -/// is valid and not being used by others, so that the allocated memory is also -/// valid. -/// -/// This function should be called only once, and before any allocation. -pub fn global_init(start_vaddr: usize, size: usize) { - debug!( - "initialize global allocator at: [{:#x}, {:#x})", - start_vaddr, - start_vaddr + size - ); - GLOBAL_ALLOCATOR.init(start_vaddr, size); -} - -/// Add the given memory region to the global allocator. -/// -/// Users should ensure that the region is valid and not being used by others, -/// so that the allocated memory is also valid. -/// -/// It's similar to [`global_init`], but can be called multiple times. -pub fn global_add_memory(start_vaddr: usize, size: usize) -> AllocResult { - debug!( - "add a memory region to global allocator: [{:#x}, {:#x})", - start_vaddr, - start_vaddr + size - ); - GLOBAL_ALLOCATOR.add_memory(start_vaddr, size) -} diff --git a/arceos/modules/axalloc/src/page.rs b/arceos/modules/axalloc/src/page.rs deleted file mode 100644 index f4a69129b..000000000 --- a/arceos/modules/axalloc/src/page.rs +++ /dev/null @@ -1,108 +0,0 @@ -use allocator::AllocError; -use axerrno::{AxError, AxResult}; -use memory_addr::{PhysAddr, VirtAddr}; - -use crate::{global_allocator, PAGE_SIZE}; - -/// A RAII wrapper of contiguous 4K-sized pages. -/// -/// It will automatically deallocate the pages when dropped. -#[derive(Debug)] -pub struct GlobalPage { - start_vaddr: VirtAddr, - num_pages: usize, -} - -impl GlobalPage { - /// Allocate one 4K-sized page. - pub fn alloc() -> AxResult { - global_allocator() - .alloc_pages(1, PAGE_SIZE) - .map(|vaddr| Self { - start_vaddr: vaddr.into(), - num_pages: 1, - }) - .map_err(alloc_err_to_ax_err) - } - - /// Allocate one 4K-sized page and fill with zero. - pub fn alloc_zero() -> AxResult { - let mut p = Self::alloc()?; - p.zero(); - Ok(p) - } - - /// Allocate contiguous 4K-sized pages. - pub fn alloc_contiguous(num_pages: usize, align_pow2: usize) -> AxResult { - global_allocator() - .alloc_pages(num_pages, align_pow2) - .map(|vaddr| Self { - start_vaddr: vaddr.into(), - num_pages, - }) - .map_err(alloc_err_to_ax_err) - } - - /// Get the start virtual address of this page. - pub fn start_vaddr(&self) -> VirtAddr { - self.start_vaddr - } - - /// Get the start physical address of this page. - pub fn start_paddr(&self, virt_to_phys: F) -> PhysAddr - where - F: FnOnce(VirtAddr) -> PhysAddr, - { - virt_to_phys(self.start_vaddr) - } - - /// Get the total size (in bytes) of these page(s). - pub fn size(&self) -> usize { - self.num_pages * PAGE_SIZE - } - - /// Convert to a raw pointer. - pub fn as_ptr(&self) -> *const u8 { - self.start_vaddr.as_ptr() - } - - /// Convert to a mutable raw pointer. - pub fn as_mut_ptr(&mut self) -> *mut u8 { - self.start_vaddr.as_mut_ptr() - } - - /// Fill `self` with `byte`. - pub fn fill(&mut self, byte: u8) { - unsafe { core::ptr::write_bytes(self.as_mut_ptr(), byte, self.size()) } - } - - /// Fill `self` with zero. - pub fn zero(&mut self) { - self.fill(0) - } - - /// Forms a slice that can read data. - pub fn as_slice(&self) -> &[u8] { - unsafe { core::slice::from_raw_parts(self.as_ptr(), self.size()) } - } - - /// Forms a mutable slice that can write data. - pub fn as_slice_mut(&mut self) -> &mut [u8] { - unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr(), self.size()) } - } -} - -impl Drop for GlobalPage { - fn drop(&mut self) { - global_allocator().dealloc_pages(self.start_vaddr.into(), self.num_pages); - } -} - -const fn alloc_err_to_ax_err(e: AllocError) -> AxError { - match e { - AllocError::InvalidParam | AllocError::MemoryOverlap | AllocError::NotAllocated => { - AxError::InvalidInput - } - AllocError::NoMemory => AxError::NoMemory, - } -} diff --git a/arceos/modules/axconfig/Cargo.toml b/arceos/modules/axconfig/Cargo.toml deleted file mode 100644 index 834319d1d..000000000 --- a/arceos/modules/axconfig/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "axconfig" -version.workspace = true -edition = "2021" -authors = ["Yuekai Jia "] -description = "Platform-specific constants and parameters for ArceOS" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/modules/axconfig" -documentation = "https://arceos-org.github.io/arceos/axconfig/index.html" - -[build-dependencies] -toml_edit = "0.22" -serde = "1.0" diff --git a/arceos/modules/axconfig/build.rs b/arceos/modules/axconfig/build.rs deleted file mode 100644 index e8a28b11e..000000000 --- a/arceos/modules/axconfig/build.rs +++ /dev/null @@ -1,172 +0,0 @@ -use std::io::{Result, Write}; -use std::path::{Path, PathBuf}; -use toml_edit::{Decor, DocumentMut, Item, Table, Value}; - -fn resolve_config_path(platform: Option<&str>) -> Result { - let mut root_dir = PathBuf::from(std::env!("CARGO_MANIFEST_DIR")); - root_dir.extend(["..", ".."]); - let config_dir = root_dir.join("platforms"); - - let builtin_platforms = std::fs::read_dir(&config_dir)? - .filter_map(|e| { - e.unwrap() - .file_name() - .to_str()? - .strip_suffix(".toml") - .map(String::from) - }) - .collect::>(); - - let path = match platform { - None | Some("") => "defconfig.toml".into(), - Some(plat) if builtin_platforms.contains(&plat.to_string()) => { - config_dir.join(format!("{plat}.toml")) - } - Some(plat) => { - let path = PathBuf::from(&plat); - if path.is_absolute() { - path - } else { - root_dir.join(plat) - } - } - }; - - Ok(path) -} - -fn get_comments<'a>(config: &'a Table, key: &str) -> Option<&'a str> { - config - .key(key) - .and_then(|k| k.leaf_decor().prefix()) - .and_then(|s| s.as_str()) - .map(|s| s.trim()) -} - -fn add_config(config: &mut Table, key: &str, item: Item, comments: Option<&str>) { - config.insert(key, item); - if let Some(comm) = comments { - if let Some(mut dst) = config.key_mut(key) { - *dst.leaf_decor_mut() = Decor::new(comm, ""); - } - } -} - -fn load_config_toml(config_path: &Path) -> Result { - let config_content = std::fs::read_to_string(config_path)?; - let toml = config_content - .parse::() - .expect("failed to parse config file") - .as_table() - .clone(); - Ok(toml) -} - -fn gen_config_rs(config_path: &Path) -> Result> { - fn is_num(s: &str) -> bool { - let s = s.replace('_', ""); - if s.parse::().is_ok() { - true - } else if let Some(s) = s.strip_prefix("0x") { - usize::from_str_radix(s, 16).is_ok() - } else { - false - } - } - - // Load TOML config file - let mut config = if config_path == Path::new("defconfig.toml") { - load_config_toml(config_path)? - } else { - // Set default values for missing items - let defconfig = load_config_toml(Path::new("defconfig.toml"))?; - let mut config = load_config_toml(config_path)?; - - for (key, item) in defconfig.iter() { - if !config.contains_key(key) { - add_config( - &mut config, - key, - item.clone(), - get_comments(&defconfig, key), - ); - } - } - config - }; - - add_config( - &mut config, - "smp", - toml_edit::value(std::env::var("AX_SMP").unwrap_or("1".into())), - Some("# Number of CPUs"), - ); - - // Generate config.rs - let mut output = Vec::new(); - writeln!( - output, - "// Platform constants and parameters for {}.", - config["platform"].as_str().unwrap(), - )?; - writeln!(output, "// Generated by build.rs, DO NOT edit!\n")?; - - for (key, item) in config.iter() { - let var_name = key.to_uppercase().replace('-', "_"); - if let Item::Value(value) = item { - let comments = get_comments(&config, key) - .unwrap_or_default() - .replace('#', "///"); - match value { - Value::String(s) => { - writeln!(output, "{comments}")?; - let s = s.value(); - if is_num(s) { - writeln!(output, "pub const {var_name}: usize = {s};")?; - } else { - writeln!(output, "pub const {var_name}: &str = \"{s}\";")?; - } - } - Value::Array(regions) => { - if key != "mmio-regions" && key != "virtio-mmio-regions" && key != "pci-ranges" - { - continue; - } - writeln!(output, "{comments}")?; - writeln!(output, "pub const {var_name}: &[(usize, usize)] = &[")?; - for r in regions.iter() { - let r = r.as_array().unwrap(); - writeln!( - output, - " ({}, {}),", - r.get(0).unwrap().as_str().unwrap(), - r.get(1).unwrap().as_str().unwrap() - )?; - } - writeln!(output, "];")?; - } - _ => {} - } - } - } - - Ok(output) -} - -fn main() -> Result<()> { - let platform = option_env!("AX_PLATFORM"); - let config_path = resolve_config_path(platform)?; - - println!("Reading config file: {:?}", config_path); - let config_rs = gen_config_rs(&config_path)?; - - let out_dir = std::env::var("OUT_DIR").unwrap(); - let out_path = Path::new(&out_dir).join("config.rs"); - println!("Generating config file: {}", out_path.display()); - std::fs::write(out_path, config_rs)?; - - println!("cargo:rerun-if-changed={}", config_path.display()); - println!("cargo:rerun-if-env-changed=AX_PLATFORM"); - println!("cargo:rerun-if-env-changed=AX_SMP"); - Ok(()) -} diff --git a/arceos/modules/axconfig/defconfig.toml b/arceos/modules/axconfig/defconfig.toml deleted file mode 100644 index 5bd110e70..000000000 --- a/arceos/modules/axconfig/defconfig.toml +++ /dev/null @@ -1,48 +0,0 @@ -# Architecture identifier. -arch = "unknown" -# Platform identifier. -platform = "dummy" -# Platform family. -family = "dummy" - -# Base address of the whole physical memory. -phys-memory-base = "0" -# Size of the whole physical memory. -phys-memory-size = "0" -# Base physical address of the kernel image. -kernel-base-paddr = "0" -# Base virtual address of the kernel image. -kernel-base-vaddr = "0" -# Linear mapping offset, for quick conversions between physical and virtual -# addresses. -phys-virt-offset = "0" -# Offset of bus address and phys address. some boards, the bus address is -# different from the physical address. -phys-bus-offset = "0" -# Kernel address space base. -kernel-aspace-base = "0" -# Kernel address space size. -kernel-aspace-size = "0" -# MMIO regions with format (`base_paddr`, `size`). -mmio-regions = [] -# VirtIO MMIO regions with format (`base_paddr`, `size`). -virtio-mmio-regions = [] -# Base physical address of the PCIe ECAM space. -pci-ecam-base = "0" -# End PCI bus number. -pci-bus-end = "0" -# PCI device memory ranges. -pci-ranges = [] - -# Timer interrupt frequency in Hz. -timer-frequency = "0" - -# Stack size of each task. -task-stack-size = "0x40000" # 256 K - -# Number of timer ticks per second (Hz). A timer tick may contain several timer -# interrupts. -ticks-per-sec = "100" - -# Number of CPUs -smp = "1" diff --git a/arceos/modules/axconfig/src/lib.rs b/arceos/modules/axconfig/src/lib.rs deleted file mode 100644 index 6488790b0..000000000 --- a/arceos/modules/axconfig/src/lib.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Platform-specific constants and parameters for [ArceOS]. -//! -//! Currently supported platforms can be found in the [platforms] directory of -//! the [ArceOS] root. -//! -//! [ArceOS]: https://github.com/arceos-org/arceos -//! [platforms]: https://github.com/arceos-org/arceos/tree/main/platforms - -#![no_std] - -#[rustfmt::skip] -mod config { - include!(concat!(env!("OUT_DIR"), "/config.rs")); -} - -pub use config::*; - -/// End address of the whole physical memory. -pub const PHYS_MEMORY_END: usize = PHYS_MEMORY_BASE + PHYS_MEMORY_SIZE; diff --git a/arceos/modules/axdisplay/Cargo.toml b/arceos/modules/axdisplay/Cargo.toml deleted file mode 100644 index 31c596a0d..000000000 --- a/arceos/modules/axdisplay/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "axdisplay" -version.workspace = true -edition = "2021" -authors = ["Shiping Yuan "] -description = "ArceOS graphics module" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/modules/axdisplay" -documentation = "https://arceos-org.github.io/arceos/axdisplay/index.html" - -[dependencies] -log = "0.4.21" -lazyinit = "0.2" -axdriver = { workspace = true, features = ["display"] } -axsync = { workspace = true } -axdriver_display = { git = "https://github.com/arceos-org/axdriver_crates.git", tag = "v0.1.0" } diff --git a/arceos/modules/axdisplay/src/lib.rs b/arceos/modules/axdisplay/src/lib.rs deleted file mode 100644 index 12318bdd7..000000000 --- a/arceos/modules/axdisplay/src/lib.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! [ArceOS](https://github.com/arceos-org/arceos) graphics module. -//! -//! Currently only supports direct writing to the framebuffer. - -#![no_std] - -#[macro_use] -extern crate log; - -#[doc(no_inline)] -pub use axdriver_display::DisplayInfo; - -use axdriver::{prelude::*, AxDeviceContainer}; -use axsync::Mutex; -use lazyinit::LazyInit; - -static MAIN_DISPLAY: LazyInit> = LazyInit::new(); - -/// Initializes the graphics subsystem by underlayer devices. -pub fn init_display(mut display_devs: AxDeviceContainer) { - info!("Initialize graphics subsystem..."); - - let dev = display_devs.take_one().expect("No graphics device found!"); - info!(" use graphics device 0: {:?}", dev.device_name()); - MAIN_DISPLAY.init_once(Mutex::new(dev)); -} - -/// Gets the framebuffer information. -pub fn framebuffer_info() -> DisplayInfo { - MAIN_DISPLAY.lock().info() -} - -/// Flushes the framebuffer, i.e. show on the screen. -pub fn framebuffer_flush() { - MAIN_DISPLAY.lock().flush().unwrap(); -} diff --git a/arceos/modules/axdma/Cargo.toml b/arceos/modules/axdma/Cargo.toml deleted file mode 100644 index 9ae9fcd3e..000000000 --- a/arceos/modules/axdma/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "axdma" -edition = "2021" -version.workspace = true -authors = ["Zhour Rui "] -license.workspace = true -homepage.workspace = true -keywords.workspace = true -categories.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/modules/axdma" -documentation = "https://arceos-org.github.io/arceos/axdma/index.html" - -[dependencies] -log = "0.4.21" -kspin = "0.1" -memory_addr = "0.3" -axerrno = "0.1" -allocator = { git = "https://github.com/arceos-org/allocator.git", tag = "v0.1.0" } -axalloc = { workspace = true } -axmm = { workspace = true } -axconfig = { workspace = true } -axhal = { workspace = true, features = ["paging"] } \ No newline at end of file diff --git a/arceos/modules/axdma/src/dma.rs b/arceos/modules/axdma/src/dma.rs deleted file mode 100644 index 41bd86263..000000000 --- a/arceos/modules/axdma/src/dma.rs +++ /dev/null @@ -1,128 +0,0 @@ -use core::{alloc::Layout, ptr::NonNull}; - -use allocator::{AllocError, AllocResult, BaseAllocator, ByteAllocator}; -use axalloc::{global_allocator, DefaultByteAllocator}; -use axhal::{mem::virt_to_phys, paging::MappingFlags}; -use kspin::SpinNoIrq; -use log::{debug, error}; -use memory_addr::{va, VirtAddr, PAGE_SIZE_4K}; - -use crate::{phys_to_bus, BusAddr, DMAInfo}; - -pub(crate) static ALLOCATOR: SpinNoIrq = SpinNoIrq::new(DmaAllocator::new()); - -pub(crate) struct DmaAllocator { - alloc: DefaultByteAllocator, -} - -impl DmaAllocator { - pub const fn new() -> Self { - Self { - alloc: DefaultByteAllocator::new(), - } - } - - /// Allocate arbitrary number of bytes. Returns the left bound of the - /// allocated region. - /// - /// It firstly tries to allocate from the coherent byte allocator. If there is no - /// memory, it asks the global page allocator for more memory and adds it to the - /// byte allocator. - pub unsafe fn alloc_coherent(&mut self, layout: Layout) -> AllocResult { - if layout.size() >= PAGE_SIZE_4K { - self.alloc_coherent_pages(layout) - } else { - self.alloc_coherent_bytes(layout) - } - } - - fn alloc_coherent_bytes(&mut self, layout: Layout) -> AllocResult { - let mut is_expanded = false; - loop { - if let Ok(data) = self.alloc.alloc(layout) { - let cpu_addr = va!(data.as_ptr() as usize); - return Ok(DMAInfo { - cpu_addr: data, - bus_addr: virt_to_bus(cpu_addr), - }); - } else { - if is_expanded { - return Err(AllocError::NoMemory); - } - is_expanded = true; - let available_pages = global_allocator().available_pages(); - // 4 pages or available pages. - let num_pages = 4.min(available_pages); - let expand_size = num_pages * PAGE_SIZE_4K; - let vaddr_raw = global_allocator().alloc_pages(num_pages, PAGE_SIZE_4K)?; - let vaddr = va!(vaddr_raw); - self.update_flags( - vaddr, - num_pages, - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::UNCACHED, - )?; - self.alloc - .add_memory(vaddr_raw, expand_size) - .inspect_err(|e| error!("add memory fail: {e:?}"))?; - debug!("expand memory @{vaddr:#X}, size: {expand_size:#X} bytes"); - } - } - } - - fn alloc_coherent_pages(&mut self, layout: Layout) -> AllocResult { - let num_pages = layout_pages(&layout); - let vaddr_raw = - global_allocator().alloc_pages(num_pages, PAGE_SIZE_4K.max(layout.align()))?; - let vaddr = va!(vaddr_raw); - self.update_flags( - vaddr, - num_pages, - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::UNCACHED, - )?; - Ok(DMAInfo { - cpu_addr: unsafe { NonNull::new_unchecked(vaddr_raw as *mut u8) }, - bus_addr: virt_to_bus(vaddr), - }) - } - - fn update_flags( - &mut self, - vaddr: VirtAddr, - num_pages: usize, - flags: MappingFlags, - ) -> AllocResult<()> { - let expand_size = num_pages * PAGE_SIZE_4K; - axmm::kernel_aspace() - .lock() - .protect(vaddr, expand_size, flags) - .map_err(|e| { - error!("change table flag fail: {e:?}"); - AllocError::NoMemory - }) - } - - /// Gives back the allocated region to the byte allocator. - pub unsafe fn dealloc_coherent(&mut self, dma: DMAInfo, layout: Layout) { - if layout.size() >= PAGE_SIZE_4K { - let num_pages = layout_pages(&layout); - let virt_raw = dma.cpu_addr.as_ptr() as usize; - global_allocator().dealloc_pages(virt_raw, num_pages); - let _ = self.update_flags( - va!(virt_raw), - num_pages, - MappingFlags::READ | MappingFlags::WRITE, - ); - } else { - self.alloc.dealloc(dma.cpu_addr, layout) - } - } -} - -const fn virt_to_bus(addr: VirtAddr) -> BusAddr { - let paddr = virt_to_phys(addr); - phys_to_bus(paddr) -} - -const fn layout_pages(layout: &Layout) -> usize { - memory_addr::align_up_4k(layout.size()) / PAGE_SIZE_4K -} diff --git a/arceos/modules/axdma/src/lib.rs b/arceos/modules/axdma/src/lib.rs deleted file mode 100644 index bc896a710..000000000 --- a/arceos/modules/axdma/src/lib.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! [ArceOS](https://github.com/arceos-org/arceos) global DMA allocator. - -#![no_std] - -extern crate alloc; - -mod dma; - -use core::{alloc::Layout, ptr::NonNull}; - -use allocator::AllocResult; -use memory_addr::PhysAddr; - -use self::dma::ALLOCATOR; - -/// Converts a physical address to a bus address. -/// -/// It assumes that there is a linear mapping with the offset -/// [`axconfig::PHYS_BUS_OFFSET`], that maps all the physical memory to the virtual -/// space at the address plus the offset. So we have -/// `baddr = paddr + PHYS_BUS_OFFSET`. -#[inline] -pub const fn phys_to_bus(paddr: PhysAddr) -> BusAddr { - BusAddr::new((paddr.as_usize() + axconfig::PHYS_BUS_OFFSET) as u64) -} - -/// Allocates **coherent** memory that meets Direct Memory Access (DMA) requirements. -/// -/// This function allocates a block of memory through the global allocator. The memory pages must be contiguous, undivided, and have consistent read and write access. -/// -/// - `layout`: The memory layout, which describes the size and alignment requirements of the requested memory. -/// -/// Returns an [`DMAInfo`] structure containing details about the allocated memory, such as the starting address and size. If it's not possible to allocate memory meeting the criteria, returns [`None`]. -/// # Safety -/// This function is unsafe because it directly interacts with the global allocator, which can potentially cause memory leaks or other issues if not used correctly. -pub unsafe fn alloc_coherent(layout: Layout) -> AllocResult { - ALLOCATOR.lock().alloc_coherent(layout) -} - -/// Frees coherent memory previously allocated. -/// -/// This function releases the memory block that was previously allocated and marked as coherent. It ensures proper deallocation and management of resources associated with the memory block. -/// -/// - `dma_info`: An instance of [`DMAInfo`] containing the details of the memory block to be freed, such as its starting address and size. -/// # Safety -/// This function is unsafe because it directly interacts with the global allocator, which can potentially cause memory leaks or other issues if not used correctly. -pub unsafe fn dealloc_coherent(dma: DMAInfo, layout: Layout) { - ALLOCATOR.lock().dealloc_coherent(dma, layout) -} - -/// A bus memory address. -/// -/// It's a wrapper type around an [`u64`]. -#[repr(transparent)] -#[derive(Copy, Clone, Default, Ord, PartialOrd, Eq, PartialEq)] -pub struct BusAddr(u64); - -impl BusAddr { - /// Converts an [`u64`] to a physical address. - pub const fn new(addr: u64) -> Self { - Self(addr) - } - - /// Converts the address to an [`u64`]. - pub const fn as_u64(self) -> u64 { - self.0 - } -} - -impl From for BusAddr { - fn from(value: u64) -> Self { - Self::new(value) - } -} - -impl core::fmt::Debug for BusAddr { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_tuple("BusAddr") - .field(&format_args!("{:#X}", self.0)) - .finish() - } -} - -/// Represents information related to a DMA operation. -#[derive(Debug, Clone, Copy)] -pub struct DMAInfo { - /// The `cpu_addr` field represents the address at which the CPU accesses this memory region. - /// This address is a virtual memory address used by the CPU to access memory. - pub cpu_addr: NonNull, - /// The `bus_addr` field represents the physical address of this memory region on the bus. - /// The DMA controller uses this address to directly access memory. - pub bus_addr: BusAddr, -} diff --git a/arceos/modules/axdriver/Cargo.toml b/arceos/modules/axdriver/Cargo.toml deleted file mode 100644 index 1bc362a0a..000000000 --- a/arceos/modules/axdriver/Cargo.toml +++ /dev/null @@ -1,46 +0,0 @@ -[package] -name = "axdriver" -version.workspace = true -edition = "2021" -authors = ["Yuekai Jia ", "ChengXiang Qi "] -description = "ArceOS device drivers" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/modules/axdriver" -documentation = "https://arceos-org.github.io/arceos/axdriver/index.html" - -[features] -dyn = [] -bus-mmio = [] -bus-pci = ["dep:axdriver_pci", "dep:axhal", "dep:axconfig"] -net = ["axdriver_net"] -block = ["axdriver_block"] -display = ["axdriver_display"] - -# Enabled by features `virtio-*` -virtio = ["axdriver_virtio", "dep:axalloc", "dep:axhal", "dep:axconfig"] - -# various types of drivers -virtio-blk = ["block", "virtio", "axdriver_virtio/block"] -virtio-net = ["net", "virtio", "axdriver_virtio/net"] -virtio-gpu = ["display", "virtio", "axdriver_virtio/gpu"] -ramdisk = ["block", "axdriver_block/ramdisk"] -bcm2835-sdhci = ["block", "axdriver_block/bcm2835-sdhci"] -ixgbe = ["net", "axdriver_net/ixgbe", "dep:axalloc", "dep:axhal", "dep:axdma"] -# more devices example: e1000 = ["net", "axdriver_net/e1000"] - -default = ["bus-pci"] - -[dependencies] -log = "0.4.21" -cfg-if = "1.0" -axdriver_base = { git = "https://github.com/arceos-org/axdriver_crates.git", tag = "v0.1.0" } -axdriver_block = { git = "https://github.com/arceos-org/axdriver_crates.git", tag = "v0.1.0", optional = true } -axdriver_net = { git = "https://github.com/arceos-org/axdriver_crates.git", tag = "v0.1.0", optional = true } -axdriver_display = { git = "https://github.com/arceos-org/axdriver_crates.git", tag = "v0.1.0", optional = true } -axdriver_pci = { git = "https://github.com/arceos-org/axdriver_crates.git", tag = "v0.1.0", optional = true } -axdriver_virtio = { git = "https://github.com/arceos-org/axdriver_crates.git", tag = "v0.1.0", optional = true } -axalloc = { workspace = true, optional = true } -axhal = { workspace = true, optional = true } -axconfig = { workspace = true, optional = true } -axdma = { workspace = true, optional = true } \ No newline at end of file diff --git a/arceos/modules/axdriver/build.rs b/arceos/modules/axdriver/build.rs deleted file mode 100644 index 8d5fd0710..000000000 --- a/arceos/modules/axdriver/build.rs +++ /dev/null @@ -1,75 +0,0 @@ -const NET_DEV_FEATURES: &[&str] = &["ixgbe", "virtio-net"]; -const BLOCK_DEV_FEATURES: &[&str] = &["ramdisk", "bcm2835-sdhci", "virtio-blk"]; -const DISPLAY_DEV_FEATURES: &[&str] = &["virtio-gpu"]; - -fn make_cfg_values(str_list: &[&str]) -> String { - str_list - .iter() - .map(|s| format!("{:?}", s)) - .collect::>() - .join(", ") -} - -fn has_feature(feature: &str) -> bool { - std::env::var(format!( - "CARGO_FEATURE_{}", - feature.to_uppercase().replace('-', "_") - )) - .is_ok() -} - -fn enable_cfg(key: &str, value: &str) { - println!("cargo:rustc-cfg={key}=\"{value}\""); -} - -fn main() { - if has_feature("bus-mmio") { - enable_cfg("bus", "mmio"); - } else { - enable_cfg("bus", "pci"); - } - - // Generate cfgs like `net_dev="virtio-net"`. if `dyn` is not enabled, only one device is - // selected for each device category. If no device is selected, `dummy` is selected. - let is_dyn = has_feature("dyn"); - for (dev_kind, feat_list) in [ - ("net", NET_DEV_FEATURES), - ("block", BLOCK_DEV_FEATURES), - ("display", DISPLAY_DEV_FEATURES), - ] { - if !has_feature(dev_kind) { - continue; - } - - let mut selected = false; - for feat in feat_list { - if has_feature(feat) { - enable_cfg(&format!("{dev_kind}_dev"), feat); - selected = true; - if !is_dyn { - break; - } - } - } - if !is_dyn && !selected { - enable_cfg(&format!("{dev_kind}_dev"), "dummy"); - } - } - - println!( - "cargo::rustc-check-cfg=cfg(bus, values({}))", - make_cfg_values(&["pci", "mmio"]) - ); - println!( - "cargo::rustc-check-cfg=cfg(net_dev, values({}, \"dummy\"))", - make_cfg_values(NET_DEV_FEATURES) - ); - println!( - "cargo::rustc-check-cfg=cfg(block_dev, values({}, \"dummy\"))", - make_cfg_values(BLOCK_DEV_FEATURES) - ); - println!( - "cargo::rustc-check-cfg=cfg(display_dev, values({}, \"dummy\"))", - make_cfg_values(DISPLAY_DEV_FEATURES) - ); -} diff --git a/arceos/modules/axdriver/src/bus/mmio.rs b/arceos/modules/axdriver/src/bus/mmio.rs deleted file mode 100644 index 5a3573a6a..000000000 --- a/arceos/modules/axdriver/src/bus/mmio.rs +++ /dev/null @@ -1,23 +0,0 @@ -#[allow(unused_imports)] -use crate::{prelude::*, AllDevices}; - -impl AllDevices { - pub(crate) fn probe_bus_devices(&mut self) { - // TODO: parse device tree - #[cfg(feature = "virtio")] - for reg in axconfig::VIRTIO_MMIO_REGIONS { - for_each_drivers!(type Driver, { - if let Some(dev) = Driver::probe_mmio(reg.0, reg.1) { - info!( - "registered a new {:?} device at [PA:{:#x}, PA:{:#x}): {:?}", - dev.device_type(), - reg.0, reg.0 + reg.1, - dev.device_name(), - ); - self.add_device(dev); - continue; // skip to the next device - } - }); - } - } -} diff --git a/arceos/modules/axdriver/src/bus/mod.rs b/arceos/modules/axdriver/src/bus/mod.rs deleted file mode 100644 index bc7f80f5a..000000000 --- a/arceos/modules/axdriver/src/bus/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg(bus = "mmio")] -mod mmio; -#[cfg(bus = "pci")] -mod pci; diff --git a/arceos/modules/axdriver/src/bus/pci.rs b/arceos/modules/axdriver/src/bus/pci.rs deleted file mode 100644 index a83ae9af5..000000000 --- a/arceos/modules/axdriver/src/bus/pci.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::{prelude::*, AllDevices}; -use axdriver_pci::{ - BarInfo, Cam, Command, DeviceFunction, HeaderType, MemoryBarType, PciRangeAllocator, PciRoot, -}; -use axhal::mem::phys_to_virt; - -const PCI_BAR_NUM: u8 = 6; - -fn config_pci_device( - root: &mut PciRoot, - bdf: DeviceFunction, - allocator: &mut Option, -) -> DevResult { - let mut bar = 0; - while bar < PCI_BAR_NUM { - let info = root.bar_info(bdf, bar).unwrap(); - if let BarInfo::Memory { - address_type, - address, - size, - .. - } = info - { - // if the BAR address is not assigned, call the allocator and assign it. - if size > 0 && address == 0 { - let new_addr = allocator - .as_mut() - .expect("No memory ranges available for PCI BARs!") - .alloc(size as _) - .ok_or(DevError::NoMemory)?; - if address_type == MemoryBarType::Width32 { - root.set_bar_32(bdf, bar, new_addr as _); - } else if address_type == MemoryBarType::Width64 { - root.set_bar_64(bdf, bar, new_addr); - } - } - } - - // read the BAR info again after assignment. - let info = root.bar_info(bdf, bar).unwrap(); - match info { - BarInfo::IO { address, size } => { - if address > 0 && size > 0 { - debug!(" BAR {}: IO [{:#x}, {:#x})", bar, address, address + size); - } - } - BarInfo::Memory { - address_type, - prefetchable, - address, - size, - } => { - if address > 0 && size > 0 { - debug!( - " BAR {}: MEM [{:#x}, {:#x}){}{}", - bar, - address, - address + size as u64, - if address_type == MemoryBarType::Width64 { - " 64bit" - } else { - "" - }, - if prefetchable { " pref" } else { "" }, - ); - } - } - } - - bar += 1; - if info.takes_two_entries() { - bar += 1; - } - } - - // Enable the device. - let (_status, cmd) = root.get_status_command(bdf); - root.set_command( - bdf, - cmd | Command::IO_SPACE | Command::MEMORY_SPACE | Command::BUS_MASTER, - ); - Ok(()) -} - -impl AllDevices { - pub(crate) fn probe_bus_devices(&mut self) { - let base_vaddr = phys_to_virt(axconfig::PCI_ECAM_BASE.into()); - let mut root = unsafe { PciRoot::new(base_vaddr.as_mut_ptr(), Cam::Ecam) }; - - // PCI 32-bit MMIO space - let mut allocator = axconfig::PCI_RANGES - .get(1) - .map(|range| PciRangeAllocator::new(range.0 as u64, range.1 as u64)); - - for bus in 0..=axconfig::PCI_BUS_END as u8 { - for (bdf, dev_info) in root.enumerate_bus(bus) { - debug!("PCI {}: {}", bdf, dev_info); - if dev_info.header_type != HeaderType::Standard { - continue; - } - match config_pci_device(&mut root, bdf, &mut allocator) { - Ok(_) => for_each_drivers!(type Driver, { - if let Some(dev) = Driver::probe_pci(&mut root, bdf, &dev_info) { - info!( - "registered a new {:?} device at {}: {:?}", - dev.device_type(), - bdf, - dev.device_name(), - ); - self.add_device(dev); - continue; // skip to the next device - } - }), - Err(e) => warn!( - "failed to enable PCI device at {}({}): {:?}", - bdf, dev_info, e - ), - } - } - } - } -} diff --git a/arceos/modules/axdriver/src/drivers.rs b/arceos/modules/axdriver/src/drivers.rs deleted file mode 100644 index 4c9d467d5..000000000 --- a/arceos/modules/axdriver/src/drivers.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! Defines types and probe methods of all supported devices. - -#![allow(unused_imports, dead_code)] - -use crate::AxDeviceEnum; -use axdriver_base::DeviceType; - -#[cfg(feature = "virtio")] -use crate::virtio::{self, VirtIoDevMeta}; - -#[cfg(feature = "bus-pci")] -use axdriver_pci::{DeviceFunction, DeviceFunctionInfo, PciRoot}; - -pub use super::dummy::*; - -pub trait DriverProbe { - fn probe_global() -> Option { - None - } - - #[cfg(bus = "mmio")] - fn probe_mmio(_mmio_base: usize, _mmio_size: usize) -> Option { - None - } - - #[cfg(bus = "pci")] - fn probe_pci( - _root: &mut PciRoot, - _bdf: DeviceFunction, - _dev_info: &DeviceFunctionInfo, - ) -> Option { - None - } -} - -#[cfg(net_dev = "virtio-net")] -register_net_driver!( - ::Driver, - ::Device -); - -#[cfg(block_dev = "virtio-blk")] -register_block_driver!( - ::Driver, - ::Device -); - -#[cfg(display_dev = "virtio-gpu")] -register_display_driver!( - ::Driver, - ::Device -); - -cfg_if::cfg_if! { - if #[cfg(block_dev = "ramdisk")] { - pub struct RamDiskDriver; - register_block_driver!(RamDiskDriver, axdriver_block::ramdisk::RamDisk); - - impl DriverProbe for RamDiskDriver { - fn probe_global() -> Option { - // TODO: format RAM disk - Some(AxDeviceEnum::from_block( - axdriver_block::ramdisk::RamDisk::new(0x100_0000), // 16 MiB - )) - } - } - } -} - -cfg_if::cfg_if! { - if #[cfg(block_dev = "bcm2835-sdhci")]{ - pub struct BcmSdhciDriver; - register_block_driver!(MmckDriver, axdriver_block::bcm2835sdhci::SDHCIDriver); - - impl DriverProbe for BcmSdhciDriver { - fn probe_global() -> Option { - debug!("mmc probe"); - axdriver_block::bcm2835sdhci::SDHCIDriver::try_new().ok().map(AxDeviceEnum::from_block) - } - } - } -} - -cfg_if::cfg_if! { - if #[cfg(net_dev = "ixgbe")] { - use crate::ixgbe::IxgbeHalImpl; - use axhal::mem::phys_to_virt; - pub struct IxgbeDriver; - register_net_driver!(IxgbeDriver, axdriver_net::ixgbe::IxgbeNic); - impl DriverProbe for IxgbeDriver { - #[cfg(bus = "pci")] - fn probe_pci( - root: &mut axdriver_pci::PciRoot, - bdf: axdriver_pci::DeviceFunction, - dev_info: &axdriver_pci::DeviceFunctionInfo, - ) -> Option { - use axdriver_net::ixgbe::{INTEL_82599, INTEL_VEND, IxgbeNic}; - if dev_info.vendor_id == INTEL_VEND && dev_info.device_id == INTEL_82599 { - // Intel 10Gb Network - info!("ixgbe PCI device found at {:?}", bdf); - - // Initialize the device - // These can be changed according to the requirments specified in the ixgbe init function. - const QN: u16 = 1; - const QS: usize = 1024; - let bar_info = root.bar_info(bdf, 0).unwrap(); - match bar_info { - axdriver_pci::BarInfo::Memory { - address, - size, - .. - } => { - let ixgbe_nic = IxgbeNic::::init( - phys_to_virt((address as usize).into()).into(), - size as usize - ) - .expect("failed to initialize ixgbe device"); - return Some(AxDeviceEnum::from_net(ixgbe_nic)); - } - axdriver_pci::BarInfo::IO { .. } => { - error!("ixgbe: BAR0 is of I/O type"); - return None; - } - } - } - None - } - } - } -} diff --git a/arceos/modules/axdriver/src/dummy.rs b/arceos/modules/axdriver/src/dummy.rs deleted file mode 100644 index 1bea0fcb9..000000000 --- a/arceos/modules/axdriver/src/dummy.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! Dummy types used if no device of a certain category is selected. - -#![allow(unused_imports)] -#![allow(dead_code)] - -use super::prelude::*; -use cfg_if::cfg_if; - -cfg_if! { - if #[cfg(net_dev = "dummy")] { - use axdriver_net::{EthernetAddress, NetBuf, NetBufBox, NetBufPool, NetBufPtr}; - - pub struct DummyNetDev; - pub struct DummyNetDrvier; - register_net_driver!(DummyNetDriver, DummyNetDev); - - impl BaseDriverOps for DummyNetDev { - fn device_type(&self) -> DeviceType { DeviceType::Net } - fn device_name(&self) -> &str { "dummy-net" } - } - - impl NetDriverOps for DummyNetDev { - fn mac_address(&self) -> EthernetAddress { unreachable!() } - fn can_transmit(&self) -> bool { false } - fn can_receive(&self) -> bool { false } - fn rx_queue_size(&self) -> usize { 0 } - fn tx_queue_size(&self) -> usize { 0 } - fn recycle_rx_buffer(&mut self, _: NetBufPtr) -> DevResult { Err(DevError::Unsupported) } - fn recycle_tx_buffers(&mut self) -> DevResult { Err(DevError::Unsupported) } - fn transmit(&mut self, _: NetBufPtr) -> DevResult { Err(DevError::Unsupported) } - fn receive(&mut self) -> DevResult { Err(DevError::Unsupported) } - fn alloc_tx_buffer(&mut self, _: usize) -> DevResult { Err(DevError::Unsupported) } - } - } -} - -cfg_if! { - if #[cfg(block_dev = "dummy")] { - pub struct DummyBlockDev; - pub struct DummyBlockDriver; - register_block_driver!(DummyBlockDriver, DummyBlockDev); - - impl BaseDriverOps for DummyBlockDev { - fn device_type(&self) -> DeviceType { - DeviceType::Block - } - fn device_name(&self) -> &str { - "dummy-block" - } - } - - impl BlockDriverOps for DummyBlockDev { - fn num_blocks(&self) -> u64 { - 0 - } - fn block_size(&self) -> usize { - 0 - } - fn read_block(&mut self, _: u64, _: &mut [u8]) -> DevResult { - Err(DevError::Unsupported) - } - fn write_block(&mut self, _: u64, _: &[u8]) -> DevResult { - Err(DevError::Unsupported) - } - fn flush(&mut self) -> DevResult { - Err(DevError::Unsupported) - } - } - } -} - -cfg_if! { - if #[cfg(display_dev = "dummy")] { - pub struct DummyDisplayDev; - pub struct DummyDisplayDriver; - register_display_driver!(DummyDisplayDriver, DummyDisplayDev); - - impl BaseDriverOps for DummyDisplayDev { - fn device_type(&self) -> DeviceType { - DeviceType::Display - } - fn device_name(&self) -> &str { - "dummy-display" - } - } - - impl DisplayDriverOps for DummyDisplayDev { - fn info(&self) -> axdriver_display::DisplayInfo { - unreachable!() - } - fn fb(&self) -> axdriver_display::FrameBuffer { - unreachable!() - } - fn need_flush(&self) -> bool { - false - } - fn flush(&mut self) -> DevResult { - Err(DevError::Unsupported) - } - } - } -} diff --git a/arceos/modules/axdriver/src/ixgbe.rs b/arceos/modules/axdriver/src/ixgbe.rs deleted file mode 100644 index b42fa9c69..000000000 --- a/arceos/modules/axdriver/src/ixgbe.rs +++ /dev/null @@ -1,39 +0,0 @@ -use axdma::{alloc_coherent, dealloc_coherent, BusAddr, DMAInfo}; -use axdriver_net::ixgbe::{IxgbeHal, PhysAddr as IxgbePhysAddr}; -use axhal::mem::{phys_to_virt, virt_to_phys}; -use core::{alloc::Layout, ptr::NonNull}; - -pub struct IxgbeHalImpl; - -unsafe impl IxgbeHal for IxgbeHalImpl { - fn dma_alloc(size: usize) -> (IxgbePhysAddr, NonNull) { - let layout = Layout::from_size_align(size, 8).unwrap(); - match unsafe { alloc_coherent(layout) } { - Ok(dma_info) => (dma_info.bus_addr.as_u64() as usize, dma_info.cpu_addr), - Err(_) => (0, NonNull::dangling()), - } - } - - unsafe fn dma_dealloc(paddr: IxgbePhysAddr, vaddr: NonNull, size: usize) -> i32 { - let layout = Layout::from_size_align(size, 8).unwrap(); - let dma_info = DMAInfo { - cpu_addr: vaddr, - bus_addr: BusAddr::from(paddr as u64), - }; - unsafe { dealloc_coherent(dma_info, layout) }; - 0 - } - - unsafe fn mmio_phys_to_virt(paddr: IxgbePhysAddr, _size: usize) -> NonNull { - NonNull::new(phys_to_virt(paddr.into()).as_mut_ptr()).unwrap() - } - - unsafe fn mmio_virt_to_phys(vaddr: NonNull, _size: usize) -> IxgbePhysAddr { - virt_to_phys((vaddr.as_ptr() as usize).into()).into() - } - - fn wait_until(duration: core::time::Duration) -> Result<(), &'static str> { - axhal::time::busy_wait_until(duration); - Ok(()) - } -} diff --git a/arceos/modules/axdriver/src/lib.rs b/arceos/modules/axdriver/src/lib.rs deleted file mode 100644 index 659d95cde..000000000 --- a/arceos/modules/axdriver/src/lib.rs +++ /dev/null @@ -1,184 +0,0 @@ -//! [ArceOS](https://github.com/arceos-org/arceos) device drivers. -//! -//! # Usage -//! -//! All detected devices are composed into a large struct [`AllDevices`] -//! and returned by the [`init_drivers`] function. The upperlayer subsystems -//! (e.g., the network stack) may unpack the struct to get the specified device -//! driver they want. -//! -//! For each device category (i.e., net, block, display, etc.), an unified type -//! is used to represent all devices in that category. Currently, there are 3 -//! categories: [`AxNetDevice`], [`AxBlockDevice`], and [`AxDisplayDevice`]. -//! -//! # Concepts -//! -//! This crate supports two device models depending on the `dyn` feature: -//! -//! - **Static**: The type of all devices is static, it is determined at compile -//! time by corresponding cargo features. For example, [`AxNetDevice`] will be -//! an alias of [`VirtioNetDev`] if the `virtio-net` feature is enabled. This -//! model provides the best performance as it avoids dynamic dispatch. But on -//! limitation, only one device instance is supported for each device category. -//! - **Dynamic**: All device instance is using [trait objects] and wrapped in a -//! `Box`. For example, [`AxNetDevice`] will be [`Box`]. -//! When call a method provided by the device, it uses [dynamic dispatch][dyn] -//! that may introduce a little overhead. But on the other hand, it is more -//! flexible, multiple instances of each device category are supported. -//! -//! # Supported Devices -//! -//! | Device Category | Cargo Feature | Description | -//! |-|-|-| -//! | Block | `ramdisk` | A RAM disk that stores data in a vector | -//! | Block | `virtio-blk` | VirtIO block device | -//! | Network | `virtio-net` | VirtIO network device | -//! | Display | `virtio-gpu` | VirtIO graphics device | -//! -//! # Other Cargo Features -//! -//! - `dyn`: use the dynamic device model (see above). -//! - `bus-mmio`: use device tree to probe all MMIO devices. -//! - `bus-pci`: use PCI bus to probe all PCI devices. This feature is -//! enabeld by default. -//! - `virtio`: use VirtIO devices. This is enabled if any of `virtio-blk`, -//! `virtio-net` or `virtio-gpu` is enabled. -//! - `net`: use network devices. This is enabled if any feature of network -//! devices is selected. If this feature is enabled without any network device -//! features, a dummy struct is used for [`AxNetDevice`]. -//! - `block`: use block storage devices. Similar to the `net` feature. -//! - `display`: use graphics display devices. Similar to the `net` feature. -//! -//! [`VirtioNetDev`]: axdriver_virtio::VirtIoNetDev -//! [`Box`]: axdriver_net::NetDriverOps -//! [trait objects]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html -//! [dyn]: https://doc.rust-lang.org/std/keyword.dyn.html - -#![no_std] -#![feature(doc_auto_cfg)] -#![feature(associated_type_defaults)] - -#[macro_use] -extern crate log; - -#[cfg(feature = "dyn")] -extern crate alloc; - -#[macro_use] -mod macros; - -mod bus; -mod drivers; -mod dummy; -mod structs; - -#[cfg(feature = "virtio")] -mod virtio; - -#[cfg(feature = "ixgbe")] -mod ixgbe; - -pub mod prelude; - -#[allow(unused_imports)] -use self::prelude::*; -pub use self::structs::{AxDeviceContainer, AxDeviceEnum}; - -#[cfg(feature = "block")] -pub use self::structs::AxBlockDevice; -#[cfg(feature = "display")] -pub use self::structs::AxDisplayDevice; -#[cfg(feature = "net")] -pub use self::structs::AxNetDevice; - -/// A structure that contains all device drivers, organized by their category. -#[derive(Default)] -pub struct AllDevices { - /// All network device drivers. - #[cfg(feature = "net")] - pub net: AxDeviceContainer, - /// All block device drivers. - #[cfg(feature = "block")] - pub block: AxDeviceContainer, - /// All graphics device drivers. - #[cfg(feature = "display")] - pub display: AxDeviceContainer, -} - -impl AllDevices { - /// Returns the device model used, either `dyn` or `static`. - /// - /// See the [crate-level documentation](crate) for more details. - pub const fn device_model() -> &'static str { - if cfg!(feature = "dyn") { - "dyn" - } else { - "static" - } - } - - /// Probes all supported devices. - fn probe(&mut self) { - for_each_drivers!(type Driver, { - if let Some(dev) = Driver::probe_global() { - info!( - "registered a new {:?} device: {:?}", - dev.device_type(), - dev.device_name(), - ); - self.add_device(dev); - } - }); - - self.probe_bus_devices(); - } - - /// Adds one device into the corresponding container, according to its device category. - #[allow(dead_code)] - fn add_device(&mut self, dev: AxDeviceEnum) { - match dev { - #[cfg(feature = "net")] - AxDeviceEnum::Net(dev) => self.net.push(dev), - #[cfg(feature = "block")] - AxDeviceEnum::Block(dev) => self.block.push(dev), - #[cfg(feature = "display")] - AxDeviceEnum::Display(dev) => self.display.push(dev), - } - } -} - -/// Probes and initializes all device drivers, returns the [`AllDevices`] struct. -pub fn init_drivers() -> AllDevices { - info!("Initialize device drivers..."); - info!(" device model: {}", AllDevices::device_model()); - - let mut all_devs = AllDevices::default(); - all_devs.probe(); - - #[cfg(feature = "net")] - { - debug!("number of NICs: {}", all_devs.net.len()); - for (i, dev) in all_devs.net.iter().enumerate() { - assert_eq!(dev.device_type(), DeviceType::Net); - debug!(" NIC {}: {:?}", i, dev.device_name()); - } - } - #[cfg(feature = "block")] - { - debug!("number of block devices: {}", all_devs.block.len()); - for (i, dev) in all_devs.block.iter().enumerate() { - assert_eq!(dev.device_type(), DeviceType::Block); - debug!(" block device {}: {:?}", i, dev.device_name()); - } - } - #[cfg(feature = "display")] - { - debug!("number of graphics devices: {}", all_devs.display.len()); - for (i, dev) in all_devs.display.iter().enumerate() { - assert_eq!(dev.device_type(), DeviceType::Display); - debug!(" graphics device {}: {:?}", i, dev.device_name()); - } - } - - all_devs -} diff --git a/arceos/modules/axdriver/src/macros.rs b/arceos/modules/axdriver/src/macros.rs deleted file mode 100644 index b90e813e7..000000000 --- a/arceos/modules/axdriver/src/macros.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! TODO: generate registered drivers in `for_each_drivers!` automatically. - -#![allow(unused_macros)] - -macro_rules! register_net_driver { - ($driver_type:ty, $device_type:ty) => { - /// The unified type of the NIC devices. - #[cfg(not(feature = "dyn"))] - pub type AxNetDevice = $device_type; - }; -} - -macro_rules! register_block_driver { - ($driver_type:ty, $device_type:ty) => { - /// The unified type of the NIC devices. - #[cfg(not(feature = "dyn"))] - pub type AxBlockDevice = $device_type; - }; -} - -macro_rules! register_display_driver { - ($driver_type:ty, $device_type:ty) => { - /// The unified type of the NIC devices. - #[cfg(not(feature = "dyn"))] - pub type AxDisplayDevice = $device_type; - }; -} - -macro_rules! for_each_drivers { - (type $drv_type:ident, $code:block) => {{ - #[allow(unused_imports)] - use crate::drivers::DriverProbe; - #[cfg(feature = "virtio")] - #[allow(unused_imports)] - use crate::virtio::{self, VirtIoDevMeta}; - - #[cfg(net_dev = "virtio-net")] - { - type $drv_type = ::Driver; - $code - } - #[cfg(block_dev = "virtio-blk")] - { - type $drv_type = ::Driver; - $code - } - #[cfg(display_dev = "virtio-gpu")] - { - type $drv_type = ::Driver; - $code - } - #[cfg(block_dev = "ramdisk")] - { - type $drv_type = crate::drivers::RamDiskDriver; - $code - } - #[cfg(block_dev = "bcm2835-sdhci")] - { - type $drv_type = crate::drivers::BcmSdhciDriver; - $code - } - #[cfg(net_dev = "ixgbe")] - { - type $drv_type = crate::drivers::IxgbeDriver; - $code - } - }}; -} diff --git a/arceos/modules/axdriver/src/prelude.rs b/arceos/modules/axdriver/src/prelude.rs deleted file mode 100644 index 11e960fee..000000000 --- a/arceos/modules/axdriver/src/prelude.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Device driver prelude that includes some traits and types. - -pub use axdriver_base::{BaseDriverOps, DevError, DevResult, DeviceType}; - -#[cfg(feature = "block")] -pub use {crate::structs::AxBlockDevice, axdriver_block::BlockDriverOps}; -#[cfg(feature = "display")] -pub use {crate::structs::AxDisplayDevice, axdriver_display::DisplayDriverOps}; -#[cfg(feature = "net")] -pub use {crate::structs::AxNetDevice, axdriver_net::NetDriverOps}; diff --git a/arceos/modules/axdriver/src/structs/dyn.rs b/arceos/modules/axdriver/src/structs/dyn.rs deleted file mode 100644 index c4d04cb97..000000000 --- a/arceos/modules/axdriver/src/structs/dyn.rs +++ /dev/null @@ -1,85 +0,0 @@ -#![allow(unused_imports)] - -use crate::prelude::*; -use alloc::{boxed::Box, vec, vec::Vec}; - -/// The unified type of the NIC devices. -#[cfg(feature = "net")] -pub type AxNetDevice = Box; -/// The unified type of the block storage devices. -#[cfg(feature = "block")] -pub type AxBlockDevice = Box; -/// The unified type of the graphics display devices. -#[cfg(feature = "display")] -pub type AxDisplayDevice = Box; - -impl super::AxDeviceEnum { - /// Constructs a network device. - #[cfg(feature = "net")] - pub fn from_net(dev: impl NetDriverOps + 'static) -> Self { - Self::Net(Box::new(dev)) - } - - /// Constructs a block device. - #[cfg(feature = "block")] - pub fn from_block(dev: impl BlockDriverOps + 'static) -> Self { - Self::Block(Box::new(dev)) - } - - /// Constructs a display device. - #[cfg(feature = "display")] - pub fn from_display(dev: impl DisplayDriverOps + 'static) -> Self { - Self::Display(Box::new(dev)) - } -} - -/// A structure that contains all device drivers of a certain category. -/// -/// If the feature `dyn` is enabled, the inner type is [`Vec`]. Otherwise, -/// the inner type is [`Option`] and at most one device can be contained. -pub struct AxDeviceContainer(Vec); - -impl AxDeviceContainer { - /// Returns number of devices in this container. - pub fn len(&self) -> usize { - self.0.len() - } - - /// Returns whether the container is empty. - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Takes one device out of the container (will remove it from the container). - pub fn take_one(&mut self) -> Option { - if self.is_empty() { - None - } else { - Some(self.0.remove(0)) - } - } - - /// Constructs the container from one device. - pub fn from_one(dev: D) -> Self { - Self(vec![dev]) - } - - /// Adds one device into the container. - #[allow(dead_code)] - pub(crate) fn push(&mut self, dev: D) { - self.0.push(dev); - } -} - -impl core::ops::Deref for AxDeviceContainer { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Default for AxDeviceContainer { - fn default() -> Self { - Self(Default::default()) - } -} diff --git a/arceos/modules/axdriver/src/structs/mod.rs b/arceos/modules/axdriver/src/structs/mod.rs deleted file mode 100644 index da8be37c7..000000000 --- a/arceos/modules/axdriver/src/structs/mod.rs +++ /dev/null @@ -1,51 +0,0 @@ -#[cfg_attr(feature = "dyn", path = "dyn.rs")] -#[cfg_attr(not(feature = "dyn"), path = "static.rs")] -mod imp; - -use axdriver_base::{BaseDriverOps, DeviceType}; - -pub use imp::*; - -/// A unified enum that represents different categories of devices. -#[allow(clippy::large_enum_variant)] -pub enum AxDeviceEnum { - /// Network card device. - #[cfg(feature = "net")] - Net(AxNetDevice), - /// Block storage device. - #[cfg(feature = "block")] - Block(AxBlockDevice), - /// Graphic display device. - #[cfg(feature = "display")] - Display(AxDisplayDevice), -} - -impl BaseDriverOps for AxDeviceEnum { - #[inline] - #[allow(unreachable_patterns)] - fn device_type(&self) -> DeviceType { - match self { - #[cfg(feature = "net")] - Self::Net(_) => DeviceType::Net, - #[cfg(feature = "block")] - Self::Block(_) => DeviceType::Block, - #[cfg(feature = "display")] - Self::Display(_) => DeviceType::Display, - _ => unreachable!(), - } - } - - #[inline] - #[allow(unreachable_patterns)] - fn device_name(&self) -> &str { - match self { - #[cfg(feature = "net")] - Self::Net(dev) => dev.device_name(), - #[cfg(feature = "block")] - Self::Block(dev) => dev.device_name(), - #[cfg(feature = "display")] - Self::Display(dev) => dev.device_name(), - _ => unreachable!(), - } - } -} diff --git a/arceos/modules/axdriver/src/structs/static.rs b/arceos/modules/axdriver/src/structs/static.rs deleted file mode 100644 index 9adff2c24..000000000 --- a/arceos/modules/axdriver/src/structs/static.rs +++ /dev/null @@ -1,79 +0,0 @@ -#[cfg(feature = "block")] -pub use crate::drivers::AxBlockDevice; -#[cfg(feature = "display")] -pub use crate::drivers::AxDisplayDevice; -#[cfg(feature = "net")] -pub use crate::drivers::AxNetDevice; - -impl super::AxDeviceEnum { - /// Constructs a network device. - #[cfg(feature = "net")] - pub const fn from_net(dev: AxNetDevice) -> Self { - Self::Net(dev) - } - - /// Constructs a block device. - #[cfg(feature = "block")] - pub const fn from_block(dev: AxBlockDevice) -> Self { - Self::Block(dev) - } - - /// Constructs a display device. - #[cfg(feature = "display")] - pub const fn from_display(dev: AxDisplayDevice) -> Self { - Self::Display(dev) - } -} - -/// A structure that contains all device drivers of a certain category. -/// -/// If the feature `dyn` is enabled, the inner type is [`Vec`]. Otherwise, -/// the inner type is [`Option`] and at most one device can be contained. -pub struct AxDeviceContainer(Option); - -impl AxDeviceContainer { - /// Returns number of devices in this container. - pub const fn len(&self) -> usize { - if self.0.is_some() { - 1 - } else { - 0 - } - } - - /// Returns whether the container is empty. - pub const fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Takes one device out of the container (will remove it from the container). - pub fn take_one(&mut self) -> Option { - self.0.take() - } - - /// Constructs the container from one device. - pub const fn from_one(dev: D) -> Self { - Self(Some(dev)) - } - - /// Adds one device into the container. - #[allow(dead_code)] - pub(crate) fn push(&mut self, dev: D) { - if self.0.is_none() { - self.0 = Some(dev); - } - } -} - -impl core::ops::Deref for AxDeviceContainer { - type Target = Option; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Default for AxDeviceContainer { - fn default() -> Self { - Self(Default::default()) - } -} diff --git a/arceos/modules/axdriver/src/virtio.rs b/arceos/modules/axdriver/src/virtio.rs deleted file mode 100644 index 6d3d9ac54..000000000 --- a/arceos/modules/axdriver/src/virtio.rs +++ /dev/null @@ -1,172 +0,0 @@ -use core::marker::PhantomData; -use core::ptr::NonNull; - -use axalloc::global_allocator; -use axdriver_base::{BaseDriverOps, DevResult, DeviceType}; -use axdriver_virtio::{BufferDirection, PhysAddr, VirtIoHal}; -use axhal::mem::{phys_to_virt, virt_to_phys}; -use cfg_if::cfg_if; - -use crate::{drivers::DriverProbe, AxDeviceEnum}; - -cfg_if! { - if #[cfg(bus = "pci")] { - use axdriver_pci::{PciRoot, DeviceFunction, DeviceFunctionInfo}; - type VirtIoTransport = axdriver_virtio::PciTransport; - } else if #[cfg(bus = "mmio")] { - type VirtIoTransport = axdriver_virtio::MmioTransport; - } -} - -/// A trait for VirtIO device meta information. -pub trait VirtIoDevMeta { - const DEVICE_TYPE: DeviceType; - - type Device: BaseDriverOps; - type Driver = VirtIoDriver; - - fn try_new(transport: VirtIoTransport) -> DevResult; -} - -cfg_if! { - if #[cfg(net_dev = "virtio-net")] { - pub struct VirtIoNet; - - impl VirtIoDevMeta for VirtIoNet { - const DEVICE_TYPE: DeviceType = DeviceType::Net; - type Device = axdriver_virtio::VirtIoNetDev; - - fn try_new(transport: VirtIoTransport) -> DevResult { - Ok(AxDeviceEnum::from_net(Self::Device::try_new(transport)?)) - } - } - } -} - -cfg_if! { - if #[cfg(block_dev = "virtio-blk")] { - pub struct VirtIoBlk; - - impl VirtIoDevMeta for VirtIoBlk { - const DEVICE_TYPE: DeviceType = DeviceType::Block; - type Device = axdriver_virtio::VirtIoBlkDev; - - fn try_new(transport: VirtIoTransport) -> DevResult { - Ok(AxDeviceEnum::from_block(Self::Device::try_new(transport)?)) - } - } - } -} - -cfg_if! { - if #[cfg(display_dev = "virtio-gpu")] { - pub struct VirtIoGpu; - - impl VirtIoDevMeta for VirtIoGpu { - const DEVICE_TYPE: DeviceType = DeviceType::Display; - type Device = axdriver_virtio::VirtIoGpuDev; - - fn try_new(transport: VirtIoTransport) -> DevResult { - Ok(AxDeviceEnum::from_display(Self::Device::try_new(transport)?)) - } - } - } -} - -/// A common driver for all VirtIO devices that implements [`DriverProbe`]. -pub struct VirtIoDriver(PhantomData); - -impl DriverProbe for VirtIoDriver { - #[cfg(bus = "mmio")] - fn probe_mmio(mmio_base: usize, mmio_size: usize) -> Option { - let base_vaddr = phys_to_virt(mmio_base.into()); - if let Some((ty, transport)) = - axdriver_virtio::probe_mmio_device(base_vaddr.as_mut_ptr(), mmio_size) - { - if ty == D::DEVICE_TYPE { - match D::try_new(transport) { - Ok(dev) => return Some(dev), - Err(e) => { - warn!( - "failed to initialize MMIO device at [PA:{:#x}, PA:{:#x}): {:?}", - mmio_base, - mmio_base + mmio_size, - e - ); - return None; - } - } - } - } - None - } - - #[cfg(bus = "pci")] - fn probe_pci( - root: &mut PciRoot, - bdf: DeviceFunction, - dev_info: &DeviceFunctionInfo, - ) -> Option { - if dev_info.vendor_id != 0x1af4 { - return None; - } - match (D::DEVICE_TYPE, dev_info.device_id) { - (DeviceType::Net, 0x1000) | (DeviceType::Net, 0x1041) => {} - (DeviceType::Block, 0x1001) | (DeviceType::Block, 0x1042) => {} - (DeviceType::Display, 0x1050) => {} - _ => return None, - } - - if let Some((ty, transport)) = - axdriver_virtio::probe_pci_device::(root, bdf, dev_info) - { - if ty == D::DEVICE_TYPE { - match D::try_new(transport) { - Ok(dev) => return Some(dev), - Err(e) => { - warn!( - "failed to initialize PCI device at {}({}): {:?}", - bdf, dev_info, e - ); - return None; - } - } - } - } - None - } -} - -pub struct VirtIoHalImpl; - -unsafe impl VirtIoHal for VirtIoHalImpl { - fn dma_alloc(pages: usize, _direction: BufferDirection) -> (PhysAddr, NonNull) { - let vaddr = if let Ok(vaddr) = global_allocator().alloc_pages(pages, 0x1000) { - vaddr - } else { - return (0, NonNull::dangling()); - }; - let paddr = virt_to_phys(vaddr.into()); - let ptr = NonNull::new(vaddr as _).unwrap(); - (paddr.as_usize(), ptr) - } - - unsafe fn dma_dealloc(_paddr: PhysAddr, vaddr: NonNull, pages: usize) -> i32 { - global_allocator().dealloc_pages(vaddr.as_ptr() as usize, pages); - 0 - } - - #[inline] - unsafe fn mmio_phys_to_virt(paddr: PhysAddr, _size: usize) -> NonNull { - NonNull::new(phys_to_virt(paddr.into()).as_mut_ptr()).unwrap() - } - - #[inline] - unsafe fn share(buffer: NonNull<[u8]>, _direction: BufferDirection) -> PhysAddr { - let vaddr = buffer.as_ptr() as *mut u8 as usize; - virt_to_phys(vaddr.into()).into() - } - - #[inline] - unsafe fn unshare(_paddr: PhysAddr, _buffer: NonNull<[u8]>, _direction: BufferDirection) {} -} diff --git a/arceos/modules/axfs/Cargo.toml b/arceos/modules/axfs/Cargo.toml deleted file mode 100644 index d1562fa93..000000000 --- a/arceos/modules/axfs/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -[package] -name = "axfs" -version.workspace = true -edition = "2021" -authors = ["Yuekai Jia "] -description = "ArceOS filesystem module" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/modules/axfs" -documentation = "https://arceos-org.github.io/arceos/axfs/index.html" - -[features] -devfs = ["dep:axfs_devfs"] -ramfs = ["dep:axfs_ramfs"] -procfs = ["dep:axfs_ramfs"] -sysfs = ["dep:axfs_ramfs"] -fatfs = ["dep:fatfs"] -myfs = ["dep:crate_interface"] -use-ramdisk = [] - -default = ["devfs", "ramfs", "fatfs", "procfs", "sysfs"] - -[dependencies] -log = "0.4.21" -cfg-if = "1.0" -lazyinit = "0.2" -cap_access = "0.1" -axio = { version = "0.1", features = ["alloc"] } -axerrno = "0.1" -axfs_vfs = "0.1" -axfs_devfs = { version = "0.1", optional = true } -axfs_ramfs = { version = "0.1", optional = true } -crate_interface = { version = "0.1", optional = true } -axsync = { workspace = true } -axdriver = { workspace = true, features = ["block"] } -axdriver_block = { git = "https://github.com/arceos-org/axdriver_crates.git", tag = "v0.1.0" } - -[dependencies.fatfs] -git = "https://github.com/rafalh/rust-fatfs" -rev = "85f06e0" -optional = true -default-features = false -features = [ # no std - "alloc", - "lfn", - "log_level_trace", - "unicode", -] - -[dev-dependencies] -axdriver = { workspace = true, features = ["block", "ramdisk"] } -axdriver_block = { git = "https://github.com/arceos-org/axdriver_crates.git", tag = "v0.1.0", features = ["ramdisk"] } -axsync = { workspace = true, features = ["multitask"] } -axtask = { workspace = true, features = ["test"] } diff --git a/arceos/modules/axfs/resources/create_test_img.sh b/arceos/modules/axfs/resources/create_test_img.sh deleted file mode 100755 index d51cef84d..000000000 --- a/arceos/modules/axfs/resources/create_test_img.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -# From https://github.com/rafalh/rust-fatfs/blob/master/scripts/create-test-img.sh - -CUR_DIR=`dirname $0` - -echo $OUT_DIR - -create_test_img() { - local name=$1 - local blkcount=$2 - local fatSize=$3 - dd if=/dev/zero of="$name" bs=1024 count=$blkcount - mkfs.vfat -s 1 -F $fatSize -n "Test!" -i 12345678 "$name" - mkdir -p mnt - sudo mount -o loop "$name" mnt -o rw,uid=$USER,gid=$USER - for i in $(seq 1 1000); do - echo "Rust is cool!" >>"mnt/long.txt" - done - echo "Rust is cool!" >>"mnt/short.txt" - mkdir -p "mnt/very/long/path" - echo "Rust is cool!" >>"mnt/very/long/path/test.txt" - mkdir -p "mnt/very-long-dir-name" - echo "Rust is cool!" >>"mnt/very-long-dir-name/very-long-file-name.txt" - - sudo umount mnt -} - -create_test_img "$CUR_DIR/fat16.img" 2500 16 -create_test_img "$CUR_DIR/fat32.img" 34000 32 diff --git a/arceos/modules/axfs/src/api/dir.rs b/arceos/modules/axfs/src/api/dir.rs deleted file mode 100644 index 55ad5ab32..000000000 --- a/arceos/modules/axfs/src/api/dir.rs +++ /dev/null @@ -1,150 +0,0 @@ -use alloc::string::String; -use axio::Result; -use core::fmt; - -use super::FileType; -use crate::fops; - -/// Iterator over the entries in a directory. -pub struct ReadDir<'a> { - path: &'a str, - inner: fops::Directory, - buf_pos: usize, - buf_end: usize, - end_of_stream: bool, - dirent_buf: [fops::DirEntry; 31], -} - -/// Entries returned by the [`ReadDir`] iterator. -pub struct DirEntry<'a> { - dir_path: &'a str, - entry_name: String, - entry_type: FileType, -} - -/// A builder used to create directories in various manners. -#[derive(Default, Debug)] -pub struct DirBuilder { - recursive: bool, -} - -impl<'a> ReadDir<'a> { - pub(super) fn new(path: &'a str) -> Result { - let mut opts = fops::OpenOptions::new(); - opts.read(true); - let inner = fops::Directory::open_dir(path, &opts)?; - const EMPTY: fops::DirEntry = fops::DirEntry::default(); - let dirent_buf = [EMPTY; 31]; - Ok(ReadDir { - path, - inner, - end_of_stream: false, - buf_pos: 0, - buf_end: 0, - dirent_buf, - }) - } -} - -impl<'a> Iterator for ReadDir<'a> { - type Item = Result>; - - fn next(&mut self) -> Option>> { - if self.end_of_stream { - return None; - } - - loop { - if self.buf_pos >= self.buf_end { - match self.inner.read_dir(&mut self.dirent_buf) { - Ok(n) => { - if n == 0 { - self.end_of_stream = true; - return None; - } - self.buf_pos = 0; - self.buf_end = n; - } - Err(e) => { - self.end_of_stream = true; - return Some(Err(e)); - } - } - } - let entry = &self.dirent_buf[self.buf_pos]; - self.buf_pos += 1; - let name_bytes = entry.name_as_bytes(); - if name_bytes == b"." || name_bytes == b".." { - continue; - } - let entry_name = unsafe { core::str::from_utf8_unchecked(name_bytes).into() }; - let entry_type = entry.entry_type(); - - return Some(Ok(DirEntry { - dir_path: self.path, - entry_name, - entry_type, - })); - } - } -} - -impl<'a> DirEntry<'a> { - /// Returns the full path to the file that this entry represents. - /// - /// The full path is created by joining the original path to `read_dir` - /// with the filename of this entry. - pub fn path(&self) -> String { - String::from(self.dir_path.trim_end_matches('/')) + "/" + &self.entry_name - } - - /// Returns the bare file name of this directory entry without any other - /// leading path component. - pub fn file_name(&self) -> String { - self.entry_name.clone() - } - - /// Returns the file type for the file that this entry points at. - pub fn file_type(&self) -> FileType { - self.entry_type - } -} - -impl fmt::Debug for DirEntry<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("DirEntry").field(&self.path()).finish() - } -} - -impl DirBuilder { - /// Creates a new set of options with default mode/security settings for all - /// platforms and also non-recursive. - pub fn new() -> Self { - Self { recursive: false } - } - - /// Indicates that directories should be created recursively, creating all - /// parent directories. Parents that do not exist are created with the same - /// security and permissions settings. - pub fn recursive(&mut self, recursive: bool) -> &mut Self { - self.recursive = recursive; - self - } - - /// Creates the specified directory with the options configured in this - /// builder. - pub fn create(&self, path: &str) -> Result<()> { - if self.recursive { - self.create_dir_all(path) - } else { - crate::root::create_dir(None, path) - } - } - - fn create_dir_all(&self, _path: &str) -> Result<()> { - axerrno::ax_err!( - Unsupported, - "Recursive directory creation is not supported yet" - ) - } -} diff --git a/arceos/modules/axfs/src/api/file.rs b/arceos/modules/axfs/src/api/file.rs deleted file mode 100644 index 6941c90cb..000000000 --- a/arceos/modules/axfs/src/api/file.rs +++ /dev/null @@ -1,187 +0,0 @@ -use axio::{prelude::*, Result, SeekFrom}; -use core::fmt; - -use crate::fops; - -/// A structure representing a type of file with accessors for each file type. -/// It is returned by [`Metadata::file_type`] method. -pub type FileType = fops::FileType; - -/// Representation of the various permissions on a file. -pub type Permissions = fops::FilePerm; - -/// An object providing access to an open file on the filesystem. -pub struct File { - inner: fops::File, -} - -/// Metadata information about a file. -pub struct Metadata(fops::FileAttr); - -/// Options and flags which can be used to configure how a file is opened. -#[derive(Clone, Debug)] -pub struct OpenOptions(fops::OpenOptions); - -impl OpenOptions { - /// Creates a blank new set of options ready for configuration. - pub const fn new() -> Self { - OpenOptions(fops::OpenOptions::new()) - } - - /// Sets the option for read access. - pub fn read(&mut self, read: bool) -> &mut Self { - self.0.read(read); - self - } - - /// Sets the option for write access. - pub fn write(&mut self, write: bool) -> &mut Self { - self.0.write(write); - self - } - - /// Sets the option for the append mode. - pub fn append(&mut self, append: bool) -> &mut Self { - self.0.append(append); - self - } - - /// Sets the option for truncating a previous file. - pub fn truncate(&mut self, truncate: bool) -> &mut Self { - self.0.truncate(truncate); - self - } - - /// Sets the option to create a new file, or open it if it already exists. - pub fn create(&mut self, create: bool) -> &mut Self { - self.0.create(create); - self - } - - /// Sets the option to create a new file, failing if it already exists. - pub fn create_new(&mut self, create_new: bool) -> &mut Self { - self.0.create_new(create_new); - self - } - - /// Opens a file at `path` with the options specified by `self`. - pub fn open(&self, path: &str) -> Result { - fops::File::open(path, &self.0).map(|inner| File { inner }) - } -} - -impl Metadata { - /// Returns the file type for this metadata. - pub const fn file_type(&self) -> FileType { - self.0.file_type() - } - - /// Returns `true` if this metadata is for a directory. The - /// result is mutually exclusive to the result of - /// [`Metadata::is_file`]. - pub const fn is_dir(&self) -> bool { - self.0.is_dir() - } - - /// Returns `true` if this metadata is for a regular file. The - /// result is mutually exclusive to the result of - /// [`Metadata::is_dir`]. - pub const fn is_file(&self) -> bool { - self.0.is_file() - } - - /// Returns the size of the file, in bytes, this metadata is for. - #[allow(clippy::len_without_is_empty)] - pub const fn len(&self) -> u64 { - self.0.size() - } - - /// Returns the permissions of the file this metadata is for. - pub const fn permissions(&self) -> Permissions { - self.0.perm() - } - - /// Returns the total size of this file in bytes. - pub const fn size(&self) -> u64 { - self.0.size() - } - - /// Returns the number of blocks allocated to the file, in 512-byte units. - pub const fn blocks(&self) -> u64 { - self.0.blocks() - } -} - -impl fmt::Debug for Metadata { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Metadata") - .field("file_type", &self.file_type()) - .field("is_dir", &self.is_dir()) - .field("is_file", &self.is_file()) - .field("permissions", &self.permissions()) - .finish_non_exhaustive() - } -} - -impl File { - /// Attempts to open a file in read-only mode. - pub fn open(path: &str) -> Result { - OpenOptions::new().read(true).open(path) - } - - /// Opens a file in write-only mode. - pub fn create(path: &str) -> Result { - OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(path) - } - - /// Creates a new file in read-write mode; error if the file exists. - pub fn create_new(path: &str) -> Result { - OpenOptions::new() - .read(true) - .write(true) - .create_new(true) - .open(path) - } - - /// Returns a new OpenOptions object. - pub fn options() -> OpenOptions { - OpenOptions::new() - } - - /// Truncates or extends the underlying file, updating the size of - /// this file to become `size`. - pub fn set_len(&self, size: u64) -> Result<()> { - self.inner.truncate(size) - } - - /// Queries metadata about the underlying file. - pub fn metadata(&self) -> Result { - self.inner.get_attr().map(Metadata) - } -} - -impl Read for File { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.inner.read(buf) - } -} - -impl Write for File { - fn write(&mut self, buf: &[u8]) -> Result { - self.inner.write(buf) - } - - fn flush(&mut self) -> Result<()> { - self.inner.flush() - } -} - -impl Seek for File { - fn seek(&mut self, pos: SeekFrom) -> Result { - self.inner.seek(pos) - } -} diff --git a/arceos/modules/axfs/src/api/mod.rs b/arceos/modules/axfs/src/api/mod.rs deleted file mode 100644 index c8fb3aa30..000000000 --- a/arceos/modules/axfs/src/api/mod.rs +++ /dev/null @@ -1,89 +0,0 @@ -//! [`std::fs`]-like high-level filesystem manipulation operations. - -mod dir; -mod file; - -pub use self::dir::{DirBuilder, DirEntry, ReadDir}; -pub use self::file::{File, FileType, Metadata, OpenOptions, Permissions}; - -use alloc::{string::String, vec::Vec}; -use axio::{self as io, prelude::*}; - -/// Returns an iterator over the entries within a directory. -pub fn read_dir(path: &str) -> io::Result { - ReadDir::new(path) -} - -/// Returns the canonical, absolute form of a path with all intermediate -/// components normalized. -pub fn canonicalize(path: &str) -> io::Result { - crate::root::absolute_path(path) -} - -/// Returns the current working directory as a [`String`]. -pub fn current_dir() -> io::Result { - crate::root::current_dir() -} - -/// Changes the current working directory to the specified path. -pub fn set_current_dir(path: &str) -> io::Result<()> { - crate::root::set_current_dir(path) -} - -/// Read the entire contents of a file into a bytes vector. -pub fn read(path: &str) -> io::Result> { - let mut file = File::open(path)?; - let size = file.metadata().map(|m| m.len()).unwrap_or(0); - let mut bytes = Vec::with_capacity(size as usize); - file.read_to_end(&mut bytes)?; - Ok(bytes) -} - -/// Read the entire contents of a file into a string. -pub fn read_to_string(path: &str) -> io::Result { - let mut file = File::open(path)?; - let size = file.metadata().map(|m| m.len()).unwrap_or(0); - let mut string = String::with_capacity(size as usize); - file.read_to_string(&mut string)?; - Ok(string) -} - -/// Write a slice as the entire contents of a file. -pub fn write>(path: &str, contents: C) -> io::Result<()> { - File::create(path)?.write_all(contents.as_ref()) -} - -/// Given a path, query the file system to get information about a file, -/// directory, etc. -pub fn metadata(path: &str) -> io::Result { - File::open(path)?.metadata() -} - -/// Creates a new, empty directory at the provided path. -pub fn create_dir(path: &str) -> io::Result<()> { - DirBuilder::new().create(path) -} - -/// Recursively create a directory and all of its parent components if they -/// are missing. -pub fn create_dir_all(path: &str) -> io::Result<()> { - DirBuilder::new().recursive(true).create(path) -} - -/// Removes an empty directory. -pub fn remove_dir(path: &str) -> io::Result<()> { - crate::root::remove_dir(None, path) -} - -/// Removes a file from the filesystem. -pub fn remove_file(path: &str) -> io::Result<()> { - crate::root::remove_file(None, path) -} - -/// Rename a file or directory to a new name. -/// Delete the original file if `old` already exists. -/// -/// This only works then the new path is in the same mounted fs. -pub fn rename(old: &str, new: &str) -> io::Result<()> { - crate::root::rename(old, new) -} diff --git a/arceos/modules/axfs/src/dev.rs b/arceos/modules/axfs/src/dev.rs deleted file mode 100644 index 47cc2d2f3..000000000 --- a/arceos/modules/axfs/src/dev.rs +++ /dev/null @@ -1,92 +0,0 @@ -use axdriver::prelude::*; - -const BLOCK_SIZE: usize = 512; - -/// A disk device with a cursor. -pub struct Disk { - block_id: u64, - offset: usize, - dev: AxBlockDevice, -} - -impl Disk { - /// Create a new disk. - pub fn new(dev: AxBlockDevice) -> Self { - assert_eq!(BLOCK_SIZE, dev.block_size()); - Self { - block_id: 0, - offset: 0, - dev, - } - } - - /// Get the size of the disk. - pub fn size(&self) -> u64 { - self.dev.num_blocks() * BLOCK_SIZE as u64 - } - - /// Get the position of the cursor. - pub fn position(&self) -> u64 { - self.block_id * BLOCK_SIZE as u64 + self.offset as u64 - } - - /// Set the position of the cursor. - pub fn set_position(&mut self, pos: u64) { - self.block_id = pos / BLOCK_SIZE as u64; - self.offset = pos as usize % BLOCK_SIZE; - } - - /// Read within one block, returns the number of bytes read. - pub fn read_one(&mut self, buf: &mut [u8]) -> DevResult { - let read_size = if self.offset == 0 && buf.len() >= BLOCK_SIZE { - // whole block - self.dev - .read_block(self.block_id, &mut buf[0..BLOCK_SIZE])?; - self.block_id += 1; - BLOCK_SIZE - } else { - // partial block - let mut data = [0u8; BLOCK_SIZE]; - let start = self.offset; - let count = buf.len().min(BLOCK_SIZE - self.offset); - - self.dev.read_block(self.block_id, &mut data)?; - buf[..count].copy_from_slice(&data[start..start + count]); - - self.offset += count; - if self.offset >= BLOCK_SIZE { - self.block_id += 1; - self.offset -= BLOCK_SIZE; - } - count - }; - Ok(read_size) - } - - /// Write within one block, returns the number of bytes written. - pub fn write_one(&mut self, buf: &[u8]) -> DevResult { - let write_size = if self.offset == 0 && buf.len() >= BLOCK_SIZE { - // whole block - self.dev.write_block(self.block_id, &buf[0..BLOCK_SIZE])?; - self.block_id += 1; - BLOCK_SIZE - } else { - // partial block - let mut data = [0u8; BLOCK_SIZE]; - let start = self.offset; - let count = buf.len().min(BLOCK_SIZE - self.offset); - - self.dev.read_block(self.block_id, &mut data)?; - data[start..start + count].copy_from_slice(&buf[..count]); - self.dev.write_block(self.block_id, &data)?; - - self.offset += count; - if self.offset >= BLOCK_SIZE { - self.block_id += 1; - self.offset -= BLOCK_SIZE; - } - count - }; - Ok(write_size) - } -} diff --git a/arceos/modules/axfs/src/fops.rs b/arceos/modules/axfs/src/fops.rs deleted file mode 100644 index 621a09450..000000000 --- a/arceos/modules/axfs/src/fops.rs +++ /dev/null @@ -1,412 +0,0 @@ -//! Low-level filesystem operations. - -use axerrno::{ax_err, ax_err_type, AxError, AxResult}; -use axfs_vfs::{VfsError, VfsNodeRef}; -use axio::SeekFrom; -use cap_access::{Cap, WithCap}; -use core::fmt; - -#[cfg(feature = "myfs")] -pub use crate::dev::Disk; -#[cfg(feature = "myfs")] -pub use crate::fs::myfs::MyFileSystemIf; - -/// Alias of [`axfs_vfs::VfsNodeType`]. -pub type FileType = axfs_vfs::VfsNodeType; -/// Alias of [`axfs_vfs::VfsDirEntry`]. -pub type DirEntry = axfs_vfs::VfsDirEntry; -/// Alias of [`axfs_vfs::VfsNodeAttr`]. -pub type FileAttr = axfs_vfs::VfsNodeAttr; -/// Alias of [`axfs_vfs::VfsNodePerm`]. -pub type FilePerm = axfs_vfs::VfsNodePerm; - -/// An opened file object, with open permissions and a cursor. -pub struct File { - node: WithCap, - is_append: bool, - offset: u64, -} - -/// An opened directory object, with open permissions and a cursor for -/// [`read_dir`](Directory::read_dir). -pub struct Directory { - node: WithCap, - entry_idx: usize, -} - -/// Options and flags which can be used to configure how a file is opened. -#[derive(Clone)] -pub struct OpenOptions { - // generic - read: bool, - write: bool, - append: bool, - truncate: bool, - create: bool, - create_new: bool, - // system-specific - _custom_flags: i32, - _mode: u32, -} - -impl OpenOptions { - /// Creates a blank new set of options ready for configuration. - pub const fn new() -> Self { - Self { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - // system-specific - _custom_flags: 0, - _mode: 0o666, - } - } - /// Sets the option for read access. - pub fn read(&mut self, read: bool) { - self.read = read; - } - /// Sets the option for write access. - pub fn write(&mut self, write: bool) { - self.write = write; - } - /// Sets the option for the append mode. - pub fn append(&mut self, append: bool) { - self.append = append; - } - /// Sets the option for truncating a previous file. - pub fn truncate(&mut self, truncate: bool) { - self.truncate = truncate; - } - /// Sets the option to create a new file, or open it if it already exists. - pub fn create(&mut self, create: bool) { - self.create = create; - } - /// Sets the option to create a new file, failing if it already exists. - pub fn create_new(&mut self, create_new: bool) { - self.create_new = create_new; - } - - const fn is_valid(&self) -> bool { - if !self.read && !self.write && !self.append { - return false; - } - match (self.write, self.append) { - (true, false) => {} - (false, false) => { - if self.truncate || self.create || self.create_new { - return false; - } - } - (_, true) => { - if self.truncate && !self.create_new { - return false; - } - } - } - true - } -} - -impl File { - fn access_node(&self, cap: Cap) -> AxResult<&VfsNodeRef> { - self.node.access_or_err(cap, AxError::PermissionDenied) - } - - fn _open_at(dir: Option<&VfsNodeRef>, path: &str, opts: &OpenOptions) -> AxResult { - debug!("open file: {} {:?}", path, opts); - if !opts.is_valid() { - return ax_err!(InvalidInput); - } - - let node_option = crate::root::lookup(dir, path); - let node = if opts.create || opts.create_new { - match node_option { - Ok(node) => { - // already exists - if opts.create_new { - return ax_err!(AlreadyExists); - } - node - } - // not exists, create new - Err(VfsError::NotFound) => crate::root::create_file(dir, path)?, - Err(e) => return Err(e), - } - } else { - // just open the existing - node_option? - }; - - let attr = node.get_attr()?; - if attr.is_dir() - && (opts.create || opts.create_new || opts.write || opts.append || opts.truncate) - { - return ax_err!(IsADirectory); - } - let access_cap = opts.into(); - if !perm_to_cap(attr.perm()).contains(access_cap) { - return ax_err!(PermissionDenied); - } - - node.open()?; - if opts.truncate { - node.truncate(0)?; - } - Ok(Self { - node: WithCap::new(node, access_cap), - is_append: opts.append, - offset: 0, - }) - } - - /// Opens a file at the path relative to the current directory. Returns a - /// [`File`] object. - pub fn open(path: &str, opts: &OpenOptions) -> AxResult { - Self::_open_at(None, path, opts) - } - - /// Truncates the file to the specified size. - pub fn truncate(&self, size: u64) -> AxResult { - self.access_node(Cap::WRITE)?.truncate(size)?; - Ok(()) - } - - /// Reads the file at the current position. Returns the number of bytes - /// read. - /// - /// After the read, the cursor will be advanced by the number of bytes read. - pub fn read(&mut self, buf: &mut [u8]) -> AxResult { - let node = self.access_node(Cap::READ)?; - let read_len = node.read_at(self.offset, buf)?; - self.offset += read_len as u64; - Ok(read_len) - } - - /// Reads the file at the given position. Returns the number of bytes read. - /// - /// It does not update the file cursor. - pub fn read_at(&self, offset: u64, buf: &mut [u8]) -> AxResult { - let node = self.access_node(Cap::READ)?; - let read_len = node.read_at(offset, buf)?; - Ok(read_len) - } - - /// Writes the file at the current position. Returns the number of bytes - /// written. - /// - /// After the write, the cursor will be advanced by the number of bytes - /// written. - pub fn write(&mut self, buf: &[u8]) -> AxResult { - let offset = if self.is_append { - self.get_attr()?.size() - } else { - self.offset - }; - let node = self.access_node(Cap::WRITE)?; - let write_len = node.write_at(offset, buf)?; - self.offset = offset + write_len as u64; - Ok(write_len) - } - - /// Writes the file at the given position. Returns the number of bytes - /// written. - /// - /// It does not update the file cursor. - pub fn write_at(&self, offset: u64, buf: &[u8]) -> AxResult { - let node = self.access_node(Cap::WRITE)?; - let write_len = node.write_at(offset, buf)?; - Ok(write_len) - } - - /// Flushes the file, writes all buffered data to the underlying device. - pub fn flush(&self) -> AxResult { - self.access_node(Cap::WRITE)?.fsync()?; - Ok(()) - } - - /// Sets the cursor of the file to the specified offset. Returns the new - /// position after the seek. - pub fn seek(&mut self, pos: SeekFrom) -> AxResult { - let size = self.get_attr()?.size(); - let new_offset = match pos { - SeekFrom::Start(pos) => Some(pos), - SeekFrom::Current(off) => self.offset.checked_add_signed(off), - SeekFrom::End(off) => size.checked_add_signed(off), - } - .ok_or_else(|| ax_err_type!(InvalidInput))?; - self.offset = new_offset; - Ok(new_offset) - } - - /// Gets the file attributes. - pub fn get_attr(&self) -> AxResult { - self.access_node(Cap::empty())?.get_attr() - } -} - -impl Directory { - fn access_node(&self, cap: Cap) -> AxResult<&VfsNodeRef> { - self.node.access_or_err(cap, AxError::PermissionDenied) - } - - fn _open_dir_at(dir: Option<&VfsNodeRef>, path: &str, opts: &OpenOptions) -> AxResult { - debug!("open dir: {}", path); - if !opts.read { - return ax_err!(InvalidInput); - } - if opts.create || opts.create_new || opts.write || opts.append || opts.truncate { - return ax_err!(InvalidInput); - } - - let node = crate::root::lookup(dir, path)?; - let attr = node.get_attr()?; - if !attr.is_dir() { - return ax_err!(NotADirectory); - } - let access_cap = opts.into(); - if !perm_to_cap(attr.perm()).contains(access_cap) { - return ax_err!(PermissionDenied); - } - - node.open()?; - Ok(Self { - node: WithCap::new(node, access_cap), - entry_idx: 0, - }) - } - - fn access_at(&self, path: &str) -> AxResult> { - if path.starts_with('/') { - Ok(None) - } else { - Ok(Some(self.access_node(Cap::EXECUTE)?)) - } - } - - /// Opens a directory at the path relative to the current directory. - /// Returns a [`Directory`] object. - pub fn open_dir(path: &str, opts: &OpenOptions) -> AxResult { - Self::_open_dir_at(None, path, opts) - } - - /// Opens a directory at the path relative to this directory. Returns a - /// [`Directory`] object. - pub fn open_dir_at(&self, path: &str, opts: &OpenOptions) -> AxResult { - Self::_open_dir_at(self.access_at(path)?, path, opts) - } - - /// Opens a file at the path relative to this directory. Returns a [`File`] - /// object. - pub fn open_file_at(&self, path: &str, opts: &OpenOptions) -> AxResult { - File::_open_at(self.access_at(path)?, path, opts) - } - - /// Creates an empty file at the path relative to this directory. - pub fn create_file(&self, path: &str) -> AxResult { - crate::root::create_file(self.access_at(path)?, path) - } - - /// Creates an empty directory at the path relative to this directory. - pub fn create_dir(&self, path: &str) -> AxResult { - crate::root::create_dir(self.access_at(path)?, path) - } - - /// Removes a file at the path relative to this directory. - pub fn remove_file(&self, path: &str) -> AxResult { - crate::root::remove_file(self.access_at(path)?, path) - } - - /// Removes a directory at the path relative to this directory. - pub fn remove_dir(&self, path: &str) -> AxResult { - crate::root::remove_dir(self.access_at(path)?, path) - } - - /// Reads directory entries starts from the current position into the - /// given buffer. Returns the number of entries read. - /// - /// After the read, the cursor will be advanced by the number of entries - /// read. - pub fn read_dir(&mut self, dirents: &mut [DirEntry]) -> AxResult { - let n = self - .access_node(Cap::READ)? - .read_dir(self.entry_idx, dirents)?; - self.entry_idx += n; - Ok(n) - } - - /// Rename a file or directory to a new name. - /// Delete the original file if `old` already exists. - /// - /// This only works then the new path is in the same mounted fs. - pub fn rename(&self, old: &str, new: &str) -> AxResult { - crate::root::rename(old, new) - } -} - -impl Drop for File { - fn drop(&mut self) { - unsafe { self.node.access_unchecked().release().ok() }; - } -} - -impl Drop for Directory { - fn drop(&mut self) { - unsafe { self.node.access_unchecked().release().ok() }; - } -} - -impl fmt::Debug for OpenOptions { - #[allow(unused_assignments)] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut written = false; - macro_rules! fmt_opt { - ($field: ident, $label: literal) => { - if self.$field { - if written { - write!(f, " | ")?; - } - write!(f, $label)?; - written = true; - } - }; - } - fmt_opt!(read, "READ"); - fmt_opt!(write, "WRITE"); - fmt_opt!(append, "APPEND"); - fmt_opt!(truncate, "TRUNC"); - fmt_opt!(create, "CREATE"); - fmt_opt!(create_new, "CREATE_NEW"); - Ok(()) - } -} - -impl From<&OpenOptions> for Cap { - fn from(opts: &OpenOptions) -> Cap { - let mut cap = Cap::empty(); - if opts.read { - cap |= Cap::READ; - } - if opts.write | opts.append { - cap |= Cap::WRITE; - } - cap - } -} - -fn perm_to_cap(perm: FilePerm) -> Cap { - let mut cap = Cap::empty(); - if perm.owner_readable() { - cap |= Cap::READ; - } - if perm.owner_writable() { - cap |= Cap::WRITE; - } - if perm.owner_executable() { - cap |= Cap::EXECUTE; - } - cap -} diff --git a/arceos/modules/axfs/src/fs/fatfs.rs b/arceos/modules/axfs/src/fs/fatfs.rs deleted file mode 100644 index 5d0c4c813..000000000 --- a/arceos/modules/axfs/src/fs/fatfs.rs +++ /dev/null @@ -1,283 +0,0 @@ -use alloc::sync::Arc; -use core::cell::UnsafeCell; - -use axfs_vfs::{VfsDirEntry, VfsError, VfsNodePerm, VfsResult}; -use axfs_vfs::{VfsNodeAttr, VfsNodeOps, VfsNodeRef, VfsNodeType, VfsOps}; -use axsync::Mutex; -use fatfs::{Dir, File, LossyOemCpConverter, NullTimeProvider, Read, Seek, SeekFrom, Write}; - -use crate::dev::Disk; - -const BLOCK_SIZE: usize = 512; - -pub struct FatFileSystem { - inner: fatfs::FileSystem, - root_dir: UnsafeCell>, -} - -pub struct FileWrapper<'a>(Mutex>); -pub struct DirWrapper<'a>(Dir<'a, Disk, NullTimeProvider, LossyOemCpConverter>); - -unsafe impl Sync for FatFileSystem {} -unsafe impl Send for FatFileSystem {} -unsafe impl<'a> Send for FileWrapper<'a> {} -unsafe impl<'a> Sync for FileWrapper<'a> {} -unsafe impl<'a> Send for DirWrapper<'a> {} -unsafe impl<'a> Sync for DirWrapper<'a> {} - -impl FatFileSystem { - #[cfg(feature = "use-ramdisk")] - pub fn new(mut disk: Disk) -> Self { - let opts = fatfs::FormatVolumeOptions::new(); - fatfs::format_volume(&mut disk, opts).expect("failed to format volume"); - let inner = fatfs::FileSystem::new(disk, fatfs::FsOptions::new()) - .expect("failed to initialize FAT filesystem"); - Self { - inner, - root_dir: UnsafeCell::new(None), - } - } - - #[cfg(not(feature = "use-ramdisk"))] - pub fn new(disk: Disk) -> Self { - let inner = fatfs::FileSystem::new(disk, fatfs::FsOptions::new()) - .expect("failed to initialize FAT filesystem"); - Self { - inner, - root_dir: UnsafeCell::new(None), - } - } - - pub fn init(&'static self) { - // must be called before later operations - unsafe { *self.root_dir.get() = Some(Self::new_dir(self.inner.root_dir())) } - } - - fn new_file(file: File<'_, Disk, NullTimeProvider, LossyOemCpConverter>) -> Arc { - Arc::new(FileWrapper(Mutex::new(file))) - } - - fn new_dir(dir: Dir<'_, Disk, NullTimeProvider, LossyOemCpConverter>) -> Arc { - Arc::new(DirWrapper(dir)) - } -} - -impl VfsNodeOps for FileWrapper<'static> { - axfs_vfs::impl_vfs_non_dir_default! {} - - fn get_attr(&self) -> VfsResult { - let size = self.0.lock().seek(SeekFrom::End(0)).map_err(as_vfs_err)?; - let blocks = (size + BLOCK_SIZE as u64 - 1) / BLOCK_SIZE as u64; - // FAT fs doesn't support permissions, we just set everything to 755 - let perm = VfsNodePerm::from_bits_truncate(0o755); - Ok(VfsNodeAttr::new(perm, VfsNodeType::File, size, blocks)) - } - - fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { - let mut file = self.0.lock(); - file.seek(SeekFrom::Start(offset)).map_err(as_vfs_err)?; // TODO: more efficient - file.read(buf).map_err(as_vfs_err) - } - - fn write_at(&self, offset: u64, buf: &[u8]) -> VfsResult { - let mut file = self.0.lock(); - file.seek(SeekFrom::Start(offset)).map_err(as_vfs_err)?; // TODO: more efficient - file.write(buf).map_err(as_vfs_err) - } - - fn truncate(&self, size: u64) -> VfsResult { - let mut file = self.0.lock(); - file.seek(SeekFrom::Start(size)).map_err(as_vfs_err)?; // TODO: more efficient - file.truncate().map_err(as_vfs_err) - } -} - -impl VfsNodeOps for DirWrapper<'static> { - axfs_vfs::impl_vfs_dir_default! {} - - fn get_attr(&self) -> VfsResult { - // FAT fs doesn't support permissions, we just set everything to 755 - Ok(VfsNodeAttr::new( - VfsNodePerm::from_bits_truncate(0o755), - VfsNodeType::Dir, - BLOCK_SIZE as u64, - 1, - )) - } - - fn parent(&self) -> Option { - self.0 - .open_dir("..") - .map_or(None, |dir| Some(FatFileSystem::new_dir(dir))) - } - - fn lookup(self: Arc, path: &str) -> VfsResult { - debug!("lookup at fatfs: {}", path); - let path = path.trim_matches('/'); - if path.is_empty() || path == "." { - return Ok(self.clone()); - } - if let Some(rest) = path.strip_prefix("./") { - return self.lookup(rest); - } - - // TODO: use `fatfs::Dir::find_entry`, but it's not public. - if let Ok(file) = self.0.open_file(path) { - Ok(FatFileSystem::new_file(file)) - } else if let Ok(dir) = self.0.open_dir(path) { - Ok(FatFileSystem::new_dir(dir)) - } else { - Err(VfsError::NotFound) - } - } - - fn create(&self, path: &str, ty: VfsNodeType) -> VfsResult { - debug!("create {:?} at fatfs: {}", ty, path); - let path = path.trim_matches('/'); - if path.is_empty() || path == "." { - return Ok(()); - } - if let Some(rest) = path.strip_prefix("./") { - return self.create(rest, ty); - } - - match ty { - VfsNodeType::File => { - self.0.create_file(path).map_err(as_vfs_err)?; - Ok(()) - } - VfsNodeType::Dir => { - self.0.create_dir(path).map_err(as_vfs_err)?; - Ok(()) - } - _ => Err(VfsError::Unsupported), - } - } - - fn remove(&self, path: &str) -> VfsResult { - debug!("remove at fatfs: {}", path); - let path = path.trim_matches('/'); - assert!(!path.is_empty()); // already check at `root.rs` - if let Some(rest) = path.strip_prefix("./") { - return self.remove(rest); - } - self.0.remove(path).map_err(as_vfs_err) - } - - fn read_dir(&self, start_idx: usize, dirents: &mut [VfsDirEntry]) -> VfsResult { - let mut iter = self.0.iter().skip(start_idx); - for (i, out_entry) in dirents.iter_mut().enumerate() { - let x = iter.next(); - match x { - Some(Ok(entry)) => { - let ty = if entry.is_dir() { - VfsNodeType::Dir - } else if entry.is_file() { - VfsNodeType::File - } else { - unreachable!() - }; - *out_entry = VfsDirEntry::new(&entry.file_name(), ty); - } - _ => return Ok(i), - } - } - Ok(dirents.len()) - } - - fn rename(&self, src_path: &str, dst_path: &str) -> VfsResult { - // `src_path` and `dst_path` should in the same mounted fs - debug!( - "rename at fatfs, src_path: {}, dst_path: {}", - src_path, dst_path - ); - - self.0 - .rename(src_path, &self.0, dst_path) - .map_err(as_vfs_err) - } -} - -impl VfsOps for FatFileSystem { - fn root_dir(&self) -> VfsNodeRef { - let root_dir = unsafe { (*self.root_dir.get()).as_ref().unwrap() }; - root_dir.clone() - } -} - -impl fatfs::IoBase for Disk { - type Error = (); -} - -impl Read for Disk { - fn read(&mut self, mut buf: &mut [u8]) -> Result { - let mut read_len = 0; - while !buf.is_empty() { - match self.read_one(buf) { - Ok(0) => break, - Ok(n) => { - let tmp = buf; - buf = &mut tmp[n..]; - read_len += n; - } - Err(_) => return Err(()), - } - } - Ok(read_len) - } -} - -impl Write for Disk { - fn write(&mut self, mut buf: &[u8]) -> Result { - let mut write_len = 0; - while !buf.is_empty() { - match self.write_one(buf) { - Ok(0) => break, - Ok(n) => { - buf = &buf[n..]; - write_len += n; - } - Err(_) => return Err(()), - } - } - Ok(write_len) - } - fn flush(&mut self) -> Result<(), Self::Error> { - Ok(()) - } -} - -impl Seek for Disk { - fn seek(&mut self, pos: SeekFrom) -> Result { - let size = self.size(); - let new_pos = match pos { - SeekFrom::Start(pos) => Some(pos), - SeekFrom::Current(off) => self.position().checked_add_signed(off), - SeekFrom::End(off) => size.checked_add_signed(off), - } - .ok_or(())?; - if new_pos > size { - warn!("Seek beyond the end of the block device"); - } - self.set_position(new_pos); - Ok(new_pos) - } -} - -const fn as_vfs_err(err: fatfs::Error<()>) -> VfsError { - use fatfs::Error::*; - match err { - AlreadyExists => VfsError::AlreadyExists, - CorruptedFileSystem => VfsError::InvalidData, - DirectoryIsNotEmpty => VfsError::DirectoryNotEmpty, - InvalidInput | InvalidFileNameLength | UnsupportedFileNameCharacter => { - VfsError::InvalidInput - } - NotEnoughSpace => VfsError::StorageFull, - NotFound => VfsError::NotFound, - UnexpectedEof => VfsError::UnexpectedEof, - WriteZero => VfsError::WriteZero, - Io(_) => VfsError::Io, - _ => VfsError::Io, - } -} diff --git a/arceos/modules/axfs/src/fs/mod.rs b/arceos/modules/axfs/src/fs/mod.rs deleted file mode 100644 index 77aad60f2..000000000 --- a/arceos/modules/axfs/src/fs/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -cfg_if::cfg_if! { - if #[cfg(feature = "myfs")] { - pub mod myfs; - } else if #[cfg(feature = "fatfs")] { - pub mod fatfs; - } -} - -#[cfg(feature = "devfs")] -pub use axfs_devfs as devfs; - -#[cfg(feature = "ramfs")] -pub use axfs_ramfs as ramfs; diff --git a/arceos/modules/axfs/src/fs/myfs.rs b/arceos/modules/axfs/src/fs/myfs.rs deleted file mode 100644 index ca24fd5c7..000000000 --- a/arceos/modules/axfs/src/fs/myfs.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::dev::Disk; -use alloc::sync::Arc; -use axfs_vfs::VfsOps; - -/// The interface to define custom filesystems in user apps. -#[crate_interface::def_interface] -pub trait MyFileSystemIf { - /// Creates a new instance of the filesystem with initialization. - /// - /// TODO: use generic disk type - fn new_myfs(disk: Disk) -> Arc; -} - -pub(crate) fn new_myfs(disk: Disk) -> Arc { - crate_interface::call_interface!(MyFileSystemIf::new_myfs(disk)) -} diff --git a/arceos/modules/axfs/src/lib.rs b/arceos/modules/axfs/src/lib.rs deleted file mode 100644 index 3fd60b399..000000000 --- a/arceos/modules/axfs/src/lib.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! [ArceOS](https://github.com/arceos-org/arceos) filesystem module. -//! -//! It provides unified filesystem operations for various filesystems. -//! -//! # Cargo Features -//! -//! - `fatfs`: Use [FAT] as the main filesystem and mount it on `/`. This feature -//! is **enabled** by default. -//! - `devfs`: Mount [`axfs_devfs::DeviceFileSystem`] on `/dev`. This feature is -//! **enabled** by default. -//! - `ramfs`: Mount [`axfs_ramfs::RamFileSystem`] on `/tmp`. This feature is -//! **enabled** by default. -//! - `myfs`: Allow users to define their custom filesystems to override the -//! default. In this case, [`MyFileSystemIf`] is required to be implemented -//! to create and initialize other filesystems. This feature is **disabled** by -//! by default, but it will override other filesystem selection features if -//! both are enabled. -//! -//! [FAT]: https://en.wikipedia.org/wiki/File_Allocation_Table -//! [`MyFileSystemIf`]: fops::MyFileSystemIf - -#![cfg_attr(all(not(test), not(doc)), no_std)] -#![feature(doc_auto_cfg)] - -#[macro_use] -extern crate log; -extern crate alloc; - -mod dev; -mod fs; -mod mounts; -mod root; - -pub mod api; -pub mod fops; - -use axdriver::{prelude::*, AxDeviceContainer}; - -/// Initializes filesystems by block devices. -pub fn init_filesystems(mut blk_devs: AxDeviceContainer) { - info!("Initialize filesystems..."); - - let dev = blk_devs.take_one().expect("No block device found!"); - info!(" use block device 0: {:?}", dev.device_name()); - self::root::init_rootfs(self::dev::Disk::new(dev)); -} diff --git a/arceos/modules/axfs/src/mounts.rs b/arceos/modules/axfs/src/mounts.rs deleted file mode 100644 index d3a0e5093..000000000 --- a/arceos/modules/axfs/src/mounts.rs +++ /dev/null @@ -1,80 +0,0 @@ -use alloc::sync::Arc; -use axfs_vfs::{VfsNodeType, VfsOps, VfsResult}; - -use crate::fs; - -#[cfg(feature = "devfs")] -pub(crate) fn devfs() -> Arc { - let null = fs::devfs::NullDev; - let zero = fs::devfs::ZeroDev; - let bar = fs::devfs::ZeroDev; - let devfs = fs::devfs::DeviceFileSystem::new(); - let foo_dir = devfs.mkdir("foo"); - devfs.add("null", Arc::new(null)); - devfs.add("zero", Arc::new(zero)); - foo_dir.add("bar", Arc::new(bar)); - Arc::new(devfs) -} - -#[cfg(feature = "ramfs")] -pub(crate) fn ramfs() -> Arc { - Arc::new(fs::ramfs::RamFileSystem::new()) -} - -#[cfg(feature = "procfs")] -pub(crate) fn procfs() -> VfsResult> { - let procfs = fs::ramfs::RamFileSystem::new(); - let proc_root = procfs.root_dir(); - - // Create /proc/sys/net/core/somaxconn - proc_root.create("sys", VfsNodeType::Dir)?; - proc_root.create("sys/net", VfsNodeType::Dir)?; - proc_root.create("sys/net/core", VfsNodeType::Dir)?; - proc_root.create("sys/net/core/somaxconn", VfsNodeType::File)?; - let file_somaxconn = proc_root.clone().lookup("./sys/net/core/somaxconn")?; - file_somaxconn.write_at(0, b"4096\n")?; - - // Create /proc/sys/vm/overcommit_memory - proc_root.create("sys/vm", VfsNodeType::Dir)?; - proc_root.create("sys/vm/overcommit_memory", VfsNodeType::File)?; - let file_over = proc_root.clone().lookup("./sys/vm/overcommit_memory")?; - file_over.write_at(0, b"0\n")?; - - // Create /proc/self/stat - proc_root.create("self", VfsNodeType::Dir)?; - proc_root.create("self/stat", VfsNodeType::File)?; - - Ok(Arc::new(procfs)) -} - -#[cfg(feature = "sysfs")] -pub(crate) fn sysfs() -> VfsResult> { - let sysfs = fs::ramfs::RamFileSystem::new(); - let sys_root = sysfs.root_dir(); - - // Create /sys/kernel/mm/transparent_hugepage/enabled - sys_root.create("kernel", VfsNodeType::Dir)?; - sys_root.create("kernel/mm", VfsNodeType::Dir)?; - sys_root.create("kernel/mm/transparent_hugepage", VfsNodeType::Dir)?; - sys_root.create("kernel/mm/transparent_hugepage/enabled", VfsNodeType::File)?; - let file_hp = sys_root - .clone() - .lookup("./kernel/mm/transparent_hugepage/enabled")?; - file_hp.write_at(0, b"always [madvise] never\n")?; - - // Create /sys/devices/system/clocksource/clocksource0/current_clocksource - sys_root.create("devices", VfsNodeType::Dir)?; - sys_root.create("devices/system", VfsNodeType::Dir)?; - sys_root.create("devices/system/clocksource", VfsNodeType::Dir)?; - sys_root.create("devices/system/clocksource/clocksource0", VfsNodeType::Dir)?; - sys_root.create( - "devices/system/clocksource/clocksource0/current_clocksource", - VfsNodeType::File, - )?; - let file_cc = sys_root - .clone() - .lookup("devices/system/clocksource/clocksource0/current_clocksource")?; - file_cc.write_at(0, b"tsc\n")?; - - Ok(Arc::new(sysfs)) -} diff --git a/arceos/modules/axfs/src/root.rs b/arceos/modules/axfs/src/root.rs deleted file mode 100644 index c1ddcd018..000000000 --- a/arceos/modules/axfs/src/root.rs +++ /dev/null @@ -1,310 +0,0 @@ -//! Root directory of the filesystem -//! -//! TODO: it doesn't work very well if the mount points have containment relationships. - -use alloc::{string::String, sync::Arc, vec::Vec}; -use axerrno::{ax_err, AxError, AxResult}; -use axfs_vfs::{VfsNodeAttr, VfsNodeOps, VfsNodeRef, VfsNodeType, VfsOps, VfsResult}; -use axsync::Mutex; -use lazyinit::LazyInit; - -use crate::{api::FileType, fs, mounts}; - -static CURRENT_DIR_PATH: Mutex = Mutex::new(String::new()); -static CURRENT_DIR: LazyInit> = LazyInit::new(); - -struct MountPoint { - path: &'static str, - fs: Arc, -} - -struct RootDirectory { - main_fs: Arc, - mounts: Vec, -} - -static ROOT_DIR: LazyInit> = LazyInit::new(); - -impl MountPoint { - pub fn new(path: &'static str, fs: Arc) -> Self { - Self { path, fs } - } -} - -impl Drop for MountPoint { - fn drop(&mut self) { - self.fs.umount().ok(); - } -} - -impl RootDirectory { - pub const fn new(main_fs: Arc) -> Self { - Self { - main_fs, - mounts: Vec::new(), - } - } - - pub fn mount(&mut self, path: &'static str, fs: Arc) -> AxResult { - if path == "/" { - return ax_err!(InvalidInput, "cannot mount root filesystem"); - } - if !path.starts_with('/') { - return ax_err!(InvalidInput, "mount path must start with '/'"); - } - if self.mounts.iter().any(|mp| mp.path == path) { - return ax_err!(InvalidInput, "mount point already exists"); - } - // create the mount point in the main filesystem if it does not exist - self.main_fs.root_dir().create(path, FileType::Dir)?; - fs.mount(path, self.main_fs.root_dir().lookup(path)?)?; - self.mounts.push(MountPoint::new(path, fs)); - Ok(()) - } - - pub fn _umount(&mut self, path: &str) { - self.mounts.retain(|mp| mp.path != path); - } - - pub fn contains(&self, path: &str) -> bool { - self.mounts.iter().any(|mp| mp.path == path) - } - - fn lookup_mounted_fs(&self, path: &str, f: F) -> AxResult - where - F: FnOnce(Arc, &str) -> AxResult, - { - debug!("lookup at root: {}", path); - let path = path.trim_matches('/'); - if let Some(rest) = path.strip_prefix("./") { - return self.lookup_mounted_fs(rest, f); - } - - let mut idx = 0; - let mut max_len = 0; - - // Find the filesystem that has the longest mounted path match - // TODO: more efficient, e.g. trie - for (i, mp) in self.mounts.iter().enumerate() { - // skip the first '/' - if path.starts_with(&mp.path[1..]) && mp.path.len() - 1 > max_len { - max_len = mp.path.len() - 1; - idx = i; - } - } - - if max_len == 0 { - f(self.main_fs.clone(), path) // not matched any mount point - } else { - f(self.mounts[idx].fs.clone(), &path[max_len..]) // matched at `idx` - } - } -} - -impl VfsNodeOps for RootDirectory { - axfs_vfs::impl_vfs_dir_default! {} - - fn get_attr(&self) -> VfsResult { - self.main_fs.root_dir().get_attr() - } - - fn lookup(self: Arc, path: &str) -> VfsResult { - self.lookup_mounted_fs(path, |fs, rest_path| fs.root_dir().lookup(rest_path)) - } - - fn create(&self, path: &str, ty: VfsNodeType) -> VfsResult { - self.lookup_mounted_fs(path, |fs, rest_path| { - if rest_path.is_empty() { - Ok(()) // already exists - } else { - fs.root_dir().create(rest_path, ty) - } - }) - } - - fn remove(&self, path: &str) -> VfsResult { - self.lookup_mounted_fs(path, |fs, rest_path| { - if rest_path.is_empty() { - ax_err!(PermissionDenied) // cannot remove mount points - } else { - fs.root_dir().remove(rest_path) - } - }) - } - - fn rename(&self, src_path: &str, dst_path: &str) -> VfsResult { - self.lookup_mounted_fs(src_path, |fs, rest_path| { - if rest_path.is_empty() { - ax_err!(PermissionDenied) // cannot rename mount points - } else { - fs.root_dir().rename(rest_path, dst_path) - } - }) - } -} - -pub(crate) fn init_rootfs(disk: crate::dev::Disk) { - cfg_if::cfg_if! { - if #[cfg(feature = "myfs")] { // override the default filesystem - let main_fs = fs::myfs::new_myfs(disk); - } else if #[cfg(feature = "fatfs")] { - static FAT_FS: LazyInit> = LazyInit::new(); - FAT_FS.init_once(Arc::new(fs::fatfs::FatFileSystem::new(disk))); - FAT_FS.init(); - let main_fs = FAT_FS.clone(); - } - } - - let mut root_dir = RootDirectory::new(main_fs); - - #[cfg(feature = "devfs")] - root_dir - .mount("/dev", mounts::devfs()) - .expect("failed to mount devfs at /dev"); - - #[cfg(feature = "ramfs")] - root_dir - .mount("/tmp", mounts::ramfs()) - .expect("failed to mount ramfs at /tmp"); - - // Mount another ramfs as procfs - #[cfg(feature = "procfs")] - root_dir // should not fail - .mount("/proc", mounts::procfs().unwrap()) - .expect("fail to mount procfs at /proc"); - - // Mount another ramfs as sysfs - #[cfg(feature = "sysfs")] - root_dir // should not fail - .mount("/sys", mounts::sysfs().unwrap()) - .expect("fail to mount sysfs at /sys"); - - ROOT_DIR.init_once(Arc::new(root_dir)); - CURRENT_DIR.init_once(Mutex::new(ROOT_DIR.clone())); - *CURRENT_DIR_PATH.lock() = "/".into(); -} - -fn parent_node_of(dir: Option<&VfsNodeRef>, path: &str) -> VfsNodeRef { - if path.starts_with('/') { - ROOT_DIR.clone() - } else { - dir.cloned().unwrap_or_else(|| CURRENT_DIR.lock().clone()) - } -} - -pub(crate) fn absolute_path(path: &str) -> AxResult { - if path.starts_with('/') { - Ok(axfs_vfs::path::canonicalize(path)) - } else { - let path = CURRENT_DIR_PATH.lock().clone() + path; - Ok(axfs_vfs::path::canonicalize(&path)) - } -} - -pub(crate) fn lookup(dir: Option<&VfsNodeRef>, path: &str) -> AxResult { - if path.is_empty() { - return ax_err!(NotFound); - } - let node = parent_node_of(dir, path).lookup(path)?; - if path.ends_with('/') && !node.get_attr()?.is_dir() { - ax_err!(NotADirectory) - } else { - Ok(node) - } -} - -pub(crate) fn create_file(dir: Option<&VfsNodeRef>, path: &str) -> AxResult { - if path.is_empty() { - return ax_err!(NotFound); - } else if path.ends_with('/') { - return ax_err!(NotADirectory); - } - let parent = parent_node_of(dir, path); - parent.create(path, VfsNodeType::File)?; - parent.lookup(path) -} - -pub(crate) fn create_dir(dir: Option<&VfsNodeRef>, path: &str) -> AxResult { - match lookup(dir, path) { - Ok(_) => ax_err!(AlreadyExists), - Err(AxError::NotFound) => parent_node_of(dir, path).create(path, VfsNodeType::Dir), - Err(e) => Err(e), - } -} - -pub(crate) fn remove_file(dir: Option<&VfsNodeRef>, path: &str) -> AxResult { - let node = lookup(dir, path)?; - let attr = node.get_attr()?; - if attr.is_dir() { - ax_err!(IsADirectory) - } else if !attr.perm().owner_writable() { - ax_err!(PermissionDenied) - } else { - parent_node_of(dir, path).remove(path) - } -} - -pub(crate) fn remove_dir(dir: Option<&VfsNodeRef>, path: &str) -> AxResult { - if path.is_empty() { - return ax_err!(NotFound); - } - let path_check = path.trim_matches('/'); - if path_check.is_empty() { - return ax_err!(DirectoryNotEmpty); // rm -d '/' - } else if path_check == "." - || path_check == ".." - || path_check.ends_with("/.") - || path_check.ends_with("/..") - { - return ax_err!(InvalidInput); - } - if ROOT_DIR.contains(&absolute_path(path)?) { - return ax_err!(PermissionDenied); - } - - let node = lookup(dir, path)?; - let attr = node.get_attr()?; - if !attr.is_dir() { - ax_err!(NotADirectory) - } else if !attr.perm().owner_writable() { - ax_err!(PermissionDenied) - } else { - parent_node_of(dir, path).remove(path) - } -} - -pub(crate) fn current_dir() -> AxResult { - Ok(CURRENT_DIR_PATH.lock().clone()) -} - -pub(crate) fn set_current_dir(path: &str) -> AxResult { - let mut abs_path = absolute_path(path)?; - if !abs_path.ends_with('/') { - abs_path += "/"; - } - if abs_path == "/" { - *CURRENT_DIR.lock() = ROOT_DIR.clone(); - *CURRENT_DIR_PATH.lock() = "/".into(); - return Ok(()); - } - - let node = lookup(None, &abs_path)?; - let attr = node.get_attr()?; - if !attr.is_dir() { - ax_err!(NotADirectory) - } else if !attr.perm().owner_executable() { - ax_err!(PermissionDenied) - } else { - *CURRENT_DIR.lock() = node; - *CURRENT_DIR_PATH.lock() = abs_path; - Ok(()) - } -} - -pub(crate) fn rename(old: &str, new: &str) -> AxResult { - if parent_node_of(None, new).lookup(new).is_ok() { - warn!("dst file already exist, now remove it"); - remove_file(None, new)?; - } - parent_node_of(None, old).rename(old, new) -} diff --git a/arceos/modules/axfs/tests/test_common/mod.rs b/arceos/modules/axfs/tests/test_common/mod.rs deleted file mode 100644 index 4746e37b4..000000000 --- a/arceos/modules/axfs/tests/test_common/mod.rs +++ /dev/null @@ -1,262 +0,0 @@ -use axfs::api as fs; -use axio as io; - -use fs::{File, FileType, OpenOptions}; -use io::{prelude::*, Error, Result}; - -macro_rules! assert_err { - ($expr: expr) => { - assert!(($expr).is_err()) - }; - ($expr: expr, $err: ident) => { - assert_eq!(($expr).err(), Some(Error::$err)) - }; -} - -fn test_read_write_file() -> Result<()> { - let fname = "///very/long//.././long//./path/./test.txt"; - println!("read and write file {:?}:", fname); - - // read and write - let mut file = File::options().read(true).write(true).open(fname)?; - let file_size = file.metadata()?.len(); - let mut contents = String::new(); - file.read_to_string(&mut contents)?; - print!("{}", contents); - assert_eq!(contents.len(), file_size as usize); - assert_eq!(file.write(b"Hello, world!\n")?, 14); // append - drop(file); - - // read again and check - let new_contents = fs::read_to_string(fname)?; - print!("{}", new_contents); - assert_eq!(new_contents, contents + "Hello, world!\n"); - - // append and check - let mut file = OpenOptions::new().append(true).open(fname)?; - assert_eq!(file.write(b"new line\n")?, 9); - drop(file); - - let new_contents2 = fs::read_to_string(fname)?; - print!("{}", new_contents2); - assert_eq!(new_contents2, new_contents + "new line\n"); - - // open a non-exist file - assert_err!(File::open("/not/exist/file"), NotFound); - - println!("test_read_write_file() OK!"); - Ok(()) -} - -fn test_read_dir() -> Result<()> { - let dir = "/././//./"; - println!("list directory {:?}:", dir); - for entry in fs::read_dir(dir)? { - let entry = entry?; - println!(" {}", entry.file_name()); - } - println!("test_read_dir() OK!"); - Ok(()) -} - -fn test_file_permission() -> Result<()> { - let fname = "./short.txt"; - println!("test permission {:?}:", fname); - - // write a file that open with read-only mode - let mut buf = [0; 256]; - let mut file = File::open(fname)?; - let n = file.read(&mut buf)?; - assert_err!(file.write(&buf), PermissionDenied); - drop(file); - - // read a file that open with write-only mode - let mut file = File::create(fname)?; - assert_err!(file.read(&mut buf), PermissionDenied); - assert!(file.write(&buf[..n]).is_ok()); - drop(file); - - // open with empty options - assert_err!(OpenOptions::new().open(fname), InvalidInput); - - // read as a directory - assert_err!(fs::read_dir(fname), NotADirectory); - assert_err!(fs::read("short.txt/"), NotADirectory); - assert_err!(fs::metadata("/short.txt/"), NotADirectory); - - // create as a directory - assert_err!(fs::write("error/", "should not create"), NotADirectory); - assert_err!(fs::metadata("error/"), NotFound); - assert_err!(fs::metadata("error"), NotFound); - - // read/write a directory - assert_err!(fs::read_to_string("/dev"), IsADirectory); - assert_err!(fs::write(".", "test"), IsADirectory); - - println!("test_file_permisson() OK!"); - Ok(()) -} - -fn test_create_file_dir() -> Result<()> { - // create a file and test existence - let fname = "././/very-long-dir-name/..///new-file.txt"; - println!("test create file {:?}:", fname); - assert_err!(fs::metadata(fname), NotFound); - let contents = "create a new file!\n"; - fs::write(fname, contents)?; - - let dirents = fs::read_dir(".")? - .map(|e| e.unwrap().file_name()) - .collect::>(); - println!("dirents = {:?}", dirents); - assert!(dirents.contains(&"new-file.txt".into())); - assert_eq!(fs::read_to_string(fname)?, contents); - assert_err!(File::create_new(fname), AlreadyExists); - - // create a directory and test existence - let dirname = "///././/very//.//long/./new-dir"; - println!("test create dir {:?}:", dirname); - assert_err!(fs::metadata(dirname), NotFound); - fs::create_dir(dirname)?; - - let dirents = fs::read_dir("./very/long")? - .map(|e| e.unwrap().file_name()) - .collect::>(); - println!("dirents = {:?}", dirents); - assert!(dirents.contains(&"new-dir".into())); - assert!(fs::metadata(dirname)?.is_dir()); - assert_err!(fs::create_dir(dirname), AlreadyExists); - - println!("test_create_file_dir() OK!"); - Ok(()) -} - -fn test_remove_file_dir() -> Result<()> { - // remove a file and test existence - let fname = "//very-long-dir-name/..///new-file.txt"; - println!("test remove file {:?}:", fname); - assert_err!(fs::remove_dir(fname), NotADirectory); - assert!(fs::remove_file(fname).is_ok()); - assert_err!(fs::metadata(fname), NotFound); - assert_err!(fs::remove_file(fname), NotFound); - - // remove a directory and test existence - let dirname = "very//.//long/../long/.//./new-dir////"; - println!("test remove dir {:?}:", dirname); - assert_err!(fs::remove_file(dirname), IsADirectory); - assert!(fs::remove_dir(dirname).is_ok()); - assert_err!(fs::metadata(dirname), NotFound); - assert_err!(fs::remove_dir(fname), NotFound); - - // error cases - assert_err!(fs::remove_file(""), NotFound); - assert_err!(fs::remove_dir("/"), DirectoryNotEmpty); - assert_err!(fs::remove_dir("."), InvalidInput); - assert_err!(fs::remove_dir("../"), InvalidInput); - assert_err!(fs::remove_dir("./././/"), InvalidInput); - assert_err!(fs::remove_file("///very/./"), IsADirectory); - assert_err!(fs::remove_file("short.txt/"), NotADirectory); - assert_err!(fs::remove_dir(".///"), InvalidInput); - assert_err!(fs::remove_dir("/./very///"), DirectoryNotEmpty); - assert_err!(fs::remove_dir("very/long/.."), InvalidInput); - - println!("test_remove_file_dir() OK!"); - Ok(()) -} - -fn test_devfs_ramfs() -> Result<()> { - const N: usize = 32; - let mut buf = [1; N]; - - // list '/' and check if /dev and /tmp exist - let dirents = fs::read_dir("././//.//")? - .map(|e| e.unwrap().file_name()) - .collect::>(); - assert!(dirents.contains(&"dev".into())); - assert!(dirents.contains(&"tmp".into())); - - // read and write /dev/null - let mut file = File::options().read(true).write(true).open("/dev/./null")?; - assert_eq!(file.read_to_end(&mut Vec::new())?, 0); - assert_eq!(file.write(&buf)?, N); - assert_eq!(buf, [1; N]); - - // read and write /dev/zero - let mut file = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .truncate(true) - .open("////dev/zero")?; - assert_eq!(file.read(&mut buf)?, N); - assert!(file.write_all(&buf).is_ok()); - assert_eq!(buf, [0; N]); - - // list /dev - let dirents = fs::read_dir("/dev")? - .map(|e| e.unwrap().file_name()) - .collect::>(); - assert!(dirents.contains(&"null".into())); - assert!(dirents.contains(&"zero".into())); - - // stat /dev - let dname = "/dev"; - let dir = File::open(dname)?; - let md = dir.metadata()?; - println!("metadata of {:?}: {:?}", dname, md); - assert_eq!(md.file_type(), FileType::Dir); - assert!(!md.is_file()); - assert!(md.is_dir()); - - // stat /dev/foo/bar - let fname = ".//.///././/./dev///.///./foo//././bar"; - let file = File::open(fname)?; - let md = file.metadata()?; - println!("metadata of {:?}: {:?}", fname, md); - assert_eq!(md.file_type(), FileType::CharDevice); - assert!(!md.is_dir()); - - // error cases - assert_err!(fs::metadata("/dev/null/"), NotADirectory); - assert_err!(fs::create_dir("dev"), AlreadyExists); - assert_err!(File::create_new("/dev/"), AlreadyExists); - assert_err!(fs::create_dir("/dev/zero"), AlreadyExists); - assert_err!(fs::write("/dev/stdout", "test"), PermissionDenied); - assert_err!(fs::create_dir("/dev/test"), PermissionDenied); - assert_err!(fs::remove_file("/dev/null"), PermissionDenied); - assert_err!(fs::remove_dir("./dev"), PermissionDenied); - assert_err!(fs::remove_dir("./dev/."), InvalidInput); - assert_err!(fs::remove_dir("///dev//..//"), InvalidInput); - - // parent of '/dev' - assert_eq!(fs::create_dir("///dev//..//233//"), Ok(())); - assert_eq!(fs::write(".///dev//..//233//.///test.txt", "test"), Ok(())); - assert_err!(fs::remove_file("./dev//../..//233//.///test.txt"), NotFound); - assert_eq!(fs::remove_file("./dev//..//233//../233/./test.txt"), Ok(())); - assert_eq!(fs::remove_dir("dev//foo/../foo/../.././/233"), Ok(())); - assert_err!(fs::remove_dir("very/../dev//"), PermissionDenied); - - // tests in /tmp - assert_eq!(fs::metadata("tmp")?.file_type(), FileType::Dir); - assert_eq!(fs::create_dir(".///tmp///././dir"), Ok(())); - assert_eq!(fs::read_dir("tmp").unwrap().count(), 1); - assert_eq!(fs::write(".///tmp///dir//.///test.txt", "test"), Ok(())); - assert_eq!(fs::read("tmp//././/dir//.///test.txt"), Ok("test".into())); - // assert_err!(fs::remove_dir("dev/../tmp//dir"), DirectoryNotEmpty); // TODO - assert_err!(fs::remove_dir("/tmp/dir/../dir"), DirectoryNotEmpty); - assert_eq!(fs::remove_file("./tmp//dir//test.txt"), Ok(())); - assert_eq!(fs::remove_dir("tmp/dir/.././dir///"), Ok(())); - assert_eq!(fs::read_dir("tmp").unwrap().count(), 0); - - println!("test_devfs_ramfs() OK!"); - Ok(()) -} - -pub fn test_all() { - test_read_write_file().expect("test_read_write_file() failed"); - test_read_dir().expect("test_read_dir() failed"); - test_file_permission().expect("test_file_permission() failed"); - test_create_file_dir().expect("test_create_file_dir() failed"); - test_remove_file_dir().expect("test_remove_file_dir() failed"); - test_devfs_ramfs().expect("test_devfs_ramfs() failed"); -} diff --git a/arceos/modules/axfs/tests/test_fatfs.rs b/arceos/modules/axfs/tests/test_fatfs.rs deleted file mode 100644 index b05950d50..000000000 --- a/arceos/modules/axfs/tests/test_fatfs.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![cfg(not(feature = "myfs"))] - -mod test_common; - -use axdriver::AxDeviceContainer; -use axdriver_block::ramdisk::RamDisk; - -const IMG_PATH: &str = "resources/fat16.img"; - -fn make_disk() -> std::io::Result { - let path = std::env::current_dir()?.join(IMG_PATH); - println!("Loading disk image from {:?} ...", path); - let data = std::fs::read(path)?; - println!("size = {} bytes", data.len()); - Ok(RamDisk::from(&data)) -} - -#[test] -fn test_fatfs() { - println!("Testing fatfs with ramdisk ..."); - - let disk = make_disk().expect("failed to load disk image"); - axtask::init_scheduler(); // call this to use `axsync::Mutex`. - axfs::init_filesystems(AxDeviceContainer::from_one(disk)); - - test_common::test_all(); -} diff --git a/arceos/modules/axfs/tests/test_ramfs.rs b/arceos/modules/axfs/tests/test_ramfs.rs deleted file mode 100644 index 914c245bc..000000000 --- a/arceos/modules/axfs/tests/test_ramfs.rs +++ /dev/null @@ -1,56 +0,0 @@ -#![cfg(feature = "myfs")] - -mod test_common; - -use std::sync::Arc; - -use axdriver::AxDeviceContainer; -use axdriver_block::ramdisk::RamDisk; -use axfs::api::{self as fs, File}; -use axfs::fops::{Disk, MyFileSystemIf}; -use axfs_ramfs::RamFileSystem; -use axfs_vfs::VfsOps; -use axio::{Result, Write}; - -struct MyFileSystemIfImpl; - -#[crate_interface::impl_interface] -impl MyFileSystemIf for MyFileSystemIfImpl { - fn new_myfs(_disk: Disk) -> Arc { - Arc::new(RamFileSystem::new()) - } -} - -fn create_init_files() -> Result<()> { - fs::write("./short.txt", "Rust is cool!\n")?; - let mut file = File::create_new("/long.txt")?; - for _ in 0..100 { - file.write_fmt(format_args!("Rust is cool!\n"))?; - } - - fs::create_dir("very-long-dir-name")?; - fs::write( - "very-long-dir-name/very-long-file-name.txt", - "Rust is cool!\n", - )?; - - fs::create_dir("very")?; - fs::create_dir("//very/long")?; - fs::create_dir("/./very/long/path")?; - fs::write(".//very/long/path/test.txt", "Rust is cool!\n")?; - Ok(()) -} - -#[test] -fn test_ramfs() { - println!("Testing ramfs ..."); - - axtask::init_scheduler(); // call this to use `axsync::Mutex`. - axfs::init_filesystems(AxDeviceContainer::from_one(RamDisk::default())); // dummy disk, actually not used. - - if let Err(e) = create_init_files() { - log::warn!("failed to create init files: {:?}", e); - } - - test_common::test_all(); -} diff --git a/arceos/modules/axhal/.gitignore b/arceos/modules/axhal/.gitignore deleted file mode 100644 index 8092b09fe..000000000 --- a/arceos/modules/axhal/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/linker_*.lds diff --git a/arceos/modules/axhal/Cargo.toml b/arceos/modules/axhal/Cargo.toml deleted file mode 100644 index 871d38a3c..000000000 --- a/arceos/modules/axhal/Cargo.toml +++ /dev/null @@ -1,63 +0,0 @@ -[package] -name = "axhal" -version.workspace = true -edition = "2021" -authors = ["Yuekai Jia "] -description = "ArceOS hardware abstraction layer, provides unified APIs for platform-specific operations" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/modules/axhal" -documentation = "https://arceos-org.github.io/arceos/axhal/index.html" - -[features] -smp = [] -alloc = [] -fp_simd = [] -paging = ["axalloc", "page_table_multiarch"] -irq = [] -tls = ["alloc"] -rtc = ["x86_rtc", "riscv_goldfish", "arm_pl031"] -uspace = ["paging"] -default = [] - -[dependencies] -log = "0.4.21" -cfg-if = "1.0" -linkme = "0.3" -bitflags = "2.6" -static_assertions = "1.1.0" -kernel_guard = "0.1" -kspin = "0.1" -int_ratio = "0.1" -lazyinit = "0.2" -percpu = "0.1" -memory_addr = "0.3" -handler_table = "0.1" -page_table_entry = "0.4" -page_table_multiarch = { version = "0.4", optional = true } -axlog = { workspace = true } -axconfig = { workspace = true } -axalloc = { workspace = true, optional = true } - -[target.'cfg(target_arch = "x86_64")'.dependencies] -x86 = "0.52" -x86_64 = "0.15" -x2apic = "0.4" -raw-cpuid = "11.1" -x86_rtc = { version = "0.1", optional = true } - -[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies] -riscv = "0.11" -sbi-rt = { version = "0.0.3", features = ["legacy"] } -riscv_goldfish = { version = "0.1", optional = true } - -[target.'cfg(target_arch = "aarch64")'.dependencies] -aarch64-cpu = "9.4" -tock-registers = "0.8" -arm_gicv2 = "0.1" -arm_pl011 = "0.1" -arm_pl031 = { version = "0.2", optional = true } -dw_apb_uart = "0.1" - -[build-dependencies] -axconfig = { workspace = true } diff --git a/arceos/modules/axhal/build.rs b/arceos/modules/axhal/build.rs deleted file mode 100644 index c40f60359..000000000 --- a/arceos/modules/axhal/build.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::io::Result; -use std::path::Path; - -const BUILTIN_PLATFORMS: &[&str] = &[ - "aarch64-bsta1000b", - "aarch64-qemu-virt", - "aarch64-raspi4", - "riscv64-qemu-virt", - "x86_64-pc-oslab", - "x86_64-qemu-q35", -]; - -const BUILTIN_PLATFORM_FAMILIES: &[&str] = &[ - "aarch64-bsta1000b", - "aarch64-qemu-virt", - "aarch64-raspi", - "riscv64-qemu-virt", - "x86-pc", -]; - -fn make_cfg_values(str_list: &[&str]) -> String { - str_list - .iter() - .map(|s| format!("{:?}", s)) - .collect::>() - .join(", ") -} - -fn main() { - let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - let platform = axconfig::PLATFORM; - if platform != "dummy" { - gen_linker_script(&arch, platform).unwrap(); - } - - println!("cargo:rustc-cfg=platform=\"{}\"", platform); - println!("cargo:rustc-cfg=platform_family=\"{}\"", axconfig::FAMILY); - println!( - "cargo::rustc-check-cfg=cfg(platform, values({}))", - make_cfg_values(BUILTIN_PLATFORMS) - ); - println!( - "cargo::rustc-check-cfg=cfg(platform_family, values({}))", - make_cfg_values(BUILTIN_PLATFORM_FAMILIES) - ); -} - -fn gen_linker_script(arch: &str, platform: &str) -> Result<()> { - let fname = format!("linker_{}.lds", platform); - let output_arch = if arch == "x86_64" { - "i386:x86-64" - } else if arch.contains("riscv") { - "riscv" // OUTPUT_ARCH of both riscv32/riscv64 is "riscv" - } else { - arch - }; - let ld_content = std::fs::read_to_string("linker.lds.S")?; - let ld_content = ld_content.replace("%ARCH%", output_arch); - let ld_content = ld_content.replace( - "%KERNEL_BASE%", - &format!("{:#x}", axconfig::KERNEL_BASE_VADDR), - ); - let ld_content = ld_content.replace("%SMP%", &format!("{}", axconfig::SMP)); - - // target///build/axhal-xxxx/out - let out_dir = std::env::var("OUT_DIR").unwrap(); - // target///linker_xxxx.lds - let out_path = Path::new(&out_dir).join("../../..").join(fname); - std::fs::write(out_path, ld_content)?; - Ok(()) -} diff --git a/arceos/modules/axhal/linker.lds.S b/arceos/modules/axhal/linker.lds.S deleted file mode 100644 index b8d42ee77..000000000 --- a/arceos/modules/axhal/linker.lds.S +++ /dev/null @@ -1,93 +0,0 @@ -OUTPUT_ARCH(%ARCH%) - -BASE_ADDRESS = %KERNEL_BASE%; - -ENTRY(_start) -SECTIONS -{ - . = BASE_ADDRESS; - _skernel = .; - - .text : ALIGN(4K) { - _stext = .; - *(.text.boot) - *(.text .text.*) - . = ALIGN(4K); - _etext = .; - } - - .rodata : ALIGN(4K) { - _srodata = .; - *(.rodata .rodata.*) - *(.srodata .srodata.*) - *(.sdata2 .sdata2.*) - . = ALIGN(4K); - _erodata = .; - } - - .data : ALIGN(4K) { - _sdata = .; - *(.data.boot_page_table) - . = ALIGN(4K); - *(.data .data.*) - *(.sdata .sdata.*) - *(.got .got.*) - } - - .tdata : ALIGN(0x10) { - _stdata = .; - *(.tdata .tdata.*) - _etdata = .; - } - - .tbss : ALIGN(0x10) { - _stbss = .; - *(.tbss .tbss.*) - *(.tcommon) - _etbss = .; - } - - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * %SMP%; - } - . = _percpu_end; - - . = ALIGN(4K); - _edata = .; - - .bss : ALIGN(4K) { - boot_stack = .; - *(.bss.stack) - . = ALIGN(4K); - boot_stack_top = .; - - _sbss = .; - *(.bss .bss.*) - *(.sbss .sbss.*) - *(COMMON) - . = ALIGN(4K); - _ebss = .; - } - - _ekernel = .; - - /DISCARD/ : { - *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) - } -} - -SECTIONS { - linkme_IRQ : { *(linkme_IRQ) } - linkm2_IRQ : { *(linkm2_IRQ) } - linkme_PAGE_FAULT : { *(linkme_PAGE_FAULT) } - linkm2_PAGE_FAULT : { *(linkm2_PAGE_FAULT) } - linkme_SYSCALL : { *(linkme_SYSCALL) } - linkm2_SYSCALL : { *(linkm2_SYSCALL) } -} -INSERT AFTER .tbss; diff --git a/arceos/modules/axhal/src/arch/aarch64/context.rs b/arceos/modules/axhal/src/arch/aarch64/context.rs deleted file mode 100644 index 67b923364..000000000 --- a/arceos/modules/axhal/src/arch/aarch64/context.rs +++ /dev/null @@ -1,179 +0,0 @@ -use core::arch::asm; -use memory_addr::VirtAddr; - -/// Saved registers when a trap (exception) occurs. -#[repr(C)] -#[derive(Debug, Default, Clone, Copy)] -pub struct TrapFrame { - /// General-purpose registers (R0..R30). - pub r: [u64; 31], - /// User Stack Pointer (SP_EL0). - pub usp: u64, - /// Exception Link Register (ELR_EL1). - pub elr: u64, - /// Saved Process Status Register (SPSR_EL1). - pub spsr: u64, -} - -/// FP & SIMD registers. -#[repr(C, align(16))] -#[derive(Debug, Default)] -pub struct FpState { - /// 128-bit SIMD & FP registers (V0..V31) - pub regs: [u128; 32], - /// Floating-point Control Register (FPCR) - pub fpcr: u32, - /// Floating-point Status Register (FPSR) - pub fpsr: u32, -} - -#[cfg(feature = "fp_simd")] -impl FpState { - fn switch_to(&mut self, next_fpstate: &FpState) { - unsafe { fpstate_switch(self, next_fpstate) } - } -} - -/// Saved hardware states of a task. -/// -/// The context usually includes: -/// -/// - Callee-saved registers -/// - Stack pointer register -/// - Thread pointer register (for thread-local storage, currently unsupported) -/// - FP/SIMD registers -/// -/// On context switch, current task saves its context from CPU to memory, -/// and the next task restores its context from memory to CPU. -#[allow(missing_docs)] -#[repr(C)] -#[derive(Debug)] -pub struct TaskContext { - pub sp: u64, - pub tpidr_el0: u64, - pub r19: u64, - pub r20: u64, - pub r21: u64, - pub r22: u64, - pub r23: u64, - pub r24: u64, - pub r25: u64, - pub r26: u64, - pub r27: u64, - pub r28: u64, - pub r29: u64, - pub lr: u64, // r30 - #[cfg(feature = "fp_simd")] - pub fp_state: FpState, -} - -impl TaskContext { - /// Creates a new default context for a new task. - pub const fn new() -> Self { - unsafe { core::mem::MaybeUninit::zeroed().assume_init() } - } - - /// Initializes the context for a new task, with the given entry point and - /// kernel stack. - pub fn init(&mut self, entry: usize, kstack_top: VirtAddr, tls_area: VirtAddr) { - self.sp = kstack_top.as_usize() as u64; - self.lr = entry as u64; - self.tpidr_el0 = tls_area.as_usize() as u64; - } - - /// Switches to another task. - /// - /// It first saves the current task's context from CPU to this place, and then - /// restores the next task's context from `next_ctx` to CPU. - pub fn switch_to(&mut self, next_ctx: &Self) { - #[cfg(feature = "fp_simd")] - self.fp_state.switch_to(&next_ctx.fp_state); - unsafe { context_switch(self, next_ctx) } - } -} - -#[naked] -unsafe extern "C" fn context_switch(_current_task: &mut TaskContext, _next_task: &TaskContext) { - asm!( - " - // save old context (callee-saved registers) - stp x29, x30, [x0, 12 * 8] - stp x27, x28, [x0, 10 * 8] - stp x25, x26, [x0, 8 * 8] - stp x23, x24, [x0, 6 * 8] - stp x21, x22, [x0, 4 * 8] - stp x19, x20, [x0, 2 * 8] - mov x19, sp - mrs x20, tpidr_el0 - stp x19, x20, [x0] - - // restore new context - ldp x19, x20, [x1] - mov sp, x19 - msr tpidr_el0, x20 - ldp x19, x20, [x1, 2 * 8] - ldp x21, x22, [x1, 4 * 8] - ldp x23, x24, [x1, 6 * 8] - ldp x25, x26, [x1, 8 * 8] - ldp x27, x28, [x1, 10 * 8] - ldp x29, x30, [x1, 12 * 8] - - ret", - options(noreturn), - ) -} - -#[naked] -#[cfg(feature = "fp_simd")] -unsafe extern "C" fn fpstate_switch(_current_fpstate: &mut FpState, _next_fpstate: &FpState) { - asm!( - " - // save fp/neon context - mrs x9, fpcr - mrs x10, fpsr - stp q0, q1, [x0, 0 * 16] - stp q2, q3, [x0, 2 * 16] - stp q4, q5, [x0, 4 * 16] - stp q6, q7, [x0, 6 * 16] - stp q8, q9, [x0, 8 * 16] - stp q10, q11, [x0, 10 * 16] - stp q12, q13, [x0, 12 * 16] - stp q14, q15, [x0, 14 * 16] - stp q16, q17, [x0, 16 * 16] - stp q18, q19, [x0, 18 * 16] - stp q20, q21, [x0, 20 * 16] - stp q22, q23, [x0, 22 * 16] - stp q24, q25, [x0, 24 * 16] - stp q26, q27, [x0, 26 * 16] - stp q28, q29, [x0, 28 * 16] - stp q30, q31, [x0, 30 * 16] - str x9, [x0, 64 * 8] - str x10, [x0, 65 * 8] - - // restore fp/neon context - ldp q0, q1, [x1, 0 * 16] - ldp q2, q3, [x1, 2 * 16] - ldp q4, q5, [x1, 4 * 16] - ldp q6, q7, [x1, 6 * 16] - ldp q8, q9, [x1, 8 * 16] - ldp q10, q11, [x1, 10 * 16] - ldp q12, q13, [x1, 12 * 16] - ldp q14, q15, [x1, 14 * 16] - ldp q16, q17, [x1, 16 * 16] - ldp q18, q19, [x1, 18 * 16] - ldp q20, q21, [x1, 20 * 16] - ldp q22, q23, [x1, 22 * 16] - ldp q24, q25, [x1, 24 * 16] - ldp q26, q27, [x1, 26 * 16] - ldp q28, q29, [x1, 28 * 16] - ldp q30, q31, [x1, 30 * 16] - ldr x9, [x1, 64 * 8] - ldr x10, [x1, 65 * 8] - msr fpcr, x9 - msr fpsr, x10 - - isb - ret", - options(noreturn), - ) -} diff --git a/arceos/modules/axhal/src/arch/aarch64/mod.rs b/arceos/modules/axhal/src/arch/aarch64/mod.rs deleted file mode 100644 index 160dabdd1..000000000 --- a/arceos/modules/axhal/src/arch/aarch64/mod.rs +++ /dev/null @@ -1,137 +0,0 @@ -mod context; -pub(crate) mod trap; - -use core::arch::asm; - -use aarch64_cpu::registers::{DAIF, TPIDR_EL0, TTBR0_EL1, TTBR1_EL1, VBAR_EL1}; -use memory_addr::{PhysAddr, VirtAddr}; -use tock_registers::interfaces::{Readable, Writeable}; - -pub use self::context::{FpState, TaskContext, TrapFrame}; - -/// Allows the current CPU to respond to interrupts. -#[inline] -pub fn enable_irqs() { - unsafe { asm!("msr daifclr, #2") }; -} - -/// Makes the current CPU to ignore interrupts. -#[inline] -pub fn disable_irqs() { - unsafe { asm!("msr daifset, #2") }; -} - -/// Returns whether the current CPU is allowed to respond to interrupts. -#[inline] -pub fn irqs_enabled() -> bool { - !DAIF.matches_all(DAIF::I::Masked) -} - -/// Relaxes the current CPU and waits for interrupts. -/// -/// It must be called with interrupts enabled, otherwise it will never return. -#[inline] -pub fn wait_for_irqs() { - aarch64_cpu::asm::wfi(); -} - -/// Halt the current CPU. -#[inline] -pub fn halt() { - disable_irqs(); - aarch64_cpu::asm::wfi(); // should never return -} - -/// Reads the register that stores the current page table root. -/// -/// Returns the physical address of the page table root. -#[inline] -pub fn read_page_table_root() -> PhysAddr { - let root = TTBR1_EL1.get(); - pa!(root as usize) -} - -/// Reads the `TTBR0_EL1` register. -pub fn read_page_table_root0() -> PhysAddr { - let root = TTBR0_EL1.get(); - pa!(root as usize) -} - -/// Writes the register to update the current page table root. -/// -/// # Safety -/// -/// This function is unsafe as it changes the virtual memory address space. -pub unsafe fn write_page_table_root(root_paddr: PhysAddr) { - let old_root = read_page_table_root(); - trace!("set page table root: {:#x} => {:#x}", old_root, root_paddr); - if old_root != root_paddr { - // kernel space page table use TTBR1 (0xffff_0000_0000_0000..0xffff_ffff_ffff_ffff) - TTBR1_EL1.set(root_paddr.as_usize() as _); - flush_tlb(None); - } -} - -/// Writes the `TTBR0_EL1` register. -/// -/// # Safety -/// -/// This function is unsafe as it changes the virtual memory address space. -pub unsafe fn write_page_table_root0(root_paddr: PhysAddr) { - TTBR0_EL1.set(root_paddr.as_usize() as _); - flush_tlb(None); -} - -/// Flushes the TLB. -/// -/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB -/// entry that maps the given virtual address. -#[inline] -pub fn flush_tlb(vaddr: Option) { - unsafe { - if let Some(vaddr) = vaddr { - asm!("tlbi vaae1is, {}; dsb sy; isb", in(reg) vaddr.as_usize()) - } else { - // flush the entire TLB - asm!("tlbi vmalle1; dsb sy; isb") - } - } -} - -/// Flushes the entire instruction cache. -#[inline] -pub fn flush_icache_all() { - unsafe { asm!("ic iallu; dsb sy; isb") }; -} - -/// Sets the base address of the exception vector (writes `VBAR_EL1`). -#[inline] -pub fn set_exception_vector_base(vbar_el1: usize) { - VBAR_EL1.set(vbar_el1 as _); -} - -/// Flushes the data cache line (64 bytes) at the given virtual address -#[inline] -pub fn flush_dcache_line(vaddr: VirtAddr) { - unsafe { asm!("dc ivac, {0:x}; dsb sy; isb", in(reg) vaddr.as_usize()) }; -} - -/// Reads the thread pointer of the current CPU. -/// -/// It is used to implement TLS (Thread Local Storage). -#[inline] -pub fn read_thread_pointer() -> usize { - TPIDR_EL0.get() as usize -} - -/// Writes the thread pointer of the current CPU. -/// -/// It is used to implement TLS (Thread Local Storage). -/// -/// # Safety -/// -/// This function is unsafe as it changes the CPU states. -#[inline] -pub unsafe fn write_thread_pointer(tpidr_el0: usize) { - TPIDR_EL0.set(tpidr_el0 as _) -} diff --git a/arceos/modules/axhal/src/arch/aarch64/trap.S b/arceos/modules/axhal/src/arch/aarch64/trap.S deleted file mode 100644 index 7167610ac..000000000 --- a/arceos/modules/axhal/src/arch/aarch64/trap.S +++ /dev/null @@ -1,107 +0,0 @@ -.macro SAVE_REGS - sub sp, sp, 34 * 8 - stp x0, x1, [sp] - stp x2, x3, [sp, 2 * 8] - stp x4, x5, [sp, 4 * 8] - stp x6, x7, [sp, 6 * 8] - stp x8, x9, [sp, 8 * 8] - stp x10, x11, [sp, 10 * 8] - stp x12, x13, [sp, 12 * 8] - stp x14, x15, [sp, 14 * 8] - stp x16, x17, [sp, 16 * 8] - stp x18, x19, [sp, 18 * 8] - stp x20, x21, [sp, 20 * 8] - stp x22, x23, [sp, 22 * 8] - stp x24, x25, [sp, 24 * 8] - stp x26, x27, [sp, 26 * 8] - stp x28, x29, [sp, 28 * 8] - - mrs x9, sp_el0 - mrs x10, elr_el1 - mrs x11, spsr_el1 - stp x30, x9, [sp, 30 * 8] - stp x10, x11, [sp, 32 * 8] -.endm - -.macro RESTORE_REGS - ldp x10, x11, [sp, 32 * 8] - ldp x30, x9, [sp, 30 * 8] - msr sp_el0, x9 - msr elr_el1, x10 - msr spsr_el1, x11 - - ldp x28, x29, [sp, 28 * 8] - ldp x26, x27, [sp, 26 * 8] - ldp x24, x25, [sp, 24 * 8] - ldp x22, x23, [sp, 22 * 8] - ldp x20, x21, [sp, 20 * 8] - ldp x18, x19, [sp, 18 * 8] - ldp x16, x17, [sp, 16 * 8] - ldp x14, x15, [sp, 14 * 8] - ldp x12, x13, [sp, 12 * 8] - ldp x10, x11, [sp, 10 * 8] - ldp x8, x9, [sp, 8 * 8] - ldp x6, x7, [sp, 6 * 8] - ldp x4, x5, [sp, 4 * 8] - ldp x2, x3, [sp, 2 * 8] - ldp x0, x1, [sp] - add sp, sp, 34 * 8 -.endm - -.macro INVALID_EXCP, kind, source -.p2align 7 - SAVE_REGS - mov x0, sp - mov x1, \kind - mov x2, \source - bl invalid_exception - b .Lexception_return -.endm - -.macro HANDLE_SYNC -.p2align 7 - SAVE_REGS - mov x0, sp - bl handle_sync_exception - b .Lexception_return -.endm - -.macro HANDLE_IRQ -.p2align 7 - SAVE_REGS - mov x0, sp - bl handle_irq_exception - b .Lexception_return -.endm - -.section .text -.p2align 11 -.global exception_vector_base -exception_vector_base: - // current EL, with SP_EL0 - INVALID_EXCP 0 0 - INVALID_EXCP 1 0 - INVALID_EXCP 2 0 - INVALID_EXCP 3 0 - - // current EL, with SP_ELx - HANDLE_SYNC - HANDLE_IRQ - INVALID_EXCP 2 1 - INVALID_EXCP 3 1 - - // lower EL, aarch64 - HANDLE_SYNC - HANDLE_IRQ - INVALID_EXCP 2 2 - INVALID_EXCP 3 2 - - // lower EL, aarch32 - INVALID_EXCP 0 3 - INVALID_EXCP 1 3 - INVALID_EXCP 2 3 - INVALID_EXCP 3 3 - -.Lexception_return: - RESTORE_REGS - eret diff --git a/arceos/modules/axhal/src/arch/aarch64/trap.rs b/arceos/modules/axhal/src/arch/aarch64/trap.rs deleted file mode 100644 index 9bee97474..000000000 --- a/arceos/modules/axhal/src/arch/aarch64/trap.rs +++ /dev/null @@ -1,122 +0,0 @@ -use core::arch::global_asm; - -use aarch64_cpu::registers::{ESR_EL1, FAR_EL1}; -use page_table_entry::MappingFlags; -use tock_registers::interfaces::Readable; - -use super::TrapFrame; - -global_asm!(include_str!("trap.S")); - -#[repr(u8)] -#[derive(Debug)] -#[allow(dead_code)] -enum TrapKind { - Synchronous = 0, - Irq = 1, - Fiq = 2, - SError = 3, -} - -#[repr(u8)] -#[derive(Debug)] -#[allow(dead_code)] -enum TrapSource { - CurrentSpEl0 = 0, - CurrentSpElx = 1, - LowerAArch64 = 2, - LowerAArch32 = 3, -} - -#[no_mangle] -fn invalid_exception(tf: &TrapFrame, kind: TrapKind, source: TrapSource) { - panic!( - "Invalid exception {:?} from {:?}:\n{:#x?}", - kind, source, tf - ); -} - -#[no_mangle] -fn handle_irq_exception(_tf: &TrapFrame) { - handle_trap!(IRQ, 0); -} - -fn handle_instruction_abort(tf: &TrapFrame, iss: u64, is_user: bool) { - let mut access_flags = MappingFlags::EXECUTE; - if is_user { - access_flags |= MappingFlags::USER; - } - let vaddr = va!(FAR_EL1.get() as usize); - - // Only handle Translation fault and Permission fault - if !matches!(iss & 0b111100, 0b0100 | 0b1100) // IFSC or DFSC bits - || !handle_trap!(PAGE_FAULT, vaddr, access_flags, is_user) - { - panic!( - "Unhandled {} Instruction Abort @ {:#x}, fault_vaddr={:#x}, ISS={:#x} ({:?}):\n{:#x?}", - if is_user { "EL0" } else { "EL1" }, - tf.elr, - vaddr, - iss, - access_flags, - tf, - ); - } -} - -fn handle_data_abort(tf: &TrapFrame, iss: u64, is_user: bool) { - let wnr = (iss & (1 << 6)) != 0; // WnR: Write not Read - let cm = (iss & (1 << 8)) != 0; // CM: Cache maintenance - let mut access_flags = if wnr & !cm { - MappingFlags::WRITE - } else { - MappingFlags::READ - }; - if is_user { - access_flags |= MappingFlags::USER; - } - let vaddr = va!(FAR_EL1.get() as usize); - - // Only handle Translation fault and Permission fault - if !matches!(iss & 0b111100, 0b0100 | 0b1100) // IFSC or DFSC bits - || !handle_trap!(PAGE_FAULT, vaddr, access_flags, is_user) - { - panic!( - "Unhandled {} Data Abort @ {:#x}, fault_vaddr={:#x}, ISS=0b{:08b} ({:?}):\n{:#x?}", - if is_user { "EL0" } else { "EL1" }, - tf.elr, - vaddr, - iss, - access_flags, - tf, - ); - } -} - -#[no_mangle] -fn handle_sync_exception(tf: &mut TrapFrame) { - let esr = ESR_EL1.extract(); - let iss = esr.read(ESR_EL1::ISS); - match esr.read_as_enum(ESR_EL1::EC) { - Some(ESR_EL1::EC::Value::SVC64) => { - warn!("No syscall is supported currently!"); - } - Some(ESR_EL1::EC::Value::InstrAbortLowerEL) => handle_instruction_abort(tf, iss, true), - Some(ESR_EL1::EC::Value::InstrAbortCurrentEL) => handle_instruction_abort(tf, iss, false), - Some(ESR_EL1::EC::Value::DataAbortLowerEL) => handle_data_abort(tf, iss, true), - Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => handle_data_abort(tf, iss, false), - Some(ESR_EL1::EC::Value::Brk64) => { - debug!("BRK #{:#x} @ {:#x} ", iss, tf.elr); - tf.elr += 4; - } - _ => { - panic!( - "Unhandled synchronous exception @ {:#x}: ESR={:#x} (EC {:#08b}, ISS {:#x})", - tf.elr, - esr.get(), - esr.read(ESR_EL1::EC), - esr.read(ESR_EL1::ISS), - ); - } - } -} diff --git a/arceos/modules/axhal/src/arch/mod.rs b/arceos/modules/axhal/src/arch/mod.rs deleted file mode 100644 index b8bc0af3d..000000000 --- a/arceos/modules/axhal/src/arch/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! Architecture-specific types and operations. - -cfg_if::cfg_if! { - if #[cfg(target_arch = "x86_64")] { - mod x86_64; - pub use self::x86_64::*; - } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] { - mod riscv; - pub use self::riscv::*; - } else if #[cfg(target_arch = "aarch64")]{ - mod aarch64; - pub use self::aarch64::*; - } -} diff --git a/arceos/modules/axhal/src/arch/riscv/context.rs b/arceos/modules/axhal/src/arch/riscv/context.rs deleted file mode 100644 index 6542ca4be..000000000 --- a/arceos/modules/axhal/src/arch/riscv/context.rs +++ /dev/null @@ -1,323 +0,0 @@ -use core::arch::asm; -use memory_addr::VirtAddr; -#[cfg(feature = "uspace")] -use memory_addr::PhysAddr; - -include_asm_marcos!(); - -/// General registers of RISC-V. -#[allow(missing_docs)] -#[repr(C)] -#[derive(Debug, Default, Clone, Copy)] -pub struct GeneralRegisters { - pub ra: usize, - pub sp: usize, - pub gp: usize, // only valid for user traps - pub tp: usize, // only valid for user traps - pub t0: usize, - pub t1: usize, - pub t2: usize, - pub s0: usize, - pub s1: usize, - pub a0: usize, - pub a1: usize, - pub a2: usize, - pub a3: usize, - pub a4: usize, - pub a5: usize, - pub a6: usize, - pub a7: usize, - pub s2: usize, - pub s3: usize, - pub s4: usize, - pub s5: usize, - pub s6: usize, - pub s7: usize, - pub s8: usize, - pub s9: usize, - pub s10: usize, - pub s11: usize, - pub t3: usize, - pub t4: usize, - pub t5: usize, - pub t6: usize, -} - -/// Saved registers when a trap (interrupt or exception) occurs. -#[repr(C)] -#[derive(Debug, Default, Clone, Copy)] -pub struct TrapFrame { - /// All general registers. - pub regs: GeneralRegisters, - /// Supervisor Exception Program Counter. - pub sepc: usize, - /// Supervisor Status Register. - pub sstatus: usize, -} - -impl TrapFrame { - /// Gets the 0th syscall argument. - pub const fn arg0(&self) -> usize { - self.regs.a0 - } - - /// Gets the 1st syscall argument. - pub const fn arg1(&self) -> usize { - self.regs.a1 - } - - /// Gets the 2nd syscall argument. - pub const fn arg2(&self) -> usize { - self.regs.a2 - } - - /// Gets the 3rd syscall argument. - pub const fn arg3(&self) -> usize { - self.regs.a3 - } - - /// Gets the 4th syscall argument. - pub const fn arg4(&self) -> usize { - self.regs.a4 - } - - /// Gets the 5th syscall argument. - pub const fn arg5(&self) -> usize { - self.regs.a5 - } -} - -/// Saved hardware states of a task. -/// -/// The context usually includes: -/// -/// - Callee-saved registers -/// - Stack pointer register -/// - Thread pointer register (for thread-local storage, currently unsupported) -/// - FP/SIMD registers -/// -/// On context switch, current task saves its context from CPU to memory, -/// and the next task restores its context from memory to CPU. -#[allow(missing_docs)] -#[repr(C)] -#[derive(Debug, Default)] -pub struct TaskContext { - pub ra: usize, // return address (x1) - pub sp: usize, // stack pointer (x2) - - pub s0: usize, // x8-x9 - pub s1: usize, - - pub s2: usize, // x18-x27 - pub s3: usize, - pub s4: usize, - pub s5: usize, - pub s6: usize, - pub s7: usize, - pub s8: usize, - pub s9: usize, - pub s10: usize, - pub s11: usize, - - pub tp: usize, - /// The `satp` register value, i.e., the page table root. - #[cfg(feature = "uspace")] - pub satp: PhysAddr, - // TODO: FP states -} - -impl TaskContext { - /// Creates a dummy context for a new task. - /// - /// Note the context is not initialized, it will be filled by [`switch_to`] - /// (for initial tasks) and [`init`] (for regular tasks) methods. - /// - /// [`init`]: TaskContext::init - /// [`switch_to`]: TaskContext::switch_to - pub fn new() -> Self { - Self { - #[cfg(feature = "uspace")] - satp: crate::paging::kernel_page_table_root(), - ..Default::default() - } - } - - /// Initializes the context for a new task, with the given entry point and - /// kernel stack. - pub fn init(&mut self, entry: usize, kstack_top: VirtAddr, tls_area: VirtAddr) { - self.sp = kstack_top.as_usize(); - self.ra = entry; - self.tp = tls_area.as_usize(); - } - - /// Changes the page table root (`satp` register for riscv64). - /// - /// If not set, the kernel page table root is used (obtained by - /// [`axhal::paging::kernel_page_table_root`][1]). - /// - /// [1]: crate::paging::kernel_page_table_root - #[cfg(feature = "uspace")] - pub fn set_page_table_root(&mut self, satp: PhysAddr) { - self.satp = satp; - } - - /// Switches to another task. - /// - /// It first saves the current task's context from CPU to this place, and then - /// restores the next task's context from `next_ctx` to CPU. - pub fn switch_to(&mut self, next_ctx: &Self) { - #[cfg(feature = "tls")] - { - self.tp = super::read_thread_pointer(); - unsafe { super::write_thread_pointer(next_ctx.tp) }; - } - #[cfg(feature = "uspace")] - unsafe { - if self.satp != next_ctx.satp { - super::write_page_table_root(next_ctx.satp); - } - } - unsafe { - // TODO: switch FP states - context_switch(self, next_ctx) - } - } -} - -/// Context to enter user space. -#[cfg(feature = "uspace")] -pub struct UspaceContext(TrapFrame); - -#[cfg(feature = "uspace")] -impl UspaceContext { - /// Creates an empty context with all registers set to zero. - pub const fn empty() -> Self { - unsafe { core::mem::MaybeUninit::zeroed().assume_init() } - } - - /// Creates a new context with the given entry point, user stack pointer, - /// and the argument. - pub fn new(entry: usize, ustack_top: VirtAddr) -> Self { - const SPIE: usize = 1 << 5; - const SUM: usize = 1 << 18; - Self(TrapFrame { - regs: GeneralRegisters { - sp: ustack_top.as_usize(), - ..Default::default() - }, - sepc: entry, - sstatus: SPIE | SUM, - }) - } - - /// Creates a new context from the given [`TrapFrame`]. - pub const fn from(trap_frame: &TrapFrame) -> Self { - Self(*trap_frame) - } - - /// Gets the instruction pointer. - pub const fn get_ip(&self) -> usize { - self.0.sepc - } - - /// Gets the stack pointer. - pub const fn get_sp(&self) -> usize { - self.0.regs.sp - } - - /// Sets the instruction pointer. - pub const fn set_ip(&mut self, pc: usize) { - self.0.sepc = pc; - } - - /// Sets the stack pointer. - pub const fn set_sp(&mut self, sp: usize) { - self.0.regs.sp = sp; - } - - /// Sets the return value register. - pub const fn set_retval(&mut self, a0: usize) { - self.0.regs.a0 = a0; - } - - /// Enters user space. - /// - /// It restores the user registers and jumps to the user entry point - /// (saved in `sepc`). - /// When an exception or syscall occurs, the kernel stack pointer is - /// switched to `kstack_top`. - /// - /// # Safety - /// - /// This function is unsafe because it changes processor mode and the stack. - #[inline(never)] - #[no_mangle] - pub unsafe fn enter_uspace(&self, kstack_top: VirtAddr) -> ! { - use riscv::register::{sepc, sscratch}; - - super::disable_irqs(); - sscratch::write(kstack_top.as_usize()); - sepc::write(self.0.sepc); - // Address of the top of the kernel stack after saving the trap frame. - let kernel_trap_addr = kstack_top.as_usize() - core::mem::size_of::(); - asm!(" - mv sp, {tf} - - STR gp, {kernel_trap_addr}, 2 - LDR gp, sp, 2 - - STR tp, {kernel_trap_addr}, 3 - LDR tp, sp, 3 - - LDR t0, sp, 32 - csrw sstatus, t0 - POP_GENERAL_REGS - LDR sp, sp, 1 - sret", - tf = in(reg) &(self.0), - kernel_trap_addr = in(reg) kernel_trap_addr, - options(noreturn), - ) - } -} - -#[naked] -unsafe extern "C" fn context_switch(_current_task: &mut TaskContext, _next_task: &TaskContext) { - asm!( - " - // save old context (callee-saved registers) - STR ra, a0, 0 - STR sp, a0, 1 - STR s0, a0, 2 - STR s1, a0, 3 - STR s2, a0, 4 - STR s3, a0, 5 - STR s4, a0, 6 - STR s5, a0, 7 - STR s6, a0, 8 - STR s7, a0, 9 - STR s8, a0, 10 - STR s9, a0, 11 - STR s10, a0, 12 - STR s11, a0, 13 - - // restore new context - LDR s11, a1, 13 - LDR s10, a1, 12 - LDR s9, a1, 11 - LDR s8, a1, 10 - LDR s7, a1, 9 - LDR s6, a1, 8 - LDR s5, a1, 7 - LDR s4, a1, 6 - LDR s3, a1, 5 - LDR s2, a1, 4 - LDR s1, a1, 3 - LDR s0, a1, 2 - LDR sp, a1, 1 - LDR ra, a1, 0 - - ret", - options(noreturn), - ) -} diff --git a/arceos/modules/axhal/src/arch/riscv/macros.rs b/arceos/modules/axhal/src/arch/riscv/macros.rs deleted file mode 100644 index c36c4da80..000000000 --- a/arceos/modules/axhal/src/arch/riscv/macros.rs +++ /dev/null @@ -1,81 +0,0 @@ -macro_rules! include_asm_marcos { - () => { - #[cfg(target_arch = "riscv32")] - core::arch::global_asm!( - r" - .ifndef XLENB - .equ XLENB, 4 - - .macro LDR rd, rs, off - lw \rd, \off*XLENB(\rs) - .endm - .macro STR rs2, rs1, off - sw \rs2, \off*XLENB(\rs1) - .endm - - .endif" - ); - - #[cfg(target_arch = "riscv64")] - core::arch::global_asm!( - r" - .ifndef XLENB - .equ XLENB, 8 - - .macro LDR rd, rs, off - ld \rd, \off*XLENB(\rs) - .endm - .macro STR rs2, rs1, off - sd \rs2, \off*XLENB(\rs1) - .endm - - .endif", - ); - - core::arch::global_asm!( - r" - .ifndef .LPUSH_POP_GENERAL_REGS - .equ .LPUSH_POP_GENERAL_REGS, 0 - - .macro PUSH_POP_GENERAL_REGS, op - \op ra, sp, 0 - \op t0, sp, 4 - \op t1, sp, 5 - \op t2, sp, 6 - \op s0, sp, 7 - \op s1, sp, 8 - \op a0, sp, 9 - \op a1, sp, 10 - \op a2, sp, 11 - \op a3, sp, 12 - \op a4, sp, 13 - \op a5, sp, 14 - \op a6, sp, 15 - \op a7, sp, 16 - \op s2, sp, 17 - \op s3, sp, 18 - \op s4, sp, 19 - \op s5, sp, 20 - \op s6, sp, 21 - \op s7, sp, 22 - \op s8, sp, 23 - \op s9, sp, 24 - \op s10, sp, 25 - \op s11, sp, 26 - \op t3, sp, 27 - \op t4, sp, 28 - \op t5, sp, 29 - \op t6, sp, 30 - .endm - - .macro PUSH_GENERAL_REGS - PUSH_POP_GENERAL_REGS STR - .endm - .macro POP_GENERAL_REGS - PUSH_POP_GENERAL_REGS LDR - .endm - - .endif" - ); - }; -} diff --git a/arceos/modules/axhal/src/arch/riscv/mod.rs b/arceos/modules/axhal/src/arch/riscv/mod.rs deleted file mode 100644 index cdd004572..000000000 --- a/arceos/modules/axhal/src/arch/riscv/mod.rs +++ /dev/null @@ -1,138 +0,0 @@ -#[macro_use] -mod macros; - -mod context; -mod trap; - -use memory_addr::{PhysAddr, VirtAddr}; -use riscv::asm; -use riscv::register::{satp, sstatus, stvec}; - -#[cfg(feature = "uspace")] -pub use self::context::UspaceContext; -pub use self::context::{GeneralRegisters, TaskContext, TrapFrame}; - -/// Allows the current CPU to respond to interrupts. -#[inline] -pub fn enable_irqs() { - unsafe { sstatus::set_sie() } -} - -/// Makes the current CPU to ignore interrupts. -#[inline] -pub fn disable_irqs() { - unsafe { sstatus::clear_sie() } -} - -/// Returns whether the current CPU is allowed to respond to interrupts. -#[inline] -pub fn irqs_enabled() -> bool { - sstatus::read().sie() -} - -/// Relaxes the current CPU and waits for interrupts. -/// -/// It must be called with interrupts enabled, otherwise it will never return. -#[inline] -pub fn wait_for_irqs() { - riscv::asm::wfi() -} - -/// Halt the current CPU. -#[inline] -pub fn halt() { - disable_irqs(); - riscv::asm::wfi() // should never return -} - -/// Reads the register that stores the current page table root. -/// -/// Returns the physical address of the page table root. -#[inline] -pub fn read_page_table_root() -> PhysAddr { - pa!(satp::read().ppn() << 12) -} - -/// Writes the register to update the current page table root. -/// -/// # Safety -/// -/// This function is unsafe as it changes the virtual memory address space. -pub unsafe fn write_page_table_root(root_paddr: PhysAddr) { - let old_root = read_page_table_root(); - trace!("set page table root: {:#x} => {:#x}", old_root, root_paddr); - if old_root != root_paddr { - satp::set(satp::Mode::Sv39, 0, root_paddr.as_usize() >> 12); - asm::sfence_vma_all(); - } -} - -/// Flushes the TLB. -/// -/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB -/// entry that maps the given virtual address. -#[inline] -pub fn flush_tlb(vaddr: Option) { - unsafe { - if let Some(vaddr) = vaddr { - asm::sfence_vma(0, vaddr.as_usize()) - } else { - asm::sfence_vma_all(); - } - } -} - -/// Writes Supervisor Trap Vector Base Address Register (`stvec`). -#[inline] -pub fn set_trap_vector_base(stvec: usize) { - unsafe { stvec::write(stvec, stvec::TrapMode::Direct) } -} - -/// Reads the thread pointer of the current CPU. -/// -/// It is used to implement TLS (Thread Local Storage). -#[inline] -pub fn read_thread_pointer() -> usize { - let tp; - unsafe { core::arch::asm!("mv {}, tp", out(reg) tp) }; - tp -} - -/// Writes the thread pointer of the current CPU. -/// -/// It is used to implement TLS (Thread Local Storage). -/// -/// # Safety -/// -/// This function is unsafe as it changes the CPU states. -#[inline] -pub unsafe fn write_thread_pointer(tp: usize) { - core::arch::asm!("mv tp, {}", in(reg) tp) -} - -/// Initializes CPU states on the current CPU. -/// -/// On RISC-V, it sets the trap vector base address. -pub fn cpu_init() { - extern "C" { - fn trap_vector_base(); - } - set_trap_vector_base(trap_vector_base as usize); -} - -/// Bit 1: Supervisor Interrupt Enable -const SIE_BIT: usize = 1 << 1; - -#[inline] -pub fn local_irq_save_and_disable() -> usize { - let flags: usize; - // clear the `SIE` bit, and return the old CSR - unsafe { core::arch::asm!("csrrc {}, sstatus, {}", out(reg) flags, const SIE_BIT) }; - flags & SIE_BIT -} - -#[inline] -pub fn local_irq_restore(flags: usize) { - // restore the `SIE` bit - unsafe { core::arch::asm!("csrrs x0, sstatus, {}", in(reg) flags) }; -} diff --git a/arceos/modules/axhal/src/arch/riscv/trap.S b/arceos/modules/axhal/src/arch/riscv/trap.S deleted file mode 100644 index 8a594b8ad..000000000 --- a/arceos/modules/axhal/src/arch/riscv/trap.S +++ /dev/null @@ -1,69 +0,0 @@ -.macro SAVE_REGS, from_user - addi sp, sp, -{trapframe_size} - PUSH_GENERAL_REGS - - csrr t0, sepc - csrr t1, sstatus - csrrw t2, sscratch, zero // save sscratch (sp) and zero it - STR t0, sp, 31 // tf.sepc - STR t1, sp, 32 // tf.sstatus - STR t2, sp, 1 // tf.regs.sp - -.if \from_user == 1 - LDR t0, sp, 2 // load supervisor gp - LDR t1, sp, 3 // load supervisor tp - STR gp, sp, 2 // save user gp and tp - STR tp, sp, 3 - mv gp, t0 - mv tp, t1 -.endif -.endm - -.macro RESTORE_REGS, from_user -.if \from_user == 1 - LDR t1, sp, 2 // load user gp and tp - LDR t0, sp, 3 - STR gp, sp, 2 // save supervisor gp - STR tp, sp, 3 // save supervisor gp and tp - mv gp, t1 - mv tp, t0 - addi t0, sp, {trapframe_size} // put supervisor sp to scratch - csrw sscratch, t0 -.endif - - LDR t0, sp, 31 - LDR t1, sp, 32 - csrw sepc, t0 - csrw sstatus, t1 - - POP_GENERAL_REGS - LDR sp, sp, 1 // load sp from tf.regs.sp -.endm - -.section .text -.balign 4 -.global trap_vector_base -trap_vector_base: - // sscratch == 0: trap from S mode - // sscratch != 0: trap from U mode - csrrw sp, sscratch, sp // swap sscratch and sp - bnez sp, .Ltrap_entry_u - - csrr sp, sscratch // put supervisor sp back - j .Ltrap_entry_s - -.Ltrap_entry_s: - SAVE_REGS 0 - mv a0, sp - li a1, 0 - call riscv_trap_handler - RESTORE_REGS 0 - sret - -.Ltrap_entry_u: - SAVE_REGS 1 - mv a0, sp - li a1, 1 - call riscv_trap_handler - RESTORE_REGS 1 - sret diff --git a/arceos/modules/axhal/src/arch/riscv/trap.rs b/arceos/modules/axhal/src/arch/riscv/trap.rs deleted file mode 100644 index 59a0f938b..000000000 --- a/arceos/modules/axhal/src/arch/riscv/trap.rs +++ /dev/null @@ -1,63 +0,0 @@ -use page_table_entry::MappingFlags; -use riscv::register::scause::{self, Exception as E, Trap}; -use riscv::register::stval; - -use super::TrapFrame; - -include_asm_marcos!(); - -core::arch::global_asm!( - include_str!("trap.S"), - trapframe_size = const core::mem::size_of::(), -); - -fn handle_breakpoint(sepc: &mut usize) { - debug!("Exception(Breakpoint) @ {:#x} ", sepc); - *sepc += 2 -} - -fn handle_page_fault(tf: &TrapFrame, mut access_flags: MappingFlags, is_user: bool) { - if is_user { - access_flags |= MappingFlags::USER; - } - let vaddr = va!(stval::read()); - if !handle_trap!(PAGE_FAULT, vaddr, access_flags, is_user) { - panic!( - "Unhandled {} Page Fault @ {:#x}, fault_vaddr={:#x} ({:?}):\n{:#x?}", - if is_user { "User" } else { "Supervisor" }, - tf.sepc, - vaddr, - access_flags, - tf, - ); - } -} - -#[no_mangle] -fn riscv_trap_handler(tf: &mut TrapFrame, from_user: bool) { - let scause = scause::read(); - match scause.cause() { - #[cfg(feature = "uspace")] - Trap::Exception(E::UserEnvCall) => { - tf.regs.a0 = crate::trap::handle_syscall(tf, tf.regs.a7) as usize; - tf.sepc += 4; - } - Trap::Exception(E::LoadPageFault) => handle_page_fault(tf, MappingFlags::READ, from_user), - Trap::Exception(E::StorePageFault) => handle_page_fault(tf, MappingFlags::WRITE, from_user), - Trap::Exception(E::InstructionPageFault) => { - handle_page_fault(tf, MappingFlags::EXECUTE, from_user) - } - Trap::Exception(E::Breakpoint) => handle_breakpoint(&mut tf.sepc), - Trap::Interrupt(_) => { - handle_trap!(IRQ, scause.bits()); - } - _ => { - panic!( - "Unhandled trap {:?} @ {:#x}:\n{:#x?}", - scause.cause(), - tf.sepc, - tf - ); - } - } -} diff --git a/arceos/modules/axhal/src/arch/x86_64/context.rs b/arceos/modules/axhal/src/arch/x86_64/context.rs deleted file mode 100644 index 4b788dc9c..000000000 --- a/arceos/modules/axhal/src/arch/x86_64/context.rs +++ /dev/null @@ -1,221 +0,0 @@ -use core::{arch::asm, fmt}; -use memory_addr::VirtAddr; - -/// Saved registers when a trap (interrupt or exception) occurs. -#[allow(missing_docs)] -#[repr(C)] -#[derive(Debug, Default, Clone)] -pub struct TrapFrame { - pub rax: u64, - pub rcx: u64, - pub rdx: u64, - pub rbx: u64, - pub rbp: u64, - pub rsi: u64, - pub rdi: u64, - pub r8: u64, - pub r9: u64, - pub r10: u64, - pub r11: u64, - pub r12: u64, - pub r13: u64, - pub r14: u64, - pub r15: u64, - - // Pushed by `trap.S` - pub vector: u64, - pub error_code: u64, - - // Pushed by CPU - pub rip: u64, - pub cs: u64, - pub rflags: u64, - pub rsp: u64, - pub ss: u64, -} - -impl TrapFrame { - /// Whether the trap is from userspace. - pub const fn is_user(&self) -> bool { - self.cs & 0b11 == 3 - } -} - -#[repr(C)] -#[derive(Debug, Default)] -struct ContextSwitchFrame { - r15: u64, - r14: u64, - r13: u64, - r12: u64, - rbx: u64, - rbp: u64, - rip: u64, -} - -/// A 512-byte memory region for the FXSAVE/FXRSTOR instruction to save and -/// restore the x87 FPU, MMX, XMM, and MXCSR registers. -/// -/// See for more details. -#[allow(missing_docs)] -#[repr(C, align(16))] -#[derive(Debug)] -pub struct FxsaveArea { - pub fcw: u16, - pub fsw: u16, - pub ftw: u16, - pub fop: u16, - pub fip: u64, - pub fdp: u64, - pub mxcsr: u32, - pub mxcsr_mask: u32, - pub st: [u64; 16], - pub xmm: [u64; 32], - _padding: [u64; 12], -} - -static_assertions::const_assert_eq!(core::mem::size_of::(), 512); - -/// Extended state of a task, such as FP/SIMD states. -pub struct ExtendedState { - /// Memory region for the FXSAVE/FXRSTOR instruction. - pub fxsave_area: FxsaveArea, -} - -#[cfg(feature = "fp_simd")] -impl ExtendedState { - #[inline] - fn save(&mut self) { - unsafe { core::arch::x86_64::_fxsave64(&mut self.fxsave_area as *mut _ as *mut u8) } - } - - #[inline] - fn restore(&self) { - unsafe { core::arch::x86_64::_fxrstor64(&self.fxsave_area as *const _ as *const u8) } - } - - const fn default() -> Self { - let mut area: FxsaveArea = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; - area.fcw = 0x37f; - area.ftw = 0xffff; - area.mxcsr = 0x1f80; - Self { fxsave_area: area } - } -} - -impl fmt::Debug for ExtendedState { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("ExtendedState") - .field("fxsave_area", &self.fxsave_area) - .finish() - } -} - -/// Saved hardware states of a task. -/// -/// The context usually includes: -/// -/// - Callee-saved registers -/// - Stack pointer register -/// - Thread pointer register (for thread-local storage, currently unsupported) -/// - FP/SIMD registers -/// -/// On context switch, current task saves its context from CPU to memory, -/// and the next task restores its context from memory to CPU. -/// -/// On x86_64, callee-saved registers are saved to the kernel stack by the -/// `PUSH` instruction. So that [`rsp`] is the `RSP` after callee-saved -/// registers are pushed, and [`kstack_top`] is the top of the kernel stack -/// (`RSP` before any push). -/// -/// [`rsp`]: TaskContext::rsp -/// [`kstack_top`]: TaskContext::kstack_top -#[derive(Debug)] -pub struct TaskContext { - /// The kernel stack top of the task. - pub kstack_top: VirtAddr, - /// `RSP` after all callee-saved registers are pushed. - pub rsp: u64, - /// Thread Local Storage (TLS). - pub fs_base: usize, - /// Extended states, i.e., FP/SIMD states. - #[cfg(feature = "fp_simd")] - pub ext_state: ExtendedState, -} - -impl TaskContext { - /// Creates a new default context for a new task. - pub const fn new() -> Self { - Self { - kstack_top: va!(0), - rsp: 0, - fs_base: 0, - #[cfg(feature = "fp_simd")] - ext_state: ExtendedState::default(), - } - } - - /// Initializes the context for a new task, with the given entry point and - /// kernel stack. - pub fn init(&mut self, entry: usize, kstack_top: VirtAddr, tls_area: VirtAddr) { - unsafe { - // x86_64 calling convention: the stack must be 16-byte aligned before - // calling a function. That means when entering a new task (`ret` in `context_switch` - // is executed), (stack pointer + 8) should be 16-byte aligned. - let frame_ptr = (kstack_top.as_mut_ptr() as *mut u64).sub(1); - let frame_ptr = (frame_ptr as *mut ContextSwitchFrame).sub(1); - core::ptr::write( - frame_ptr, - ContextSwitchFrame { - rip: entry as _, - ..Default::default() - }, - ); - self.rsp = frame_ptr as u64; - } - self.kstack_top = kstack_top; - self.fs_base = tls_area.as_usize(); - } - - /// Switches to another task. - /// - /// It first saves the current task's context from CPU to this place, and then - /// restores the next task's context from `next_ctx` to CPU. - pub fn switch_to(&mut self, next_ctx: &Self) { - #[cfg(feature = "fp_simd")] - { - self.ext_state.save(); - next_ctx.ext_state.restore(); - } - #[cfg(feature = "tls")] - { - self.fs_base = super::read_thread_pointer(); - unsafe { super::write_thread_pointer(next_ctx.fs_base) }; - } - unsafe { context_switch(&mut self.rsp, &next_ctx.rsp) } - } -} - -#[naked] -unsafe extern "C" fn context_switch(_current_stack: &mut u64, _next_stack: &u64) { - asm!( - " - push rbp - push rbx - push r12 - push r13 - push r14 - push r15 - mov [rdi], rsp - - mov rsp, [rsi] - pop r15 - pop r14 - pop r13 - pop r12 - pop rbx - pop rbp - ret", - options(noreturn), - ) -} diff --git a/arceos/modules/axhal/src/arch/x86_64/gdt.rs b/arceos/modules/axhal/src/arch/x86_64/gdt.rs deleted file mode 100644 index e0ab99ac6..000000000 --- a/arceos/modules/axhal/src/arch/x86_64/gdt.rs +++ /dev/null @@ -1,88 +0,0 @@ -use core::fmt; - -use x86_64::instructions::tables::{lgdt, load_tss}; -use x86_64::registers::segmentation::{Segment, SegmentSelector, CS}; -use x86_64::structures::gdt::{Descriptor, DescriptorFlags}; -use x86_64::structures::{tss::TaskStateSegment, DescriptorTablePointer}; -use x86_64::{addr::VirtAddr, PrivilegeLevel}; - -/// A wrapper of the Global Descriptor Table (GDT) with maximum 16 entries. -#[repr(align(16))] -pub struct GdtStruct { - table: [u64; 16], -} - -impl GdtStruct { - /// Kernel code segment for 32-bit mode. - pub const KCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(1, PrivilegeLevel::Ring0); - /// Kernel code segment for 64-bit mode. - pub const KCODE64_SELECTOR: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring0); - /// Kernel data segment. - pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring0); - /// User code segment for 32-bit mode. - pub const UCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3); - /// User data segment. - pub const UDATA_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring3); - /// User code segment for 64-bit mode. - pub const UCODE64_SELECTOR: SegmentSelector = SegmentSelector::new(6, PrivilegeLevel::Ring3); - /// TSS segment. - pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(7, PrivilegeLevel::Ring0); - - /// Constructs a new GDT struct that filled with the default segment - /// descriptors, including the given TSS segment. - pub fn new(tss: &'static TaskStateSegment) -> Self { - let mut table = [0; 16]; - // first 3 entries are the same as in multiboot.S - table[1] = DescriptorFlags::KERNEL_CODE32.bits(); // 0x00cf9b000000ffff - table[2] = DescriptorFlags::KERNEL_CODE64.bits(); // 0x00af9b000000ffff - table[3] = DescriptorFlags::KERNEL_DATA.bits(); // 0x00cf93000000ffff - table[4] = DescriptorFlags::USER_CODE32.bits(); // 0x00cffb000000ffff - table[5] = DescriptorFlags::USER_DATA.bits(); // 0x00cff3000000ffff - table[6] = DescriptorFlags::USER_CODE64.bits(); // 0x00affb000000ffff - if let Descriptor::SystemSegment(low, high) = Descriptor::tss_segment(tss) { - table[7] = low; - table[8] = high; - } - Self { table } - } - - /// Returns the GDT pointer (base and limit) that can be used in `lgdt` - /// instruction. - pub fn pointer(&self) -> DescriptorTablePointer { - DescriptorTablePointer { - base: VirtAddr::new(self.table.as_ptr() as u64), - limit: (core::mem::size_of_val(&self.table) - 1) as u16, - } - } - - /// Loads the GDT into the CPU (executes the `lgdt` instruction), and - /// updates the code segment register (`CS`). - /// - /// # Safety - /// - /// This function is unsafe because it manipulates the CPU's privileged - /// states. - pub unsafe fn load(&'static self) { - lgdt(&self.pointer()); - CS::set_reg(Self::KCODE64_SELECTOR); - } - - /// Loads the TSS into the CPU (executes the `ltr` instruction). - /// - /// # Safety - /// - /// This function is unsafe because it manipulates the CPU's privileged - /// states. - pub unsafe fn load_tss(&'static self) { - load_tss(Self::TSS_SELECTOR); - } -} - -impl fmt::Debug for GdtStruct { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("GdtStruct") - .field("pointer", &self.pointer()) - .field("table", &self.table) - .finish() - } -} diff --git a/arceos/modules/axhal/src/arch/x86_64/idt.rs b/arceos/modules/axhal/src/arch/x86_64/idt.rs deleted file mode 100644 index ce488bdac..000000000 --- a/arceos/modules/axhal/src/arch/x86_64/idt.rs +++ /dev/null @@ -1,68 +0,0 @@ -use core::fmt; - -use x86_64::addr::VirtAddr; -use x86_64::structures::idt::{Entry, HandlerFunc, InterruptDescriptorTable}; -use x86_64::structures::DescriptorTablePointer; - -const NUM_INT: usize = 256; - -/// A wrapper of the Interrupt Descriptor Table (IDT). -#[repr(transparent)] -pub struct IdtStruct { - table: InterruptDescriptorTable, -} - -impl IdtStruct { - /// Constructs a new IDT struct that filled with entries from - /// `trap_handler_table`. - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - extern "C" { - #[link_name = "trap_handler_table"] - static ENTRIES: [extern "C" fn(); NUM_INT]; - } - let mut idt = Self { - table: InterruptDescriptorTable::new(), - }; - - let entries = unsafe { - core::slice::from_raw_parts_mut( - &mut idt.table as *mut _ as *mut Entry, - NUM_INT, - ) - }; - for i in 0..NUM_INT { - #[allow(clippy::missing_transmute_annotations)] - entries[i].set_handler_fn(unsafe { core::mem::transmute(ENTRIES[i]) }); - } - idt - } - - /// Returns the IDT pointer (base and limit) that can be used in the `lidt` - /// instruction. - pub fn pointer(&self) -> DescriptorTablePointer { - DescriptorTablePointer { - base: VirtAddr::new(&self.table as *const _ as u64), - limit: (core::mem::size_of::() - 1) as u16, - } - } - - /// Loads the IDT into the CPU (executes the `lidt` instruction). - /// - /// # Safety - /// - /// This function is unsafe because it manipulates the CPU's privileged - /// states. - pub unsafe fn load(&'static self) { - self.table.load(); - } -} - -impl fmt::Debug for IdtStruct { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("IdtStruct") - .field("pointer", &self.pointer()) - .field("table", &self.table) - .finish() - } -} diff --git a/arceos/modules/axhal/src/arch/x86_64/mod.rs b/arceos/modules/axhal/src/arch/x86_64/mod.rs deleted file mode 100644 index f19469b72..000000000 --- a/arceos/modules/axhal/src/arch/x86_64/mod.rs +++ /dev/null @@ -1,110 +0,0 @@ -mod context; -mod gdt; -mod idt; - -#[cfg(target_os = "none")] -mod trap; - -use core::arch::asm; - -use memory_addr::{MemoryAddr, PhysAddr, VirtAddr}; -use x86::{controlregs, msr, tlb}; -use x86_64::instructions::interrupts; - -pub use self::context::{ExtendedState, FxsaveArea, TaskContext, TrapFrame}; -pub use self::gdt::GdtStruct; -pub use self::idt::IdtStruct; -pub use x86_64::structures::tss::TaskStateSegment; - -/// Allows the current CPU to respond to interrupts. -#[inline] -pub fn enable_irqs() { - #[cfg(target_os = "none")] - interrupts::enable() -} - -/// Makes the current CPU to ignore interrupts. -#[inline] -pub fn disable_irqs() { - #[cfg(target_os = "none")] - interrupts::disable() -} - -/// Returns whether the current CPU is allowed to respond to interrupts. -#[inline] -pub fn irqs_enabled() -> bool { - interrupts::are_enabled() -} - -/// Relaxes the current CPU and waits for interrupts. -/// -/// It must be called with interrupts enabled, otherwise it will never return. -#[inline] -pub fn wait_for_irqs() { - if cfg!(target_os = "none") { - unsafe { asm!("hlt") } - } else { - core::hint::spin_loop() - } -} - -/// Halt the current CPU. -#[inline] -pub fn halt() { - disable_irqs(); - wait_for_irqs(); // should never return -} - -/// Reads the register that stores the current page table root. -/// -/// Returns the physical address of the page table root. -#[inline] -pub fn read_page_table_root() -> PhysAddr { - pa!(unsafe { controlregs::cr3() } as usize).align_down_4k() -} - -/// Writes the register to update the current page table root. -/// -/// # Safety -/// -/// This function is unsafe as it changes the virtual memory address space. -pub unsafe fn write_page_table_root(root_paddr: PhysAddr) { - let old_root = read_page_table_root(); - trace!("set page table root: {:#x} => {:#x}", old_root, root_paddr); - if old_root != root_paddr { - controlregs::cr3_write(root_paddr.as_usize() as _) - } -} - -/// Flushes the TLB. -/// -/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB -/// entry that maps the given virtual address. -#[inline] -pub fn flush_tlb(vaddr: Option) { - if let Some(vaddr) = vaddr { - unsafe { tlb::flush(vaddr.into()) } - } else { - unsafe { tlb::flush_all() } - } -} - -/// Reads the thread pointer of the current CPU. -/// -/// It is used to implement TLS (Thread Local Storage). -#[inline] -pub fn read_thread_pointer() -> usize { - unsafe { msr::rdmsr(msr::IA32_FS_BASE) as usize } -} - -/// Writes the thread pointer of the current CPU. -/// -/// It is used to implement TLS (Thread Local Storage). -/// -/// # Safety -/// -/// This function is unsafe as it changes the CPU states. -#[inline] -pub unsafe fn write_thread_pointer(fs_base: usize) { - unsafe { msr::wrmsr(msr::IA32_FS_BASE, fs_base as u64) } -} diff --git a/arceos/modules/axhal/src/arch/x86_64/trap.S b/arceos/modules/axhal/src/arch/x86_64/trap.S deleted file mode 100644 index 4bd0d941e..000000000 --- a/arceos/modules/axhal/src/arch/x86_64/trap.S +++ /dev/null @@ -1,84 +0,0 @@ -.equ NUM_INT, 256 - -.altmacro -.macro DEF_HANDLER, i -.Ltrap_handler_\i: -.if \i == 8 || (\i >= 10 && \i <= 14) || \i == 17 - # error code pushed by CPU - push \i # interrupt vector - jmp .Ltrap_common -.else - push 0 # fill in error code in TrapFrame - push \i # interrupt vector - jmp .Ltrap_common -.endif -.endm - -.macro DEF_TABLE_ENTRY, i - .quad .Ltrap_handler_\i -.endm - -.section .text -.code64 -_trap_handlers: -.set i, 0 -.rept NUM_INT - DEF_HANDLER %i - .set i, i + 1 -.endr - -.Ltrap_common: - test byte ptr [rsp + 3 * 8], 3 # swap GS if it comes from user space - jz 1f - swapgs -1: - push r15 - push r14 - push r13 - push r12 - push r11 - push r10 - push r9 - push r8 - push rdi - push rsi - push rbp - push rbx - push rdx - push rcx - push rax - - mov rdi, rsp - call x86_trap_handler - - pop rax - pop rcx - pop rdx - pop rbx - pop rbp - pop rsi - pop rdi - pop r8 - pop r9 - pop r10 - pop r11 - pop r12 - pop r13 - pop r14 - pop r15 - - test byte ptr [rsp + 3 * 8], 3 # swap GS back if return to user space - jz 2f - swapgs -2: - add rsp, 16 # pop vector, error_code - iretq - -.section .rodata -.global trap_handler_table -trap_handler_table: -.set i, 0 -.rept NUM_INT - DEF_TABLE_ENTRY %i - .set i, i + 1 -.endr diff --git a/arceos/modules/axhal/src/arch/x86_64/trap.rs b/arceos/modules/axhal/src/arch/x86_64/trap.rs deleted file mode 100644 index 2ff9d2817..000000000 --- a/arceos/modules/axhal/src/arch/x86_64/trap.rs +++ /dev/null @@ -1,87 +0,0 @@ -use page_table_entry::MappingFlags; -use x86::{controlregs::cr2, irq::*}; -use x86_64::structures::idt::PageFaultErrorCode; - -use super::context::TrapFrame; - -core::arch::global_asm!(include_str!("trap.S")); - -const IRQ_VECTOR_START: u8 = 0x20; -const IRQ_VECTOR_END: u8 = 0xff; - -fn handle_page_fault(tf: &TrapFrame) { - let access_flags = err_code_to_flags(tf.error_code) - .unwrap_or_else(|e| panic!("Invalid #PF error code: {:#x}", e)); - let vaddr = va!(unsafe { cr2() }); - if !handle_trap!(PAGE_FAULT, vaddr, access_flags, tf.is_user()) { - panic!( - "Unhandled {} #PF @ {:#x}, fault_vaddr={:#x}, error_code={:#x} ({:?}):\n{:#x?}", - if tf.is_user() { "user" } else { "kernel" }, - tf.rip, - vaddr, - tf.error_code, - access_flags, - tf, - ); - } -} - -#[no_mangle] -fn x86_trap_handler(tf: &TrapFrame) { - match tf.vector as u8 { - PAGE_FAULT_VECTOR => handle_page_fault(tf), - BREAKPOINT_VECTOR => debug!("#BP @ {:#x} ", tf.rip), - GENERAL_PROTECTION_FAULT_VECTOR => { - panic!( - "#GP @ {:#x}, error_code={:#x}:\n{:#x?}", - tf.rip, tf.error_code, tf - ); - } - IRQ_VECTOR_START..=IRQ_VECTOR_END => { - handle_trap!(IRQ, tf.vector as _); - } - _ => { - panic!( - "Unhandled exception {} ({}, error_code={:#x}) @ {:#x}:\n{:#x?}", - tf.vector, - vec_to_str(tf.vector), - tf.error_code, - tf.rip, - tf - ); - } - } -} - -fn vec_to_str(vec: u64) -> &'static str { - if vec < 32 { - EXCEPTIONS[vec as usize].mnemonic - } else { - "Unknown" - } -} - -fn err_code_to_flags(err_code: u64) -> Result { - let code = PageFaultErrorCode::from_bits_truncate(err_code); - let reserved_bits = (PageFaultErrorCode::CAUSED_BY_WRITE - | PageFaultErrorCode::USER_MODE - | PageFaultErrorCode::INSTRUCTION_FETCH) - .complement(); - if code.intersects(reserved_bits) { - Err(err_code) - } else { - let mut flags = MappingFlags::empty(); - if code.contains(PageFaultErrorCode::CAUSED_BY_WRITE) { - flags |= MappingFlags::WRITE; - } else { - flags |= MappingFlags::READ; - } - if code.contains(PageFaultErrorCode::USER_MODE) { - flags |= MappingFlags::USER; - } - if code.contains(PageFaultErrorCode::INSTRUCTION_FETCH) { - flags |= MappingFlags::EXECUTE; - } - Ok(flags) - } -} diff --git a/arceos/modules/axhal/src/cpu.rs b/arceos/modules/axhal/src/cpu.rs deleted file mode 100644 index d0ee27a34..000000000 --- a/arceos/modules/axhal/src/cpu.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! CPU-related operations. - -#[percpu::def_percpu] -static CPU_ID: usize = 0; - -#[percpu::def_percpu] -static IS_BSP: bool = false; - -#[percpu::def_percpu] -static CURRENT_TASK_PTR: usize = 0; - -/// Returns the ID of the current CPU. -#[inline] -pub fn this_cpu_id() -> usize { - CPU_ID.read_current() -} - -/// Returns whether the current CPU is the primary CPU (aka the bootstrap -/// processor or BSP) -#[inline] -pub fn this_cpu_is_bsp() -> bool { - IS_BSP.read_current() -} - -/// Gets the pointer to the current task with preemption-safety. -/// -/// Preemption may be enabled when calling this function. This function will -/// guarantee the correctness even the current task is preempted. -#[inline] -pub fn current_task_ptr() -> *const T { - #[cfg(target_arch = "x86_64")] - unsafe { - // on x86, only one instruction is needed to read the per-CPU task pointer from `gs:[off]`. - CURRENT_TASK_PTR.read_current_raw() as _ - } - #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] - unsafe { - // on RISC-V, reading `CURRENT_TASK_PTR` requires multiple instruction, so we disable local IRQs. - let _guard = kernel_guard::IrqSave::new(); - CURRENT_TASK_PTR.read_current_raw() as _ - } - #[cfg(target_arch = "aarch64")] - { - // on ARM64, we use `SP_EL0` to store the task pointer. - use tock_registers::interfaces::Readable; - aarch64_cpu::registers::SP_EL0.get() as _ - } -} - -/// Sets the pointer to the current task with preemption-safety. -/// -/// Preemption may be enabled when calling this function. This function will -/// guarantee the correctness even the current task is preempted. -/// -/// # Safety -/// -/// The given `ptr` must be pointed to a valid task structure. -#[inline] -pub unsafe fn set_current_task_ptr(ptr: *const T) { - #[cfg(target_arch = "x86_64")] - { - CURRENT_TASK_PTR.write_current_raw(ptr as usize) - } - #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] - { - let _guard = kernel_guard::IrqSave::new(); - CURRENT_TASK_PTR.write_current_raw(ptr as usize) - } - #[cfg(target_arch = "aarch64")] - { - use tock_registers::interfaces::Writeable; - aarch64_cpu::registers::SP_EL0.set(ptr as u64) - } -} - -#[allow(dead_code)] -pub(crate) fn init_primary(cpu_id: usize) { - percpu::init(axconfig::SMP); - percpu::set_local_thread_pointer(cpu_id); - unsafe { - CPU_ID.write_current_raw(cpu_id); - IS_BSP.write_current_raw(true); - } -} - -#[allow(dead_code)] -pub(crate) fn init_secondary(cpu_id: usize) { - percpu::set_local_thread_pointer(cpu_id); - unsafe { - CPU_ID.write_current_raw(cpu_id); - IS_BSP.write_current_raw(false); - } -} diff --git a/arceos/modules/axhal/src/irq.rs b/arceos/modules/axhal/src/irq.rs deleted file mode 100644 index fdaa78846..000000000 --- a/arceos/modules/axhal/src/irq.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Interrupt management. - -use handler_table::HandlerTable; - -use crate::platform::irq::{dispatch_irq, MAX_IRQ_COUNT}; -use crate::trap::{register_trap_handler, IRQ}; - -pub use crate::platform::irq::{register_handler, set_enable}; - -/// The type if an IRQ handler. -pub type IrqHandler = handler_table::Handler; - -static IRQ_HANDLER_TABLE: HandlerTable = HandlerTable::new(); - -/// Platform-independent IRQ dispatching. -#[allow(dead_code)] -pub(crate) fn dispatch_irq_common(irq_num: usize) { - trace!("IRQ {}", irq_num); - if !IRQ_HANDLER_TABLE.handle(irq_num) { - warn!("Unhandled IRQ {}", irq_num); - } -} - -/// Platform-independent IRQ handler registration. -/// -/// It also enables the IRQ if the registration succeeds. It returns `false` if -/// the registration failed. -#[allow(dead_code)] -pub(crate) fn register_handler_common(irq_num: usize, handler: IrqHandler) -> bool { - if irq_num < MAX_IRQ_COUNT && IRQ_HANDLER_TABLE.register_handler(irq_num, handler) { - set_enable(irq_num, true); - return true; - } - warn!("register handler for IRQ {} failed", irq_num); - false -} - -#[register_trap_handler(IRQ)] -fn handler_irq(irq_num: usize) -> bool { - let guard = kernel_guard::NoPreempt::new(); - dispatch_irq(irq_num); - drop(guard); // rescheduling may occur when preemption is re-enabled. - true -} diff --git a/arceos/modules/axhal/src/lib.rs b/arceos/modules/axhal/src/lib.rs deleted file mode 100644 index 20626a96e..000000000 --- a/arceos/modules/axhal/src/lib.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! [ArceOS] hardware abstraction layer, provides unified APIs for -//! platform-specific operations. -//! -//! It does the bootstrapping and initialization process for the specified -//! platform, and provides useful operations on the hardware. -//! -//! Currently supported platforms (specify by cargo features): -//! -//! - `x86-pc`: Standard PC with x86_64 ISA. -//! - `riscv64-qemu-virt`: QEMU virt machine with RISC-V ISA. -//! - `aarch64-qemu-virt`: QEMU virt machine with AArch64 ISA. -//! - `aarch64-raspi`: Raspberry Pi with AArch64 ISA. -//! - `dummy`: If none of the above platform is selected, the dummy platform -//! will be used. In this platform, most of the operations are no-op or -//! `unimplemented!()`. This platform is mainly used for [cargo test]. -//! -//! # Cargo Features -//! -//! - `smp`: Enable SMP (symmetric multiprocessing) support. -//! - `fp_simd`: Enable floating-point and SIMD support. -//! - `paging`: Enable page table manipulation. -//! - `irq`: Enable interrupt handling support. -//! -//! [ArceOS]: https://github.com/arceos-org/arceos -//! [cargo test]: https://doc.rust-lang.org/cargo/guide/tests.html - -#![no_std] -#![feature(asm_const)] -#![feature(naked_functions)] -#![feature(const_option)] -#![feature(doc_auto_cfg)] -#![feature(const_mut_refs)] - -#[allow(unused_imports)] -#[macro_use] -extern crate log; - -#[allow(unused_imports)] -#[macro_use] -extern crate memory_addr; - -mod platform; - -#[macro_use] -pub mod trap; - -pub mod arch; -pub mod cpu; -pub mod mem; -pub mod time; - -#[cfg(feature = "tls")] -pub mod tls; - -#[cfg(feature = "irq")] -pub mod irq; - -#[cfg(feature = "paging")] -pub mod paging; - -/// Console input and output. -pub mod console { - pub use super::platform::console::*; - - /// Write a slice of bytes to the console. - pub fn write_bytes(bytes: &[u8]) { - for c in bytes { - putchar(*c); - } - } -} - -/// Miscellaneous operation, e.g. terminate the system. -pub mod misc; - -/// Multi-core operations. -#[cfg(feature = "smp")] -pub mod mp { - pub use super::platform::mp::*; -} - -pub use self::platform::platform_init; - -#[cfg(feature = "smp")] -pub use self::platform::platform_init_secondary; diff --git a/arceos/modules/axhal/src/mem.rs b/arceos/modules/axhal/src/mem.rs deleted file mode 100644 index 69fa89d54..000000000 --- a/arceos/modules/axhal/src/mem.rs +++ /dev/null @@ -1,163 +0,0 @@ -//! Physical memory management. - -use core::fmt; - -#[doc(no_inline)] -pub use memory_addr::{MemoryAddr, PhysAddr, VirtAddr, PAGE_SIZE_4K}; - -bitflags::bitflags! { - /// The flags of a physical memory region. - pub struct MemRegionFlags: usize { - /// Readable. - const READ = 1 << 0; - /// Writable. - const WRITE = 1 << 1; - /// Executable. - const EXECUTE = 1 << 2; - /// Device memory. (e.g., MMIO regions) - const DEVICE = 1 << 4; - /// Uncachable memory. (e.g., framebuffer) - const UNCACHED = 1 << 5; - /// Reserved memory, do not use for allocation. - const RESERVED = 1 << 6; - /// Free memory for allocation. - const FREE = 1 << 7; - } -} - -impl fmt::Debug for MemRegionFlags { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } -} - -/// A physical memory region. -#[derive(Debug)] -pub struct MemRegion { - /// The start physical address of the region. - pub paddr: PhysAddr, - /// The size in bytes of the region. - pub size: usize, - /// The region flags, see [`MemRegionFlags`]. - pub flags: MemRegionFlags, - /// The region name, used for identification. - pub name: &'static str, -} - -/// Converts a virtual address to a physical address. -/// -/// It assumes that there is a linear mapping with the offset -/// [`PHYS_VIRT_OFFSET`], that maps all the physical memory to the virtual -/// space at the address plus the offset. So we have -/// `paddr = vaddr - PHYS_VIRT_OFFSET`. -/// -/// [`PHYS_VIRT_OFFSET`]: axconfig::PHYS_VIRT_OFFSET -#[inline] -pub const fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr { - pa!(vaddr.as_usize() - axconfig::PHYS_VIRT_OFFSET) -} - -/// Converts a physical address to a virtual address. -/// -/// It assumes that there is a linear mapping with the offset -/// [`PHYS_VIRT_OFFSET`], that maps all the physical memory to the virtual -/// space at the address plus the offset. So we have -/// `vaddr = paddr + PHYS_VIRT_OFFSET`. -/// -/// [`PHYS_VIRT_OFFSET`]: axconfig::PHYS_VIRT_OFFSET -#[inline] -pub const fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { - va!(paddr.as_usize() + axconfig::PHYS_VIRT_OFFSET) -} - -/// Returns an iterator over all physical memory regions. -pub fn memory_regions() -> impl Iterator { - kernel_image_regions().chain(crate::platform::mem::platform_regions()) -} - -/// Returns the memory regions of the kernel image (code and data sections). -fn kernel_image_regions() -> impl Iterator { - [ - MemRegion { - paddr: virt_to_phys((_stext as usize).into()), - size: _etext as usize - _stext as usize, - flags: MemRegionFlags::RESERVED | MemRegionFlags::READ | MemRegionFlags::EXECUTE, - name: ".text", - }, - MemRegion { - paddr: virt_to_phys((_srodata as usize).into()), - size: _erodata as usize - _srodata as usize, - flags: MemRegionFlags::RESERVED | MemRegionFlags::READ, - name: ".rodata", - }, - MemRegion { - paddr: virt_to_phys((_sdata as usize).into()), - size: _edata as usize - _sdata as usize, - flags: MemRegionFlags::RESERVED | MemRegionFlags::READ | MemRegionFlags::WRITE, - name: ".data .tdata .tbss .percpu", - }, - MemRegion { - paddr: virt_to_phys((boot_stack as usize).into()), - size: boot_stack_top as usize - boot_stack as usize, - flags: MemRegionFlags::RESERVED | MemRegionFlags::READ | MemRegionFlags::WRITE, - name: "boot stack", - }, - MemRegion { - paddr: virt_to_phys((_sbss as usize).into()), - size: _ebss as usize - _sbss as usize, - flags: MemRegionFlags::RESERVED | MemRegionFlags::READ | MemRegionFlags::WRITE, - name: ".bss", - }, - ] - .into_iter() -} - -/// Returns the default MMIO memory regions (from [`axconfig::MMIO_REGIONS`]). -#[allow(dead_code)] -pub(crate) fn default_mmio_regions() -> impl Iterator { - axconfig::MMIO_REGIONS.iter().map(|reg| MemRegion { - paddr: reg.0.into(), - size: reg.1, - flags: MemRegionFlags::RESERVED - | MemRegionFlags::DEVICE - | MemRegionFlags::READ - | MemRegionFlags::WRITE, - name: "mmio", - }) -} - -/// Returns the default free memory regions (kernel image end to physical memory end). -#[allow(dead_code)] -pub(crate) fn default_free_regions() -> impl Iterator { - let start = virt_to_phys((_ekernel as usize).into()).align_up_4k(); - let end = pa!(axconfig::PHYS_MEMORY_END).align_down_4k(); - core::iter::once(MemRegion { - paddr: start, - size: end.as_usize() - start.as_usize(), - flags: MemRegionFlags::FREE | MemRegionFlags::READ | MemRegionFlags::WRITE, - name: "free memory", - }) -} - -/// Fills the `.bss` section with zeros. -#[allow(dead_code)] -pub(crate) fn clear_bss() { - unsafe { - core::slice::from_raw_parts_mut(_sbss as usize as *mut u8, _ebss as usize - _sbss as usize) - .fill(0); - } -} - -extern "C" { - fn _stext(); - fn _etext(); - fn _srodata(); - fn _erodata(); - fn _sdata(); - fn _edata(); - fn _sbss(); - fn _ebss(); - fn _ekernel(); - fn boot_stack(); - fn boot_stack_top(); -} diff --git a/arceos/modules/axhal/src/misc.rs b/arceos/modules/axhal/src/misc.rs deleted file mode 100644 index 9a91ba110..000000000 --- a/arceos/modules/axhal/src/misc.rs +++ /dev/null @@ -1,21 +0,0 @@ -pub use super::platform::misc::*; - -use kspin::SpinNoIrq; -use crate::time; - -static PARK_MILLER_LEHMER_SEED: SpinNoIrq = SpinNoIrq::new(0); -const RAND_MAX: u64 = 2_147_483_647; - -pub fn random() -> u128 { - let mut seed = PARK_MILLER_LEHMER_SEED.lock(); - if *seed == 0 { - *seed = time::current_ticks() as u32; - } - - let mut ret: u128 = 0; - for _ in 0..4 { - *seed = ((u64::from(*seed) * 48271) % RAND_MAX) as u32; - ret = (ret << 32) | (*seed as u128); - } - ret -} diff --git a/arceos/modules/axhal/src/paging.rs b/arceos/modules/axhal/src/paging.rs deleted file mode 100644 index 49c779e6c..000000000 --- a/arceos/modules/axhal/src/paging.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! Page table manipulation. - -use axalloc::global_allocator; -use lazyinit::LazyInit; -use page_table_multiarch::PagingHandler; - -use crate::mem::{phys_to_virt, virt_to_phys, MemRegionFlags, PhysAddr, VirtAddr, PAGE_SIZE_4K}; - -#[doc(no_inline)] -pub use page_table_multiarch::{MappingFlags, PageSize, PagingError, PagingResult}; - -impl From for MappingFlags { - fn from(f: MemRegionFlags) -> Self { - let mut ret = Self::empty(); - if f.contains(MemRegionFlags::READ) { - ret |= Self::READ; - } - if f.contains(MemRegionFlags::WRITE) { - ret |= Self::WRITE; - } - if f.contains(MemRegionFlags::EXECUTE) { - ret |= Self::EXECUTE; - } - if f.contains(MemRegionFlags::DEVICE) { - ret |= Self::DEVICE; - } - if f.contains(MemRegionFlags::UNCACHED) { - ret |= Self::UNCACHED; - } - ret - } -} - -/// Implementation of [`PagingHandler`], to provide physical memory manipulation to -/// the [page_table_multiarch] crate. -pub struct PagingHandlerImpl; - -impl PagingHandler for PagingHandlerImpl { - fn alloc_frame() -> Option { - global_allocator() - .alloc_pages(1, PAGE_SIZE_4K) - .map(|vaddr| virt_to_phys(vaddr.into())) - .ok() - } - - fn dealloc_frame(paddr: PhysAddr) { - global_allocator().dealloc_pages(phys_to_virt(paddr).as_usize(), 1) - } - - #[inline] - fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { - phys_to_virt(paddr) - } -} - -cfg_if::cfg_if! { - if #[cfg(target_arch = "x86_64")] { - /// The architecture-specific page table. - pub type PageTable = page_table_multiarch::x86_64::X64PageTable; - } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] { - /// The architecture-specific page table. - pub type PageTable = page_table_multiarch::riscv::Sv39PageTable; - } else if #[cfg(target_arch = "aarch64")]{ - /// The architecture-specific page table. - pub type PageTable = page_table_multiarch::aarch64::A64PageTable; - } -} - -static KERNEL_PAGE_TABLE_ROOT: LazyInit = LazyInit::new(); - -/// Saves the root physical address of the kernel page table, which may be used -/// on context switch. -pub fn set_kernel_page_table_root(root_paddr: PhysAddr) { - KERNEL_PAGE_TABLE_ROOT.call_once(|| root_paddr); - unsafe { crate::arch::write_page_table_root(root_paddr) }; -} - -/// Get the root physical address of the kernel page table. -/// -/// # Panics -/// -/// It must be called after [`set_kernel_page_table_root`], otherwise it will panic. -pub fn kernel_page_table_root() -> PhysAddr { - *KERNEL_PAGE_TABLE_ROOT - .get() - .expect("kernel page table not initialized") -} diff --git a/arceos/modules/axhal/src/platform/aarch64_bsta1000b/dw_apb_uart.rs b/arceos/modules/axhal/src/platform/aarch64_bsta1000b/dw_apb_uart.rs deleted file mode 100644 index ef6b3276e..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_bsta1000b/dw_apb_uart.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! snps,dw-apb-uart serial driver - -use crate::mem::phys_to_virt; -use dw_apb_uart::DW8250; -use kspin::SpinNoIrq; -use memory_addr::PhysAddr; - -const UART_BASE: PhysAddr = pa!(axconfig::UART_PADDR); - -static UART: SpinNoIrq = SpinNoIrq::new(DW8250::new(phys_to_virt(UART_BASE).as_usize())); - -/// Writes a byte to the console. -pub fn putchar(c: u8) { - let mut uart = UART.lock(); - match c { - b'\r' | b'\n' => { - uart.putchar(b'\r'); - uart.putchar(b'\n'); - } - c => uart.putchar(c), - } -} - -/// Reads a byte from the console, or returns [`None`] if no input is available. -pub fn getchar() -> Option { - UART.lock().getchar() -} - -/// UART simply initialize -pub fn init_early() { - UART.lock().init(); -} - -/// Set UART IRQ Enable -#[cfg(feature = "irq")] -pub fn init_irq() { - UART.lock().set_ier(true); - crate::irq::register_handler(crate::platform::irq::UART_IRQ_NUM, handle); -} - -/// UART IRQ Handler -pub fn handle() { - trace!("Uart IRQ Handler"); -} diff --git a/arceos/modules/axhal/src/platform/aarch64_bsta1000b/mem.rs b/arceos/modules/axhal/src/platform/aarch64_bsta1000b/mem.rs deleted file mode 100644 index 47320aca4..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_bsta1000b/mem.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::mem::MemRegion; -use page_table_entry::{aarch64::A64PTE, GenericPTE, MappingFlags}; - -/// Returns platform-specific memory regions. -pub(crate) fn platform_regions() -> impl Iterator { - crate::mem::default_free_regions().chain(crate::mem::default_mmio_regions()) -} - -pub(crate) unsafe fn init_boot_page_table( - boot_pt_l0: *mut [A64PTE; 512], - boot_pt_l1: *mut [A64PTE; 512], -) { - let boot_pt_l0 = &mut *boot_pt_l0; - let boot_pt_l1 = &mut *boot_pt_l1; - // 0x0000_0000_0000 ~ 0x0080_0000_0000, table - boot_pt_l0[0] = A64PTE::new_table(pa!(boot_pt_l1.as_ptr() as usize)); - // 0x0000_0000_0000..0x0000_4000_0000, 1G block, device memory - boot_pt_l1[0] = A64PTE::new_page( - pa!(0), - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::DEVICE, - true, - ); - // 1G block, device memory - boot_pt_l1[1] = A64PTE::new_page( - pa!(0x40000000), - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::DEVICE, - true, - ); - // 1G block, normal memory - boot_pt_l1[2] = A64PTE::new_page( - pa!(0x80000000), - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE, - true, - ); -} diff --git a/arceos/modules/axhal/src/platform/aarch64_bsta1000b/misc.rs b/arceos/modules/axhal/src/platform/aarch64_bsta1000b/misc.rs deleted file mode 100644 index 8954132e1..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_bsta1000b/misc.rs +++ /dev/null @@ -1,60 +0,0 @@ -pub use crate::platform::aarch64_common::psci::system_off as terminate; - -use crate::mem::phys_to_virt; -use crate::time::{busy_wait, Duration}; -use core::ptr::{read_volatile, write_volatile}; - -/// Do QSPI reset -pub fn reset_qspi() { - // qspi exit 4-byte mode - // exit_4byte_qspi(); - - let ptr = phys_to_virt((axconfig::A1000BASE_SAFETYCRM + 0x8).into()).as_mut_ptr() as *mut u32; - unsafe { - let value = read_volatile(ptr); - trace!("SAFETY CRM RESET CTRL = {:#x}", value); - write_volatile(ptr, value & !(0b11 << 15)); - busy_wait(Duration::from_millis(100)); - - write_volatile(ptr, value | (0b11 << 15)); - busy_wait(Duration::from_millis(100)); - } -} - -/// Do CPU reset -pub fn reset_cpu() { - reset_qspi(); - - //Data Width = 32 - let ptr = phys_to_virt((axconfig::A1000BASE_SAFETYCRM + 0x8).into()).as_mut_ptr() as *mut u32; - unsafe { - write_volatile(ptr, read_volatile(ptr) & !0b1); - } - - loop {} -} - -/// reboot system -#[allow(dead_code)] -pub fn do_reset() { - axlog::ax_println!("resetting ...\n"); - - // wait 50 ms - busy_wait(Duration::from_millis(50)); - - // disable_interrupts(); - - reset_cpu(); - - // NOT REACHED - warn!("NOT REACHED Resetting"); -} - -/// bootmode define bit [27:26], from strap pin -#[allow(dead_code)] -pub fn get_bootmode() -> u32 { - unsafe { - let ptr = phys_to_virt((axconfig::A1000BASE_TOPCRM).into()).as_mut_ptr() as *mut u32; - (ptr.read_volatile() >> 26) & 0x7 - } -} diff --git a/arceos/modules/axhal/src/platform/aarch64_bsta1000b/mod.rs b/arceos/modules/axhal/src/platform/aarch64_bsta1000b/mod.rs deleted file mode 100644 index 8c7634bcf..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_bsta1000b/mod.rs +++ /dev/null @@ -1,62 +0,0 @@ -mod dw_apb_uart; - -pub mod mem; -pub mod misc; - -#[cfg(feature = "smp")] -pub mod mp; - -#[cfg(feature = "irq")] -pub mod irq { - pub use crate::platform::aarch64_common::gic::*; -} - -pub mod console { - pub use super::dw_apb_uart::*; -} - -pub mod time { - pub use crate::platform::aarch64_common::generic_timer::*; -} - -extern "C" { - fn exception_vector_base(); - fn rust_main(cpu_id: usize, dtb: usize); - #[cfg(feature = "smp")] - fn rust_main_secondary(cpu_id: usize); -} - -pub(crate) unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { - crate::mem::clear_bss(); - crate::arch::set_exception_vector_base(exception_vector_base as usize); - crate::cpu::init_primary(cpu_id); - dw_apb_uart::init_early(); - super::aarch64_common::generic_timer::init_early(); - rust_main(cpu_id, dtb); -} - -#[cfg(feature = "smp")] -pub(crate) unsafe extern "C" fn rust_entry_secondary(cpu_id: usize) { - crate::arch::set_exception_vector_base(exception_vector_base as usize); - crate::cpu::init_secondary(cpu_id); - rust_main_secondary(cpu_id); -} - -/// Initializes the platform devices for the primary CPU. -/// -/// For example, the interrupt controller and the timer. -pub fn platform_init() { - #[cfg(feature = "irq")] - super::aarch64_common::gic::init_primary(); - super::aarch64_common::generic_timer::init_percpu(); - #[cfg(feature = "irq")] - dw_apb_uart::init_irq(); -} - -/// Initializes the platform devices for secondary CPUs. -#[cfg(feature = "smp")] -pub fn platform_init_secondary() { - #[cfg(feature = "irq")] - super::aarch64_common::gic::init_secondary(); - super::aarch64_common::generic_timer::init_percpu(); -} diff --git a/arceos/modules/axhal/src/platform/aarch64_bsta1000b/mp.rs b/arceos/modules/axhal/src/platform/aarch64_bsta1000b/mp.rs deleted file mode 100644 index e5ee9bf9a..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_bsta1000b/mp.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::mem::{virt_to_phys, PhysAddr}; - -/// Hart number of bsta1000b board -pub const MAX_HARTS: usize = 8; -/// CPU HWID from cpu device tree nodes with "reg" property -pub const CPU_HWID: [usize; MAX_HARTS] = [0x00, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700]; - -/// Starts the given secondary CPU with its boot stack. -pub fn start_secondary_cpu(cpu_id: usize, stack_top: PhysAddr) { - if cpu_id >= MAX_HARTS { - error!("No support for bsta1000b core {}", cpu_id); - return; - } - extern "C" { - fn _start_secondary(); - } - let entry = virt_to_phys(va!(_start_secondary as usize)); - crate::platform::aarch64_common::psci::cpu_on( - CPU_HWID[cpu_id], - entry.as_usize(), - stack_top.as_usize(), - ); -} diff --git a/arceos/modules/axhal/src/platform/aarch64_common/boot.rs b/arceos/modules/axhal/src/platform/aarch64_common/boot.rs deleted file mode 100644 index 854d32ff5..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_common/boot.rs +++ /dev/null @@ -1,173 +0,0 @@ -use aarch64_cpu::{asm, asm::barrier, registers::*}; -use core::ptr::addr_of_mut; -use page_table_entry::aarch64::{MemAttr, A64PTE}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; - -use axconfig::TASK_STACK_SIZE; - -#[link_section = ".bss.stack"] -static mut BOOT_STACK: [u8; TASK_STACK_SIZE] = [0; TASK_STACK_SIZE]; - -#[link_section = ".data.boot_page_table"] -static mut BOOT_PT_L0: [A64PTE; 512] = [A64PTE::empty(); 512]; - -#[link_section = ".data.boot_page_table"] -static mut BOOT_PT_L1: [A64PTE; 512] = [A64PTE::empty(); 512]; - -unsafe fn switch_to_el1() { - SPSel.write(SPSel::SP::ELx); - SP_EL0.set(0); - let current_el = CurrentEL.read(CurrentEL::EL); - if current_el >= 2 { - if current_el == 3 { - // Set EL2 to 64bit and enable the HVC instruction. - SCR_EL3.write( - SCR_EL3::NS::NonSecure + SCR_EL3::HCE::HvcEnabled + SCR_EL3::RW::NextELIsAarch64, - ); - // Set the return address and exception level. - SPSR_EL3.write( - SPSR_EL3::M::EL1h - + SPSR_EL3::D::Masked - + SPSR_EL3::A::Masked - + SPSR_EL3::I::Masked - + SPSR_EL3::F::Masked, - ); - ELR_EL3.set(LR.get()); - } - // Disable EL1 timer traps and the timer offset. - CNTHCTL_EL2.modify(CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET); - CNTVOFF_EL2.set(0); - // Set EL1 to 64bit. - HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64); - // Set the return address and exception level. - SPSR_EL2.write( - SPSR_EL2::M::EL1h - + SPSR_EL2::D::Masked - + SPSR_EL2::A::Masked - + SPSR_EL2::I::Masked - + SPSR_EL2::F::Masked, - ); - core::arch::asm!( - " - mov x8, sp - msr sp_el1, x8" - ); - ELR_EL2.set(LR.get()); - asm::eret(); - } -} - -unsafe fn init_mmu() { - MAIR_EL1.set(MemAttr::MAIR_VALUE); - - // Enable TTBR0 and TTBR1 walks, page size = 4K, vaddr size = 48 bits, paddr size = 40 bits. - let tcr_flags0 = TCR_EL1::EPD0::EnableTTBR0Walks - + TCR_EL1::TG0::KiB_4 - + TCR_EL1::SH0::Inner - + TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::T0SZ.val(16); - let tcr_flags1 = TCR_EL1::EPD1::EnableTTBR1Walks - + TCR_EL1::TG1::KiB_4 - + TCR_EL1::SH1::Inner - + TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::T1SZ.val(16); - TCR_EL1.write(TCR_EL1::IPS::Bits_48 + tcr_flags0 + tcr_flags1); - barrier::isb(barrier::SY); - - // Set both TTBR0 and TTBR1 - let root_paddr = pa!(BOOT_PT_L0.as_ptr() as usize).as_usize() as _; - TTBR0_EL1.set(root_paddr); - TTBR1_EL1.set(root_paddr); - - // Flush the entire TLB - crate::arch::flush_tlb(None); - - // Enable the MMU and turn on I-cache and D-cache - SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable); - barrier::isb(barrier::SY); -} - -unsafe fn enable_fp() { - if cfg!(feature = "fp_simd") { - CPACR_EL1.write(CPACR_EL1::FPEN::TrapNothing); - barrier::isb(barrier::SY); - } -} - -unsafe fn init_boot_page_table() { - crate::platform::mem::init_boot_page_table(addr_of_mut!(BOOT_PT_L0), addr_of_mut!(BOOT_PT_L1)); -} - -/// The earliest entry point for the primary CPU. -#[naked] -#[no_mangle] -#[link_section = ".text.boot"] -unsafe extern "C" fn _start() -> ! { - // PC = 0x8_0000 - // X0 = dtb - core::arch::asm!(" - mrs x19, mpidr_el1 - and x19, x19, #0xffffff // get current CPU id - mov x20, x0 // save DTB pointer - - adrp x8, {boot_stack} // setup boot stack - add x8, x8, {boot_stack_size} - mov sp, x8 - - bl {switch_to_el1} // switch to EL1 - bl {enable_fp} // enable fp/neon - bl {init_boot_page_table} - bl {init_mmu} // setup MMU - - mov x8, {phys_virt_offset} // set SP to the high address - add sp, sp, x8 - - mov x0, x19 // call rust_entry(cpu_id, dtb) - mov x1, x20 - ldr x8, ={entry} - blr x8 - b .", - switch_to_el1 = sym switch_to_el1, - init_boot_page_table = sym init_boot_page_table, - init_mmu = sym init_mmu, - enable_fp = sym enable_fp, - boot_stack = sym BOOT_STACK, - boot_stack_size = const TASK_STACK_SIZE, - phys_virt_offset = const axconfig::PHYS_VIRT_OFFSET, - entry = sym crate::platform::rust_entry, - options(noreturn), - ) -} - -/// The earliest entry point for the secondary CPUs. -#[cfg(feature = "smp")] -#[naked] -#[no_mangle] -#[link_section = ".text.boot"] -unsafe extern "C" fn _start_secondary() -> ! { - core::arch::asm!(" - mrs x19, mpidr_el1 - and x19, x19, #0xffffff // get current CPU id - - mov sp, x0 - bl {switch_to_el1} - bl {init_mmu} - bl {enable_fp} - - mov x8, {phys_virt_offset} // set SP to the high address - add sp, sp, x8 - - mov x0, x19 // call rust_entry_secondary(cpu_id) - ldr x8, ={entry} - blr x8 - b .", - switch_to_el1 = sym switch_to_el1, - init_mmu = sym init_mmu, - enable_fp = sym enable_fp, - phys_virt_offset = const axconfig::PHYS_VIRT_OFFSET, - entry = sym crate::platform::rust_entry_secondary, - options(noreturn), - ) -} diff --git a/arceos/modules/axhal/src/platform/aarch64_common/generic_timer.rs b/arceos/modules/axhal/src/platform/aarch64_common/generic_timer.rs deleted file mode 100644 index 61da059d0..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_common/generic_timer.rs +++ /dev/null @@ -1,86 +0,0 @@ -#![allow(unused_imports)] - -use aarch64_cpu::registers::{CNTFRQ_EL0, CNTPCT_EL0, CNTP_CTL_EL0, CNTP_TVAL_EL0}; -use int_ratio::Ratio; -use tock_registers::interfaces::{Readable, Writeable}; - -static mut CNTPCT_TO_NANOS_RATIO: Ratio = Ratio::zero(); -static mut NANOS_TO_CNTPCT_RATIO: Ratio = Ratio::zero(); -/// RTC wall time offset in nanoseconds at monotonic time base. -static mut RTC_EPOCHOFFSET_NANOS: u64 = 0; - -/// Returns the current clock time in hardware ticks. -#[inline] -pub fn current_ticks() -> u64 { - CNTPCT_EL0.get() -} - -/// Converts hardware ticks to nanoseconds. -#[inline] -pub fn ticks_to_nanos(ticks: u64) -> u64 { - unsafe { CNTPCT_TO_NANOS_RATIO.mul_trunc(ticks) } -} - -/// Converts nanoseconds to hardware ticks. -#[inline] -pub fn nanos_to_ticks(nanos: u64) -> u64 { - unsafe { NANOS_TO_CNTPCT_RATIO.mul_trunc(nanos) } -} - -/// Return epoch offset in nanoseconds (wall time offset to monotonic clock start). -pub fn epochoffset_nanos() -> u64 { - unsafe { RTC_EPOCHOFFSET_NANOS } -} - -/// Set a one-shot timer. -/// -/// A timer interrupt will be triggered at the specified monotonic time deadline (in nanoseconds). -#[cfg(feature = "irq")] -pub fn set_oneshot_timer(deadline_ns: u64) { - let cnptct = CNTPCT_EL0.get(); - let cnptct_deadline = nanos_to_ticks(deadline_ns); - if cnptct < cnptct_deadline { - let interval = cnptct_deadline - cnptct; - debug_assert!(interval <= u32::MAX as u64); - CNTP_TVAL_EL0.set(interval); - } else { - CNTP_TVAL_EL0.set(0); - } -} - -/// Early stage initialization: stores the timer frequency. -pub(crate) fn init_early() { - let freq = CNTFRQ_EL0.get(); - unsafe { - CNTPCT_TO_NANOS_RATIO = Ratio::new(crate::time::NANOS_PER_SEC as u32, freq as u32); - NANOS_TO_CNTPCT_RATIO = CNTPCT_TO_NANOS_RATIO.inverse(); - } - - // Make sure `RTC_PADDR` is valid in platform config file. - #[cfg(feature = "rtc")] - if axconfig::RTC_PADDR != 0 { - use crate::mem::phys_to_virt; - use arm_pl031::Rtc; - use memory_addr::PhysAddr; - - const PL031_BASE: PhysAddr = pa!(axconfig::RTC_PADDR); - - let rtc = unsafe { Rtc::new(phys_to_virt(PL031_BASE).as_usize() as _) }; - // Get the current time in microseconds since the epoch (1970-01-01) from the aarch64 pl031 RTC. - // Subtract the timer ticks to get the actual time when ArceOS was booted. - let epoch_time_nanos = rtc.get_unix_timestamp() as u64 * 1_000_000_000; - - unsafe { - RTC_EPOCHOFFSET_NANOS = epoch_time_nanos - ticks_to_nanos(current_ticks()); - } - } -} - -pub(crate) fn init_percpu() { - #[cfg(feature = "irq")] - { - CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET); - CNTP_TVAL_EL0.set(0); - crate::platform::irq::set_enable(crate::platform::irq::TIMER_IRQ_NUM, true); - } -} diff --git a/arceos/modules/axhal/src/platform/aarch64_common/gic.rs b/arceos/modules/axhal/src/platform/aarch64_common/gic.rs deleted file mode 100644 index 80a9f8621..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_common/gic.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::{irq::IrqHandler, mem::phys_to_virt}; -use arm_gicv2::{translate_irq, GicCpuInterface, GicDistributor, InterruptType}; -use kspin::SpinNoIrq; -use memory_addr::PhysAddr; - -/// The maximum number of IRQs. -pub const MAX_IRQ_COUNT: usize = 1024; - -/// The timer IRQ number. -pub const TIMER_IRQ_NUM: usize = translate_irq(14, InterruptType::PPI).unwrap(); - -/// The UART IRQ number. -pub const UART_IRQ_NUM: usize = translate_irq(axconfig::UART_IRQ, InterruptType::SPI).unwrap(); - -const GICD_BASE: PhysAddr = pa!(axconfig::GICD_PADDR); -const GICC_BASE: PhysAddr = pa!(axconfig::GICC_PADDR); - -static GICD: SpinNoIrq = - SpinNoIrq::new(GicDistributor::new(phys_to_virt(GICD_BASE).as_mut_ptr())); - -// per-CPU, no lock -static GICC: GicCpuInterface = GicCpuInterface::new(phys_to_virt(GICC_BASE).as_mut_ptr()); - -/// Enables or disables the given IRQ. -pub fn set_enable(irq_num: usize, enabled: bool) { - trace!("GICD set enable: {} {}", irq_num, enabled); - GICD.lock().set_enable(irq_num as _, enabled); -} - -/// Registers an IRQ handler for the given IRQ. -/// -/// It also enables the IRQ if the registration succeeds. It returns `false` if -/// the registration failed. -pub fn register_handler(irq_num: usize, handler: IrqHandler) -> bool { - trace!("register handler irq {}", irq_num); - crate::irq::register_handler_common(irq_num, handler) -} - -/// Dispatches the IRQ. -/// -/// This function is called by the common interrupt handler. It looks -/// up in the IRQ handler table and calls the corresponding handler. If -/// necessary, it also acknowledges the interrupt controller after handling. -pub fn dispatch_irq(_unused: usize) { - GICC.handle_irq(|irq_num| crate::irq::dispatch_irq_common(irq_num as _)); -} - -/// Initializes GICD, GICC on the primary CPU. -pub(crate) fn init_primary() { - info!("Initialize GICv2..."); - GICD.lock().init(); - GICC.init(); -} - -/// Initializes GICC on secondary CPUs. -#[cfg(feature = "smp")] -pub(crate) fn init_secondary() { - GICC.init(); -} diff --git a/arceos/modules/axhal/src/platform/aarch64_common/mod.rs b/arceos/modules/axhal/src/platform/aarch64_common/mod.rs deleted file mode 100644 index c585541fe..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_common/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod boot; - -pub mod generic_timer; -#[cfg(not(platform_family = "aarch64-raspi"))] -pub mod psci; - -#[cfg(feature = "irq")] -pub mod gic; - -#[cfg(not(platform_family = "aarch64-bsta1000b"))] -pub mod pl011; diff --git a/arceos/modules/axhal/src/platform/aarch64_common/pl011.rs b/arceos/modules/axhal/src/platform/aarch64_common/pl011.rs deleted file mode 100644 index c0afd5bbf..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_common/pl011.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! PL011 UART. - -use arm_pl011::Pl011Uart; -use kspin::SpinNoIrq; -use memory_addr::PhysAddr; - -use crate::mem::phys_to_virt; - -const UART_BASE: PhysAddr = pa!(axconfig::UART_PADDR); - -static UART: SpinNoIrq = - SpinNoIrq::new(Pl011Uart::new(phys_to_virt(UART_BASE).as_mut_ptr())); - -/// Writes a byte to the console. -pub fn putchar(c: u8) { - let mut uart = UART.lock(); - match c { - b'\n' => { - uart.putchar(b'\r'); - uart.putchar(b'\n'); - } - c => uart.putchar(c), - } -} - -/// Reads a byte from the console, or returns [`None`] if no input is available. -pub fn getchar() -> Option { - UART.lock().getchar() -} - -/// Initialize the UART -pub fn init_early() { - UART.lock().init(); -} - -/// Set UART IRQ Enable -pub fn init() { - #[cfg(feature = "irq")] - crate::irq::set_enable(crate::platform::irq::UART_IRQ_NUM, true); -} - -/// UART IRQ Handler -pub fn handle() { - let is_receive_interrupt = UART.lock().is_receive_interrupt(); - UART.lock().ack_interrupts(); - if is_receive_interrupt { - while let Some(c) = getchar() { - putchar(c); - } - } -} diff --git a/arceos/modules/axhal/src/platform/aarch64_common/psci.rs b/arceos/modules/axhal/src/platform/aarch64_common/psci.rs deleted file mode 100644 index feca7ba6d..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_common/psci.rs +++ /dev/null @@ -1,129 +0,0 @@ -//! ARM Power State Coordination Interface. - -#![allow(dead_code)] - -pub const PSCI_0_2_FN_BASE: u32 = 0x84000000; -pub const PSCI_0_2_64BIT: u32 = 0x40000000; -pub const PSCI_0_2_FN_CPU_SUSPEND: u32 = PSCI_0_2_FN_BASE + 1; -pub const PSCI_0_2_FN_CPU_OFF: u32 = PSCI_0_2_FN_BASE + 2; -pub const PSCI_0_2_FN_CPU_ON: u32 = PSCI_0_2_FN_BASE + 3; -pub const PSCI_0_2_FN_MIGRATE: u32 = PSCI_0_2_FN_BASE + 5; -pub const PSCI_0_2_FN_SYSTEM_OFF: u32 = PSCI_0_2_FN_BASE + 8; -pub const PSCI_0_2_FN_SYSTEM_RESET: u32 = PSCI_0_2_FN_BASE + 9; -pub const PSCI_0_2_FN64_CPU_SUSPEND: u32 = PSCI_0_2_FN_BASE + PSCI_0_2_64BIT + 1; -pub const PSCI_0_2_FN64_CPU_ON: u32 = PSCI_0_2_FN_BASE + PSCI_0_2_64BIT + 3; -pub const PSCI_0_2_FN64_MIGRATE: u32 = PSCI_0_2_FN_BASE + PSCI_0_2_64BIT + 5; - -/// PSCI return values, inclusive of all PSCI versions. -#[derive(PartialEq, Debug)] -#[repr(i32)] -pub enum PsciError { - NotSupported = -1, - InvalidParams = -2, - Denied = -3, - AlreadyOn = -4, - OnPending = -5, - InternalFailure = -6, - NotPresent = -7, - Disabled = -8, - InvalidAddress = -9, -} - -impl From for PsciError { - fn from(code: i32) -> PsciError { - use PsciError::*; - match code { - -1 => NotSupported, - -2 => InvalidParams, - -3 => Denied, - -4 => AlreadyOn, - -5 => OnPending, - -6 => InternalFailure, - -7 => NotPresent, - -8 => Disabled, - -9 => InvalidAddress, - _ => panic!("Unknown PSCI error code: {}", code), - } - } -} - -/// arm,psci method: smc -/// when SMCCC_CONDUIT_SMC = 1 -fn arm_smccc_smc(func: u32, arg0: usize, arg1: usize, arg2: usize) -> usize { - let mut ret; - unsafe { - core::arch::asm!( - "smc #0", - inlateout("x0") func as usize => ret, - in("x1") arg0, - in("x2") arg1, - in("x3") arg2, - ) - } - ret -} - -/// psci "hvc" method call -fn psci_hvc_call(func: u32, arg0: usize, arg1: usize, arg2: usize) -> usize { - let ret; - unsafe { - core::arch::asm!( - "hvc #0", - inlateout("x0") func as usize => ret, - in("x1") arg0, - in("x2") arg1, - in("x3") arg2, - ) - } - ret -} - -fn psci_call(func: u32, arg0: usize, arg1: usize, arg2: usize) -> Result<(), PsciError> { - let ret = match axconfig::PSCI_METHOD { - "smc" => arm_smccc_smc(func, arg0, arg1, arg2), - "hvc" => psci_hvc_call(func, arg0, arg1, arg2), - _ => panic!("Unknown PSCI method: {}", axconfig::PSCI_METHOD), - }; - if ret == 0 { - Ok(()) - } else { - Err(PsciError::from(ret as i32)) - } -} - -/// Shutdown the whole system, including all CPUs. -pub fn system_off() -> ! { - info!("Shutting down..."); - psci_call(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0).ok(); - warn!("It should shutdown!"); - loop { - crate::arch::halt(); - } -} - -/// Power up a core. This call is used to power up cores that either: -/// -/// * Have not yet been booted into the calling supervisory software. -/// * Have been previously powered down with a `cpu_off` call. -/// -/// `target_cpu` contains a copy of the affinity fields of the MPIDR register. -/// `entry_point` is the physical address of the secondary CPU's entry point. -/// `arg` will be passed to the `X0` register of the secondary CPU. -pub fn cpu_on(target_cpu: usize, entry_point: usize, arg: usize) { - info!("Starting CPU {:x} ON ...", target_cpu); - let res = psci_call(PSCI_0_2_FN64_CPU_ON, target_cpu, entry_point, arg); - if let Err(e) = res { - error!("failed to boot CPU {:x} ({:?})", target_cpu, e); - } -} - -/// Power down the calling core. This call is intended for use in hotplug. A -/// core that is powered down by `cpu_off` can only be powered up again in -/// response to a `cpu_on`. -pub fn cpu_off() { - const PSCI_POWER_STATE_TYPE_STANDBY: u32 = 0; - const PSCI_POWER_STATE_TYPE_POWER_DOWN: u32 = 1; - const PSCI_0_2_POWER_STATE_TYPE_SHIFT: u32 = 16; - let state: u32 = PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT; - psci_call(PSCI_0_2_FN_CPU_OFF, state as usize, 0, 0).ok(); -} diff --git a/arceos/modules/axhal/src/platform/aarch64_qemu_virt/mem.rs b/arceos/modules/axhal/src/platform/aarch64_qemu_virt/mem.rs deleted file mode 100644 index 6b41b2feb..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_qemu_virt/mem.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::mem::MemRegion; -use page_table_entry::{aarch64::A64PTE, GenericPTE, MappingFlags}; - -/// Returns platform-specific memory regions. -pub(crate) fn platform_regions() -> impl Iterator { - crate::mem::default_free_regions().chain(crate::mem::default_mmio_regions()) -} - -pub(crate) unsafe fn init_boot_page_table( - boot_pt_l0: *mut [A64PTE; 512], - boot_pt_l1: *mut [A64PTE; 512], -) { - let boot_pt_l0 = &mut *boot_pt_l0; - let boot_pt_l1 = &mut *boot_pt_l1; - // 0x0000_0000_0000 ~ 0x0080_0000_0000, table - boot_pt_l0[0] = A64PTE::new_table(pa!(boot_pt_l1.as_ptr() as usize)); - // 0x0000_0000_0000..0x0000_4000_0000, 1G block, device memory - boot_pt_l1[0] = A64PTE::new_page( - pa!(0), - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::DEVICE, - true, - ); - // 0x0000_4000_0000..0x0000_8000_0000, 1G block, normal memory - boot_pt_l1[1] = A64PTE::new_page( - pa!(0x4000_0000), - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE, - true, - ); -} diff --git a/arceos/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs b/arceos/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs deleted file mode 100644 index 2a452fa08..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs +++ /dev/null @@ -1,64 +0,0 @@ -pub mod mem; - -#[cfg(feature = "smp")] -pub mod mp; - -#[cfg(feature = "irq")] -pub mod irq { - pub use crate::platform::aarch64_common::gic::*; -} - -pub mod console { - pub use crate::platform::aarch64_common::pl011::*; -} - -pub mod time { - pub use crate::platform::aarch64_common::generic_timer::*; -} - -pub mod misc { - pub use crate::platform::aarch64_common::psci::system_off as terminate; -} - -extern "C" { - fn exception_vector_base(); - fn rust_main(cpu_id: usize, dtb: usize); - #[cfg(feature = "smp")] - fn rust_main_secondary(cpu_id: usize); -} - -pub(crate) unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { - crate::mem::clear_bss(); - crate::arch::set_exception_vector_base(exception_vector_base as usize); - crate::arch::write_page_table_root0(0.into()); // disable low address access - crate::cpu::init_primary(cpu_id); - super::aarch64_common::pl011::init_early(); - super::aarch64_common::generic_timer::init_early(); - rust_main(cpu_id, dtb); -} - -#[cfg(feature = "smp")] -pub(crate) unsafe extern "C" fn rust_entry_secondary(cpu_id: usize) { - crate::arch::set_exception_vector_base(exception_vector_base as usize); - crate::arch::write_page_table_root0(0.into()); // disable low address access - crate::cpu::init_secondary(cpu_id); - rust_main_secondary(cpu_id); -} - -/// Initializes the platform devices for the primary CPU. -/// -/// For example, the interrupt controller and the timer. -pub fn platform_init() { - #[cfg(feature = "irq")] - super::aarch64_common::gic::init_primary(); - super::aarch64_common::generic_timer::init_percpu(); - super::aarch64_common::pl011::init(); -} - -/// Initializes the platform devices for secondary CPUs. -#[cfg(feature = "smp")] -pub fn platform_init_secondary() { - #[cfg(feature = "irq")] - super::aarch64_common::gic::init_secondary(); - super::aarch64_common::generic_timer::init_percpu(); -} diff --git a/arceos/modules/axhal/src/platform/aarch64_qemu_virt/mp.rs b/arceos/modules/axhal/src/platform/aarch64_qemu_virt/mp.rs deleted file mode 100644 index 5c3936dd1..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_qemu_virt/mp.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::mem::{virt_to_phys, PhysAddr}; - -/// Starts the given secondary CPU with its boot stack. -pub fn start_secondary_cpu(cpu_id: usize, stack_top: PhysAddr) { - extern "C" { - fn _start_secondary(); - } - let entry = virt_to_phys(va!(_start_secondary as usize)); - crate::platform::aarch64_common::psci::cpu_on(cpu_id, entry.as_usize(), stack_top.as_usize()); -} diff --git a/arceos/modules/axhal/src/platform/aarch64_raspi/mem.rs b/arceos/modules/axhal/src/platform/aarch64_raspi/mem.rs deleted file mode 100644 index d7b238df7..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_raspi/mem.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::mem::{MemRegion, MemRegionFlags}; -use page_table_entry::{aarch64::A64PTE, GenericPTE, MappingFlags}; - -/// Returns platform-specific memory regions. -pub(crate) fn platform_regions() -> impl Iterator { - core::iter::once(MemRegion { - paddr: 0x0.into(), - size: 0x1000, - flags: MemRegionFlags::RESERVED | MemRegionFlags::READ | MemRegionFlags::WRITE, - name: "spintable", - }) - .chain(crate::mem::default_free_regions()) - .chain(crate::mem::default_mmio_regions()) -} - -pub(crate) unsafe fn init_boot_page_table( - boot_pt_l0: *mut [A64PTE; 512], - boot_pt_l1: *mut [A64PTE; 512], -) { - let boot_pt_l0 = &mut *boot_pt_l0; - let boot_pt_l1 = &mut *boot_pt_l1; - // 0x0000_0000_0000 ~ 0x0080_0000_0000, table - boot_pt_l0[0] = A64PTE::new_table(pa!(boot_pt_l1.as_ptr() as usize)); - // 0x0000_0000_0000..0x0000_4000_0000, 1G block, device memory - boot_pt_l1[0] = A64PTE::new_page( - pa!(0), - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE, - true, - ); - // 0x0000_4000_0000..0x0000_8000_0000, 1G block, normal memory - boot_pt_l1[1] = A64PTE::new_page( - pa!(0x4000_0000), - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE, - true, - ); - // 0x0000_8000_0000..0x0000_C000_0000, 1G block, normal memory - boot_pt_l1[2] = A64PTE::new_page( - pa!(0x8000_0000), - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE, - true, - ); - // 0x0000_C000_0000..0x0001_0000_0000, 1G block, DEVICE memory - boot_pt_l1[3] = A64PTE::new_page( - pa!(0xc000_0000), - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::DEVICE, - true, - ); -} diff --git a/arceos/modules/axhal/src/platform/aarch64_raspi/mod.rs b/arceos/modules/axhal/src/platform/aarch64_raspi/mod.rs deleted file mode 100644 index c7c7264d4..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_raspi/mod.rs +++ /dev/null @@ -1,69 +0,0 @@ -pub mod mem; - -#[cfg(feature = "smp")] -pub mod mp; - -#[cfg(feature = "irq")] -pub mod irq { - pub use crate::platform::aarch64_common::gic::*; -} - -pub mod console { - pub use crate::platform::aarch64_common::pl011::*; -} - -pub mod time { - pub use crate::platform::aarch64_common::generic_timer::*; -} - -pub mod misc { - pub fn terminate() -> ! { - info!("Shutting down..."); - loop { - crate::arch::halt(); - } - } -} - -extern "C" { - fn exception_vector_base(); - fn rust_main(cpu_id: usize, dtb: usize); - #[cfg(feature = "smp")] - fn rust_main_secondary(cpu_id: usize); -} - -pub(crate) unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { - crate::mem::clear_bss(); - crate::arch::set_exception_vector_base(exception_vector_base as usize); - crate::arch::write_page_table_root0(0.into()); // disable low address access - crate::cpu::init_primary(cpu_id); - super::aarch64_common::pl011::init_early(); - super::aarch64_common::generic_timer::init_early(); - rust_main(cpu_id, dtb); -} - -#[cfg(feature = "smp")] -pub(crate) unsafe extern "C" fn rust_entry_secondary(cpu_id: usize) { - crate::arch::set_exception_vector_base(exception_vector_base as usize); - crate::arch::write_page_table_root0(0.into()); // disable low address access - crate::cpu::init_secondary(cpu_id); - rust_main_secondary(cpu_id); -} - -/// Initializes the platform devices for the primary CPU. -/// -/// For example, the interrupt controller and the timer. -pub fn platform_init() { - #[cfg(feature = "irq")] - super::aarch64_common::gic::init_primary(); - super::aarch64_common::generic_timer::init_percpu(); - super::aarch64_common::pl011::init(); -} - -/// Initializes the platform devices for secondary CPUs. -#[cfg(feature = "smp")] -pub fn platform_init_secondary() { - #[cfg(feature = "irq")] - super::aarch64_common::gic::init_secondary(); - super::aarch64_common::generic_timer::init_percpu(); -} diff --git a/arceos/modules/axhal/src/platform/aarch64_raspi/mp.rs b/arceos/modules/axhal/src/platform/aarch64_raspi/mp.rs deleted file mode 100644 index 8447daec8..000000000 --- a/arceos/modules/axhal/src/platform/aarch64_raspi/mp.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::mem::{phys_to_virt, virt_to_phys, PhysAddr}; - -static mut SECONDARY_STACK_TOP: usize = 0; - -extern "C" { - fn _start_secondary(); -} - -#[naked] -#[link_section = ".text.boot"] -unsafe extern "C" fn modify_stack_and_start() { - core::arch::asm!(" - ldr x21, ={secondary_boot_stack} // the secondary CPU hasn't set the TTBR1 - mov x8, {phys_virt_offset} // minus the offset to get the phys addr of the boot stack - sub x21, x21, x8 - ldr x21, [x21] - mov x0, x21 // x0 will be set to SP in the beginning of _start_secondary - b _start_secondary", - secondary_boot_stack = sym SECONDARY_STACK_TOP, - phys_virt_offset = const axconfig::PHYS_VIRT_OFFSET, - options(noreturn) - ); -} - -pub static CPU_SPIN_TABLE: [PhysAddr; 4] = [pa!(0xd8), pa!(0xe0), pa!(0xe8), pa!(0xf0)]; - -/// Starts the given secondary CPU with its boot stack. -pub fn start_secondary_cpu(cpu_id: usize, stack_top: PhysAddr) { - let entry_paddr = virt_to_phys(va!(modify_stack_and_start as usize)).as_usize(); - unsafe { - // set the boot code address of the given secondary CPU - let spintable_vaddr = phys_to_virt(CPU_SPIN_TABLE[cpu_id]); - let release_ptr = spintable_vaddr.as_mut_ptr() as *mut usize; - release_ptr.write_volatile(entry_paddr); - crate::arch::flush_dcache_line(spintable_vaddr); - - // set the boot stack of the given secondary CPU - SECONDARY_STACK_TOP = stack_top.as_usize(); - crate::arch::flush_dcache_line(va!(core::ptr::addr_of!(SECONDARY_STACK_TOP) as usize)); - } - aarch64_cpu::asm::sev(); -} diff --git a/arceos/modules/axhal/src/platform/dummy/mod.rs b/arceos/modules/axhal/src/platform/dummy/mod.rs deleted file mode 100644 index 389f14c77..000000000 --- a/arceos/modules/axhal/src/platform/dummy/mod.rs +++ /dev/null @@ -1,92 +0,0 @@ -#![allow(unused_variables)] -#![allow(dead_code)] - -pub mod console { - /// Writes a byte to the console. - pub fn putchar(c: u8) { - unimplemented!() - } - - /// Reads a byte from the console, or returns [`None`] if no input is available. - pub fn getchar() -> Option { - unimplemented!() - } -} - -pub mod misc { - /// Shutdown the whole system, including all CPUs. - pub fn terminate() -> ! { - unimplemented!() - } -} - -#[cfg(feature = "smp")] -pub mod mp { - /// Starts the given secondary CPU with its boot stack. - pub fn start_secondary_cpu(cpu_id: usize, stack_top: crate::mem::PhysAddr) {} -} - -pub mod mem { - /// Returns platform-specific memory regions. - pub(crate) fn platform_regions() -> impl Iterator { - core::iter::empty() - } -} - -pub mod time { - /// Returns the current clock time in hardware ticks. - pub fn current_ticks() -> u64 { - 0 - } - - /// Converts hardware ticks to nanoseconds. - pub fn ticks_to_nanos(ticks: u64) -> u64 { - ticks - } - - /// Converts nanoseconds to hardware ticks. - pub fn nanos_to_ticks(nanos: u64) -> u64 { - nanos - } - - /// Set a one-shot timer. - /// - /// A timer interrupt will be triggered at the specified monotonic time deadline (in nanoseconds). - pub fn set_oneshot_timer(deadline_ns: u64) {} - - /// Return epoch offset in nanoseconds (wall time offset to monotonic clock start). - pub fn epochoffset_nanos() -> u64 { - 0 - } -} - -#[cfg(feature = "irq")] -pub mod irq { - /// The maximum number of IRQs. - pub const MAX_IRQ_COUNT: usize = 256; - - /// The timer IRQ number. - pub const TIMER_IRQ_NUM: usize = 0; - - /// Enables or disables the given IRQ. - pub fn set_enable(irq_num: usize, enabled: bool) {} - - /// Registers an IRQ handler for the given IRQ. - pub fn register_handler(irq_num: usize, handler: crate::irq::IrqHandler) -> bool { - false - } - - /// Dispatches the IRQ. - /// - /// This function is called by the common interrupt handler. It looks - /// up in the IRQ handler table and calls the corresponding handler. If - /// necessary, it also acknowledges the interrupt controller after handling. - pub fn dispatch_irq(irq_num: usize) {} -} - -/// Initializes the platform devices for the primary CPU. -pub fn platform_init() {} - -/// Initializes the platform devices for secondary CPUs. -#[cfg(feature = "smp")] -pub fn platform_init_secondary() {} diff --git a/arceos/modules/axhal/src/platform/mod.rs b/arceos/modules/axhal/src/platform/mod.rs deleted file mode 100644 index a39151c47..000000000 --- a/arceos/modules/axhal/src/platform/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Platform-specific operations. - -cfg_if::cfg_if! { - if #[cfg(target_arch = "aarch64")]{ - mod aarch64_common; - } -} - -cfg_if::cfg_if! { - if #[cfg(all(target_arch = "x86_64", platform_family = "x86-pc"))] { - mod x86_pc; - pub use self::x86_pc::*; - } else if #[cfg(all(target_arch = "riscv64", platform_family = "riscv64-qemu-virt"))] { - mod riscv64_qemu_virt; - pub use self::riscv64_qemu_virt::*; - } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-qemu-virt"))] { - mod aarch64_qemu_virt; - pub use self::aarch64_qemu_virt::*; - } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-raspi"))] { - mod aarch64_raspi; - pub use self::aarch64_raspi::*; - } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-bsta1000b"))] { - mod aarch64_bsta1000b; - pub use self::aarch64_bsta1000b::*; - } else { - mod dummy; - pub use self::dummy::*; - } -} diff --git a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/boot.rs b/arceos/modules/axhal/src/platform/riscv64_qemu_virt/boot.rs deleted file mode 100644 index eb293133d..000000000 --- a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/boot.rs +++ /dev/null @@ -1,89 +0,0 @@ -use riscv::register::satp; - -use axconfig::{PHYS_VIRT_OFFSET, TASK_STACK_SIZE}; - -#[link_section = ".bss.stack"] -static mut BOOT_STACK: [u8; TASK_STACK_SIZE] = [0; TASK_STACK_SIZE]; - -#[link_section = ".data.boot_page_table"] -static mut BOOT_PT_SV39: [u64; 512] = [0; 512]; - -unsafe fn init_boot_page_table() { - // 0x8000_0000..0xc000_0000, VRWX_GAD, 1G block - BOOT_PT_SV39[2] = (0x80000 << 10) | 0xef; - // 0xffff_ffc0_8000_0000..0xffff_ffc0_c000_0000, VRWX_GAD, 1G block - BOOT_PT_SV39[0x102] = (0x80000 << 10) | 0xef; -} - -unsafe fn init_mmu() { - let page_table_root = BOOT_PT_SV39.as_ptr() as usize; - satp::set(satp::Mode::Sv39, 0, page_table_root >> 12); - riscv::asm::sfence_vma_all(); -} - -/// The earliest entry point for the primary CPU. -#[naked] -#[no_mangle] -#[link_section = ".text.boot"] -unsafe extern "C" fn _start() -> ! { - // PC = 0x8020_0000 - // a0 = hartid - // a1 = dtb - core::arch::asm!(" - mv s0, a0 // save hartid - mv s1, a1 // save DTB pointer - la sp, {boot_stack} - li t0, {boot_stack_size} - add sp, sp, t0 // setup boot stack - - call {init_boot_page_table} - call {init_mmu} // setup boot page table and enabel MMU - - li s2, {phys_virt_offset} // fix up virtual high address - add sp, sp, s2 - - mv a0, s0 - mv a1, s1 - la a2, {entry} - add a2, a2, s2 - jalr a2 // call rust_entry(hartid, dtb) - j .", - phys_virt_offset = const PHYS_VIRT_OFFSET, - boot_stack_size = const TASK_STACK_SIZE, - boot_stack = sym BOOT_STACK, - init_boot_page_table = sym init_boot_page_table, - init_mmu = sym init_mmu, - entry = sym super::rust_entry, - options(noreturn), - ) -} - -/// The earliest entry point for secondary CPUs. -#[cfg(feature = "smp")] -#[naked] -#[no_mangle] -#[link_section = ".text.boot"] -unsafe extern "C" fn _start_secondary() -> ! { - // a0 = hartid - // a1 = SP - core::arch::asm!(" - mv s0, a0 // save hartid - mv sp, a1 // set SP - - call {init_mmu} // setup boot page table and enabel MMU - - li s1, {phys_virt_offset} // fix up virtual high address - add a1, a1, s1 - add sp, sp, s1 - - mv a0, s0 - la a1, {entry} - add a1, a1, s1 - jalr a1 // call rust_entry_secondary(hartid) - j .", - phys_virt_offset = const PHYS_VIRT_OFFSET, - init_mmu = sym init_mmu, - entry = sym super::rust_entry_secondary, - options(noreturn), - ) -} diff --git a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/console.rs b/arceos/modules/axhal/src/platform/riscv64_qemu_virt/console.rs deleted file mode 100644 index a7ec3e646..000000000 --- a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/console.rs +++ /dev/null @@ -1,14 +0,0 @@ -/// Writes a byte to the console. -pub fn putchar(c: u8) { - #[allow(deprecated)] - sbi_rt::legacy::console_putchar(c as usize); -} - -/// Reads a byte from the console, or returns [`None`] if no input is available. -pub fn getchar() -> Option { - #[allow(deprecated)] - match sbi_rt::legacy::console_getchar() as isize { - -1 => None, - c => Some(c as u8), - } -} diff --git a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/irq.rs b/arceos/modules/axhal/src/platform/riscv64_qemu_virt/irq.rs deleted file mode 100644 index d46dfb301..000000000 --- a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/irq.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! TODO: PLIC - -use crate::irq::IrqHandler; -use lazyinit::LazyInit; -use riscv::register::sie; - -/// `Interrupt` bit in `scause` -pub(super) const INTC_IRQ_BASE: usize = 1 << (usize::BITS - 1); - -/// Supervisor software interrupt in `scause` -#[allow(unused)] -pub(super) const S_SOFT: usize = INTC_IRQ_BASE + 1; - -/// Supervisor timer interrupt in `scause` -pub(super) const S_TIMER: usize = INTC_IRQ_BASE + 5; - -/// Supervisor external interrupt in `scause` -pub(super) const S_EXT: usize = INTC_IRQ_BASE + 9; - -static TIMER_HANDLER: LazyInit = LazyInit::new(); - -/// The maximum number of IRQs. -pub const MAX_IRQ_COUNT: usize = 1024; - -/// The timer IRQ number (supervisor timer interrupt in `scause`). -pub const TIMER_IRQ_NUM: usize = S_TIMER; - -macro_rules! with_cause { - ($cause: expr, @TIMER => $timer_op: expr, @EXT => $ext_op: expr $(,)?) => { - match $cause { - S_TIMER => $timer_op, - S_EXT => $ext_op, - _ => panic!("invalid trap cause: {:#x}", $cause), - } - }; -} - -/// Enables or disables the given IRQ. -pub fn set_enable(scause: usize, _enabled: bool) { - if scause == S_EXT { - // TODO: set enable in PLIC - } -} - -/// Registers an IRQ handler for the given IRQ. -/// -/// It also enables the IRQ if the registration succeeds. It returns `false` if -/// the registration failed. -pub fn register_handler(scause: usize, handler: IrqHandler) -> bool { - with_cause!( - scause, - @TIMER => if !TIMER_HANDLER.is_inited() { - TIMER_HANDLER.init_once(handler); - true - } else { - false - }, - @EXT => crate::irq::register_handler_common(scause & !INTC_IRQ_BASE, handler), - ) -} - -/// Dispatches the IRQ. -/// -/// This function is called by the common interrupt handler. It looks -/// up in the IRQ handler table and calls the corresponding handler. If -/// necessary, it also acknowledges the interrupt controller after handling. -pub fn dispatch_irq(scause: usize) { - with_cause!( - scause, - @TIMER => { - trace!("IRQ: timer"); - TIMER_HANDLER(); - }, - @EXT => crate::irq::dispatch_irq_common(0), // TODO: get IRQ number from PLIC - ); -} - -pub(super) fn init_percpu() { - // enable soft interrupts, timer interrupts, and external interrupts - unsafe { - sie::set_ssoft(); - sie::set_stimer(); - sie::set_sext(); - } -} diff --git a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/mem.rs b/arceos/modules/axhal/src/platform/riscv64_qemu_virt/mem.rs deleted file mode 100644 index bad6113c4..000000000 --- a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/mem.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::mem::MemRegion; - -/// Returns platform-specific memory regions. -pub(crate) fn platform_regions() -> impl Iterator { - crate::mem::default_free_regions().chain(crate::mem::default_mmio_regions()) -} diff --git a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/misc.rs b/arceos/modules/axhal/src/platform/riscv64_qemu_virt/misc.rs deleted file mode 100644 index 6b6e02fcb..000000000 --- a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/misc.rs +++ /dev/null @@ -1,9 +0,0 @@ -/// Shutdown the whole system, including all CPUs. -pub fn terminate() -> ! { - info!("Shutting down..."); - sbi_rt::system_reset(sbi_rt::Shutdown, sbi_rt::NoReason); - warn!("It should shutdown!"); - loop { - crate::arch::halt(); - } -} diff --git a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/mod.rs b/arceos/modules/axhal/src/platform/riscv64_qemu_virt/mod.rs deleted file mode 100644 index 4f2eccf00..000000000 --- a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/mod.rs +++ /dev/null @@ -1,51 +0,0 @@ -mod boot; - -pub mod console; -pub mod mem; -pub mod misc; -pub mod time; - -#[cfg(feature = "irq")] -pub mod irq; - -#[cfg(feature = "smp")] -pub mod mp; - -extern "C" { - fn trap_vector_base(); - fn rust_main(cpu_id: usize, dtb: usize); - #[cfg(feature = "smp")] - fn rust_main_secondary(cpu_id: usize); -} - -unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { - crate::mem::clear_bss(); - crate::cpu::init_primary(cpu_id); - crate::arch::set_trap_vector_base(trap_vector_base as usize); - self::time::init_early(); - rust_main(cpu_id, dtb); -} - -#[cfg(feature = "smp")] -unsafe extern "C" fn rust_entry_secondary(cpu_id: usize) { - crate::arch::set_trap_vector_base(trap_vector_base as usize); - crate::cpu::init_secondary(cpu_id); - rust_main_secondary(cpu_id); -} - -/// Initializes the platform devices for the primary CPU. -/// -/// For example, the interrupt controller and the timer. -pub fn platform_init() { - #[cfg(feature = "irq")] - self::irq::init_percpu(); - self::time::init_percpu(); -} - -/// Initializes the platform devices for secondary CPUs. -#[cfg(feature = "smp")] -pub fn platform_init_secondary() { - #[cfg(feature = "irq")] - self::irq::init_percpu(); - self::time::init_percpu(); -} diff --git a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/mp.rs b/arceos/modules/axhal/src/platform/riscv64_qemu_virt/mp.rs deleted file mode 100644 index ddcecca4d..000000000 --- a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/mp.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::mem::{virt_to_phys, PhysAddr}; - -/// Starts the given secondary CPU with its boot stack. -pub fn start_secondary_cpu(hartid: usize, stack_top: PhysAddr) { - extern "C" { - fn _start_secondary(); - } - if sbi_rt::probe_extension(sbi_rt::Hsm).is_unavailable() { - warn!("HSM SBI extension is not supported for current SEE."); - return; - } - let entry = virt_to_phys(va!(_start_secondary as usize)); - sbi_rt::hart_start(hartid, entry.as_usize(), stack_top.as_usize()); -} diff --git a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/time.rs b/arceos/modules/axhal/src/platform/riscv64_qemu_virt/time.rs deleted file mode 100644 index 538bddadd..000000000 --- a/arceos/modules/axhal/src/platform/riscv64_qemu_virt/time.rs +++ /dev/null @@ -1,60 +0,0 @@ -use riscv::register::time; - -const NANOS_PER_TICK: u64 = crate::time::NANOS_PER_SEC / axconfig::TIMER_FREQUENCY as u64; -/// RTC wall time offset in nanoseconds at monotonic time base. -static mut RTC_EPOCHOFFSET_NANOS: u64 = 0; - -/// Returns the current clock time in hardware ticks. -#[inline] -pub fn current_ticks() -> u64 { - time::read() as u64 -} - -/// Converts hardware ticks to nanoseconds. -#[inline] -pub const fn ticks_to_nanos(ticks: u64) -> u64 { - ticks * NANOS_PER_TICK -} - -/// Converts nanoseconds to hardware ticks. -#[inline] -pub const fn nanos_to_ticks(nanos: u64) -> u64 { - nanos / NANOS_PER_TICK -} - -/// Return epoch offset in nanoseconds (wall time offset to monotonic clock start). -pub fn epochoffset_nanos() -> u64 { - unsafe { RTC_EPOCHOFFSET_NANOS } -} - -/// Set a one-shot timer. -/// -/// A timer interrupt will be triggered at the specified monotonic time deadline (in nanoseconds). -#[cfg(feature = "irq")] -pub fn set_oneshot_timer(deadline_ns: u64) { - sbi_rt::set_timer(nanos_to_ticks(deadline_ns)); -} - -pub(super) fn init_early() { - #[cfg(feature = "rtc")] - if axconfig::RTC_PADDR != 0 { - use crate::mem::phys_to_virt; - use memory_addr::PhysAddr; - use riscv_goldfish::Rtc; - - const GOLDFISH_BASE: PhysAddr = pa!(axconfig::RTC_PADDR); - // Get the current time in microseconds since the epoch (1970-01-01) from the riscv RTC. - // Subtract the timer ticks to get the actual time when ArceOS was booted. - let epoch_time_nanos = - Rtc::new(phys_to_virt(GOLDFISH_BASE).as_usize()).get_unix_timestamp() * 1_000_000_000; - - unsafe { - RTC_EPOCHOFFSET_NANOS = epoch_time_nanos - ticks_to_nanos(current_ticks()); - } - } -} - -pub(super) fn init_percpu() { - #[cfg(feature = "irq")] - sbi_rt::set_timer(0); -} diff --git a/arceos/modules/axhal/src/platform/x86_pc/ap_start.S b/arceos/modules/axhal/src/platform/x86_pc/ap_start.S deleted file mode 100644 index 9784f7672..000000000 --- a/arceos/modules/axhal/src/platform/x86_pc/ap_start.S +++ /dev/null @@ -1,69 +0,0 @@ -# Boot application processors into the protected mode. - -# Each non-boot CPU ("AP") is started up in response to a STARTUP -# IPI from the boot CPU. Section B.4.2 of the Multi-Processor -# Specification says that the AP will start in real mode with CS:IP -# set to XY00:0000, where XY is an 8-bit value sent with the -# STARTUP. Thus this code must start at a 4096-byte boundary. -# -# Because this code sets DS to zero, it must sit -# at an address in the low 2^16 bytes. - -.equ pa_ap_start32, ap_start32 - ap_start + {start_page_paddr} -.equ pa_ap_gdt, .Lap_tmp_gdt - ap_start + {start_page_paddr} -.equ pa_ap_gdt_desc, .Lap_tmp_gdt_desc - ap_start + {start_page_paddr} - -.equ stack_ptr, {start_page_paddr} + 0xff0 -.equ entry_ptr, {start_page_paddr} + 0xff8 - -# 0x6000 -.section .text -.code16 -.p2align 12 -.global ap_start -ap_start: - cli - wbinvd - - xor ax, ax - mov ds, ax - mov es, ax - mov ss, ax - mov fs, ax - mov gs, ax - - # load the 64-bit GDT - lgdt [pa_ap_gdt_desc] - - # switch to protected-mode - mov eax, cr0 - or eax, (1 << 0) - mov cr0, eax - - # far jump to 32-bit code. 0x8 is code32 segment selector - ljmp 0x8, offset pa_ap_start32 - -.code32 -ap_start32: - mov esp, [stack_ptr] - mov eax, [entry_ptr] - jmp eax - -.balign 8 -# .type multiboot_header, STT_OBJECT -.Lap_tmp_gdt_desc: - .short .Lap_tmp_gdt_end - .Lap_tmp_gdt - 1 # limit - .long pa_ap_gdt # base - -.balign 16 -.Lap_tmp_gdt: - .quad 0x0000000000000000 # 0x00: null - .quad 0x00cf9b000000ffff # 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) - .quad 0x00af9b000000ffff # 0x10: code segment (base=0, limit=0xfffff, type=64bit code exec/read, DPL=0, 4k) - .quad 0x00cf93000000ffff # 0x18: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) -.Lap_tmp_gdt_end: - -# 0x7000 -.p2align 12 -.global ap_end -ap_end: diff --git a/arceos/modules/axhal/src/platform/x86_pc/apic.rs b/arceos/modules/axhal/src/platform/x86_pc/apic.rs deleted file mode 100644 index 140a9bc9f..000000000 --- a/arceos/modules/axhal/src/platform/x86_pc/apic.rs +++ /dev/null @@ -1,124 +0,0 @@ -#![allow(dead_code)] - -use kspin::SpinNoIrq; -use lazyinit::LazyInit; -use memory_addr::PhysAddr; -use x2apic::ioapic::IoApic; -use x2apic::lapic::{xapic_base, LocalApic, LocalApicBuilder}; -use x86_64::instructions::port::Port; - -use self::vectors::*; -use crate::mem::phys_to_virt; - -pub(super) mod vectors { - pub const APIC_TIMER_VECTOR: u8 = 0xf0; - pub const APIC_SPURIOUS_VECTOR: u8 = 0xf1; - pub const APIC_ERROR_VECTOR: u8 = 0xf2; -} - -/// The maximum number of IRQs. -pub const MAX_IRQ_COUNT: usize = 256; - -/// The timer IRQ number. -pub const TIMER_IRQ_NUM: usize = APIC_TIMER_VECTOR as usize; - -const IO_APIC_BASE: PhysAddr = pa!(0xFEC0_0000); - -static mut LOCAL_APIC: Option = None; -static mut IS_X2APIC: bool = false; -static IO_APIC: LazyInit> = LazyInit::new(); - -/// Enables or disables the given IRQ. -#[cfg(feature = "irq")] -pub fn set_enable(vector: usize, enabled: bool) { - // should not affect LAPIC interrupts - if vector < APIC_TIMER_VECTOR as _ { - unsafe { - if enabled { - IO_APIC.lock().enable_irq(vector as u8); - } else { - IO_APIC.lock().disable_irq(vector as u8); - } - } - } -} - -/// Registers an IRQ handler for the given IRQ. -/// -/// It also enables the IRQ if the registration succeeds. It returns `false` if -/// the registration failed. -#[cfg(feature = "irq")] -pub fn register_handler(vector: usize, handler: crate::irq::IrqHandler) -> bool { - crate::irq::register_handler_common(vector, handler) -} - -/// Dispatches the IRQ. -/// -/// This function is called by the common interrupt handler. It looks -/// up in the IRQ handler table and calls the corresponding handler. If -/// necessary, it also acknowledges the interrupt controller after handling. -#[cfg(feature = "irq")] -pub fn dispatch_irq(vector: usize) { - crate::irq::dispatch_irq_common(vector); - unsafe { local_apic().end_of_interrupt() }; -} - -pub(super) fn local_apic<'a>() -> &'a mut LocalApic { - // It's safe as LAPIC is per-cpu. - unsafe { LOCAL_APIC.as_mut().unwrap() } -} - -pub(super) fn raw_apic_id(id_u8: u8) -> u32 { - if unsafe { IS_X2APIC } { - id_u8 as u32 - } else { - (id_u8 as u32) << 24 - } -} - -fn cpu_has_x2apic() -> bool { - match raw_cpuid::CpuId::new().get_feature_info() { - Some(finfo) => finfo.has_x2apic(), - None => false, - } -} - -pub(super) fn init_primary() { - info!("Initialize Local APIC..."); - - unsafe { - // Disable 8259A interrupt controllers - Port::::new(0x21).write(0xff); - Port::::new(0xA1).write(0xff); - } - - let mut builder = LocalApicBuilder::new(); - builder - .timer_vector(APIC_TIMER_VECTOR as _) - .error_vector(APIC_ERROR_VECTOR as _) - .spurious_vector(APIC_SPURIOUS_VECTOR as _); - - if cpu_has_x2apic() { - info!("Using x2APIC."); - unsafe { IS_X2APIC = true }; - } else { - info!("Using xAPIC."); - let base_vaddr = phys_to_virt(pa!(unsafe { xapic_base() } as usize)); - builder.set_xapic_base(base_vaddr.as_usize() as u64); - } - - let mut lapic = builder.build().unwrap(); - unsafe { - lapic.enable(); - LOCAL_APIC = Some(lapic); - } - - info!("Initialize IO APIC..."); - let io_apic = unsafe { IoApic::new(phys_to_virt(IO_APIC_BASE).as_usize() as u64) }; - IO_APIC.init_once(SpinNoIrq::new(io_apic)); -} - -#[cfg(feature = "smp")] -pub(super) fn init_secondary() { - unsafe { local_apic().enable() }; -} diff --git a/arceos/modules/axhal/src/platform/x86_pc/boot.rs b/arceos/modules/axhal/src/platform/x86_pc/boot.rs deleted file mode 100644 index f21f66982..000000000 --- a/arceos/modules/axhal/src/platform/x86_pc/boot.rs +++ /dev/null @@ -1,52 +0,0 @@ -use core::arch::global_asm; - -use x86_64::registers::control::{Cr0Flags, Cr4Flags}; -use x86_64::registers::model_specific::EferFlags; - -use axconfig::{PHYS_VIRT_OFFSET, TASK_STACK_SIZE}; - -/// Flags set in the ’flags’ member of the multiboot header. -/// -/// (bits 1, 16: memory information, address fields in header) -const MULTIBOOT_HEADER_FLAGS: usize = 0x0001_0002; - -/// The magic field should contain this. -const MULTIBOOT_HEADER_MAGIC: usize = 0x1BADB002; - -/// This should be in EAX. -pub(super) const MULTIBOOT_BOOTLOADER_MAGIC: usize = 0x2BADB002; - -const CR0: u64 = Cr0Flags::PROTECTED_MODE_ENABLE.bits() - | Cr0Flags::MONITOR_COPROCESSOR.bits() - | Cr0Flags::NUMERIC_ERROR.bits() - | Cr0Flags::WRITE_PROTECT.bits() - | Cr0Flags::PAGING.bits(); -const CR4: u64 = Cr4Flags::PHYSICAL_ADDRESS_EXTENSION.bits() - | Cr4Flags::PAGE_GLOBAL.bits() - | if cfg!(feature = "fp_simd") { - Cr4Flags::OSFXSR.bits() | Cr4Flags::OSXMMEXCPT_ENABLE.bits() - } else { - 0 - }; -const EFER: u64 = EferFlags::LONG_MODE_ENABLE.bits() | EferFlags::NO_EXECUTE_ENABLE.bits(); - -#[link_section = ".bss.stack"] -static mut BOOT_STACK: [u8; TASK_STACK_SIZE] = [0; TASK_STACK_SIZE]; - -global_asm!( - include_str!("multiboot.S"), - mb_magic = const MULTIBOOT_BOOTLOADER_MAGIC, - mb_hdr_magic = const MULTIBOOT_HEADER_MAGIC, - mb_hdr_flags = const MULTIBOOT_HEADER_FLAGS, - entry = sym super::rust_entry, - entry_secondary = sym super::rust_entry_secondary, - - offset = const PHYS_VIRT_OFFSET, - boot_stack_size = const TASK_STACK_SIZE, - boot_stack = sym BOOT_STACK, - - cr0 = const CR0, - cr4 = const CR4, - efer_msr = const x86::msr::IA32_EFER, - efer = const EFER, -); diff --git a/arceos/modules/axhal/src/platform/x86_pc/dtables.rs b/arceos/modules/axhal/src/platform/x86_pc/dtables.rs deleted file mode 100644 index a6af270c6..000000000 --- a/arceos/modules/axhal/src/platform/x86_pc/dtables.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! Description tables (per-CPU GDT, per-CPU ISS, IDT) - -use crate::arch::{GdtStruct, IdtStruct, TaskStateSegment}; -use lazyinit::LazyInit; - -static IDT: LazyInit = LazyInit::new(); - -#[percpu::def_percpu] -static TSS: LazyInit = LazyInit::new(); - -#[percpu::def_percpu] -static GDT: LazyInit = LazyInit::new(); - -fn init_percpu() { - unsafe { - IDT.load(); - let tss = TSS.current_ref_mut_raw(); - let gdt = GDT.current_ref_mut_raw(); - tss.init_once(TaskStateSegment::new()); - gdt.init_once(GdtStruct::new(tss)); - gdt.load(); - gdt.load_tss(); - } -} - -/// Initializes IDT, GDT on the primary CPU. -pub(super) fn init_primary() { - axlog::ax_println!("\nInitialize IDT & GDT..."); - IDT.init_once(IdtStruct::new()); - init_percpu(); -} - -/// Initializes IDT, GDT on secondary CPUs. -#[cfg(feature = "smp")] -pub(super) fn init_secondary() { - init_percpu(); -} diff --git a/arceos/modules/axhal/src/platform/x86_pc/mem.rs b/arceos/modules/axhal/src/platform/x86_pc/mem.rs deleted file mode 100644 index a321c7779..000000000 --- a/arceos/modules/axhal/src/platform/x86_pc/mem.rs +++ /dev/null @@ -1,15 +0,0 @@ -// TODO: get memory regions from multiboot info. - -use crate::mem::{MemRegion, MemRegionFlags}; - -/// Returns platform-specific memory regions. -pub(crate) fn platform_regions() -> impl Iterator { - core::iter::once(MemRegion { - paddr: pa!(0x1000), - size: 0x9e000, - flags: MemRegionFlags::RESERVED | MemRegionFlags::READ | MemRegionFlags::WRITE, - name: "low memory", - }) - .chain(crate::mem::default_free_regions()) - .chain(crate::mem::default_mmio_regions()) -} diff --git a/arceos/modules/axhal/src/platform/x86_pc/misc.rs b/arceos/modules/axhal/src/platform/x86_pc/misc.rs deleted file mode 100644 index f01c4f339..000000000 --- a/arceos/modules/axhal/src/platform/x86_pc/misc.rs +++ /dev/null @@ -1,27 +0,0 @@ -use x86_64::instructions::port::PortWriteOnly; - -/// Shutdown the whole system (in QEMU), including all CPUs. -/// -/// See for more information. -pub fn terminate() -> ! { - info!("Shutting down..."); - - #[cfg(platform = "x86_64-pc-oslab")] - { - axlog::ax_println!("System will reboot, press any key to continue ..."); - while super::console::getchar().is_none() {} - axlog::ax_println!("Rebooting ..."); - unsafe { PortWriteOnly::new(0x64).write(0xfeu8) }; - } - - #[cfg(platform = "x86_64-qemu-q35")] - unsafe { - PortWriteOnly::new(0x604).write(0x2000u16) - }; - - crate::arch::halt(); - warn!("It should shutdown!"); - loop { - crate::arch::halt(); - } -} diff --git a/arceos/modules/axhal/src/platform/x86_pc/mod.rs b/arceos/modules/axhal/src/platform/x86_pc/mod.rs deleted file mode 100644 index ba3ce4363..000000000 --- a/arceos/modules/axhal/src/platform/x86_pc/mod.rs +++ /dev/null @@ -1,68 +0,0 @@ -mod apic; -mod boot; -mod dtables; -mod uart16550; - -pub mod mem; -pub mod misc; -pub mod time; - -#[cfg(feature = "smp")] -pub mod mp; - -#[cfg(feature = "irq")] -pub mod irq { - pub use super::apic::*; -} - -pub mod console { - pub use super::uart16550::*; -} - -extern "C" { - fn rust_main(cpu_id: usize, dtb: usize) -> !; - #[cfg(feature = "smp")] - fn rust_main_secondary(cpu_id: usize) -> !; -} - -fn current_cpu_id() -> usize { - match raw_cpuid::CpuId::new().get_feature_info() { - Some(finfo) => finfo.initial_local_apic_id() as usize, - None => 0, - } -} - -unsafe extern "C" fn rust_entry(magic: usize, _mbi: usize) { - // TODO: handle multiboot info - if magic == self::boot::MULTIBOOT_BOOTLOADER_MAGIC { - crate::mem::clear_bss(); - crate::cpu::init_primary(current_cpu_id()); - self::uart16550::init(); - self::dtables::init_primary(); - self::time::init_early(); - rust_main(current_cpu_id(), 0); - } -} - -#[allow(unused_variables)] -unsafe extern "C" fn rust_entry_secondary(magic: usize) { - #[cfg(feature = "smp")] - if magic == self::boot::MULTIBOOT_BOOTLOADER_MAGIC { - crate::cpu::init_secondary(current_cpu_id()); - self::dtables::init_secondary(); - rust_main_secondary(current_cpu_id()); - } -} - -/// Initializes the platform devices for the primary CPU. -pub fn platform_init() { - self::apic::init_primary(); - self::time::init_primary(); -} - -/// Initializes the platform devices for secondary CPUs. -#[cfg(feature = "smp")] -pub fn platform_init_secondary() { - self::apic::init_secondary(); - self::time::init_secondary(); -} diff --git a/arceos/modules/axhal/src/platform/x86_pc/mp.rs b/arceos/modules/axhal/src/platform/x86_pc/mp.rs deleted file mode 100644 index fb194934d..000000000 --- a/arceos/modules/axhal/src/platform/x86_pc/mp.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::mem::{phys_to_virt, PhysAddr, PAGE_SIZE_4K}; -use crate::time::{busy_wait, Duration}; - -const START_PAGE_IDX: u8 = 6; -const START_PAGE_PADDR: PhysAddr = pa!(START_PAGE_IDX as usize * PAGE_SIZE_4K); - -core::arch::global_asm!( - include_str!("ap_start.S"), - start_page_paddr = const START_PAGE_PADDR.as_usize(), -); - -unsafe fn setup_startup_page(stack_top: PhysAddr) { - extern "C" { - fn ap_entry32(); - fn ap_start(); - fn ap_end(); - } - const U64_PER_PAGE: usize = PAGE_SIZE_4K / 8; - - let start_page_ptr = phys_to_virt(START_PAGE_PADDR).as_mut_ptr() as *mut u64; - let start_page = core::slice::from_raw_parts_mut(start_page_ptr, U64_PER_PAGE); - core::ptr::copy_nonoverlapping( - ap_start as *const u64, - start_page_ptr, - (ap_end as usize - ap_start as usize) / 8, - ); - start_page[U64_PER_PAGE - 2] = stack_top.as_usize() as u64; // stack_top - start_page[U64_PER_PAGE - 1] = ap_entry32 as usize as _; // entry -} - -/// Starts the given secondary CPU with its boot stack. -pub fn start_secondary_cpu(apic_id: usize, stack_top: PhysAddr) { - unsafe { setup_startup_page(stack_top) }; - - let apic_id = super::apic::raw_apic_id(apic_id as u8); - let lapic = super::apic::local_apic(); - - // INIT-SIPI-SIPI Sequence - // Ref: Intel SDM Vol 3C, Section 8.4.4, MP Initialization Example - unsafe { lapic.send_init_ipi(apic_id) }; - busy_wait(Duration::from_millis(10)); // 10ms - unsafe { lapic.send_sipi(START_PAGE_IDX, apic_id) }; - busy_wait(Duration::from_micros(200)); // 200us - unsafe { lapic.send_sipi(START_PAGE_IDX, apic_id) }; -} diff --git a/arceos/modules/axhal/src/platform/x86_pc/multiboot.S b/arceos/modules/axhal/src/platform/x86_pc/multiboot.S deleted file mode 100644 index b18103b1a..000000000 --- a/arceos/modules/axhal/src/platform/x86_pc/multiboot.S +++ /dev/null @@ -1,143 +0,0 @@ -# Bootstrapping from 32-bit with the Multiboot specification. -# See https://www.gnu.org/software/grub/manual/multiboot/multiboot.html - -.section .text.boot -.code32 -.global _start -_start: - mov edi, eax # arg1: magic: 0x2BADB002 - mov esi, ebx # arg2: multiboot info - jmp bsp_entry32 - -.balign 4 -.type multiboot_header, STT_OBJECT -multiboot_header: - .int {mb_hdr_magic} # magic: 0x1BADB002 - .int {mb_hdr_flags} # flags - .int -({mb_hdr_magic} + {mb_hdr_flags}) # checksum - .int multiboot_header - {offset} # header_addr - .int _skernel - {offset} # load_addr - .int _edata - {offset} # load_end - .int _ebss - {offset} # bss_end_addr - .int _start - {offset} # entry_addr - -# Common code in 32-bit, prepare states to enter 64-bit. -.macro ENTRY32_COMMON - # set data segment selectors - mov ax, 0x18 - mov ss, ax - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - # set PAE, PGE bit in CR4 - mov eax, {cr4} - mov cr4, eax - - # load the temporary page table - lea eax, [.Ltmp_pml4 - {offset}] - mov cr3, eax - - # set LME, NXE bit in IA32_EFER - mov ecx, {efer_msr} - mov edx, 0 - mov eax, {efer} - wrmsr - - # set protected mode, write protect, paging bit in CR0 - mov eax, {cr0} - mov cr0, eax -.endm - -# Common code in 64-bit -.macro ENTRY64_COMMON - # clear segment selectors - xor ax, ax - mov ss, ax - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax -.endm - -.code32 -bsp_entry32: - lgdt [.Ltmp_gdt_desc - {offset}] # load the temporary GDT - ENTRY32_COMMON - ljmp 0x10, offset bsp_entry64 - {offset} # 0x10 is code64 segment - -.code32 -.global ap_entry32 -ap_entry32: - ENTRY32_COMMON - ljmp 0x10, offset ap_entry64 - {offset} # 0x10 is code64 segment - -.code64 -bsp_entry64: - ENTRY64_COMMON - - # set RSP to boot stack - movabs rsp, offset {boot_stack} - add rsp, {boot_stack_size} - - # call rust_entry(magic, mbi) - movabs rax, offset {entry} - call rax - jmp .Lhlt - -.code64 -ap_entry64: - ENTRY64_COMMON - - # set RSP to high address (already set in ap_start.S) - mov rax, {offset} - add rsp, rax - - # call rust_entry_secondary(magic) - mov rdi, {mb_magic} - movabs rax, offset {entry_secondary} - call rax - jmp .Lhlt - -.Lhlt: - hlt - jmp .Lhlt - -.section .rodata -.balign 8 -.Ltmp_gdt_desc: - .short .Ltmp_gdt_end - .Ltmp_gdt - 1 # limit - .long .Ltmp_gdt - {offset} # base - -.section .data -.balign 16 -.Ltmp_gdt: - .quad 0x0000000000000000 # 0x00: null - .quad 0x00cf9b000000ffff # 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) - .quad 0x00af9b000000ffff # 0x10: code segment (base=0, limit=0xfffff, type=64bit code exec/read, DPL=0, 4k) - .quad 0x00cf93000000ffff # 0x18: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) -.Ltmp_gdt_end: - -.balign 4096 -.Ltmp_pml4: - # 0x0000_0000 ~ 0xffff_ffff - .quad .Ltmp_pdpt_low - {offset} + 0x3 # PRESENT | WRITABLE | paddr(tmp_pdpt) - .zero 8 * 510 - # 0xffff_ff80_0000_0000 ~ 0xffff_ff80_ffff_ffff - .quad .Ltmp_pdpt_high - {offset} + 0x3 # PRESENT | WRITABLE | paddr(tmp_pdpt) - -# FIXME: may not work on macOS using hvf as the CPU does not support 1GB page (pdpe1gb) -.Ltmp_pdpt_low: - .quad 0x0000 | 0x83 # PRESENT | WRITABLE | HUGE_PAGE | paddr(0x0) - .quad 0x40000000 | 0x83 # PRESENT | WRITABLE | HUGE_PAGE | paddr(0x4000_0000) - .quad 0x80000000 | 0x83 # PRESENT | WRITABLE | HUGE_PAGE | paddr(0x8000_0000) - .quad 0xc0000000 | 0x83 # PRESENT | WRITABLE | HUGE_PAGE | paddr(0xc000_0000) - .zero 8 * 508 - -.Ltmp_pdpt_high: - .quad 0x0000 | 0x83 # PRESENT | WRITABLE | HUGE_PAGE | paddr(0x0) - .quad 0x40000000 | 0x83 # PRESENT | WRITABLE | HUGE_PAGE | paddr(0x4000_0000) - .quad 0x80000000 | 0x83 # PRESENT | WRITABLE | HUGE_PAGE | paddr(0x8000_0000) - .quad 0xc0000000 | 0x83 # PRESENT | WRITABLE | HUGE_PAGE | paddr(0xc000_0000) - .zero 8 * 508 diff --git a/arceos/modules/axhal/src/platform/x86_pc/time.rs b/arceos/modules/axhal/src/platform/x86_pc/time.rs deleted file mode 100644 index 871ad9c3f..000000000 --- a/arceos/modules/axhal/src/platform/x86_pc/time.rs +++ /dev/null @@ -1,107 +0,0 @@ -use raw_cpuid::CpuId; - -#[cfg(feature = "irq")] -use int_ratio::Ratio; - -#[cfg(feature = "irq")] -const LAPIC_TICKS_PER_SEC: u64 = 1_000_000_000; // TODO: need to calibrate - -#[cfg(feature = "irq")] -static mut NANOS_TO_LAPIC_TICKS_RATIO: Ratio = Ratio::zero(); - -static mut INIT_TICK: u64 = 0; -static mut CPU_FREQ_MHZ: u64 = axconfig::TIMER_FREQUENCY as u64 / 1_000_000; - -/// RTC wall time offset in nanoseconds at monotonic time base. -static mut RTC_EPOCHOFFSET_NANOS: u64 = 0; - -/// Returns the current clock time in hardware ticks. -pub fn current_ticks() -> u64 { - unsafe { core::arch::x86_64::_rdtsc() - INIT_TICK } -} - -/// Converts hardware ticks to nanoseconds. -pub fn ticks_to_nanos(ticks: u64) -> u64 { - ticks * 1_000 / unsafe { CPU_FREQ_MHZ } -} - -/// Converts nanoseconds to hardware ticks. -pub fn nanos_to_ticks(nanos: u64) -> u64 { - nanos * unsafe { CPU_FREQ_MHZ } / 1_000 -} - -/// Return epoch offset in nanoseconds (wall time offset to monotonic clock start). -pub fn epochoffset_nanos() -> u64 { - unsafe { RTC_EPOCHOFFSET_NANOS } -} - -/// Set a one-shot timer. -/// -/// A timer interrupt will be triggered at the specified monotonic time deadline (in nanoseconds). -#[cfg(feature = "irq")] -pub fn set_oneshot_timer(deadline_ns: u64) { - let lapic = super::apic::local_apic(); - let now_ns = crate::time::monotonic_time_nanos(); - unsafe { - if now_ns < deadline_ns { - let apic_ticks = NANOS_TO_LAPIC_TICKS_RATIO.mul_trunc(deadline_ns - now_ns); - assert!(apic_ticks <= u32::MAX as u64); - lapic.set_timer_initial(apic_ticks.max(1) as u32); - } else { - lapic.set_timer_initial(1); - } - } -} - -pub(super) fn init_early() { - if let Some(freq) = CpuId::new() - .get_processor_frequency_info() - .map(|info| info.processor_base_frequency()) - { - if freq > 0 { - axlog::ax_println!("Got TSC frequency by CPUID: {} MHz", freq); - unsafe { CPU_FREQ_MHZ = freq as u64 } - } - } - - unsafe { - INIT_TICK = core::arch::x86_64::_rdtsc(); - } - - #[cfg(feature = "rtc")] - { - use x86_rtc::Rtc; - - // Get the current time in microseconds since the epoch (1970-01-01) from the x86 RTC. - // Subtract the timer ticks to get the actual time when ArceOS was booted. - let eopch_time_nanos = Rtc::new().get_unix_timestamp() * 1_000_000_000; - unsafe { - RTC_EPOCHOFFSET_NANOS = eopch_time_nanos - ticks_to_nanos(INIT_TICK); - } - } -} - -pub(super) fn init_primary() { - #[cfg(feature = "irq")] - unsafe { - use x2apic::lapic::{TimerDivide, TimerMode}; - let lapic = super::apic::local_apic(); - lapic.set_timer_mode(TimerMode::OneShot); - lapic.set_timer_divide(TimerDivide::Div256); // indeed it is Div1, the name is confusing. - lapic.enable_timer(); - - // TODO: calibrate with HPET - NANOS_TO_LAPIC_TICKS_RATIO = Ratio::new( - LAPIC_TICKS_PER_SEC as u32, - crate::time::NANOS_PER_SEC as u32, - ); - } -} - -#[cfg(feature = "smp")] -pub(super) fn init_secondary() { - #[cfg(feature = "irq")] - unsafe { - super::apic::local_apic().enable_timer(); - } -} diff --git a/arceos/modules/axhal/src/platform/x86_pc/uart16550.rs b/arceos/modules/axhal/src/platform/x86_pc/uart16550.rs deleted file mode 100644 index 3c773d307..000000000 --- a/arceos/modules/axhal/src/platform/x86_pc/uart16550.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Uart 16550. - -use kspin::SpinNoIrq; -use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly}; - -const UART_CLOCK_FACTOR: usize = 16; -const OSC_FREQ: usize = 1_843_200; - -static COM1: SpinNoIrq = SpinNoIrq::new(Uart16550::new(0x3f8)); - -bitflags::bitflags! { - /// Line status flags - struct LineStsFlags: u8 { - const INPUT_FULL = 1; - // 1 to 4 unknown - const OUTPUT_EMPTY = 1 << 5; - // 6 and 7 unknown - } -} - -struct Uart16550 { - data: Port, - int_en: PortWriteOnly, - fifo_ctrl: PortWriteOnly, - line_ctrl: PortWriteOnly, - modem_ctrl: PortWriteOnly, - line_sts: PortReadOnly, -} - -impl Uart16550 { - const fn new(port: u16) -> Self { - Self { - data: Port::new(port), - int_en: PortWriteOnly::new(port + 1), - fifo_ctrl: PortWriteOnly::new(port + 2), - line_ctrl: PortWriteOnly::new(port + 3), - modem_ctrl: PortWriteOnly::new(port + 4), - line_sts: PortReadOnly::new(port + 5), - } - } - - fn init(&mut self, baud_rate: usize) { - unsafe { - // Disable interrupts - self.int_en.write(0x00); - - // Enable DLAB - self.line_ctrl.write(0x80); - - // Set maximum speed according the input baud rate by configuring DLL and DLM - let divisor = OSC_FREQ / (baud_rate * UART_CLOCK_FACTOR); - self.data.write((divisor & 0xff) as u8); - self.int_en.write((divisor >> 8) as u8); - - // Disable DLAB and set data word length to 8 bits - self.line_ctrl.write(0x03); - - // Enable FIFO, clear TX/RX queues and - // set interrupt watermark at 14 bytes - self.fifo_ctrl.write(0xC7); - - // Mark data terminal ready, signal request to send - // and enable auxilliary output #2 (used as interrupt line for CPU) - self.modem_ctrl.write(0x0B); - } - } - - fn line_sts(&mut self) -> LineStsFlags { - unsafe { LineStsFlags::from_bits_truncate(self.line_sts.read()) } - } - - fn putchar(&mut self, c: u8) { - while !self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {} - unsafe { self.data.write(c) }; - } - - fn getchar(&mut self) -> Option { - if self.line_sts().contains(LineStsFlags::INPUT_FULL) { - unsafe { Some(self.data.read()) } - } else { - None - } - } -} - -/// Writes a byte to the console. -pub fn putchar(c: u8) { - let mut uart = COM1.lock(); - match c { - b'\n' => { - uart.putchar(b'\r'); - uart.putchar(b'\n'); - } - c => uart.putchar(c), - } -} - -/// Reads a byte from the console, or returns [`None`] if no input is available. -pub fn getchar() -> Option { - COM1.lock().getchar() -} - -pub(super) fn init() { - COM1.lock().init(115200); -} diff --git a/arceos/modules/axhal/src/time.rs b/arceos/modules/axhal/src/time.rs deleted file mode 100644 index 3c39e3d31..000000000 --- a/arceos/modules/axhal/src/time.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! Time-related operations. - -pub use core::time::Duration; - -/// A measurement of the system clock. -/// -/// Currently, it reuses the [`core::time::Duration`] type. But it does not -/// represent a duration, but a clock time. -pub type TimeValue = Duration; - -#[cfg(feature = "irq")] -pub use crate::platform::irq::TIMER_IRQ_NUM; -#[cfg(feature = "irq")] -pub use crate::platform::time::set_oneshot_timer; -pub use crate::platform::time::{current_ticks, epochoffset_nanos, nanos_to_ticks, ticks_to_nanos}; - -/// Number of milliseconds in a second. -pub const MILLIS_PER_SEC: u64 = 1_000; -/// Number of microseconds in a second. -pub const MICROS_PER_SEC: u64 = 1_000_000; -/// Number of nanoseconds in a second. -pub const NANOS_PER_SEC: u64 = 1_000_000_000; -/// Number of nanoseconds in a millisecond. -pub const NANOS_PER_MILLIS: u64 = 1_000_000; -/// Number of nanoseconds in a microsecond. -pub const NANOS_PER_MICROS: u64 = 1_000; - -/// Returns nanoseconds elapsed since system boot. -pub fn monotonic_time_nanos() -> u64 { - ticks_to_nanos(current_ticks()) -} - -/// Returns the time elapsed since system boot in [`TimeValue`]. -pub fn monotonic_time() -> TimeValue { - TimeValue::from_nanos(monotonic_time_nanos()) -} - -/// Returns nanoseconds elapsed since epoch (also known as realtime). -pub fn wall_time_nanos() -> u64 { - monotonic_time_nanos() + epochoffset_nanos() -} - -/// Returns the time elapsed since epoch (also known as realtime) in [`TimeValue`]. -pub fn wall_time() -> TimeValue { - TimeValue::from_nanos(monotonic_time_nanos() + epochoffset_nanos()) -} - -/// Busy waiting for the given duration. -pub fn busy_wait(dur: Duration) { - busy_wait_until(wall_time() + dur); -} - -/// Busy waiting until reaching the given deadline. -pub fn busy_wait_until(deadline: TimeValue) { - while wall_time() < deadline { - core::hint::spin_loop(); - } -} diff --git a/arceos/modules/axhal/src/tls.rs b/arceos/modules/axhal/src/tls.rs deleted file mode 100644 index 849ef0e38..000000000 --- a/arceos/modules/axhal/src/tls.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! Thread Local Storage (TLS) support. -//! -//! ## TLS layout for x86_64 -//! -//! ```text -//! aligned --> +-------------------------+- static_tls_offset -//! allocation | | \ -//! | .tdata | | -//! | address | | | -//! | grow up + - - - - - - - - - - - - + > Static TLS block -//! v | | | (length: static_tls_size) -//! | .tbss | | -//! | | | -//! +-------------------------+ | -//! | / PADDING / / / / / / / | / -//! +-------------------------+ -//! tls_ptr -+-> self pointer (void *) | \ -//! (tp_offset) | | | -//! | Custom TCB format | > Thread Control Block (TCB) -//! | (might be used | | (length: TCB_SIZE) -//! | by a libC) | | -//! | | / -//! +-------------------------+- (total length: tls_area_size) -//! ``` -//! -//! ## TLS layout for AArch64 and RISC-V -//! -//! ```text -//! +-------------------------+ -//! | | \ -//! | Custom TCB format | | -//! | (might be used | > Thread Control Block (TCB) -//! | by a libC) | | (length: TCB_SIZE) -//! | | / -//! tls_ptr -+-------------------------+ -//! (tp_offset) | GAP_ABOVE_TP | -//! +-------------------------+- static_tls_offset -//! | | \ -//! | .tdata | | -//! | | | -//! + - - - - - - - - - - - - + > Static TLS block -//! | | | (length: static_tls_size) -//! | .tbss | | -//! | | / -//! +-------------------------+- (total length: tls_area_size) -//! ``` -//! -//! Reference: -//! 1. -//! 2. - -extern crate alloc; - -use memory_addr::align_up; - -use core::alloc::Layout; -use core::ptr::NonNull; - -const TLS_ALIGN: usize = 0x10; - -cfg_if::cfg_if! { - if #[cfg(target_arch = "x86_64")] { - const TCB_SIZE: usize = 8; // to store TLS self pointer - const GAP_ABOVE_TP: usize = 0; - } else if #[cfg(target_arch = "aarch64")] { - const TCB_SIZE: usize = 0; - const GAP_ABOVE_TP: usize = 16; - } else if #[cfg(target_arch = "riscv64")] { - const TCB_SIZE: usize = 0; - const GAP_ABOVE_TP: usize = 0; - } -} - -extern "C" { - fn _stdata(); - fn _etdata(); - fn _etbss(); -} - -/// The memory region for thread-local storage. -pub struct TlsArea { - base: NonNull, - layout: Layout, -} - -impl Drop for TlsArea { - fn drop(&mut self) { - unsafe { - alloc::alloc::dealloc(self.base.as_ptr(), self.layout); - } - } -} - -impl TlsArea { - /// Returns the pointer to the TLS static area. - /// - /// One should set the hardware thread pointer register to this value. - pub fn tls_ptr(&self) -> *mut u8 { - unsafe { self.base.as_ptr().add(tp_offset()) } - } - - /// Allocates the memory region for TLS, and initializes it. - pub fn alloc() -> Self { - let layout = Layout::from_size_align(tls_area_size(), TLS_ALIGN).unwrap(); - let area_base = unsafe { alloc::alloc::alloc_zeroed(layout) }; - - let tls_load_base = _stdata as *mut u8; - let tls_load_size = _etbss as usize - _stdata as usize; - unsafe { - // copy data from .tbdata section - core::ptr::copy_nonoverlapping( - tls_load_base, - area_base.add(static_tls_offset()), - tls_load_size, - ); - // initialize TCB - init_tcb(area_base); - } - - Self { - base: NonNull::new(area_base).unwrap(), - layout, - } - } -} - -fn static_tls_size() -> usize { - align_up(_etbss as usize - _stdata as usize, TLS_ALIGN) -} - -fn static_tls_offset() -> usize { - if cfg!(target_arch = "x86_64") { - 0 - } else if cfg!(any(target_arch = "aarch64", target_arch = "riscv64")) { - TCB_SIZE + GAP_ABOVE_TP - } else { - unreachable!() - } -} - -fn tp_offset() -> usize { - if cfg!(target_arch = "x86_64") { - static_tls_size() - } else if cfg!(any(target_arch = "aarch64", target_arch = "riscv64")) { - TCB_SIZE - } else { - unreachable!() - } -} - -fn tls_area_size() -> usize { - if cfg!(target_arch = "x86_64") { - static_tls_size() + TCB_SIZE - } else if cfg!(any(target_arch = "aarch64", target_arch = "riscv64")) { - TCB_SIZE + GAP_ABOVE_TP + static_tls_size() - } else { - unreachable!() - } -} - -unsafe fn init_tcb(tls_area: *mut u8) { - if cfg!(target_arch = "x86_64") { - let tp_addr = tls_area.add(tp_offset()).cast::(); - tp_addr.write(tp_addr as usize); // write self pointer - } -} diff --git a/arceos/modules/axhal/src/trap.rs b/arceos/modules/axhal/src/trap.rs deleted file mode 100644 index a38f7e543..000000000 --- a/arceos/modules/axhal/src/trap.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! Trap handling. - -use linkme::distributed_slice as def_trap_handler; -use memory_addr::VirtAddr; -use page_table_entry::MappingFlags; - -#[cfg(feature = "uspace")] -use crate::arch::TrapFrame; - -pub use linkme::distributed_slice as register_trap_handler; - -/// A slice of IRQ handler functions. -#[def_trap_handler] -pub static IRQ: [fn(usize) -> bool]; - -/// A slice of page fault handler functions. -#[def_trap_handler] -pub static PAGE_FAULT: [fn(VirtAddr, MappingFlags, bool) -> bool]; - -/// A slice of syscall handler functions. -#[cfg(feature = "uspace")] -#[def_trap_handler] -pub static SYSCALL: [fn(&TrapFrame, usize) -> isize]; - -#[allow(unused_macros)] -macro_rules! handle_trap { - ($trap:ident, $($args:tt)*) => {{ - let mut iter = $crate::trap::$trap.iter(); - if let Some(func) = iter.next() { - if iter.next().is_some() { - warn!("Multiple handlers for trap {} are not currently supported", stringify!($trap)); - } - func($($args)*) - } else { - warn!("No registered handler for trap {}", stringify!($trap)); - false - } - }} -} - -/// Call the external syscall handler. -#[cfg(feature = "uspace")] -pub(crate) fn handle_syscall(tf: &TrapFrame, syscall_num: usize) -> isize { - SYSCALL[0](tf, syscall_num) -} diff --git a/arceos/modules/axlog/Cargo.toml b/arceos/modules/axlog/Cargo.toml deleted file mode 100644 index 503da2408..000000000 --- a/arceos/modules/axlog/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "axlog" -version.workspace = true -edition = "2021" -authors = ["Yuekai Jia "] -description = "Macros for multi-level formatted logging used by ArceOS" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/modules/axlog" -documentation = "https://arceos-org.github.io/arceos/axlog/index.html" - -[features] -std = ["dep:chrono"] -log-level-off = ["log/max_level_off"] -log-level-error = ["log/max_level_error"] -log-level-warn = ["log/max_level_warn"] -log-level-info = ["log/max_level_info"] -log-level-debug = ["log/max_level_debug"] -log-level-trace = ["log/max_level_trace"] -default = [] - -[dependencies] -cfg-if = "1.0" -log = "0.4.21" -kspin = "0.1" -crate_interface = "0.1" -chrono = { version = "0.4", optional = true } - -[dev-dependencies] -axlog = { workspace = true, features = ["std"] } diff --git a/arceos/modules/axlog/src/lib.rs b/arceos/modules/axlog/src/lib.rs deleted file mode 100644 index f5b10b31c..000000000 --- a/arceos/modules/axlog/src/lib.rs +++ /dev/null @@ -1,262 +0,0 @@ -//! Macros for multi-level formatted logging used by -//! [ArceOS](https://github.com/arceos-org/arceos). -//! -//! The log macros, in descending order of level, are: [`error!`], [`warn!`], -//! [`info!`], [`debug!`], and [`trace!`]. -//! -//! If it is used in `no_std` environment, the users need to implement the -//! [`LogIf`] to provide external functions such as console output. -//! -//! To use in the `std` environment, please enable the `std` feature: -//! -//! ```toml -//! [dependencies] -//! axlog = { version = "0.1", features = ["std"] } -//! ``` -//! -//! # Cargo features: -//! -//! - `std`: Use in the `std` environment. If it is enabled, you can use console -//! output without implementing the [`LogIf`] trait. This is disabled by default. -//! - `log-level-off`: Disable all logging. If it is enabled, all log macros -//! (e.g. [`info!`]) will be optimized out to a no-op in compilation time. -//! - `log-level-error`: Set the maximum log level to `error`. Any macro -//! with a level lower than [`error!`] (e.g, [`warn!`], [`info!`], ...) will be -//! optimized out to a no-op. -//! - `log-level-warn`, `log-level-info`, `log-level-debug`, `log-level-trace`: -//! Similar to `log-level-error`. -//! -//! # Examples -//! -//! ``` -//! use axlog::{debug, error, info, trace, warn}; -//! -//! // Initialize the logger. -//! axlog::init(); -//! // Set the maximum log level to `info`. -//! axlog::set_max_level("info"); -//! -//! // The following logs will be printed. -//! error!("error"); -//! warn!("warn"); -//! info!("info"); -//! -//! // The following logs will not be printed. -//! debug!("debug"); -//! trace!("trace"); -//! ``` - -#![cfg_attr(not(feature = "std"), no_std)] - -extern crate log; - -use core::fmt::{self, Write}; -use core::str::FromStr; - -use log::{Level, LevelFilter, Log, Metadata, Record}; - -#[cfg(not(feature = "std"))] -use crate_interface::call_interface; - -pub use log::{debug, error, info, trace, warn}; - -/// Prints to the console. -/// -/// Equivalent to the [`ax_println!`] macro except that a newline is not printed at -/// the end of the message. -#[macro_export] -macro_rules! ax_print { - ($($arg:tt)*) => { - $crate::__print_impl(format_args!($($arg)*)); - } -} - -/// Prints to the console, with a newline. -#[macro_export] -macro_rules! ax_println { - () => { $crate::ax_print!("\n") }; - ($($arg:tt)*) => { - $crate::__print_impl(format_args!("{}\n", format_args!($($arg)*))); - } -} - -macro_rules! with_color { - ($color_code:expr, $($arg:tt)*) => {{ - format_args!("\u{1B}[{}m{}\u{1B}[m", $color_code as u8, format_args!($($arg)*)) - }}; -} - -#[repr(u8)] -#[allow(dead_code)] -enum ColorCode { - Black = 30, - Red = 31, - Green = 32, - Yellow = 33, - Blue = 34, - Magenta = 35, - Cyan = 36, - White = 37, - BrightBlack = 90, - BrightRed = 91, - BrightGreen = 92, - BrightYellow = 93, - BrightBlue = 94, - BrightMagenta = 95, - BrightCyan = 96, - BrightWhite = 97, -} - -/// Extern interfaces that must be implemented in other crates. -#[crate_interface::def_interface] -pub trait LogIf { - /// Writes a string to the console. - fn console_write_str(s: &str); - - /// Gets current clock time. - fn current_time() -> core::time::Duration; - - /// Gets current CPU ID. - /// - /// Returns [`None`] if you don't want to show the CPU ID in the log. - fn current_cpu_id() -> Option; - - /// Gets current task ID. - /// - /// Returns [`None`] if you don't want to show the task ID in the log. - fn current_task_id() -> Option; -} - -struct Logger; - -impl Write for Logger { - fn write_str(&mut self, s: &str) -> fmt::Result { - cfg_if::cfg_if! { - if #[cfg(feature = "std")] { - std::print!("{}", s); - } else { - call_interface!(LogIf::console_write_str, s); - } - } - Ok(()) - } -} - -impl Log for Logger { - #[inline] - fn enabled(&self, _metadata: &Metadata) -> bool { - true - } - - fn log(&self, record: &Record) { - if !self.enabled(record.metadata()) { - return; - } - - let level = record.level(); - let line = record.line().unwrap_or(0); - let path = record.target(); - let args_color = match level { - Level::Error => ColorCode::Red, - Level::Warn => ColorCode::Yellow, - Level::Info => ColorCode::Green, - Level::Debug => ColorCode::Cyan, - Level::Trace => ColorCode::BrightBlack, - }; - - cfg_if::cfg_if! { - if #[cfg(feature = "std")] { - __print_impl(with_color!( - ColorCode::White, - "[{time} {path}:{line}] {args}\n", - time = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.6f"), - path = path, - line = line, - args = with_color!(args_color, "{}", record.args()), - )); - } else { - let cpu_id = call_interface!(LogIf::current_cpu_id); - let tid = call_interface!(LogIf::current_task_id); - let now = call_interface!(LogIf::current_time); - if let Some(cpu_id) = cpu_id { - if let Some(tid) = tid { - // show CPU ID and task ID - __print_impl(with_color!( - ColorCode::White, - "[{:>3}.{:06} {cpu_id}:{tid} {path}:{line}] {args}\n", - now.as_secs(), - now.subsec_micros(), - cpu_id = cpu_id, - tid = tid, - path = path, - line = line, - args = with_color!(args_color, "{}", record.args()), - )); - } else { - // show CPU ID only - __print_impl(with_color!( - ColorCode::White, - "[{:>3}.{:06} {cpu_id} {path}:{line}] {args}\n", - now.as_secs(), - now.subsec_micros(), - cpu_id = cpu_id, - path = path, - line = line, - args = with_color!(args_color, "{}", record.args()), - )); - } - } else { - // neither CPU ID nor task ID is shown - __print_impl(with_color!( - ColorCode::White, - "[{:>3}.{:06} {path}:{line}] {args}\n", - now.as_secs(), - now.subsec_micros(), - path = path, - line = line, - args = with_color!(args_color, "{}", record.args()), - )); - } - } - } - } - - fn flush(&self) {} -} - -/// Prints the formatted string to the console. -pub fn print_fmt(args: fmt::Arguments) -> fmt::Result { - use kspin::SpinNoIrq; // TODO: more efficient - static LOCK: SpinNoIrq<()> = SpinNoIrq::new(()); - - let _guard = LOCK.lock(); - Logger.write_fmt(args) -} - -#[doc(hidden)] -pub fn __print_impl(args: fmt::Arguments) { - print_fmt(args).unwrap(); -} - -/// Initializes the logger. -/// -/// This function should be called before any log macros are used, otherwise -/// nothing will be printed. -pub fn init() { - log::set_logger(&Logger).unwrap(); - log::set_max_level(LevelFilter::Warn); -} - -/// Set the maximum log level. -/// -/// Unlike the features such as `log-level-error`, setting the logging level in -/// this way incurs runtime overhead. In addition, this function is no effect -/// when those features are enabled. -/// -/// `level` should be one of `off`, `error`, `warn`, `info`, `debug`, `trace`. -pub fn set_max_level(level: &str) { - let lf = LevelFilter::from_str(level) - .ok() - .unwrap_or(LevelFilter::Off); - log::set_max_level(lf); -} diff --git a/arceos/modules/axmm/Cargo.toml b/arceos/modules/axmm/Cargo.toml deleted file mode 100644 index af5f1909a..000000000 --- a/arceos/modules/axmm/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "axmm" -version.workspace = true -edition = "2021" -authors = ["Yuekai Jia "] -description = "ArceOS virtual memory management module" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/modules/axmm" -documentation = "https://arceos-org.github.io/arceos/axmm/index.html" - -[dependencies] -axhal = { workspace = true, features = ["paging"] } -axconfig = { workspace = true } -axalloc = { workspace = true } - -log = "0.4.21" -axerrno = "0.1" -lazyinit = "0.2" -memory_addr = "0.3" -memory_set = "0.3" -kspin = "0.1" diff --git a/arceos/modules/axmm/src/aspace.rs b/arceos/modules/axmm/src/aspace.rs deleted file mode 100644 index e5afd2801..000000000 --- a/arceos/modules/axmm/src/aspace.rs +++ /dev/null @@ -1,334 +0,0 @@ -use core::fmt; - -use axerrno::{ax_err, AxError, AxResult}; -use axhal::{ - mem::phys_to_virt, - paging::{MappingFlags, PageTable}, -}; -use memory_addr::{ - is_aligned_4k, pa, MemoryAddr, PageIter4K, PhysAddr, VirtAddr, VirtAddrRange, PAGE_SIZE_4K, -}; -use memory_set::{MemoryArea, MemorySet}; -use crate::backend::Backend; -use crate::paging_err_to_ax_err; -use crate::mapping_err_to_ax_err; -use alloc::vec::Vec; - -/// The virtual memory address space. -pub struct AddrSpace { - va_range: VirtAddrRange, - areas: MemorySet, - pt: PageTable, -} - -impl AddrSpace { - /// Returns the address space base. - pub const fn base(&self) -> VirtAddr { - self.va_range.start - } - - /// Returns the address space end. - pub const fn end(&self) -> VirtAddr { - self.va_range.end - } - - /// Returns the address space size. - pub fn size(&self) -> usize { - self.va_range.size() - } - - /// Returns the reference to the inner page table. - pub const fn page_table(&self) -> &PageTable { - &self.pt - } - - /// Returns the root physical address of the inner page table. - pub const fn page_table_root(&self) -> PhysAddr { - self.pt.root_paddr() - } - - /// Checks if the address space contains the given address range. - pub fn contains_range(&self, start: VirtAddr, size: usize) -> bool { - self.va_range - .contains_range(VirtAddrRange::from_start_size(start, size)) - } - - /// Creates a new empty address space. - pub fn new_empty(base: VirtAddr, size: usize) -> AxResult { - Ok(Self { - va_range: VirtAddrRange::from_start_size(base, size), - areas: MemorySet::new(), - pt: PageTable::try_new().map_err(|_| AxError::NoMemory)?, - }) - } - - /// Copies page table mappings from another address space. - /// - /// It copies the page table entries only rather than the memory regions, - /// usually used to copy a portion of the kernel space mapping to the - /// user space. - /// - /// Returns an error if the two address spaces overlap. - pub fn copy_mappings_from(&mut self, other: &AddrSpace) -> AxResult { - if self.va_range.overlaps(other.va_range) { - return ax_err!(InvalidInput, "address space overlap"); - } - self.pt.copy_from(&other.pt, other.base(), other.size()); - Ok(()) - } - - /// Finds a free area that can accommodate the given size. - /// - /// The search starts from the given hint address, and the area should be within the given limit range. - /// - /// Returns the start address of the free area. Returns None if no such area is found. - pub fn find_free_area( - &self, - hint: VirtAddr, - size: usize, - limit: VirtAddrRange, - ) -> Option { - self.areas.find_free_area(hint, size, limit) - } - - /// Add a new linear mapping. - /// - /// The mapping is linear, i.e., `start_vaddr` is mapped to `start_paddr`, - /// and `start_vaddr + size` is mapped to `start_paddr + size`. - /// - /// The `flags` parameter indicates the mapping permissions and attributes. - /// - /// Returns an error if the address range is out of the address space or not - /// aligned. - pub fn map_linear( - &mut self, - start_vaddr: VirtAddr, - start_paddr: PhysAddr, - size: usize, - flags: MappingFlags, - ) -> AxResult { - if !self.contains_range(start_vaddr, size) { - return ax_err!(InvalidInput, "address out of range"); - } - if !start_vaddr.is_aligned_4k() || !start_paddr.is_aligned_4k() || !is_aligned_4k(size) { - return ax_err!(InvalidInput, "address not aligned"); - } - - let offset = start_vaddr.as_usize() - start_paddr.as_usize(); - self.pt - .map_region( - start_vaddr, - |va| pa!(va.as_usize() - offset), - size, - flags, - false, // allow_huge - false, // flush_tlb_by_page - ) - .map_err(paging_err_to_ax_err)? - .flush_all(); - Ok(()) - } - - /// Add a new allocation mapping. - /// - /// See [`Backend`] for more details about the mapping backends. - /// - /// The `flags` parameter indicates the mapping permissions and attributes. - /// - /// Returns an error if the address range is out of the address space or not - /// aligned. - pub fn map_alloc( - &mut self, - start: VirtAddr, - size: usize, - flags: MappingFlags, - populate: bool, - ) -> AxResult { - if !self.contains_range(start, size) { - return ax_err!(InvalidInput, "address out of range"); - } - if !start.is_aligned_4k() || !is_aligned_4k(size) { - return ax_err!(InvalidInput, "address not aligned"); - } - - let area = MemoryArea::new(start, size, flags, Backend::new_alloc(populate)); - self.areas - .map(area, &mut self.pt, false) - .map_err(mapping_err_to_ax_err)?; - Ok(()) - } - - /// Removes mappings within the specified virtual address range. - /// - /// Returns an error if the address range is out of the address space or not - /// aligned. - pub fn unmap(&mut self, start: VirtAddr, size: usize) -> AxResult { - if !self.contains_range(start, size) { - return ax_err!(InvalidInput, "address out of range"); - } - if !start.is_aligned_4k() || !is_aligned_4k(size) { - return ax_err!(InvalidInput, "address not aligned"); - } - - self.pt - .unmap_region(start, size, true) - .map_err(paging_err_to_ax_err)? - .ignore(); - Ok(()) - } - - /// To process data in this area with the given function. - /// - /// Now it supports reading and writing data in the given interval. - fn process_area_data(&self, start: VirtAddr, size: usize, mut f: F) -> AxResult - where - F: FnMut(VirtAddr, usize, usize), - { - if !self.contains_range(start, size) { - return ax_err!(InvalidInput, "address out of range"); - } - let mut cnt = 0; - // If start is aligned to 4K, start_align_down will be equal to start_align_up. - let end_align_up = (start + size).align_up_4k(); - for vaddr in PageIter4K::new(start.align_down_4k(), end_align_up) - .expect("Failed to create page iterator") - { - let (mut paddr, _, _) = self.pt.query(vaddr).map_err(|_| AxError::BadAddress)?; - - let mut copy_size = (size - cnt).min(PAGE_SIZE_4K); - - if copy_size == 0 { - break; - } - if vaddr == start.align_down_4k() && start.align_offset_4k() != 0 { - let align_offset = start.align_offset_4k(); - copy_size = copy_size.min(PAGE_SIZE_4K - align_offset); - paddr += align_offset; - } - f(phys_to_virt(paddr), cnt, copy_size); - cnt += copy_size; - } - Ok(()) - } - - /// To read data from the address space. - /// - /// # Arguments - /// - /// * `start` - The start virtual address to read. - /// * `buf` - The buffer to store the data. - pub fn read(&self, start: VirtAddr, buf: &mut [u8]) -> AxResult { - self.process_area_data(start, buf.len(), |src, offset, read_size| unsafe { - core::ptr::copy_nonoverlapping(src.as_ptr(), buf.as_mut_ptr().add(offset), read_size); - }) - } - - /// To write data to the address space. - /// - /// # Arguments - /// - /// * `start_vaddr` - The start virtual address to write. - /// * `buf` - The buffer to write to the address space. - pub fn write(&self, start: VirtAddr, buf: &[u8]) -> AxResult { - self.process_area_data(start, buf.len(), |dst, offset, write_size| unsafe { - core::ptr::copy_nonoverlapping(buf.as_ptr().add(offset), dst.as_mut_ptr(), write_size); - }) - } - - /// Updates mapping within the specified virtual address range. - /// - /// Returns an error if the address range is out of the address space or not - /// aligned. - pub fn protect(&mut self, start: VirtAddr, size: usize, flags: MappingFlags) -> AxResult { - if !self.contains_range(start, size) { - return ax_err!(InvalidInput, "address out of range"); - } - if !start.is_aligned_4k() || !is_aligned_4k(size) { - return ax_err!(InvalidInput, "address not aligned"); - } - - self.pt - .protect_region(start, size, flags, true) - .map_err(paging_err_to_ax_err)? - .ignore(); - Ok(()) - } - - /// Handles a page fault at the given address. - /// - /// `access_flags` indicates the access type that caused the page fault. - /// - /// Returns `true` if the page fault is handled successfully (not a real - /// fault). - pub fn handle_page_fault(&mut self, vaddr: VirtAddr, access_flags: MappingFlags) -> bool { - if !self.va_range.contains(vaddr) { - return false; - } - if let Some(area) = self.areas.find(vaddr) { - let orig_flags = area.flags(); - if orig_flags.contains(access_flags) { - return area - .backend() - .handle_page_fault(vaddr, orig_flags, &mut self.pt); - } - } - false - } - - pub fn translated_byte_buffer( - &self, - vaddr: VirtAddr, - len: usize, - ) -> Option> { - if !self.va_range.contains(vaddr) { - return None; - } - if let Some(area) = self.areas.find(vaddr) { - if len > area.size() { - warn!( - "AddrSpace translated_byte_buffer len {:#x} exceeds area length {:#x}", - len, - area.size() - ); - return None; - } - - let mut start = vaddr; - let end = start + len; - - debug!( - "start {:?} end {:?} area size {:#x}", - start, - end, - area.size() - ); - - let mut v = Vec::new(); - while start < end { - let (start_paddr, _, page_size) = self.page_table().query(start).unwrap(); - let mut end_va = start.align_down(page_size) + page_size.into(); - end_va = end_va.min(end); - - v.push(unsafe { - core::slice::from_raw_parts_mut( - phys_to_virt(start_paddr).as_mut_ptr(), - (end_va - start.as_usize()).into(), - ) - }); - start = end_va; - } - Some(v) - } else { - None - } - } -} - -impl fmt::Debug for AddrSpace { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("AddrSpace") - .field("va_range", &self.va_range) - .field("page_table_root", &self.pt.root_paddr()) - .finish() - } -} diff --git a/arceos/modules/axmm/src/backend/alloc.rs b/arceos/modules/axmm/src/backend/alloc.rs deleted file mode 100644 index e404d718a..000000000 --- a/arceos/modules/axmm/src/backend/alloc.rs +++ /dev/null @@ -1,108 +0,0 @@ -use axalloc::global_allocator; -use axhal::mem::{phys_to_virt, virt_to_phys}; -use axhal::paging::{MappingFlags, PageSize, PageTable}; -use memory_addr::{PageIter4K, PhysAddr, VirtAddr, PAGE_SIZE_4K}; - -use super::Backend; - -fn alloc_frame(zeroed: bool) -> Option { - let vaddr = VirtAddr::from(global_allocator().alloc_pages(1, PAGE_SIZE_4K).ok()?); - if zeroed { - unsafe { core::ptr::write_bytes(vaddr.as_mut_ptr(), 0, PAGE_SIZE_4K) }; - } - let paddr = virt_to_phys(vaddr); - Some(paddr) -} - -fn dealloc_frame(frame: PhysAddr) { - let vaddr = phys_to_virt(frame); - global_allocator().dealloc_pages(vaddr.as_usize(), 1); -} - -impl Backend { - /// Creates a new allocation mapping backend. - pub const fn new_alloc(populate: bool) -> Self { - Self::Alloc { populate } - } - - pub(crate) fn map_alloc( - &self, - start: VirtAddr, - size: usize, - flags: MappingFlags, - pt: &mut PageTable, - populate: bool, - ) -> bool { - debug!( - "map_alloc: [{:#x}, {:#x}) {:?} (populate={})", - start, - start + size, - flags, - populate - ); - if populate { - // allocate all possible physical frames for populated mapping. - for addr in PageIter4K::new(start, start + size).unwrap() { - if let Some(frame) = alloc_frame(true) { - if let Ok(tlb) = pt.map(addr, frame, PageSize::Size4K, flags) { - tlb.ignore(); // TLB flush on map is unnecessary, as there are no outdated mappings. - } else { - return false; - } - } - } - true - } else { - // Map to a empty entry for on-demand mapping. - let flags = MappingFlags::empty(); - pt.map_region(start, |_| 0.into(), size, flags, false, false) - .map(|tlb| tlb.ignore()) - .is_ok() - } - } - - pub(crate) fn unmap_alloc( - &self, - start: VirtAddr, - size: usize, - pt: &mut PageTable, - _populate: bool, - ) -> bool { - debug!("unmap_alloc: [{:#x}, {:#x})", start, start + size); - for addr in PageIter4K::new(start, start + size).unwrap() { - if let Ok((frame, page_size, tlb)) = pt.unmap(addr) { - // Deallocate the physical frame if there is a mapping in the - // page table. - if page_size.is_huge() { - return false; - } - tlb.flush(); - dealloc_frame(frame); - } else { - // Deallocation is needn't if the page is not mapped. - } - } - true - } - - pub(crate) fn handle_page_fault_alloc( - &self, - vaddr: VirtAddr, - orig_flags: MappingFlags, - pt: &mut PageTable, - populate: bool, - ) -> bool { - if populate { - false // Populated mappings should not trigger page faults. - } else if let Some(frame) = alloc_frame(true) { - // Allocate a physical frame lazily and map it to the fault address. - // `vaddr` does not need to be aligned. It will be automatically - // aligned during `pt.remap` regardless of the page size. - pt.remap(vaddr, frame, orig_flags) - .map(|(_, tlb)| tlb.flush()) - .is_ok() - } else { - false - } - } -} diff --git a/arceos/modules/axmm/src/backend/linear.rs b/arceos/modules/axmm/src/backend/linear.rs deleted file mode 100644 index 380776659..000000000 --- a/arceos/modules/axmm/src/backend/linear.rs +++ /dev/null @@ -1,46 +0,0 @@ -use axhal::paging::{MappingFlags, PageTable}; -use memory_addr::{PhysAddr, VirtAddr}; - -use super::Backend; - -impl Backend { - /// Creates a new linear mapping backend. - pub const fn new_linear(pa_va_offset: usize) -> Self { - Self::Linear { pa_va_offset } - } - - pub(crate) fn map_linear( - &self, - start: VirtAddr, - size: usize, - flags: MappingFlags, - pt: &mut PageTable, - pa_va_offset: usize, - ) -> bool { - let va_to_pa = |va: VirtAddr| PhysAddr::from(va.as_usize() - pa_va_offset); - debug!( - "map_linear: [{:#x}, {:#x}) -> [{:#x}, {:#x}) {:?}", - start, - start + size, - va_to_pa(start), - va_to_pa(start + size), - flags - ); - pt.map_region(start, va_to_pa, size, flags, false, false) - .map(|tlb| tlb.ignore()) // TLB flush on map is unnecessary, as there are no outdated mappings. - .is_ok() - } - - pub(crate) fn unmap_linear( - &self, - start: VirtAddr, - size: usize, - pt: &mut PageTable, - _pa_va_offset: usize, - ) -> bool { - debug!("unmap_linear: [{:#x}, {:#x})", start, start + size); - pt.unmap_region(start, size, true) - .map(|tlb| tlb.ignore()) // flush each page on unmap, do not flush the entire TLB. - .is_ok() - } -} diff --git a/arceos/modules/axmm/src/backend/mod.rs b/arceos/modules/axmm/src/backend/mod.rs deleted file mode 100644 index 33f4cd3b9..000000000 --- a/arceos/modules/axmm/src/backend/mod.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! Memory mapping backends. -#![allow(dead_code)] - -use axhal::paging::{MappingFlags, PageTable}; -use memory_addr::VirtAddr; -use memory_set::MappingBackend; - -mod alloc; -mod linear; - -/// A unified enum type for different memory mapping backends. -/// -/// Currently, two backends are implemented: -/// -/// - **Linear**: used for linear mappings. The target physical frames are -/// contiguous and their addresses should be known when creating the mapping. -/// - **Allocation**: used in general, or for lazy mappings. The target physical -/// frames are obtained from the global allocator. -#[derive(Clone)] -pub enum Backend { - /// Linear mapping backend. - /// - /// The offset between the virtual address and the physical address is - /// constant, which is specified by `pa_va_offset`. For example, the virtual - /// address `vaddr` is mapped to the physical address `vaddr - pa_va_offset`. - Linear { - /// `vaddr - paddr`. - pa_va_offset: usize, - }, - /// Allocation mapping backend. - /// - /// If `populate` is `true`, all physical frames are allocated when the - /// mapping is created, and no page faults are triggered during the memory - /// access. Otherwise, the physical frames are allocated on demand (by - /// handling page faults). - Alloc { - /// Whether to populate the physical frames when creating the mapping. - populate: bool, - }, -} - -impl MappingBackend for Backend { - type Addr = VirtAddr; - type Flags = MappingFlags; - type PageTable = PageTable; - fn map(&self, start: VirtAddr, size: usize, flags: MappingFlags, pt: &mut PageTable) -> bool { - match *self { - Self::Linear { pa_va_offset } => self.map_linear(start, size, flags, pt, pa_va_offset), - Self::Alloc { populate } => self.map_alloc(start, size, flags, pt, populate), - } - } - - fn unmap(&self, start: VirtAddr, size: usize, pt: &mut PageTable) -> bool { - match *self { - Self::Linear { pa_va_offset } => self.unmap_linear(start, size, pt, pa_va_offset), - Self::Alloc { populate } => self.unmap_alloc(start, size, pt, populate), - } - } - - fn protect( - &self, - start: Self::Addr, - size: usize, - new_flags: Self::Flags, - page_table: &mut Self::PageTable, - ) -> bool { - page_table - .protect_region(start, size, new_flags, true) - .map(|tlb| tlb.ignore()) - .is_ok() - } -} - -impl Backend { - pub(crate) fn handle_page_fault( - &self, - vaddr: VirtAddr, - orig_flags: MappingFlags, - page_table: &mut PageTable, - ) -> bool { - match *self { - Self::Linear { .. } => false, // Linear mappings should not trigger page faults. - Self::Alloc { populate } => { - self.handle_page_fault_alloc(vaddr, orig_flags, page_table, populate) - } - } - } -} diff --git a/arceos/modules/axmm/src/lib.rs b/arceos/modules/axmm/src/lib.rs deleted file mode 100644 index ed23c7140..000000000 --- a/arceos/modules/axmm/src/lib.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! [ArceOS](https://github.com/arceos-org/arceos) memory management module. - -#![no_std] - -#[macro_use] -extern crate log; -extern crate alloc; - -mod aspace; -mod backend; - -pub use self::aspace::AddrSpace; - -use axerrno::{AxError, AxResult}; -use axhal::mem::phys_to_virt; -use axhal::paging::PagingError; -use kspin::SpinNoIrq; -use lazyinit::LazyInit; -use memory_addr::{va, PhysAddr, VirtAddr}; -use memory_set::MappingError; - -const USER_ASPACE_BASE: usize = 0x0000; -const USER_ASPACE_SIZE: usize = 0x40_0000_0000; - -static KERNEL_ASPACE: LazyInit> = LazyInit::new(); - -fn mapping_err_to_ax_err(err: MappingError) -> AxError { - warn!("Mapping error: {:?}", err); - match err { - MappingError::InvalidParam => AxError::InvalidInput, - MappingError::AlreadyExists => AxError::AlreadyExists, - MappingError::BadState => AxError::BadState, - } -} - -fn paging_err_to_ax_err(err: PagingError) -> AxError { - warn!("Paging error: {:?}", err); - match err { - PagingError::NoMemory => AxError::NoMemory, - PagingError::NotAligned => AxError::InvalidInput, - PagingError::NotMapped => AxError::NotFound, - PagingError::AlreadyMapped => AxError::AlreadyExists, - PagingError::MappedToHugePage => AxError::InvalidInput, - } -} - -/// Creates a new address space for user processes. -pub fn new_user_aspace() -> AxResult { - let mut aspace = AddrSpace::new_empty(VirtAddr::from(USER_ASPACE_BASE), USER_ASPACE_SIZE)?; - aspace.copy_mappings_from(&kernel_aspace().lock())?; - Ok(aspace) -} - -/// Creates a new address space for kernel itself. -pub fn new_kernel_aspace() -> AxResult { - let mut aspace = AddrSpace::new_empty( - va!(axconfig::KERNEL_ASPACE_BASE), - axconfig::KERNEL_ASPACE_SIZE, - )?; - for r in axhal::mem::memory_regions() { - aspace.map_linear(phys_to_virt(r.paddr), r.paddr, r.size, r.flags.into())?; - } - Ok(aspace) -} - -/// Returns the globally unique kernel address space. -pub fn kernel_aspace() -> &'static SpinNoIrq { - &KERNEL_ASPACE -} - -/// Returns the root physical address of the kernel page table. -pub fn kernel_page_table_root() -> PhysAddr { - KERNEL_ASPACE.lock().page_table_root() -} - -/// Initializes virtual memory management. -/// -/// It mainly sets up the kernel virtual memory address space and recreate a -/// fine-grained kernel page table. -pub fn init_memory_management() { - info!("Initialize virtual memory management..."); - - let kernel_aspace = new_kernel_aspace().expect("failed to initialize kernel address space"); - debug!("kernel address space init OK: {:#x?}", kernel_aspace); - KERNEL_ASPACE.init_once(SpinNoIrq::new(kernel_aspace)); - axhal::paging::set_kernel_page_table_root(kernel_page_table_root()); -} - -/// Initializes kernel paging for secondary CPUs. -pub fn init_memory_management_secondary() { - unsafe { axhal::arch::write_page_table_root(kernel_page_table_root()) }; -} diff --git a/arceos/modules/axnet/Cargo.toml b/arceos/modules/axnet/Cargo.toml deleted file mode 100644 index 505cd29a8..000000000 --- a/arceos/modules/axnet/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "axnet" -version.workspace = true -edition = "2021" -authors = ["Yuekai Jia ", "ChengXiang Qi "] -description = "ArceOS network module" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/modules/axnet" -documentation = "https://arceos-org.github.io/arceos/axnet/index.html" - -[features] -smoltcp = [] -default = ["smoltcp"] - -[dependencies] -log = "0.4.21" -cfg-if = "1.0" -spin = "0.9" -lazyinit = "0.2" -axerrno = "0.1" -axio = "0.1" -axhal = { workspace = true } -axsync = { workspace = true } -axtask = { workspace = true } -axdriver = { workspace = true, features = ["net"] } -axdriver_net = { git = "https://github.com/arceos-org/axdriver_crates.git", tag = "v0.1.0" } - -[dependencies.smoltcp] -git = "https://github.com/rcore-os/smoltcp.git" -rev = "2ade274" -default-features = false -features = [ - "alloc", "log", # no std - "medium-ethernet", - "proto-ipv4", - "socket-raw", "socket-icmp", "socket-udp", "socket-tcp", "socket-dns", - # "fragmentation-buffer-size-65536", "proto-ipv4-fragmentation", - # "reassembly-buffer-size-65536", "reassembly-buffer-count-32", - # "assembler-max-segment-count-32", -] diff --git a/arceos/modules/axnet/src/lib.rs b/arceos/modules/axnet/src/lib.rs deleted file mode 100644 index c446dbf7e..000000000 --- a/arceos/modules/axnet/src/lib.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! [ArceOS](https://github.com/arceos-org/arceos) network module. -//! -//! It provides unified networking primitives for TCP/UDP communication -//! using various underlying network stacks. Currently, only [smoltcp] is -//! supported. -//! -//! # Organization -//! -//! - [`TcpSocket`]: A TCP socket that provides POSIX-like APIs. -//! - [`UdpSocket`]: A UDP socket that provides POSIX-like APIs. -//! - [`dns_query`]: Function for DNS query. -//! -//! # Cargo Features -//! -//! - `smoltcp`: Use [smoltcp] as the underlying network stack. This is enabled -//! by default. -//! -//! [smoltcp]: https://github.com/smoltcp-rs/smoltcp - -#![no_std] -#![feature(new_uninit)] - -#[macro_use] -extern crate log; -extern crate alloc; - -cfg_if::cfg_if! { - if #[cfg(feature = "smoltcp")] { - mod smoltcp_impl; - use smoltcp_impl as net_impl; - } -} - -pub use self::net_impl::TcpSocket; -pub use self::net_impl::UdpSocket; -pub use self::net_impl::{bench_receive, bench_transmit}; -pub use self::net_impl::{dns_query, poll_interfaces}; - -use axdriver::{prelude::*, AxDeviceContainer}; - -/// Initializes the network subsystem by NIC devices. -pub fn init_network(mut net_devs: AxDeviceContainer) { - info!("Initialize network subsystem..."); - - let dev = net_devs.take_one().expect("No NIC device found!"); - info!(" use NIC 0: {:?}", dev.device_name()); - net_impl::init(dev); -} diff --git a/arceos/modules/axnet/src/smoltcp_impl/addr.rs b/arceos/modules/axnet/src/smoltcp_impl/addr.rs deleted file mode 100644 index 31d2be1c7..000000000 --- a/arceos/modules/axnet/src/smoltcp_impl/addr.rs +++ /dev/null @@ -1,35 +0,0 @@ -use core::net::{IpAddr, Ipv4Addr, SocketAddr}; -use smoltcp::wire::{IpAddress, IpEndpoint, Ipv4Address}; - -pub const fn from_core_ipaddr(ip: IpAddr) -> IpAddress { - match ip { - IpAddr::V4(ipv4) => IpAddress::Ipv4(Ipv4Address(ipv4.octets())), - _ => panic!("IPv6 not supported"), - } -} - -pub const fn into_core_ipaddr(ip: IpAddress) -> IpAddr { - match ip { - IpAddress::Ipv4(ipv4) => { - IpAddr::V4(unsafe { core::mem::transmute::<[u8; 4], Ipv4Addr>(ipv4.0) }) - } // _ => panic!("IPv6 not supported"), - } -} - -pub const fn from_core_sockaddr(addr: SocketAddr) -> IpEndpoint { - IpEndpoint { - addr: from_core_ipaddr(addr.ip()), - port: addr.port(), - } -} - -pub const fn into_core_sockaddr(addr: IpEndpoint) -> SocketAddr { - SocketAddr::new(into_core_ipaddr(addr.addr), addr.port) -} - -pub fn is_unspecified(ip: IpAddress) -> bool { - ip.as_bytes() == [0, 0, 0, 0] -} - -pub const UNSPECIFIED_IP: IpAddress = IpAddress::v4(0, 0, 0, 0); -pub const UNSPECIFIED_ENDPOINT: IpEndpoint = IpEndpoint::new(UNSPECIFIED_IP, 0); diff --git a/arceos/modules/axnet/src/smoltcp_impl/bench.rs b/arceos/modules/axnet/src/smoltcp_impl/bench.rs deleted file mode 100644 index 81f21a69e..000000000 --- a/arceos/modules/axnet/src/smoltcp_impl/bench.rs +++ /dev/null @@ -1,74 +0,0 @@ -use super::{AxNetRxToken, AxNetTxToken, STANDARD_MTU}; -use super::{DeviceWrapper, InterfaceWrapper}; -use smoltcp::phy::{Device, RxToken, TxToken}; - -const GB: usize = 1000 * MB; -const MB: usize = 1000 * KB; -const KB: usize = 1000; - -impl DeviceWrapper { - pub fn bench_transmit_bandwidth(&mut self) { - // 10 Gb - const MAX_SEND_BYTES: usize = 10 * GB; - let mut send_bytes: usize = 0; - let mut past_send_bytes: usize = 0; - let mut past_time = InterfaceWrapper::current_time(); - - // Send bytes - while send_bytes < MAX_SEND_BYTES { - if let Some(tx_token) = self.transmit(InterfaceWrapper::current_time()) { - AxNetTxToken::consume(tx_token, STANDARD_MTU, |tx_buf| { - tx_buf[0..12].fill(1); - // ether type: IPv4 - tx_buf[12..14].copy_from_slice(&[0x08, 0x00]); - tx_buf[14..STANDARD_MTU].fill(1); - }); - send_bytes += STANDARD_MTU; - } - - let current_time = InterfaceWrapper::current_time(); - if (current_time - past_time).secs() == 1 { - let gb = ((send_bytes - past_send_bytes) * 8) / GB; - let mb = (((send_bytes - past_send_bytes) * 8) % GB) / MB; - let gib = (send_bytes - past_send_bytes) / GB; - let mib = ((send_bytes - past_send_bytes) % GB) / MB; - info!( - "Transmit: {}.{:03}GBytes, Bandwidth: {}.{:03}Gbits/sec.", - gib, mib, gb, mb - ); - past_time = current_time; - past_send_bytes = send_bytes; - } - } - } - - pub fn bench_receive_bandwidth(&mut self) { - // 10 Gb - const MAX_RECEIVE_BYTES: usize = 10 * GB; - let mut receive_bytes: usize = 0; - let mut past_receive_bytes: usize = 0; - let mut past_time = InterfaceWrapper::current_time(); - // Receive bytes - while receive_bytes < MAX_RECEIVE_BYTES { - if let Some(rx_token) = self.receive(InterfaceWrapper::current_time()) { - AxNetRxToken::consume(rx_token.0, |rx_buf| { - receive_bytes += rx_buf.len(); - }); - } - - let current_time = InterfaceWrapper::current_time(); - if (current_time - past_time).secs() == 1 { - let gb = ((receive_bytes - past_receive_bytes) * 8) / GB; - let mb = (((receive_bytes - past_receive_bytes) * 8) % GB) / MB; - let gib = (receive_bytes - past_receive_bytes) / GB; - let mib = ((receive_bytes - past_receive_bytes) % GB) / MB; - info!( - "Receive: {}.{:03}GBytes, Bandwidth: {}.{:03}Gbits/sec.", - gib, mib, gb, mb - ); - past_time = current_time; - past_receive_bytes = receive_bytes; - } - } - } -} diff --git a/arceos/modules/axnet/src/smoltcp_impl/dns.rs b/arceos/modules/axnet/src/smoltcp_impl/dns.rs deleted file mode 100644 index 35fd4588f..000000000 --- a/arceos/modules/axnet/src/smoltcp_impl/dns.rs +++ /dev/null @@ -1,90 +0,0 @@ -use alloc::vec::Vec; -use axerrno::{ax_err_type, AxError, AxResult}; -use core::net::IpAddr; - -use smoltcp::iface::SocketHandle; -use smoltcp::socket::dns::{self, GetQueryResultError, StartQueryError}; -use smoltcp::wire::DnsQueryType; - -use super::addr::into_core_ipaddr; -use super::{SocketSetWrapper, ETH0, SOCKET_SET}; - -/// A DNS socket. -struct DnsSocket { - handle: Option, -} - -impl DnsSocket { - #[allow(clippy::new_without_default)] - /// Creates a new DNS socket. - pub fn new() -> Self { - let socket = SocketSetWrapper::new_dns_socket(); - let handle = Some(SOCKET_SET.add(socket)); - Self { handle } - } - - #[allow(dead_code)] - /// Update the list of DNS servers, will replace all existing servers. - pub fn update_servers(self, servers: &[smoltcp::wire::IpAddress]) { - SOCKET_SET.with_socket_mut::(self.handle.unwrap(), |socket| { - socket.update_servers(servers) - }); - } - - /// Query a address with given DNS query type. - pub fn query(&self, name: &str, query_type: DnsQueryType) -> AxResult> { - // let local_addr = self.local_addr.unwrap_or_else(f); - let handle = self.handle.ok_or_else(|| ax_err_type!(InvalidInput))?; - let iface = Ð0.iface; - let query_handle = SOCKET_SET - .with_socket_mut::(handle, |socket| { - socket.start_query(iface.lock().context(), name, query_type) - }) - .map_err(|e| match e { - StartQueryError::NoFreeSlot => { - ax_err_type!(ResourceBusy, "socket query() failed: no free slot") - } - StartQueryError::InvalidName => { - ax_err_type!(InvalidInput, "socket query() failed: invalid name") - } - StartQueryError::NameTooLong => { - ax_err_type!(InvalidInput, "socket query() failed: too long name") - } - })?; - loop { - SOCKET_SET.poll_interfaces(); - match SOCKET_SET.with_socket_mut::(handle, |socket| { - socket.get_query_result(query_handle).map_err(|e| match e { - GetQueryResultError::Pending => AxError::WouldBlock, - GetQueryResultError::Failed => { - ax_err_type!(ConnectionRefused, "socket query() failed") - } - }) - }) { - Ok(n) => { - let mut res = Vec::with_capacity(n.capacity()); - for ip in n { - res.push(into_core_ipaddr(ip)) - } - return Ok(res); - } - Err(AxError::WouldBlock) => axtask::yield_now(), - Err(e) => return Err(e), - } - } - } -} - -impl Drop for DnsSocket { - fn drop(&mut self) { - if let Some(handle) = self.handle { - SOCKET_SET.remove(handle); - } - } -} - -/// Public function for DNS query. -pub fn dns_query(name: &str) -> AxResult> { - let socket = DnsSocket::new(); - socket.query(name, DnsQueryType::A) -} diff --git a/arceos/modules/axnet/src/smoltcp_impl/listen_table.rs b/arceos/modules/axnet/src/smoltcp_impl/listen_table.rs deleted file mode 100644 index 7aac9ef1e..000000000 --- a/arceos/modules/axnet/src/smoltcp_impl/listen_table.rs +++ /dev/null @@ -1,155 +0,0 @@ -use alloc::{boxed::Box, collections::VecDeque}; -use core::ops::{Deref, DerefMut}; - -use axerrno::{ax_err, AxError, AxResult}; -use axsync::Mutex; -use smoltcp::iface::{SocketHandle, SocketSet}; -use smoltcp::socket::tcp::{self, State}; -use smoltcp::wire::{IpAddress, IpEndpoint, IpListenEndpoint}; - -use super::{SocketSetWrapper, LISTEN_QUEUE_SIZE, SOCKET_SET}; - -const PORT_NUM: usize = 65536; - -struct ListenTableEntry { - listen_endpoint: IpListenEndpoint, - syn_queue: VecDeque, -} - -impl ListenTableEntry { - pub fn new(listen_endpoint: IpListenEndpoint) -> Self { - Self { - listen_endpoint, - syn_queue: VecDeque::with_capacity(LISTEN_QUEUE_SIZE), - } - } - - #[inline] - fn can_accept(&self, dst: IpAddress) -> bool { - match self.listen_endpoint.addr { - Some(addr) => addr == dst, - None => true, - } - } -} - -impl Drop for ListenTableEntry { - fn drop(&mut self) { - for &handle in &self.syn_queue { - SOCKET_SET.remove(handle); - } - } -} - -pub struct ListenTable { - tcp: Box<[Mutex>>]>, -} - -impl ListenTable { - pub fn new() -> Self { - let tcp = unsafe { - let mut buf = Box::new_uninit_slice(PORT_NUM); - for i in 0..PORT_NUM { - buf[i].write(Mutex::new(None)); - } - buf.assume_init() - }; - Self { tcp } - } - - pub fn can_listen(&self, port: u16) -> bool { - self.tcp[port as usize].lock().is_none() - } - - pub fn listen(&self, listen_endpoint: IpListenEndpoint) -> AxResult { - let port = listen_endpoint.port; - assert_ne!(port, 0); - let mut entry = self.tcp[port as usize].lock(); - if entry.is_none() { - *entry = Some(Box::new(ListenTableEntry::new(listen_endpoint))); - Ok(()) - } else { - ax_err!(AddrInUse, "socket listen() failed") - } - } - - pub fn unlisten(&self, port: u16) { - debug!("TCP socket unlisten on {}", port); - *self.tcp[port as usize].lock() = None; - } - - pub fn can_accept(&self, port: u16) -> AxResult { - if let Some(entry) = self.tcp[port as usize].lock().deref() { - Ok(entry.syn_queue.iter().any(|&handle| is_connected(handle))) - } else { - ax_err!(InvalidInput, "socket accept() failed: not listen") - } - } - - pub fn accept(&self, port: u16) -> AxResult<(SocketHandle, (IpEndpoint, IpEndpoint))> { - if let Some(entry) = self.tcp[port as usize].lock().deref_mut() { - let syn_queue = &mut entry.syn_queue; - let (idx, addr_tuple) = syn_queue - .iter() - .enumerate() - .find_map(|(idx, &handle)| { - is_connected(handle).then(|| (idx, get_addr_tuple(handle))) - }) - .ok_or(AxError::WouldBlock)?; // wait for connection - if idx > 0 { - warn!( - "slow SYN queue enumeration: index = {}, len = {}!", - idx, - syn_queue.len() - ); - } - let handle = syn_queue.swap_remove_front(idx).unwrap(); - Ok((handle, addr_tuple)) - } else { - ax_err!(InvalidInput, "socket accept() failed: not listen") - } - } - - pub fn incoming_tcp_packet( - &self, - src: IpEndpoint, - dst: IpEndpoint, - sockets: &mut SocketSet<'_>, - ) { - if let Some(entry) = self.tcp[dst.port as usize].lock().deref_mut() { - if !entry.can_accept(dst.addr) { - // not listening on this address - return; - } - if entry.syn_queue.len() >= LISTEN_QUEUE_SIZE { - // SYN queue is full, drop the packet - warn!("SYN queue overflow!"); - return; - } - let mut socket = SocketSetWrapper::new_tcp_socket(); - if socket.listen(entry.listen_endpoint).is_ok() { - let handle = sockets.add(socket); - debug!( - "TCP socket {}: prepare for connection {} -> {}", - handle, src, entry.listen_endpoint - ); - entry.syn_queue.push_back(handle); - } - } - } -} - -fn is_connected(handle: SocketHandle) -> bool { - SOCKET_SET.with_socket::(handle, |socket| { - !matches!(socket.state(), State::Listen | State::SynReceived) - }) -} - -fn get_addr_tuple(handle: SocketHandle) -> (IpEndpoint, IpEndpoint) { - SOCKET_SET.with_socket::(handle, |socket| { - ( - socket.local_endpoint().unwrap(), - socket.remote_endpoint().unwrap(), - ) - }) -} diff --git a/arceos/modules/axnet/src/smoltcp_impl/mod.rs b/arceos/modules/axnet/src/smoltcp_impl/mod.rs deleted file mode 100644 index 265088427..000000000 --- a/arceos/modules/axnet/src/smoltcp_impl/mod.rs +++ /dev/null @@ -1,330 +0,0 @@ -mod addr; -mod bench; -mod dns; -mod listen_table; -mod tcp; -mod udp; - -use alloc::vec; -use core::cell::RefCell; -use core::ops::DerefMut; - -use axdriver::prelude::*; -use axdriver_net::{DevError, NetBufPtr}; -use axhal::time::{wall_time_nanos, NANOS_PER_MICROS}; -use axsync::Mutex; -use lazyinit::LazyInit; -use smoltcp::iface::{Config, Interface, SocketHandle, SocketSet}; -use smoltcp::phy::{Device, DeviceCapabilities, Medium, RxToken, TxToken}; -use smoltcp::socket::{self, AnySocket}; -use smoltcp::time::Instant; -use smoltcp::wire::{EthernetAddress, HardwareAddress, IpAddress, IpCidr}; - -use self::listen_table::ListenTable; - -pub use self::dns::dns_query; -pub use self::tcp::TcpSocket; -pub use self::udp::UdpSocket; - -macro_rules! env_or_default { - ($key:literal) => { - match option_env!($key) { - Some(val) => val, - None => "", - } - }; -} - -const IP: &str = env_or_default!("AX_IP"); -const GATEWAY: &str = env_or_default!("AX_GW"); -const DNS_SEVER: &str = "8.8.8.8"; -const IP_PREFIX: u8 = 24; - -const STANDARD_MTU: usize = 1500; - -const RANDOM_SEED: u64 = 0xA2CE_05A2_CE05_A2CE; - -const TCP_RX_BUF_LEN: usize = 64 * 1024; -const TCP_TX_BUF_LEN: usize = 64 * 1024; -const UDP_RX_BUF_LEN: usize = 64 * 1024; -const UDP_TX_BUF_LEN: usize = 64 * 1024; -const LISTEN_QUEUE_SIZE: usize = 512; - -static LISTEN_TABLE: LazyInit = LazyInit::new(); -static SOCKET_SET: LazyInit = LazyInit::new(); -static ETH0: LazyInit = LazyInit::new(); - -struct SocketSetWrapper<'a>(Mutex>); - -struct DeviceWrapper { - inner: RefCell, // use `RefCell` is enough since it's wrapped in `Mutex` in `InterfaceWrapper`. -} - -struct InterfaceWrapper { - name: &'static str, - ether_addr: EthernetAddress, - dev: Mutex, - iface: Mutex, -} - -impl<'a> SocketSetWrapper<'a> { - fn new() -> Self { - Self(Mutex::new(SocketSet::new(vec![]))) - } - - pub fn new_tcp_socket() -> socket::tcp::Socket<'a> { - let tcp_rx_buffer = socket::tcp::SocketBuffer::new(vec![0; TCP_RX_BUF_LEN]); - let tcp_tx_buffer = socket::tcp::SocketBuffer::new(vec![0; TCP_TX_BUF_LEN]); - socket::tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer) - } - - pub fn new_udp_socket() -> socket::udp::Socket<'a> { - let udp_rx_buffer = socket::udp::PacketBuffer::new( - vec![socket::udp::PacketMetadata::EMPTY; 8], - vec![0; UDP_RX_BUF_LEN], - ); - let udp_tx_buffer = socket::udp::PacketBuffer::new( - vec![socket::udp::PacketMetadata::EMPTY; 8], - vec![0; UDP_TX_BUF_LEN], - ); - socket::udp::Socket::new(udp_rx_buffer, udp_tx_buffer) - } - - pub fn new_dns_socket() -> socket::dns::Socket<'a> { - let server_addr = DNS_SEVER.parse().expect("invalid DNS server address"); - socket::dns::Socket::new(&[server_addr], vec![]) - } - - pub fn add>(&self, socket: T) -> SocketHandle { - let handle = self.0.lock().add(socket); - debug!("socket {}: created", handle); - handle - } - - pub fn with_socket, R, F>(&self, handle: SocketHandle, f: F) -> R - where - F: FnOnce(&T) -> R, - { - let set = self.0.lock(); - let socket = set.get(handle); - f(socket) - } - - pub fn with_socket_mut, R, F>(&self, handle: SocketHandle, f: F) -> R - where - F: FnOnce(&mut T) -> R, - { - let mut set = self.0.lock(); - let socket = set.get_mut(handle); - f(socket) - } - - pub fn poll_interfaces(&self) { - ETH0.poll(&self.0); - } - - pub fn remove(&self, handle: SocketHandle) { - self.0.lock().remove(handle); - debug!("socket {}: destroyed", handle); - } -} - -impl InterfaceWrapper { - fn new(name: &'static str, dev: AxNetDevice, ether_addr: EthernetAddress) -> Self { - let mut config = Config::new(HardwareAddress::Ethernet(ether_addr)); - config.random_seed = RANDOM_SEED; - - let mut dev = DeviceWrapper::new(dev); - let iface = Mutex::new(Interface::new(config, &mut dev, Self::current_time())); - Self { - name, - ether_addr, - dev: Mutex::new(dev), - iface, - } - } - - fn current_time() -> Instant { - Instant::from_micros_const((wall_time_nanos() / NANOS_PER_MICROS) as i64) - } - - pub fn name(&self) -> &str { - self.name - } - - pub fn ethernet_address(&self) -> EthernetAddress { - self.ether_addr - } - - pub fn setup_ip_addr(&self, ip: IpAddress, prefix_len: u8) { - let mut iface = self.iface.lock(); - iface.update_ip_addrs(|ip_addrs| { - ip_addrs.push(IpCidr::new(ip, prefix_len)).unwrap(); - }); - } - - pub fn setup_gateway(&self, gateway: IpAddress) { - let mut iface = self.iface.lock(); - match gateway { - IpAddress::Ipv4(v4) => iface.routes_mut().add_default_ipv4_route(v4).unwrap(), - }; - } - - pub fn poll(&self, sockets: &Mutex) { - let mut dev = self.dev.lock(); - let mut iface = self.iface.lock(); - let mut sockets = sockets.lock(); - let timestamp = Self::current_time(); - iface.poll(timestamp, dev.deref_mut(), &mut sockets); - } -} - -impl DeviceWrapper { - fn new(inner: AxNetDevice) -> Self { - Self { - inner: RefCell::new(inner), - } - } -} - -impl Device for DeviceWrapper { - type RxToken<'a> = AxNetRxToken<'a> where Self: 'a; - type TxToken<'a> = AxNetTxToken<'a> where Self: 'a; - - fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { - let mut dev = self.inner.borrow_mut(); - if let Err(e) = dev.recycle_tx_buffers() { - warn!("recycle_tx_buffers failed: {:?}", e); - return None; - } - - if !dev.can_transmit() { - return None; - } - let rx_buf = match dev.receive() { - Ok(buf) => buf, - Err(err) => { - if !matches!(err, DevError::Again) { - warn!("receive failed: {:?}", err); - } - return None; - } - }; - Some((AxNetRxToken(&self.inner, rx_buf), AxNetTxToken(&self.inner))) - } - - fn transmit(&mut self, _timestamp: Instant) -> Option> { - let mut dev = self.inner.borrow_mut(); - if let Err(e) = dev.recycle_tx_buffers() { - warn!("recycle_tx_buffers failed: {:?}", e); - return None; - } - if dev.can_transmit() { - Some(AxNetTxToken(&self.inner)) - } else { - None - } - } - - fn capabilities(&self) -> DeviceCapabilities { - let mut caps = DeviceCapabilities::default(); - caps.max_transmission_unit = 1514; - caps.max_burst_size = None; - caps.medium = Medium::Ethernet; - caps - } -} - -struct AxNetRxToken<'a>(&'a RefCell, NetBufPtr); -struct AxNetTxToken<'a>(&'a RefCell); - -impl<'a> RxToken for AxNetRxToken<'a> { - fn preprocess(&self, sockets: &mut SocketSet<'_>) { - snoop_tcp_packet(self.1.packet(), sockets).ok(); - } - - fn consume(self, f: F) -> R - where - F: FnOnce(&mut [u8]) -> R, - { - let mut rx_buf = self.1; - trace!( - "RECV {} bytes: {:02X?}", - rx_buf.packet_len(), - rx_buf.packet() - ); - let result = f(rx_buf.packet_mut()); - self.0.borrow_mut().recycle_rx_buffer(rx_buf).unwrap(); - result - } -} - -impl<'a> TxToken for AxNetTxToken<'a> { - fn consume(self, len: usize, f: F) -> R - where - F: FnOnce(&mut [u8]) -> R, - { - let mut dev = self.0.borrow_mut(); - let mut tx_buf = dev.alloc_tx_buffer(len).unwrap(); - let ret = f(tx_buf.packet_mut()); - trace!("SEND {} bytes: {:02X?}", len, tx_buf.packet()); - dev.transmit(tx_buf).unwrap(); - ret - } -} - -fn snoop_tcp_packet(buf: &[u8], sockets: &mut SocketSet<'_>) -> Result<(), smoltcp::wire::Error> { - use smoltcp::wire::{EthernetFrame, IpProtocol, Ipv4Packet, TcpPacket}; - - let ether_frame = EthernetFrame::new_checked(buf)?; - let ipv4_packet = Ipv4Packet::new_checked(ether_frame.payload())?; - - if ipv4_packet.next_header() == IpProtocol::Tcp { - let tcp_packet = TcpPacket::new_checked(ipv4_packet.payload())?; - let src_addr = (ipv4_packet.src_addr(), tcp_packet.src_port()).into(); - let dst_addr = (ipv4_packet.dst_addr(), tcp_packet.dst_port()).into(); - let is_first = tcp_packet.syn() && !tcp_packet.ack(); - if is_first { - // create a socket for the first incoming TCP packet, as the later accept() returns. - LISTEN_TABLE.incoming_tcp_packet(src_addr, dst_addr, sockets); - } - } - Ok(()) -} - -/// Poll the network stack. -/// -/// It may receive packets from the NIC and process them, and transmit queued -/// packets to the NIC. -pub fn poll_interfaces() { - SOCKET_SET.poll_interfaces(); -} - -/// Benchmark raw socket transmit bandwidth. -pub fn bench_transmit() { - ETH0.dev.lock().bench_transmit_bandwidth(); -} - -/// Benchmark raw socket receive bandwidth. -pub fn bench_receive() { - ETH0.dev.lock().bench_receive_bandwidth(); -} - -pub(crate) fn init(net_dev: AxNetDevice) { - let ether_addr = EthernetAddress(net_dev.mac_address().0); - let eth0 = InterfaceWrapper::new("eth0", net_dev, ether_addr); - - let ip = IP.parse().expect("invalid IP address"); - let gateway = GATEWAY.parse().expect("invalid gateway IP address"); - eth0.setup_ip_addr(ip, IP_PREFIX); - eth0.setup_gateway(gateway); - - ETH0.init_once(eth0); - SOCKET_SET.init_once(SocketSetWrapper::new()); - LISTEN_TABLE.init_once(ListenTable::new()); - - info!("created net interface {:?}:", ETH0.name()); - info!(" ether: {}", ETH0.ethernet_address()); - info!(" ip: {}/{}", ip, IP_PREFIX); - info!(" gateway: {}", gateway); -} diff --git a/arceos/modules/axnet/src/smoltcp_impl/tcp.rs b/arceos/modules/axnet/src/smoltcp_impl/tcp.rs deleted file mode 100644 index 5c9d5dda1..000000000 --- a/arceos/modules/axnet/src/smoltcp_impl/tcp.rs +++ /dev/null @@ -1,527 +0,0 @@ -use core::cell::UnsafeCell; -use core::net::SocketAddr; -use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; - -use axerrno::{ax_err, ax_err_type, AxError, AxResult}; -use axio::PollState; -use axsync::Mutex; - -use smoltcp::iface::SocketHandle; -use smoltcp::socket::tcp::{self, ConnectError, State}; -use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; - -use super::addr::{from_core_sockaddr, into_core_sockaddr, is_unspecified, UNSPECIFIED_ENDPOINT}; -use super::{SocketSetWrapper, ETH0, LISTEN_TABLE, SOCKET_SET}; - -// State transitions: -// CLOSED -(connect)-> BUSY -> CONNECTING -> CONNECTED -(shutdown)-> BUSY -> CLOSED -// | -// |-(listen)-> BUSY -> LISTENING -(shutdown)-> BUSY -> CLOSED -// | -// -(bind)-> BUSY -> CLOSED -const STATE_CLOSED: u8 = 0; -const STATE_BUSY: u8 = 1; -const STATE_CONNECTING: u8 = 2; -const STATE_CONNECTED: u8 = 3; -const STATE_LISTENING: u8 = 4; - -/// A TCP socket that provides POSIX-like APIs. -/// -/// - [`connect`] is for TCP clients. -/// - [`bind`], [`listen`], and [`accept`] are for TCP servers. -/// - Other methods are for both TCP clients and servers. -/// -/// [`connect`]: TcpSocket::connect -/// [`bind`]: TcpSocket::bind -/// [`listen`]: TcpSocket::listen -/// [`accept`]: TcpSocket::accept -pub struct TcpSocket { - state: AtomicU8, - handle: UnsafeCell>, - local_addr: UnsafeCell, - peer_addr: UnsafeCell, - nonblock: AtomicBool, -} - -unsafe impl Sync for TcpSocket {} - -impl TcpSocket { - /// Creates a new TCP socket. - pub const fn new() -> Self { - Self { - state: AtomicU8::new(STATE_CLOSED), - handle: UnsafeCell::new(None), - local_addr: UnsafeCell::new(UNSPECIFIED_ENDPOINT), - peer_addr: UnsafeCell::new(UNSPECIFIED_ENDPOINT), - nonblock: AtomicBool::new(false), - } - } - - /// Creates a new TCP socket that is already connected. - const fn new_connected( - handle: SocketHandle, - local_addr: IpEndpoint, - peer_addr: IpEndpoint, - ) -> Self { - Self { - state: AtomicU8::new(STATE_CONNECTED), - handle: UnsafeCell::new(Some(handle)), - local_addr: UnsafeCell::new(local_addr), - peer_addr: UnsafeCell::new(peer_addr), - nonblock: AtomicBool::new(false), - } - } - - /// Returns the local address and port, or - /// [`Err(NotConnected)`](AxError::NotConnected) if not connected. - #[inline] - pub fn local_addr(&self) -> AxResult { - match self.get_state() { - STATE_CONNECTED | STATE_LISTENING => { - Ok(into_core_sockaddr(unsafe { self.local_addr.get().read() })) - } - _ => Err(AxError::NotConnected), - } - } - - /// Returns the remote address and port, or - /// [`Err(NotConnected)`](AxError::NotConnected) if not connected. - #[inline] - pub fn peer_addr(&self) -> AxResult { - match self.get_state() { - STATE_CONNECTED | STATE_LISTENING => { - Ok(into_core_sockaddr(unsafe { self.peer_addr.get().read() })) - } - _ => Err(AxError::NotConnected), - } - } - - /// Returns whether this socket is in nonblocking mode. - #[inline] - pub fn is_nonblocking(&self) -> bool { - self.nonblock.load(Ordering::Acquire) - } - - /// Moves this TCP stream into or out of nonblocking mode. - /// - /// This will result in `read`, `write`, `recv` and `send` operations - /// becoming nonblocking, i.e., immediately returning from their calls. - /// If the IO operation is successful, `Ok` is returned and no further - /// action is required. If the IO operation could not be completed and needs - /// to be retried, an error with kind [`Err(WouldBlock)`](AxError::WouldBlock) is - /// returned. - #[inline] - pub fn set_nonblocking(&self, nonblocking: bool) { - self.nonblock.store(nonblocking, Ordering::Release); - } - - /// Connects to the given address and port. - /// - /// The local port is generated automatically. - pub fn connect(&self, remote_addr: SocketAddr) -> AxResult { - self.update_state(STATE_CLOSED, STATE_CONNECTING, || { - // SAFETY: no other threads can read or write these fields. - let handle = unsafe { self.handle.get().read() } - .unwrap_or_else(|| SOCKET_SET.add(SocketSetWrapper::new_tcp_socket())); - - // TODO: check remote addr unreachable - let remote_endpoint = from_core_sockaddr(remote_addr); - let bound_endpoint = self.bound_endpoint()?; - let iface = Ð0.iface; - let (local_endpoint, remote_endpoint) = SOCKET_SET - .with_socket_mut::(handle, |socket| { - socket - .connect(iface.lock().context(), remote_endpoint, bound_endpoint) - .or_else(|e| match e { - ConnectError::InvalidState => { - ax_err!(BadState, "socket connect() failed") - } - ConnectError::Unaddressable => { - ax_err!(ConnectionRefused, "socket connect() failed") - } - })?; - Ok(( - socket.local_endpoint().unwrap(), - socket.remote_endpoint().unwrap(), - )) - })?; - unsafe { - // SAFETY: no other threads can read or write these fields as we - // have changed the state to `BUSY`. - self.local_addr.get().write(local_endpoint); - self.peer_addr.get().write(remote_endpoint); - self.handle.get().write(Some(handle)); - } - Ok(()) - }) - .unwrap_or_else(|_| ax_err!(AlreadyExists, "socket connect() failed: already connected"))?; // EISCONN - - // Here our state must be `CONNECTING`, and only one thread can run here. - if self.is_nonblocking() { - Err(AxError::WouldBlock) - } else { - self.block_on(|| { - let PollState { writable, .. } = self.poll_connect()?; - if !writable { - Err(AxError::WouldBlock) - } else if self.get_state() == STATE_CONNECTED { - Ok(()) - } else { - ax_err!(ConnectionRefused, "socket connect() failed") - } - }) - } - } - - /// Binds an unbound socket to the given address and port. - /// - /// If the given port is 0, it generates one automatically. - /// - /// It's must be called before [`listen`](Self::listen) and - /// [`accept`](Self::accept). - pub fn bind(&self, mut local_addr: SocketAddr) -> AxResult { - self.update_state(STATE_CLOSED, STATE_CLOSED, || { - // TODO: check addr is available - if local_addr.port() == 0 { - local_addr.set_port(get_ephemeral_port()?); - } - // SAFETY: no other threads can read or write `self.local_addr` as we - // have changed the state to `BUSY`. - unsafe { - let old = self.local_addr.get().read(); - if old != UNSPECIFIED_ENDPOINT { - return ax_err!(InvalidInput, "socket bind() failed: already bound"); - } - self.local_addr.get().write(from_core_sockaddr(local_addr)); - } - Ok(()) - }) - .unwrap_or_else(|_| ax_err!(InvalidInput, "socket bind() failed: already bound")) - } - - /// Starts listening on the bound address and port. - /// - /// It's must be called after [`bind`](Self::bind) and before - /// [`accept`](Self::accept). - pub fn listen(&self) -> AxResult { - self.update_state(STATE_CLOSED, STATE_LISTENING, || { - let bound_endpoint = self.bound_endpoint()?; - unsafe { - (*self.local_addr.get()).port = bound_endpoint.port; - } - LISTEN_TABLE.listen(bound_endpoint)?; - debug!("TCP socket listening on {}", bound_endpoint); - Ok(()) - }) - .unwrap_or(Ok(())) // ignore simultaneous `listen`s. - } - - /// Accepts a new connection. - /// - /// This function will block the calling thread until a new TCP connection - /// is established. When established, a new [`TcpSocket`] is returned. - /// - /// It's must be called after [`bind`](Self::bind) and [`listen`](Self::listen). - pub fn accept(&self) -> AxResult { - if !self.is_listening() { - return ax_err!(InvalidInput, "socket accept() failed: not listen"); - } - - // SAFETY: `self.local_addr` should be initialized after `bind()`. - let local_port = unsafe { self.local_addr.get().read().port }; - self.block_on(|| { - let (handle, (local_addr, peer_addr)) = LISTEN_TABLE.accept(local_port)?; - debug!("TCP socket accepted a new connection {}", peer_addr); - Ok(TcpSocket::new_connected(handle, local_addr, peer_addr)) - }) - } - - /// Close the connection. - pub fn shutdown(&self) -> AxResult { - // stream - self.update_state(STATE_CONNECTED, STATE_CLOSED, || { - // SAFETY: `self.handle` should be initialized in a connected socket, and - // no other threads can read or write it. - let handle = unsafe { self.handle.get().read().unwrap() }; - SOCKET_SET.with_socket_mut::(handle, |socket| { - debug!("TCP socket {}: shutting down", handle); - socket.close(); - }); - unsafe { self.local_addr.get().write(UNSPECIFIED_ENDPOINT) }; // clear bound address - SOCKET_SET.poll_interfaces(); - Ok(()) - }) - .unwrap_or(Ok(()))?; - - // listener - self.update_state(STATE_LISTENING, STATE_CLOSED, || { - // SAFETY: `self.local_addr` should be initialized in a listening socket, - // and no other threads can read or write it. - let local_port = unsafe { self.local_addr.get().read().port }; - unsafe { self.local_addr.get().write(UNSPECIFIED_ENDPOINT) }; // clear bound address - LISTEN_TABLE.unlisten(local_port); - SOCKET_SET.poll_interfaces(); - Ok(()) - }) - .unwrap_or(Ok(()))?; - - // ignore for other states - Ok(()) - } - - /// Receives data from the socket, stores it in the given buffer. - pub fn recv(&self, buf: &mut [u8]) -> AxResult { - if self.is_connecting() { - return Err(AxError::WouldBlock); - } else if !self.is_connected() { - return ax_err!(NotConnected, "socket recv() failed"); - } - - // SAFETY: `self.handle` should be initialized in a connected socket. - let handle = unsafe { self.handle.get().read().unwrap() }; - self.block_on(|| { - SOCKET_SET.with_socket_mut::(handle, |socket| { - if !socket.is_active() { - // not open - ax_err!(ConnectionRefused, "socket recv() failed") - } else if !socket.may_recv() { - // connection closed - Ok(0) - } else if socket.recv_queue() > 0 { - // data available - // TODO: use socket.recv(|buf| {...}) - let len = socket - .recv_slice(buf) - .map_err(|_| ax_err_type!(BadState, "socket recv() failed"))?; - Ok(len) - } else { - // no more data - Err(AxError::WouldBlock) - } - }) - }) - } - - /// Transmits data in the given buffer. - pub fn send(&self, buf: &[u8]) -> AxResult { - if self.is_connecting() { - return Err(AxError::WouldBlock); - } else if !self.is_connected() { - return ax_err!(NotConnected, "socket send() failed"); - } - - // SAFETY: `self.handle` should be initialized in a connected socket. - let handle = unsafe { self.handle.get().read().unwrap() }; - self.block_on(|| { - SOCKET_SET.with_socket_mut::(handle, |socket| { - if !socket.is_active() || !socket.may_send() { - // closed by remote - ax_err!(ConnectionReset, "socket send() failed") - } else if socket.can_send() { - // connected, and the tx buffer is not full - // TODO: use socket.send(|buf| {...}) - let len = socket - .send_slice(buf) - .map_err(|_| ax_err_type!(BadState, "socket send() failed"))?; - Ok(len) - } else { - // tx buffer is full - Err(AxError::WouldBlock) - } - }) - }) - } - - /// Whether the socket is readable or writable. - pub fn poll(&self) -> AxResult { - match self.get_state() { - STATE_CONNECTING => self.poll_connect(), - STATE_CONNECTED => self.poll_stream(), - STATE_LISTENING => self.poll_listener(), - _ => Ok(PollState { - readable: false, - writable: false, - }), - } - } -} - -/// Private methods -impl TcpSocket { - #[inline] - fn get_state(&self) -> u8 { - self.state.load(Ordering::Acquire) - } - - #[inline] - fn set_state(&self, state: u8) { - self.state.store(state, Ordering::Release); - } - - /// Update the state of the socket atomically. - /// - /// If the current state is `expect`, it first changes the state to `STATE_BUSY`, - /// then calls the given function. If the function returns `Ok`, it changes the - /// state to `new`, otherwise it changes the state back to `expect`. - /// - /// It returns `Ok` if the current state is `expect`, otherwise it returns - /// the current state in `Err`. - fn update_state(&self, expect: u8, new: u8, f: F) -> Result, u8> - where - F: FnOnce() -> AxResult, - { - match self - .state - .compare_exchange(expect, STATE_BUSY, Ordering::Acquire, Ordering::Acquire) - { - Ok(_) => { - let res = f(); - if res.is_ok() { - self.set_state(new); - } else { - self.set_state(expect); - } - Ok(res) - } - Err(old) => Err(old), - } - } - - #[inline] - fn is_connecting(&self) -> bool { - self.get_state() == STATE_CONNECTING - } - - #[inline] - fn is_connected(&self) -> bool { - self.get_state() == STATE_CONNECTED - } - - #[inline] - fn is_listening(&self) -> bool { - self.get_state() == STATE_LISTENING - } - - fn bound_endpoint(&self) -> AxResult { - // SAFETY: no other threads can read or write `self.local_addr`. - let local_addr = unsafe { self.local_addr.get().read() }; - let port = if local_addr.port != 0 { - local_addr.port - } else { - get_ephemeral_port()? - }; - assert_ne!(port, 0); - let addr = if !is_unspecified(local_addr.addr) { - Some(local_addr.addr) - } else { - None - }; - Ok(IpListenEndpoint { addr, port }) - } - - fn poll_connect(&self) -> AxResult { - // SAFETY: `self.handle` should be initialized above. - let handle = unsafe { self.handle.get().read().unwrap() }; - let writable = - SOCKET_SET.with_socket::(handle, |socket| match socket.state() { - State::SynSent => false, // wait for connection - State::Established => { - self.set_state(STATE_CONNECTED); // connected - debug!( - "TCP socket {}: connected to {}", - handle, - socket.remote_endpoint().unwrap(), - ); - true - } - _ => { - unsafe { - self.local_addr.get().write(UNSPECIFIED_ENDPOINT); - self.peer_addr.get().write(UNSPECIFIED_ENDPOINT); - } - self.set_state(STATE_CLOSED); // connection failed - true - } - }); - Ok(PollState { - readable: false, - writable, - }) - } - - fn poll_stream(&self) -> AxResult { - // SAFETY: `self.handle` should be initialized in a connected socket. - let handle = unsafe { self.handle.get().read().unwrap() }; - SOCKET_SET.with_socket::(handle, |socket| { - Ok(PollState { - readable: !socket.may_recv() || socket.can_recv(), - writable: !socket.may_send() || socket.can_send(), - }) - }) - } - - fn poll_listener(&self) -> AxResult { - // SAFETY: `self.local_addr` should be initialized in a listening socket. - let local_addr = unsafe { self.local_addr.get().read() }; - Ok(PollState { - readable: LISTEN_TABLE.can_accept(local_addr.port)?, - writable: false, - }) - } - - /// Block the current thread until the given function completes or fails. - /// - /// If the socket is non-blocking, it calls the function once and returns - /// immediately. Otherwise, it may call the function multiple times if it - /// returns [`Err(WouldBlock)`](AxError::WouldBlock). - fn block_on(&self, mut f: F) -> AxResult - where - F: FnMut() -> AxResult, - { - if self.is_nonblocking() { - f() - } else { - loop { - SOCKET_SET.poll_interfaces(); - match f() { - Ok(t) => return Ok(t), - Err(AxError::WouldBlock) => axtask::yield_now(), - Err(e) => return Err(e), - } - } - } - } -} - -impl Drop for TcpSocket { - fn drop(&mut self) { - self.shutdown().ok(); - // Safe because we have mut reference to `self`. - if let Some(handle) = unsafe { self.handle.get().read() } { - SOCKET_SET.remove(handle); - } - } -} - -fn get_ephemeral_port() -> AxResult { - const PORT_START: u16 = 0xc000; - const PORT_END: u16 = 0xffff; - static CURR: Mutex = Mutex::new(PORT_START); - - let mut curr = CURR.lock(); - let mut tries = 0; - // TODO: more robust - while tries <= PORT_END - PORT_START { - let port = *curr; - if *curr == PORT_END { - *curr = PORT_START; - } else { - *curr += 1; - } - if LISTEN_TABLE.can_listen(port) { - return Ok(port); - } - tries += 1; - } - ax_err!(AddrInUse, "no avaliable ports!") -} diff --git a/arceos/modules/axnet/src/smoltcp_impl/udp.rs b/arceos/modules/axnet/src/smoltcp_impl/udp.rs deleted file mode 100644 index 371640470..000000000 --- a/arceos/modules/axnet/src/smoltcp_impl/udp.rs +++ /dev/null @@ -1,294 +0,0 @@ -use core::net::SocketAddr; -use core::sync::atomic::{AtomicBool, Ordering}; - -use axerrno::{ax_err, ax_err_type, AxError, AxResult}; -use axio::PollState; -use axsync::Mutex; -use spin::RwLock; - -use smoltcp::iface::SocketHandle; -use smoltcp::socket::udp::{self, BindError, SendError}; -use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; - -use super::addr::{from_core_sockaddr, into_core_sockaddr, is_unspecified, UNSPECIFIED_ENDPOINT}; -use super::{SocketSetWrapper, SOCKET_SET}; - -/// A UDP socket that provides POSIX-like APIs. -pub struct UdpSocket { - handle: SocketHandle, - local_addr: RwLock>, - peer_addr: RwLock>, - nonblock: AtomicBool, -} - -impl UdpSocket { - /// Creates a new UDP socket. - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - let socket = SocketSetWrapper::new_udp_socket(); - let handle = SOCKET_SET.add(socket); - Self { - handle, - local_addr: RwLock::new(None), - peer_addr: RwLock::new(None), - nonblock: AtomicBool::new(false), - } - } - - /// Returns the local address and port, or - /// [`Err(NotConnected)`](AxError::NotConnected) if not connected. - pub fn local_addr(&self) -> AxResult { - match self.local_addr.try_read() { - Some(addr) => addr.map(into_core_sockaddr).ok_or(AxError::NotConnected), - None => Err(AxError::NotConnected), - } - } - - /// Returns the remote address and port, or - /// [`Err(NotConnected)`](AxError::NotConnected) if not connected. - pub fn peer_addr(&self) -> AxResult { - self.remote_endpoint().map(into_core_sockaddr) - } - - /// Returns whether this socket is in nonblocking mode. - #[inline] - pub fn is_nonblocking(&self) -> bool { - self.nonblock.load(Ordering::Acquire) - } - - /// Moves this UDP socket into or out of nonblocking mode. - /// - /// This will result in `recv`, `recv_from`, `send`, and `send_to` - /// operations becoming nonblocking, i.e., immediately returning from their - /// calls. If the IO operation is successful, `Ok` is returned and no - /// further action is required. If the IO operation could not be completed - /// and needs to be retried, an error with kind - /// [`Err(WouldBlock)`](AxError::WouldBlock) is returned. - #[inline] - pub fn set_nonblocking(&self, nonblocking: bool) { - self.nonblock.store(nonblocking, Ordering::Release); - } - - /// Binds an unbound socket to the given address and port. - /// - /// It's must be called before [`send_to`](Self::send_to) and - /// [`recv_from`](Self::recv_from). - pub fn bind(&self, mut local_addr: SocketAddr) -> AxResult { - let mut self_local_addr = self.local_addr.write(); - - if local_addr.port() == 0 { - local_addr.set_port(get_ephemeral_port()?); - } - if self_local_addr.is_some() { - return ax_err!(InvalidInput, "socket bind() failed: already bound"); - } - - let local_endpoint = from_core_sockaddr(local_addr); - let endpoint = IpListenEndpoint { - addr: (!is_unspecified(local_endpoint.addr)).then_some(local_endpoint.addr), - port: local_endpoint.port, - }; - SOCKET_SET.with_socket_mut::(self.handle, |socket| { - socket.bind(endpoint).or_else(|e| match e { - BindError::InvalidState => ax_err!(AlreadyExists, "socket bind() failed"), - BindError::Unaddressable => ax_err!(InvalidInput, "socket bind() failed"), - }) - })?; - - *self_local_addr = Some(local_endpoint); - debug!("UDP socket {}: bound on {}", self.handle, endpoint); - Ok(()) - } - - /// Sends data on the socket to the given address. On success, returns the - /// number of bytes written. - pub fn send_to(&self, buf: &[u8], remote_addr: SocketAddr) -> AxResult { - if remote_addr.port() == 0 || remote_addr.ip().is_unspecified() { - return ax_err!(InvalidInput, "socket send_to() failed: invalid address"); - } - self.send_impl(buf, from_core_sockaddr(remote_addr)) - } - - /// Receives a single datagram message on the socket. On success, returns - /// the number of bytes read and the origin. - pub fn recv_from(&self, buf: &mut [u8]) -> AxResult<(usize, SocketAddr)> { - self.recv_impl(|socket| match socket.recv_slice(buf) { - Ok((len, meta)) => Ok((len, into_core_sockaddr(meta.endpoint))), - Err(_) => ax_err!(BadState, "socket recv_from() failed"), - }) - } - - /// Receives a single datagram message on the socket, without removing it from - /// the queue. On success, returns the number of bytes read and the origin. - pub fn peek_from(&self, buf: &mut [u8]) -> AxResult<(usize, SocketAddr)> { - self.recv_impl(|socket| match socket.peek_slice(buf) { - Ok((len, meta)) => Ok((len, into_core_sockaddr(meta.endpoint))), - Err(_) => ax_err!(BadState, "socket recv_from() failed"), - }) - } - - /// Connects this UDP socket to a remote address, allowing the `send` and - /// `recv` to be used to send data and also applies filters to only receive - /// data from the specified address. - /// - /// The local port will be generated automatically if the socket is not bound. - /// It's must be called before [`send`](Self::send) and - /// [`recv`](Self::recv). - pub fn connect(&self, addr: SocketAddr) -> AxResult { - let mut self_peer_addr = self.peer_addr.write(); - - if self.local_addr.read().is_none() { - self.bind(into_core_sockaddr(UNSPECIFIED_ENDPOINT))?; - } - - *self_peer_addr = Some(from_core_sockaddr(addr)); - debug!("UDP socket {}: connected to {}", self.handle, addr); - Ok(()) - } - - /// Sends data on the socket to the remote address to which it is connected. - pub fn send(&self, buf: &[u8]) -> AxResult { - let remote_endpoint = self.remote_endpoint()?; - self.send_impl(buf, remote_endpoint) - } - - /// Receives a single datagram message on the socket from the remote address - /// to which it is connected. On success, returns the number of bytes read. - pub fn recv(&self, buf: &mut [u8]) -> AxResult { - let remote_endpoint = self.remote_endpoint()?; - self.recv_impl(|socket| { - let (len, meta) = socket - .recv_slice(buf) - .map_err(|_| ax_err_type!(BadState, "socket recv() failed"))?; - if !is_unspecified(remote_endpoint.addr) && remote_endpoint.addr != meta.endpoint.addr { - return Err(AxError::WouldBlock); - } - if remote_endpoint.port != 0 && remote_endpoint.port != meta.endpoint.port { - return Err(AxError::WouldBlock); - } - Ok(len) - }) - } - - /// Close the socket. - pub fn shutdown(&self) -> AxResult { - SOCKET_SET.with_socket_mut::(self.handle, |socket| { - debug!("UDP socket {}: shutting down", self.handle); - socket.close(); - }); - SOCKET_SET.poll_interfaces(); - Ok(()) - } - - /// Whether the socket is readable or writable. - pub fn poll(&self) -> AxResult { - if self.local_addr.read().is_none() { - return Ok(PollState { - readable: false, - writable: false, - }); - } - SOCKET_SET.with_socket_mut::(self.handle, |socket| { - Ok(PollState { - readable: socket.can_recv(), - writable: socket.can_send(), - }) - }) - } -} - -/// Private methods -impl UdpSocket { - fn remote_endpoint(&self) -> AxResult { - match self.peer_addr.try_read() { - Some(addr) => addr.ok_or(AxError::NotConnected), - None => Err(AxError::NotConnected), - } - } - - fn send_impl(&self, buf: &[u8], remote_endpoint: IpEndpoint) -> AxResult { - if self.local_addr.read().is_none() { - return ax_err!(NotConnected, "socket send() failed"); - } - - self.block_on(|| { - SOCKET_SET.with_socket_mut::(self.handle, |socket| { - if socket.can_send() { - socket - .send_slice(buf, remote_endpoint) - .map_err(|e| match e { - SendError::BufferFull => AxError::WouldBlock, - SendError::Unaddressable => { - ax_err_type!(ConnectionRefused, "socket send() failed") - } - })?; - Ok(buf.len()) - } else { - // tx buffer is full - Err(AxError::WouldBlock) - } - }) - }) - } - - fn recv_impl(&self, mut op: F) -> AxResult - where - F: FnMut(&mut udp::Socket) -> AxResult, - { - if self.local_addr.read().is_none() { - return ax_err!(NotConnected, "socket send() failed"); - } - - self.block_on(|| { - SOCKET_SET.with_socket_mut::(self.handle, |socket| { - if socket.can_recv() { - // data available - op(socket) - } else { - // no more data - Err(AxError::WouldBlock) - } - }) - }) - } - - fn block_on(&self, mut f: F) -> AxResult - where - F: FnMut() -> AxResult, - { - if self.is_nonblocking() { - f() - } else { - loop { - SOCKET_SET.poll_interfaces(); - match f() { - Ok(t) => return Ok(t), - Err(AxError::WouldBlock) => axtask::yield_now(), - Err(e) => return Err(e), - } - } - } - } -} - -impl Drop for UdpSocket { - fn drop(&mut self) { - self.shutdown().ok(); - SOCKET_SET.remove(self.handle); - } -} - -fn get_ephemeral_port() -> AxResult { - const PORT_START: u16 = 0xc000; - const PORT_END: u16 = 0xffff; - static CURR: Mutex = Mutex::new(PORT_START); - let mut curr = CURR.lock(); - - let port = *curr; - if *curr == PORT_END { - *curr = PORT_START; - } else { - *curr += 1; - } - Ok(port) -} diff --git a/arceos/modules/axruntime/Cargo.toml b/arceos/modules/axruntime/Cargo.toml deleted file mode 100644 index ff90b3507..000000000 --- a/arceos/modules/axruntime/Cargo.toml +++ /dev/null @@ -1,45 +0,0 @@ -[package] -name = "axruntime" -version.workspace = true -edition = "2021" -authors = ["Yuekai Jia "] -description = "Runtime library of ArceOS" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/modules/axruntime" -documentation = "https://arceos-org.github.io/arceos/axruntime/index.html" - -[features] -default = [] - -smp = ["axhal/smp"] -irq = ["axhal/irq", "axtask?/irq", "percpu", "kernel_guard"] -tls = ["axhal/tls", "axtask?/tls"] -alloc = ["axalloc"] -alt_alloc = ["alt_axalloc"] -paging = ["axhal/paging", "axmm"] - -multitask = ["axtask/multitask"] -fs = ["axdriver", "axfs"] -net = ["axdriver", "axnet"] -display = ["axdriver", "axdisplay"] -rtc = [] - -[dependencies] -axhal = { workspace = true } -axlog = { workspace = true } -axconfig = { workspace = true } -axalloc = { workspace = true, optional = true } -alt_axalloc = { workspace = true, optional = true } -axmm = { workspace = true, optional = true } -axdriver = { workspace = true, optional = true } -axfs = { workspace = true, optional = true } -axnet = { workspace = true, optional = true } -axdisplay = { workspace = true, optional = true } -axtask = { workspace = true, optional = true } - -crate_interface = "0.1" -percpu = { version = "0.1", optional = true } -kernel_guard = { version = "0.1", optional = true } - -chrono = { version = "0.4.38", default-features = false } diff --git a/arceos/modules/axruntime/src/lang_items.rs b/arceos/modules/axruntime/src/lang_items.rs deleted file mode 100644 index 6600cdd74..000000000 --- a/arceos/modules/axruntime/src/lang_items.rs +++ /dev/null @@ -1,7 +0,0 @@ -use core::panic::PanicInfo; - -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - error!("{}", info); - axhal::misc::terminate() -} diff --git a/arceos/modules/axruntime/src/lib.rs b/arceos/modules/axruntime/src/lib.rs deleted file mode 100644 index d6d75a6f7..000000000 --- a/arceos/modules/axruntime/src/lib.rs +++ /dev/null @@ -1,299 +0,0 @@ -//! Runtime library of [ArceOS](https://github.com/arceos-org/arceos). -//! -//! Any application uses ArceOS should link this library. It does some -//! initialization work before entering the application's `main` function. -//! -//! # Cargo Features -//! -//! - `alloc`: Enable global memory allocator. -//! - `paging`: Enable page table manipulation support. -//! - `irq`: Enable interrupt handling support. -//! - `multitask`: Enable multi-threading support. -//! - `smp`: Enable SMP (symmetric multiprocessing) support. -//! - `fs`: Enable filesystem support. -//! - `net`: Enable networking support. -//! - `display`: Enable graphics support. -//! -//! All the features are optional and disabled by default. - -#![cfg_attr(not(test), no_std)] -#![feature(doc_auto_cfg)] - -#[macro_use] -extern crate axlog; - -#[cfg(all(target_os = "none", not(test)))] -mod lang_items; - -#[cfg(feature = "smp")] -mod mp; - -#[cfg(feature = "smp")] -pub use self::mp::rust_main_secondary; - -const LOGO: &str = r#" - d8888 .d88888b. .d8888b. - d88888 d88P" "Y88b d88P Y88b - d88P888 888 888 Y88b. - d88P 888 888d888 .d8888b .d88b. 888 888 "Y888b. - d88P 888 888P" d88P" d8P Y8b 888 888 "Y88b. - d88P 888 888 888 88888888 888 888 "888 - d8888888888 888 Y88b. Y8b. Y88b. .d88P Y88b d88P -d88P 888 888 "Y8888P "Y8888 "Y88888P" "Y8888P" -"#; - -extern "C" { - fn main(); -} - -struct LogIfImpl; - -#[crate_interface::impl_interface] -impl axlog::LogIf for LogIfImpl { - fn console_write_str(s: &str) { - axhal::console::write_bytes(s.as_bytes()); - } - - fn current_time() -> core::time::Duration { - axhal::time::monotonic_time() - } - - fn current_cpu_id() -> Option { - #[cfg(feature = "smp")] - if is_init_ok() { - Some(axhal::cpu::this_cpu_id()) - } else { - None - } - #[cfg(not(feature = "smp"))] - Some(0) - } - - fn current_task_id() -> Option { - if is_init_ok() { - #[cfg(feature = "multitask")] - { - axtask::current_may_uninit().map(|curr| curr.id().as_u64()) - } - #[cfg(not(feature = "multitask"))] - None - } else { - None - } - } -} - -use core::sync::atomic::{AtomicUsize, Ordering}; - -static INITED_CPUS: AtomicUsize = AtomicUsize::new(0); - -fn is_init_ok() -> bool { - INITED_CPUS.load(Ordering::Acquire) == axconfig::SMP -} - -/// The main entry point of the ArceOS runtime. -/// -/// It is called from the bootstrapping code in [axhal]. `cpu_id` is the ID of -/// the current CPU, and `dtb` is the address of the device tree blob. It -/// finally calls the application's `main` function after all initialization -/// work is done. -/// -/// In multi-core environment, this function is called on the primary CPU, -/// and the secondary CPUs call [`rust_main_secondary`]. -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { - ax_println!("{}", LOGO); - ax_println!( - "\ - arch = {}\n\ - platform = {}\n\ - target = {}\n\ - smp = {}\n\ - build_mode = {}\n\ - log_level = {}\n\ - ", - option_env!("AX_ARCH").unwrap_or(""), - option_env!("AX_PLATFORM").unwrap_or(""), - option_env!("AX_TARGET").unwrap_or(""), - option_env!("AX_SMP").unwrap_or(""), - option_env!("AX_MODE").unwrap_or(""), - option_env!("AX_LOG").unwrap_or(""), - ); - #[cfg(feature = "rtc")] - ax_println!( - "Boot at {}\n", - chrono::DateTime::from_timestamp_nanos(axhal::time::wall_time_nanos() as _), - ); - - axlog::init(); - axlog::set_max_level(option_env!("AX_LOG").unwrap_or("")); // no effect if set `log-level-*` features - info!("Logging is enabled."); - info!("Primary CPU {} started, dtb = {:#x}.", cpu_id, dtb); - - info!("Found physcial memory regions:"); - for r in axhal::mem::memory_regions() { - info!( - " [{:x?}, {:x?}) {} ({:?})", - r.paddr, - r.paddr + r.size, - r.name, - r.flags - ); - } - - #[cfg(any(feature = "alloc", feature = "alt_alloc"))] - init_allocator(); - - #[cfg(feature = "paging")] - axmm::init_memory_management(); - - info!("Initialize platform devices..."); - axhal::platform_init(); - - #[cfg(feature = "multitask")] - axtask::init_scheduler(); - - #[cfg(any(feature = "fs", feature = "net", feature = "display"))] - { - #[allow(unused_variables)] - let all_devices = axdriver::init_drivers(); - - #[cfg(feature = "fs")] - axfs::init_filesystems(all_devices.block); - - #[cfg(feature = "net")] - axnet::init_network(all_devices.net); - - #[cfg(feature = "display")] - axdisplay::init_display(all_devices.display); - } - - #[cfg(feature = "smp")] - self::mp::start_secondary_cpus(cpu_id); - - #[cfg(feature = "irq")] - { - info!("Initialize interrupt handlers..."); - init_interrupt(); - } - - #[cfg(all(feature = "tls", not(feature = "multitask")))] - { - info!("Initialize thread local storage..."); - init_tls(); - } - - info!("Primary CPU {} init OK.", cpu_id); - INITED_CPUS.fetch_add(1, Ordering::Relaxed); - - while !is_init_ok() { - core::hint::spin_loop(); - } - - unsafe { main() }; - - #[cfg(feature = "multitask")] - axtask::exit(0); - #[cfg(not(feature = "multitask"))] - { - debug!("main task exited: exit_code={}", 0); - axhal::misc::terminate(); - } -} - -#[cfg(feature = "alloc")] -fn init_allocator() { - use axhal::mem::{memory_regions, phys_to_virt, MemRegionFlags}; - - info!("Initialize global memory allocator..."); - info!(" use {} allocator.", axalloc::global_allocator().name()); - - let mut max_region_size = 0; - let mut max_region_paddr = 0.into(); - for r in memory_regions() { - if r.flags.contains(MemRegionFlags::FREE) && r.size > max_region_size { - max_region_size = r.size; - max_region_paddr = r.paddr; - } - } - for r in memory_regions() { - if r.flags.contains(MemRegionFlags::FREE) && r.paddr == max_region_paddr { - axalloc::global_init(phys_to_virt(r.paddr).as_usize(), r.size); - break; - } - } - for r in memory_regions() { - if r.flags.contains(MemRegionFlags::FREE) && r.paddr != max_region_paddr { - axalloc::global_add_memory(phys_to_virt(r.paddr).as_usize(), r.size) - .expect("add heap memory region failed"); - } - } -} - -#[cfg(feature = "alt_alloc")] -fn init_allocator() { - use axhal::mem::{memory_regions, phys_to_virt, MemRegionFlags}; - - info!("Initialize global memory allocator..."); - info!(" use {} allocator.", alt_axalloc::global_allocator().name()); - - let mut max_region_size = 0; - let mut max_region_paddr = 0.into(); - for r in memory_regions() { - if r.flags.contains(MemRegionFlags::FREE) && r.size > max_region_size { - max_region_size = r.size; - max_region_paddr = r.paddr; - } - } - for r in memory_regions() { - if r.flags.contains(MemRegionFlags::FREE) && r.paddr == max_region_paddr { - alt_axalloc::global_init(phys_to_virt(r.paddr).as_usize(), r.size); - break; - } - } - for r in memory_regions() { - if r.flags.contains(MemRegionFlags::FREE) && r.paddr != max_region_paddr { - alt_axalloc::global_add_memory(phys_to_virt(r.paddr).as_usize(), r.size) - .expect("add heap memory region failed"); - } - } -} - -#[cfg(feature = "irq")] -fn init_interrupt() { - use axhal::time::TIMER_IRQ_NUM; - - // Setup timer interrupt handler - const PERIODIC_INTERVAL_NANOS: u64 = - axhal::time::NANOS_PER_SEC / axconfig::TICKS_PER_SEC as u64; - - #[percpu::def_percpu] - static NEXT_DEADLINE: u64 = 0; - - fn update_timer() { - let now_ns = axhal::time::monotonic_time_nanos(); - // Safety: we have disabled preemption in IRQ handler. - let mut deadline = unsafe { NEXT_DEADLINE.read_current_raw() }; - if now_ns >= deadline { - deadline = now_ns + PERIODIC_INTERVAL_NANOS; - } - unsafe { NEXT_DEADLINE.write_current_raw(deadline + PERIODIC_INTERVAL_NANOS) }; - axhal::time::set_oneshot_timer(deadline); - } - - axhal::irq::register_handler(TIMER_IRQ_NUM, || { - update_timer(); - #[cfg(feature = "multitask")] - axtask::on_timer_tick(); - }); - - // Enable IRQs before starting app - axhal::arch::enable_irqs(); -} - -#[cfg(all(feature = "tls", not(feature = "multitask")))] -fn init_tls() { - let main_tls = axhal::tls::TlsArea::alloc(); - unsafe { axhal::arch::write_thread_pointer(main_tls.tls_ptr() as usize) }; - core::mem::forget(main_tls); -} diff --git a/arceos/modules/axruntime/src/mp.rs b/arceos/modules/axruntime/src/mp.rs deleted file mode 100644 index 005d6be13..000000000 --- a/arceos/modules/axruntime/src/mp.rs +++ /dev/null @@ -1,65 +0,0 @@ -use core::sync::atomic::{AtomicUsize, Ordering}; - -use axconfig::{SMP, TASK_STACK_SIZE}; -use axhal::mem::{virt_to_phys, VirtAddr}; - -#[link_section = ".bss.stack"] -static mut SECONDARY_BOOT_STACK: [[u8; TASK_STACK_SIZE]; SMP - 1] = [[0; TASK_STACK_SIZE]; SMP - 1]; - -static ENTERED_CPUS: AtomicUsize = AtomicUsize::new(1); - -pub fn start_secondary_cpus(primary_cpu_id: usize) { - let mut logic_cpu_id = 0; - for i in 0..SMP { - if i != primary_cpu_id { - let stack_top = virt_to_phys(VirtAddr::from(unsafe { - SECONDARY_BOOT_STACK[logic_cpu_id].as_ptr_range().end as usize - })); - - debug!("starting CPU {}...", i); - axhal::mp::start_secondary_cpu(i, stack_top); - logic_cpu_id += 1; - - while ENTERED_CPUS.load(Ordering::Acquire) <= logic_cpu_id { - core::hint::spin_loop(); - } - } - } -} - -/// The main entry point of the ArceOS runtime for secondary CPUs. -/// -/// It is called from the bootstrapping code in [axhal]. -#[no_mangle] -pub extern "C" fn rust_main_secondary(cpu_id: usize) -> ! { - ENTERED_CPUS.fetch_add(1, Ordering::Relaxed); - info!("Secondary CPU {:x} started.", cpu_id); - - #[cfg(feature = "paging")] - axmm::init_memory_management_secondary(); - - axhal::platform_init_secondary(); - - #[cfg(feature = "multitask")] - axtask::init_scheduler_secondary(); - - info!("Secondary CPU {:x} init OK.", cpu_id); - super::INITED_CPUS.fetch_add(1, Ordering::Relaxed); - - while !super::is_init_ok() { - core::hint::spin_loop(); - } - - #[cfg(feature = "irq")] - axhal::arch::enable_irqs(); - - #[cfg(all(feature = "tls", not(feature = "multitask")))] - super::init_tls(); - - #[cfg(feature = "multitask")] - axtask::run_idle(); - #[cfg(not(feature = "multitask"))] - loop { - axhal::arch::wait_for_irqs(); - } -} diff --git a/arceos/modules/axsync/Cargo.toml b/arceos/modules/axsync/Cargo.toml deleted file mode 100644 index 109a7b559..000000000 --- a/arceos/modules/axsync/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "axsync" -version.workspace = true -edition = "2021" -authors = ["Yuekai Jia "] -description = "ArceOS synchronization primitives" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/modules/axsync" -documentation = "https://arceos-org.github.io/arceos/axsync/index.html" - -[features] -multitask = ["axtask/multitask"] -default = [] - -[dependencies] -kspin = "0.1" -axtask = { workspace = true } - -[dev-dependencies] -rand = "0.8" -axsync = { workspace = true, features = ["multitask"] } -axtask = { workspace = true, features = ["test"] } diff --git a/arceos/modules/axsync/src/lib.rs b/arceos/modules/axsync/src/lib.rs deleted file mode 100644 index cc71a1283..000000000 --- a/arceos/modules/axsync/src/lib.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! [ArceOS](https://github.com/arceos-org/arceos) synchronization primitives. -//! -//! Currently supported primitives: -//! -//! - [`Mutex`]: A mutual exclusion primitive. -//! - mod [`spin`]: spinlocks imported from the [`kspin`] crate. -//! -//! # Cargo Features -//! -//! - `multitask`: For use in the multi-threaded environments. If the feature is -//! not enabled, [`Mutex`] will be an alias of [`spin::SpinNoIrq`]. This -//! feature is enabled by default. - -#![cfg_attr(not(test), no_std)] -#![feature(doc_cfg)] - -pub use kspin as spin; - -#[cfg(feature = "multitask")] -mod mutex; - -#[cfg(feature = "multitask")] -#[doc(cfg(feature = "multitask"))] -pub use self::mutex::{Mutex, MutexGuard}; - -#[cfg(not(feature = "multitask"))] -#[doc(cfg(not(feature = "multitask")))] -pub use kspin::{SpinNoIrq as Mutex, SpinNoIrqGuard as MutexGuard}; diff --git a/arceos/modules/axsync/src/mutex.rs b/arceos/modules/axsync/src/mutex.rs deleted file mode 100644 index 0777bcc6b..000000000 --- a/arceos/modules/axsync/src/mutex.rs +++ /dev/null @@ -1,252 +0,0 @@ -//! A naïve sleeping mutex. - -use core::cell::UnsafeCell; -use core::fmt; -use core::ops::{Deref, DerefMut}; -use core::sync::atomic::{AtomicU64, Ordering}; - -use axtask::{current, WaitQueue}; - -/// A mutual exclusion primitive useful for protecting shared data, similar to -/// [`std::sync::Mutex`](https://doc.rust-lang.org/std/sync/struct.Mutex.html). -/// -/// When the mutex is locked, the current task will block and be put into the -/// wait queue. When the mutex is unlocked, all tasks waiting on the queue -/// will be woken up. -pub struct Mutex { - wq: WaitQueue, - owner_id: AtomicU64, - data: UnsafeCell, -} - -/// A guard that provides mutable data access. -/// -/// When the guard falls out of scope it will release the lock. -pub struct MutexGuard<'a, T: ?Sized + 'a> { - lock: &'a Mutex, - data: *mut T, -} - -// Same unsafe impls as `std::sync::Mutex` -unsafe impl Sync for Mutex {} -unsafe impl Send for Mutex {} - -impl Mutex { - /// Creates a new [`Mutex`] wrapping the supplied data. - #[inline(always)] - pub const fn new(data: T) -> Self { - Self { - wq: WaitQueue::new(), - owner_id: AtomicU64::new(0), - data: UnsafeCell::new(data), - } - } - - /// Consumes this [`Mutex`] and unwraps the underlying data. - #[inline(always)] - pub fn into_inner(self) -> T { - // We know statically that there are no outstanding references to - // `self` so there's no need to lock. - let Mutex { data, .. } = self; - data.into_inner() - } -} - -impl Mutex { - /// Returns `true` if the lock is currently held. - /// - /// # Safety - /// - /// This function provides no synchronization guarantees and so its result should be considered 'out of date' - /// the instant it is called. Do not use it for synchronization purposes. However, it may be useful as a heuristic. - #[inline(always)] - pub fn is_locked(&self) -> bool { - self.owner_id.load(Ordering::Relaxed) != 0 - } - - /// Locks the [`Mutex`] and returns a guard that permits access to the inner data. - /// - /// The returned value may be dereferenced for data access - /// and the lock will be dropped when the guard falls out of scope. - pub fn lock(&self) -> MutexGuard { - let current_id = current().id().as_u64(); - loop { - // Can fail to lock even if the spinlock is not locked. May be more efficient than `try_lock` - // when called in a loop. - match self.owner_id.compare_exchange_weak( - 0, - current_id, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => break, - Err(owner_id) => { - assert_ne!( - owner_id, - current_id, - "{} tried to acquire mutex it already owns.", - current().id_name() - ); - // Wait until the lock looks unlocked before retrying - self.wq.wait_until(|| !self.is_locked()); - } - } - } - MutexGuard { - lock: self, - data: unsafe { &mut *self.data.get() }, - } - } - - /// Try to lock this [`Mutex`], returning a lock guard if successful. - #[inline(always)] - pub fn try_lock(&self) -> Option> { - let current_id = current().id().as_u64(); - // The reason for using a strong compare_exchange is explained here: - // https://github.com/Amanieu/parking_lot/pull/207#issuecomment-575869107 - if self - .owner_id - .compare_exchange(0, current_id, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - Some(MutexGuard { - lock: self, - data: unsafe { &mut *self.data.get() }, - }) - } else { - None - } - } - - /// Force unlock the [`Mutex`]. - /// - /// # Safety - /// - /// This is *extremely* unsafe if the lock is not held by the current - /// thread. However, this can be useful in some instances for exposing - /// the lock to FFI that doesn’t know how to deal with RAII. - pub unsafe fn force_unlock(&self) { - let owner_id = self.owner_id.swap(0, Ordering::Release); - assert_eq!( - owner_id, - current().id().as_u64(), - "{} tried to release mutex it doesn't own", - current().id_name() - ); - self.wq.notify_one(true); - } - - /// Returns a mutable reference to the underlying data. - /// - /// Since this call borrows the [`Mutex`] mutably, and a mutable reference is guaranteed to be exclusive in - /// Rust, no actual locking needs to take place -- the mutable borrow statically guarantees no locks exist. As - /// such, this is a 'zero-cost' operation. - #[inline(always)] - pub fn get_mut(&mut self) -> &mut T { - // We know statically that there are no other references to `self`, so - // there's no need to lock the inner mutex. - unsafe { &mut *self.data.get() } - } -} - -impl Default for Mutex { - #[inline(always)] - fn default() -> Self { - Self::new(Default::default()) - } -} - -impl fmt::Debug for Mutex { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.try_lock() { - Some(guard) => write!(f, "Mutex {{ data: ") - .and_then(|()| (*guard).fmt(f)) - .and_then(|()| write!(f, "}}")), - None => write!(f, "Mutex {{ }}"), - } - } -} - -impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> { - type Target = T; - #[inline(always)] - fn deref(&self) -> &T { - // We know statically that only we are referencing data - unsafe { &*self.data } - } -} - -impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> { - #[inline(always)] - fn deref_mut(&mut self) -> &mut T { - // We know statically that only we are referencing data - unsafe { &mut *self.data } - } -} - -impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { - /// The dropping of the [`MutexGuard`] will release the lock it was created from. - fn drop(&mut self) { - unsafe { self.lock.force_unlock() } - } -} - -#[cfg(test)] -mod tests { - use crate::Mutex; - use axtask as thread; - use std::sync::Once; - - static INIT: Once = Once::new(); - - fn may_interrupt() { - // simulate interrupts - if rand::random::() % 3 == 0 { - thread::yield_now(); - } - } - - #[test] - fn lots_and_lots() { - INIT.call_once(thread::init_scheduler); - - const NUM_TASKS: u32 = 10; - const NUM_ITERS: u32 = 10_000; - static M: Mutex = Mutex::new(0); - - fn inc(delta: u32) { - for _ in 0..NUM_ITERS { - let mut val = M.lock(); - *val += delta; - may_interrupt(); - drop(val); - may_interrupt(); - } - } - - for _ in 0..NUM_TASKS { - thread::spawn(|| inc(1)); - thread::spawn(|| inc(2)); - } - - println!("spawn OK"); - loop { - let val = M.lock(); - if *val == NUM_ITERS * NUM_TASKS * 3 { - break; - } - may_interrupt(); - drop(val); - may_interrupt(); - } - - assert_eq!(*M.lock(), NUM_ITERS * NUM_TASKS * 3); - println!("Mutex test OK"); - } -} diff --git a/arceos/modules/axtask/Cargo.toml b/arceos/modules/axtask/Cargo.toml deleted file mode 100644 index 25fe7fb37..000000000 --- a/arceos/modules/axtask/Cargo.toml +++ /dev/null @@ -1,46 +0,0 @@ -[package] -name = "axtask" -version.workspace = true -edition = "2021" -authors = ["Yuekai Jia "] -description = "ArceOS task management module" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/modules/axtask" -documentation = "https://arceos-org.github.io/arceos/axtask/index.html" - -[features] -default = [] - -multitask = [ - "dep:axconfig", "dep:percpu", "dep:kspin", "dep:lazyinit", "dep:memory_addr", - "dep:scheduler", "dep:timer_list", "kernel_guard", "dep:crate_interface", -] -irq = [] -tls = ["axhal/tls"] -preempt = ["irq", "percpu?/preempt", "kernel_guard/preempt"] - -sched_fifo = ["multitask"] -sched_rr = ["multitask", "preempt"] -sched_cfs = ["multitask", "preempt"] - -test = ["percpu?/sp-naive"] - -[dependencies] -cfg-if = "1.0" -log = "0.4.21" -axhal = { workspace = true } -axconfig = { workspace = true, optional = true } -percpu = { version = "0.1", optional = true } -kspin = { version = "0.1", optional = true } -lazyinit = { version = "0.2", optional = true } -memory_addr = { version = "0.3", optional = true } -timer_list = { version = "0.1", optional = true } -kernel_guard = { version = "0.1", optional = true } -crate_interface = { version = "0.1", optional = true } -scheduler = { git = "https://github.com/arceos-org/scheduler.git", tag = "v0.1.0", optional = true } - -[dev-dependencies] -rand = "0.8" -axhal = { workspace = true, features = ["fp_simd"] } -axtask = { workspace = true, features = ["test", "multitask"] } diff --git a/arceos/modules/axtask/src/api.rs b/arceos/modules/axtask/src/api.rs deleted file mode 100644 index 156ba9d3b..000000000 --- a/arceos/modules/axtask/src/api.rs +++ /dev/null @@ -1,173 +0,0 @@ -//! Task APIs for multi-task configuration. - -use alloc::{string::String, sync::Arc}; - -pub(crate) use crate::run_queue::{AxRunQueue, RUN_QUEUE}; - -#[doc(cfg(feature = "multitask"))] -pub use crate::task::{CurrentTask, TaskId, TaskInner}; -#[doc(cfg(feature = "multitask"))] -pub use crate::task_ext::{TaskExtMut, TaskExtRef}; -#[doc(cfg(feature = "multitask"))] -pub use crate::wait_queue::WaitQueue; - -/// The reference type of a task. -pub type AxTaskRef = Arc; - -cfg_if::cfg_if! { - if #[cfg(feature = "sched_rr")] { - const MAX_TIME_SLICE: usize = 5; - pub(crate) type AxTask = scheduler::RRTask; - pub(crate) type Scheduler = scheduler::RRScheduler; - } else if #[cfg(feature = "sched_cfs")] { - pub(crate) type AxTask = scheduler::CFSTask; - pub(crate) type Scheduler = scheduler::CFScheduler; - } else { - // If no scheduler features are set, use FIFO as the default. - pub(crate) type AxTask = scheduler::FifoTask; - pub(crate) type Scheduler = scheduler::FifoScheduler; - } -} - -#[cfg(feature = "preempt")] -struct KernelGuardIfImpl; - -#[cfg(feature = "preempt")] -#[crate_interface::impl_interface] -impl kernel_guard::KernelGuardIf for KernelGuardIfImpl { - fn disable_preempt() { - if let Some(curr) = current_may_uninit() { - curr.disable_preempt(); - } - } - - fn enable_preempt() { - if let Some(curr) = current_may_uninit() { - curr.enable_preempt(true); - } - } -} - -/// Gets the current task, or returns [`None`] if the current task is not -/// initialized. -pub fn current_may_uninit() -> Option { - CurrentTask::try_get() -} - -/// Gets the current task. -/// -/// # Panics -/// -/// Panics if the current task is not initialized. -pub fn current() -> CurrentTask { - CurrentTask::get() -} - -/// Initializes the task scheduler (for the primary CPU). -pub fn init_scheduler() { - info!("Initialize scheduling..."); - - crate::run_queue::init(); - #[cfg(feature = "irq")] - crate::timers::init(); - - info!(" use {} scheduler.", Scheduler::scheduler_name()); -} - -/// Initializes the task scheduler for secondary CPUs. -pub fn init_scheduler_secondary() { - crate::run_queue::init_secondary(); -} - -/// Handles periodic timer ticks for the task manager. -/// -/// For example, advance scheduler states, checks timed events, etc. -#[cfg(feature = "irq")] -#[doc(cfg(feature = "irq"))] -pub fn on_timer_tick() { - crate::timers::check_events(); - RUN_QUEUE.lock().scheduler_timer_tick(); -} - -/// Adds the given task to the run queue, returns the task reference. -pub fn spawn_task(task: TaskInner) -> AxTaskRef { - let task_ref = task.into_arc(); - RUN_QUEUE.lock().add_task(task_ref.clone()); - task_ref -} - -/// Spawns a new task with the given parameters. -/// -/// Returns the task reference. -pub fn spawn_raw(f: F, name: String, stack_size: usize) -> AxTaskRef -where - F: FnOnce() + Send + 'static, -{ - spawn_task(TaskInner::new(f, name, stack_size)) -} - -/// Spawns a new task with the default parameters. -/// -/// The default task name is an empty string. The default task stack size is -/// [`axconfig::TASK_STACK_SIZE`]. -/// -/// Returns the task reference. -pub fn spawn(f: F) -> AxTaskRef -where - F: FnOnce() + Send + 'static, -{ - spawn_raw(f, "".into(), axconfig::TASK_STACK_SIZE) -} - -/// Set the priority for current task. -/// -/// The range of the priority is dependent on the underlying scheduler. For -/// example, in the [CFS] scheduler, the priority is the nice value, ranging from -/// -20 to 19. -/// -/// Returns `true` if the priority is set successfully. -/// -/// [CFS]: https://en.wikipedia.org/wiki/Completely_Fair_Scheduler -pub fn set_priority(prio: isize) -> bool { - RUN_QUEUE.lock().set_current_priority(prio) -} - -/// Current task gives up the CPU time voluntarily, and switches to another -/// ready task. -pub fn yield_now() { - RUN_QUEUE.lock().yield_current(); -} - -/// Current task is going to sleep for the given duration. -/// -/// If the feature `irq` is not enabled, it uses busy-wait instead. -pub fn sleep(dur: core::time::Duration) { - sleep_until(axhal::time::wall_time() + dur); -} - -/// Current task is going to sleep, it will be woken up at the given deadline. -/// -/// If the feature `irq` is not enabled, it uses busy-wait instead. -pub fn sleep_until(deadline: axhal::time::TimeValue) { - #[cfg(feature = "irq")] - RUN_QUEUE.lock().sleep_until(deadline); - #[cfg(not(feature = "irq"))] - axhal::time::busy_wait_until(deadline); -} - -/// Exits the current task. -pub fn exit(exit_code: i32) -> ! { - RUN_QUEUE.lock().exit_current(exit_code) -} - -/// The idle task routine. -/// -/// It runs an infinite loop that keeps calling [`yield_now()`]. -pub fn run_idle() -> ! { - loop { - yield_now(); - debug!("idle task: waiting for IRQs..."); - #[cfg(feature = "irq")] - axhal::arch::wait_for_irqs(); - } -} diff --git a/arceos/modules/axtask/src/api_s.rs b/arceos/modules/axtask/src/api_s.rs deleted file mode 100644 index aacbf805a..000000000 --- a/arceos/modules/axtask/src/api_s.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Task APIs for single-task configuration. - -/// For single-task situation, we just relax the CPU and wait for incoming -/// interrupts. -pub fn yield_now() { - if cfg!(feature = "irq") { - axhal::arch::wait_for_irqs(); - } else { - core::hint::spin_loop(); - } -} - -/// For single-task situation, we just busy wait for the given duration. -pub fn sleep(dur: core::time::Duration) { - axhal::time::busy_wait(dur); -} - -/// For single-task situation, we just busy wait until reaching the given -/// deadline. -pub fn sleep_until(deadline: axhal::time::TimeValue) { - axhal::time::busy_wait_until(deadline); -} diff --git a/arceos/modules/axtask/src/lib.rs b/arceos/modules/axtask/src/lib.rs deleted file mode 100644 index 64702634f..000000000 --- a/arceos/modules/axtask/src/lib.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! [ArceOS](https://github.com/arceos-org/arceos) task management module. -//! -//! This module provides primitives for task management, including task -//! creation, scheduling, sleeping, termination, etc. The scheduler algorithm -//! is configurable by cargo features. -//! -//! # Cargo Features -//! -//! - `multitask`: Enable multi-task support. If it's enabled, complex task -//! management and scheduling is used, as well as more task-related APIs. -//! Otherwise, only a few APIs with naive implementation is available. -//! - `irq`: Interrupts are enabled. If this feature is enabled, timer-based -//! APIs can be used, such as [`sleep`], [`sleep_until`], and -//! [`WaitQueue::wait_timeout`]. -//! - `preempt`: Enable preemptive scheduling. -//! - `sched_fifo`: Use the [FIFO cooperative scheduler][1]. It also enables the -//! `multitask` feature if it is enabled. This feature is enabled by default, -//! and it can be overriden by other scheduler features. -//! - `sched_rr`: Use the [Round-robin preemptive scheduler][2]. It also enables -//! the `multitask` and `preempt` features if it is enabled. -//! - `sched_cfs`: Use the [Completely Fair Scheduler][3]. It also enables the -//! the `multitask` and `preempt` features if it is enabled. -//! -//! [1]: scheduler::FifoScheduler -//! [2]: scheduler::RRScheduler -//! [3]: scheduler::CFScheduler - -#![cfg_attr(not(test), no_std)] -#![feature(doc_cfg)] -#![feature(doc_auto_cfg)] -#![feature(linkage)] -#![feature(const_mut_refs)] -#![feature(const_ptr_is_null)] -#![feature(const_unsafecell_get_mut)] - -#[cfg(test)] -mod tests; - -cfg_if::cfg_if! { - if #[cfg(feature = "multitask")] { - #[macro_use] - extern crate log; - extern crate alloc; - - mod run_queue; - mod task; - mod task_ext; - mod api; - mod wait_queue; - - #[cfg(feature = "irq")] - mod timers; - - #[doc(cfg(feature = "multitask"))] - pub use self::api::*; - pub use self::api::{sleep, sleep_until, yield_now}; - } else { - mod api_s; - pub use self::api_s::{sleep, sleep_until, yield_now}; - } -} diff --git a/arceos/modules/axtask/src/run_queue.rs b/arceos/modules/axtask/src/run_queue.rs deleted file mode 100644 index 1592b7637..000000000 --- a/arceos/modules/axtask/src/run_queue.rs +++ /dev/null @@ -1,240 +0,0 @@ -use alloc::collections::VecDeque; -use alloc::sync::Arc; -use kspin::SpinNoIrq; -use lazyinit::LazyInit; -use scheduler::BaseScheduler; - -use crate::task::{CurrentTask, TaskState}; -use crate::{AxTaskRef, Scheduler, TaskInner, WaitQueue}; - -// TODO: per-CPU -pub(crate) static RUN_QUEUE: LazyInit> = LazyInit::new(); - -// TODO: per-CPU -static EXITED_TASKS: SpinNoIrq> = SpinNoIrq::new(VecDeque::new()); - -static WAIT_FOR_EXIT: WaitQueue = WaitQueue::new(); - -#[percpu::def_percpu] -static IDLE_TASK: LazyInit = LazyInit::new(); - -pub(crate) struct AxRunQueue { - scheduler: Scheduler, -} - -impl AxRunQueue { - pub fn new() -> SpinNoIrq { - let gc_task = TaskInner::new(gc_entry, "gc".into(), axconfig::TASK_STACK_SIZE).into_arc(); - let mut scheduler = Scheduler::new(); - scheduler.add_task(gc_task); - SpinNoIrq::new(Self { scheduler }) - } - - pub fn add_task(&mut self, task: AxTaskRef) { - debug!("task spawn: {}", task.id_name()); - assert!(task.is_ready()); - self.scheduler.add_task(task); - } - - #[cfg(feature = "irq")] - pub fn scheduler_timer_tick(&mut self) { - let curr = crate::current(); - if !curr.is_idle() && self.scheduler.task_tick(curr.as_task_ref()) { - #[cfg(feature = "preempt")] - curr.set_preempt_pending(true); - } - } - - pub fn yield_current(&mut self) { - let curr = crate::current(); - trace!("task yield: {}", curr.id_name()); - assert!(curr.is_running()); - self.resched(false); - } - - pub fn set_current_priority(&mut self, prio: isize) -> bool { - self.scheduler - .set_priority(crate::current().as_task_ref(), prio) - } - - #[cfg(feature = "preempt")] - pub fn preempt_resched(&mut self) { - let curr = crate::current(); - assert!(curr.is_running()); - - // When we get the mutable reference of the run queue, we must - // have held the `SpinNoIrq` lock with both IRQs and preemption - // disabled. So we need to set `current_disable_count` to 1 in - // `can_preempt()` to obtain the preemption permission before - // locking the run queue. - let can_preempt = curr.can_preempt(1); - - debug!( - "current task is to be preempted: {}, allow={}", - curr.id_name(), - can_preempt - ); - if can_preempt { - self.resched(true); - } else { - curr.set_preempt_pending(true); - } - } - - pub fn exit_current(&mut self, exit_code: i32) -> ! { - let curr = crate::current(); - debug!("task exit: {}, exit_code={}", curr.id_name(), exit_code); - assert!(curr.is_running()); - assert!(!curr.is_idle()); - if curr.is_init() { - EXITED_TASKS.lock().clear(); - axhal::misc::terminate(); - } else { - curr.set_state(TaskState::Exited); - curr.notify_exit(exit_code, self); - EXITED_TASKS.lock().push_back(curr.clone()); - WAIT_FOR_EXIT.notify_one_locked(false, self); - self.resched(false); - } - unreachable!("task exited!"); - } - - pub fn block_current(&mut self, wait_queue_push: F) - where - F: FnOnce(AxTaskRef), - { - let curr = crate::current(); - debug!("task block: {}", curr.id_name()); - assert!(curr.is_running()); - assert!(!curr.is_idle()); - - // we must not block current task with preemption disabled. - #[cfg(feature = "preempt")] - assert!(curr.can_preempt(1)); - - curr.set_state(TaskState::Blocked); - wait_queue_push(curr.clone()); - self.resched(false); - } - - pub fn unblock_task(&mut self, task: AxTaskRef, resched: bool) { - debug!("task unblock: {}", task.id_name()); - if task.is_blocked() { - task.set_state(TaskState::Ready); - self.scheduler.add_task(task); // TODO: priority - if resched { - #[cfg(feature = "preempt")] - crate::current().set_preempt_pending(true); - } - } - } - - #[cfg(feature = "irq")] - pub fn sleep_until(&mut self, deadline: axhal::time::TimeValue) { - let curr = crate::current(); - debug!("task sleep: {}, deadline={:?}", curr.id_name(), deadline); - assert!(curr.is_running()); - assert!(!curr.is_idle()); - - let now = axhal::time::wall_time(); - if now < deadline { - crate::timers::set_alarm_wakeup(deadline, curr.clone()); - curr.set_state(TaskState::Blocked); - self.resched(false); - } - } -} - -impl AxRunQueue { - /// Common reschedule subroutine. If `preempt`, keep current task's time - /// slice, otherwise reset it. - fn resched(&mut self, preempt: bool) { - let prev = crate::current(); - if prev.is_running() { - prev.set_state(TaskState::Ready); - if !prev.is_idle() { - self.scheduler.put_prev_task(prev.clone(), preempt); - } - } - let next = self.scheduler.pick_next_task().unwrap_or_else(|| unsafe { - // Safety: IRQs must be disabled at this time. - IDLE_TASK.current_ref_raw().get_unchecked().clone() - }); - self.switch_to(prev, next); - } - - fn switch_to(&mut self, prev_task: CurrentTask, next_task: AxTaskRef) { - trace!( - "context switch: {} -> {}", - prev_task.id_name(), - next_task.id_name() - ); - #[cfg(feature = "preempt")] - next_task.set_preempt_pending(false); - next_task.set_state(TaskState::Running); - if prev_task.ptr_eq(&next_task) { - return; - } - - unsafe { - let prev_ctx_ptr = prev_task.ctx_mut_ptr(); - let next_ctx_ptr = next_task.ctx_mut_ptr(); - - // The strong reference count of `prev_task` will be decremented by 1, - // but won't be dropped until `gc_entry()` is called. - assert!(Arc::strong_count(prev_task.as_task_ref()) > 1); - assert!(Arc::strong_count(&next_task) >= 1); - - CurrentTask::set_current(prev_task, next_task); - (*prev_ctx_ptr).switch_to(&*next_ctx_ptr); - } - } -} - -fn gc_entry() { - loop { - // Drop all exited tasks and recycle resources. - let n = EXITED_TASKS.lock().len(); - for _ in 0..n { - // Do not do the slow drops in the critical section. - let task = EXITED_TASKS.lock().pop_front(); - if let Some(task) = task { - if Arc::strong_count(&task) == 1 { - // If I'm the last holder of the task, drop it immediately. - drop(task); - } else { - // Otherwise (e.g, `switch_to` is not compeleted, held by the - // joiner, etc), push it back and wait for them to drop first. - EXITED_TASKS.lock().push_back(task); - } - } - } - WAIT_FOR_EXIT.wait(); - } -} - -pub(crate) fn init() { - // Create the `idle` task (not current task). - const IDLE_TASK_STACK_SIZE: usize = 4096; - let idle_task = TaskInner::new(|| crate::run_idle(), "idle".into(), IDLE_TASK_STACK_SIZE); - IDLE_TASK.with_current(|i| { - i.init_once(idle_task.into_arc()); - }); - - // Put the subsequent execution into the `main` task. - let main_task = TaskInner::new_init("main".into()).into_arc(); - main_task.set_state(TaskState::Running); - unsafe { CurrentTask::init_current(main_task) }; - - RUN_QUEUE.init_once(AxRunQueue::new()); -} - -pub(crate) fn init_secondary() { - // Put the subsequent execution into the `idle` task. - let idle_task = TaskInner::new_init("idle".into()).into_arc(); - idle_task.set_state(TaskState::Running); - IDLE_TASK.with_current(|i| { - i.init_once(idle_task.clone()); - }); - unsafe { CurrentTask::init_current(idle_task) } -} diff --git a/arceos/modules/axtask/src/task.rs b/arceos/modules/axtask/src/task.rs deleted file mode 100644 index a916551eb..000000000 --- a/arceos/modules/axtask/src/task.rs +++ /dev/null @@ -1,441 +0,0 @@ -use alloc::{boxed::Box, string::String, sync::Arc}; -use core::ops::Deref; -use core::sync::atomic::{AtomicBool, AtomicI32, AtomicU64, AtomicU8, Ordering}; -use core::{alloc::Layout, cell::UnsafeCell, fmt, ptr::NonNull}; - -#[cfg(feature = "preempt")] -use core::sync::atomic::AtomicUsize; - -#[cfg(feature = "tls")] -use axhal::tls::TlsArea; - -use axhal::arch::TaskContext; -use memory_addr::{align_up_4k, VirtAddr}; - -use crate::task_ext::AxTaskExt; -use crate::{AxRunQueue, AxTask, AxTaskRef, WaitQueue}; - -/// A unique identifier for a thread. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct TaskId(u64); - -/// The possible states of a task. -#[repr(u8)] -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub(crate) enum TaskState { - Running = 1, - Ready = 2, - Blocked = 3, - Exited = 4, -} - -/// The inner task structure. -pub struct TaskInner { - id: TaskId, - name: String, - is_idle: bool, - is_init: bool, - - entry: Option<*mut dyn FnOnce()>, - state: AtomicU8, - - in_wait_queue: AtomicBool, - #[cfg(feature = "irq")] - in_timer_list: AtomicBool, - - #[cfg(feature = "preempt")] - need_resched: AtomicBool, - #[cfg(feature = "preempt")] - preempt_disable_count: AtomicUsize, - - exit_code: AtomicI32, - wait_for_exit: WaitQueue, - - kstack: Option, - ctx: UnsafeCell, - task_ext: AxTaskExt, - - #[cfg(feature = "tls")] - tls: TlsArea, -} - -impl TaskId { - fn new() -> Self { - static ID_COUNTER: AtomicU64 = AtomicU64::new(1); - Self(ID_COUNTER.fetch_add(1, Ordering::Relaxed)) - } - - /// Convert the task ID to a `u64`. - pub const fn as_u64(&self) -> u64 { - self.0 - } -} - -impl From for TaskState { - #[inline] - fn from(state: u8) -> Self { - match state { - 1 => Self::Running, - 2 => Self::Ready, - 3 => Self::Blocked, - 4 => Self::Exited, - _ => unreachable!(), - } - } -} - -unsafe impl Send for TaskInner {} -unsafe impl Sync for TaskInner {} - -impl TaskInner { - /// Create a new task with the given entry function and stack size. - pub fn new(entry: F, name: String, stack_size: usize) -> Self - where - F: FnOnce() + Send + 'static, - { - let mut t = Self::new_common(TaskId::new(), name); - debug!("new task: {}", t.id_name()); - let kstack = TaskStack::alloc(align_up_4k(stack_size)); - - #[cfg(feature = "tls")] - let tls = VirtAddr::from(t.tls.tls_ptr() as usize); - #[cfg(not(feature = "tls"))] - let tls = VirtAddr::from(0); - - t.entry = Some(Box::into_raw(Box::new(entry))); - t.ctx_mut().init(task_entry as usize, kstack.top(), tls); - t.kstack = Some(kstack); - if t.name == "idle" { - t.is_idle = true; - } - t - } - - /// Gets the ID of the task. - pub const fn id(&self) -> TaskId { - self.id - } - - /// Gets the name of the task. - pub fn name(&self) -> &str { - self.name.as_str() - } - - /// Get a combined string of the task ID and name. - pub fn id_name(&self) -> alloc::string::String { - alloc::format!("Task({}, {:?})", self.id.as_u64(), self.name) - } - - /// Wait for the task to exit, and return the exit code. - /// - /// It will return immediately if the task has already exited (but not dropped). - pub fn join(&self) -> Option { - self.wait_for_exit - .wait_until(|| self.state() == TaskState::Exited); - Some(self.exit_code.load(Ordering::Acquire)) - } - - /// Returns the pointer to the user-defined task extended data. - /// - /// # Safety - /// - /// The caller should not access the pointer directly, use [`TaskExtRef::task_ext`] - /// or [`TaskExtMut::task_ext_mut`] instead. - /// - /// [`TaskExtRef::task_ext`]: crate::task_ext::TaskExtRef::task_ext - /// [`TaskExtMut::task_ext_mut`]: crate::task_ext::TaskExtMut::task_ext_mut - pub unsafe fn task_ext_ptr(&self) -> *mut u8 { - self.task_ext.as_ptr() - } - - /// Initialize the user-defined task extended data. - /// - /// Returns a reference to the task extended data if it has not been - /// initialized yet (empty), otherwise returns [`None`]. - pub fn init_task_ext(&mut self, data: T) -> Option<&T> { - if self.task_ext.is_empty() { - self.task_ext.write(data).map(|data| &*data) - } else { - None - } - } -} - -// private methods -impl TaskInner { - fn new_common(id: TaskId, name: String) -> Self { - Self { - id, - name, - is_idle: false, - is_init: false, - entry: None, - state: AtomicU8::new(TaskState::Ready as u8), - in_wait_queue: AtomicBool::new(false), - #[cfg(feature = "irq")] - in_timer_list: AtomicBool::new(false), - #[cfg(feature = "preempt")] - need_resched: AtomicBool::new(false), - #[cfg(feature = "preempt")] - preempt_disable_count: AtomicUsize::new(0), - exit_code: AtomicI32::new(0), - wait_for_exit: WaitQueue::new(), - kstack: None, - ctx: UnsafeCell::new(TaskContext::new()), - task_ext: AxTaskExt::empty(), - #[cfg(feature = "tls")] - tls: TlsArea::alloc(), - } - } - - /// Creates an "init task" using the current CPU states, to use as the - /// current task. - /// - /// As it is the current task, no other task can switch to it until it - /// switches out. - /// - /// And there is no need to set the `entry`, `kstack` or `tls` fields, as - /// they will be filled automatically when the task is switches out. - pub(crate) fn new_init(name: String) -> Self { - let mut t = Self::new_common(TaskId::new(), name); - t.is_init = true; - if t.name == "idle" { - t.is_idle = true; - } - t - } - - pub(crate) fn into_arc(self) -> AxTaskRef { - Arc::new(AxTask::new(self)) - } - - #[inline] - pub(crate) fn state(&self) -> TaskState { - self.state.load(Ordering::Acquire).into() - } - - #[inline] - pub(crate) fn set_state(&self, state: TaskState) { - self.state.store(state as u8, Ordering::Release) - } - - #[inline] - pub(crate) fn is_running(&self) -> bool { - matches!(self.state(), TaskState::Running) - } - - #[inline] - pub(crate) fn is_ready(&self) -> bool { - matches!(self.state(), TaskState::Ready) - } - - #[inline] - pub(crate) fn is_blocked(&self) -> bool { - matches!(self.state(), TaskState::Blocked) - } - - #[inline] - pub(crate) const fn is_init(&self) -> bool { - self.is_init - } - - #[inline] - pub(crate) const fn is_idle(&self) -> bool { - self.is_idle - } - - #[inline] - pub(crate) fn in_wait_queue(&self) -> bool { - self.in_wait_queue.load(Ordering::Acquire) - } - - #[inline] - pub(crate) fn set_in_wait_queue(&self, in_wait_queue: bool) { - self.in_wait_queue.store(in_wait_queue, Ordering::Release); - } - - #[inline] - #[cfg(feature = "irq")] - pub(crate) fn in_timer_list(&self) -> bool { - self.in_timer_list.load(Ordering::Acquire) - } - - #[inline] - #[cfg(feature = "irq")] - pub(crate) fn set_in_timer_list(&self, in_timer_list: bool) { - self.in_timer_list.store(in_timer_list, Ordering::Release); - } - - #[inline] - #[cfg(feature = "preempt")] - pub(crate) fn set_preempt_pending(&self, pending: bool) { - self.need_resched.store(pending, Ordering::Release) - } - - #[inline] - #[cfg(feature = "preempt")] - pub(crate) fn can_preempt(&self, current_disable_count: usize) -> bool { - self.preempt_disable_count.load(Ordering::Acquire) == current_disable_count - } - - #[inline] - #[cfg(feature = "preempt")] - pub(crate) fn disable_preempt(&self) { - self.preempt_disable_count.fetch_add(1, Ordering::Relaxed); - } - - #[inline] - #[cfg(feature = "preempt")] - pub(crate) fn enable_preempt(&self, resched: bool) { - if self.preempt_disable_count.fetch_sub(1, Ordering::Relaxed) == 1 && resched { - // If current task is pending to be preempted, do rescheduling. - Self::current_check_preempt_pending(); - } - } - - #[cfg(feature = "preempt")] - fn current_check_preempt_pending() { - let curr = crate::current(); - if curr.need_resched.load(Ordering::Acquire) && curr.can_preempt(0) { - let mut rq = crate::RUN_QUEUE.lock(); - if curr.need_resched.load(Ordering::Acquire) { - rq.preempt_resched(); - } - } - } - - pub(crate) fn notify_exit(&self, exit_code: i32, rq: &mut AxRunQueue) { - self.exit_code.store(exit_code, Ordering::Release); - self.wait_for_exit.notify_all_locked(false, rq); - } - - #[inline] - pub(crate) const unsafe fn ctx_mut_ptr(&self) -> *mut TaskContext { - self.ctx.get() - } - - /// Returns a mutable reference to the task context. - #[inline] - pub const fn ctx_mut(&mut self) -> &mut TaskContext { - self.ctx.get_mut() - } - - /// Returns the top address of the kernel stack. - #[inline] - pub const fn kernel_stack_top(&self) -> Option { - match &self.kstack { - Some(s) => Some(s.top()), - None => None, - } - } -} - -impl fmt::Debug for TaskInner { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("TaskInner") - .field("id", &self.id) - .field("name", &self.name) - .field("state", &self.state()) - .finish() - } -} - -impl Drop for TaskInner { - fn drop(&mut self) { - debug!("task drop: {}", self.id_name()); - } -} - -struct TaskStack { - ptr: NonNull, - layout: Layout, -} - -impl TaskStack { - pub fn alloc(size: usize) -> Self { - let layout = Layout::from_size_align(size, 16).unwrap(); - Self { - ptr: NonNull::new(unsafe { alloc::alloc::alloc(layout) }).unwrap(), - layout, - } - } - - pub const fn top(&self) -> VirtAddr { - unsafe { core::mem::transmute(self.ptr.as_ptr().add(self.layout.size())) } - } -} - -impl Drop for TaskStack { - fn drop(&mut self) { - unsafe { alloc::alloc::dealloc(self.ptr.as_ptr(), self.layout) } - } -} - -use core::mem::ManuallyDrop; - -/// A wrapper of [`AxTaskRef`] as the current task. -/// -/// It won't change the reference count of the task when created or dropped. -pub struct CurrentTask(ManuallyDrop); - -impl CurrentTask { - pub(crate) fn try_get() -> Option { - let ptr: *const super::AxTask = axhal::cpu::current_task_ptr(); - if !ptr.is_null() { - Some(Self(unsafe { ManuallyDrop::new(AxTaskRef::from_raw(ptr)) })) - } else { - None - } - } - - pub(crate) fn get() -> Self { - Self::try_get().expect("current task is uninitialized") - } - - /// Converts [`CurrentTask`] to [`AxTaskRef`]. - pub fn as_task_ref(&self) -> &AxTaskRef { - &self.0 - } - - pub(crate) fn clone(&self) -> AxTaskRef { - self.0.deref().clone() - } - - pub(crate) fn ptr_eq(&self, other: &AxTaskRef) -> bool { - Arc::ptr_eq(&self.0, other) - } - - pub(crate) unsafe fn init_current(init_task: AxTaskRef) { - assert!(init_task.is_init()); - #[cfg(feature = "tls")] - axhal::arch::write_thread_pointer(init_task.tls.tls_ptr() as usize); - let ptr = Arc::into_raw(init_task); - axhal::cpu::set_current_task_ptr(ptr); - } - - pub(crate) unsafe fn set_current(prev: Self, next: AxTaskRef) { - let Self(arc) = prev; - ManuallyDrop::into_inner(arc); // `call Arc::drop()` to decrease prev task reference count. - let ptr = Arc::into_raw(next); - axhal::cpu::set_current_task_ptr(ptr); - } -} - -impl Deref for CurrentTask { - type Target = TaskInner; - fn deref(&self) -> &Self::Target { - self.0.deref() - } -} - -extern "C" fn task_entry() -> ! { - // release the lock that was implicitly held across the reschedule - unsafe { crate::RUN_QUEUE.force_unlock() }; - #[cfg(feature = "irq")] - axhal::arch::enable_irqs(); - let task = crate::current(); - if let Some(entry) = task.entry { - unsafe { Box::from_raw(entry)() }; - } - crate::exit(0); -} diff --git a/arceos/modules/axtask/src/task_ext.rs b/arceos/modules/axtask/src/task_ext.rs deleted file mode 100644 index bacd56d0a..000000000 --- a/arceos/modules/axtask/src/task_ext.rs +++ /dev/null @@ -1,187 +0,0 @@ -//! User-defined task extended data. - -use core::alloc::Layout; -use core::mem::{align_of, size_of}; - -#[no_mangle] -#[linkage = "weak"] -static __AX_TASK_EXT_SIZE: usize = 0; - -#[no_mangle] -#[linkage = "weak"] -static __AX_TASK_EXT_ALIGN: usize = 0; - -/// A wrapper of pointer to the task extended data. -pub(crate) struct AxTaskExt { - ptr: *mut u8, -} - -impl AxTaskExt { - /// Returns the expected size of the task extended structure. - pub fn size() -> usize { - extern "C" { - static __AX_TASK_EXT_SIZE: usize; - } - unsafe { __AX_TASK_EXT_SIZE } - } - - /// Returns the expected alignment of the task extended structure. - pub fn align() -> usize { - extern "C" { - static __AX_TASK_EXT_ALIGN: usize; - } - unsafe { __AX_TASK_EXT_ALIGN } - } - - /// Construct an empty task extended structure that contains no data - /// (zero size). - pub const fn empty() -> Self { - Self { - ptr: core::ptr::null_mut(), - } - } - - /// Returns `true` if the task extended structure is empty. - pub const fn is_empty(&self) -> bool { - self.ptr.is_null() - } - - /// Allocates the space for the task extended data, but does not - /// initialize the data. - pub unsafe fn uninited() -> Self { - let size = Self::size(); - let align = Self::align(); - let ptr = if size == 0 { - core::ptr::null_mut() - } else { - let layout = Layout::from_size_align(size, align).unwrap(); - unsafe { alloc::alloc::alloc(layout) } - }; - Self { ptr } - } - - /// Gets the raw pointer to the task extended data. - pub const fn as_ptr(&self) -> *mut u8 { - self.ptr - } - - /// Write the given object to the task extended data. - /// - /// Returns [`None`] if the data size is zero, otherwise returns a mutable - /// reference to the content. - /// - /// # Panics - /// - /// Panics If the sizes and alignments of the two object do not match. - pub fn write(&mut self, data: T) -> Option<&mut T> { - let data_size = size_of::(); - let data_align = align_of::(); - if data_size != Self::size() { - panic!("size mismatch: {} != {}", data_size, Self::size()); - } - if data_align != Self::align() { - panic!("align mismatch: {} != {}", data_align, Self::align()); - } - - if self.ptr.is_null() { - *self = unsafe { Self::uninited() }; - } - if data_size > 0 { - let ptr = self.ptr as *mut T; - assert!(!ptr.is_null()); - unsafe { - ptr.write(data); - Some(&mut *ptr) - } - } else { - None - } - } -} - -impl Drop for AxTaskExt { - fn drop(&mut self) { - if !self.ptr.is_null() { - let layout = Layout::from_size_align(Self::size(), 0x10).unwrap(); - unsafe { alloc::alloc::dealloc(self.ptr, layout) }; - } - } -} - -/// A trait to convert [`TaskInner::task_ext_ptr`] to the reference of the -/// concrete type. -/// -/// [`TaskInner::task_ext_ptr`]: crate::TaskInner::task_ext_ptr -pub trait TaskExtRef { - /// Get a reference to the task extended data. - fn task_ext(&self) -> &T; -} - -/// A trait to convert [`TaskInner::task_ext_ptr`] to the mutable reference of -/// the concrete type. -/// -/// [`TaskInner::task_ext_ptr`]: crate::TaskInner::task_ext_ptr -pub trait TaskExtMut { - /// Get a mutable reference to the task extended data. - fn task_ext_mut(&mut self) -> &mut T; -} - -/// Define the task extended data. -/// -/// It automatically implements [`TaskExtRef`] and [`TaskExtMut`] for -/// [`TaskInner`]. -/// -/// # Example -/// -/// ``` -/// # #![allow(non_local_definitions)] -/// use axtask::{def_task_ext, TaskExtRef, TaskInner}; -/// -/// pub struct TaskExtImpl { -/// proc_id: usize, -/// } -/// -/// def_task_ext!(TaskExtImpl); -/// -/// axtask::init_scheduler(); -/// -/// let mut inner = TaskInner::new(|| {}, "".into(), 0x1000); -/// assert!(inner.init_task_ext(TaskExtImpl { proc_id: 233 }).is_some()); -/// // cannot initialize twice -/// assert!(inner.init_task_ext(TaskExtImpl { proc_id: 0xdead }).is_none()); -/// -/// let task = axtask::spawn_task(inner); -/// assert_eq!(task.task_ext().proc_id, 233); -/// ``` -/// -/// [`TaskInner`]: crate::TaskInner -#[macro_export] -macro_rules! def_task_ext { - ($task_ext_struct:ty) => { - #[no_mangle] - static __AX_TASK_EXT_SIZE: usize = ::core::mem::size_of::<$task_ext_struct>(); - - #[no_mangle] - static __AX_TASK_EXT_ALIGN: usize = ::core::mem::align_of::<$task_ext_struct>(); - - impl $crate::TaskExtRef<$task_ext_struct> for $crate::TaskInner { - fn task_ext(&self) -> &$task_ext_struct { - unsafe { - let ptr = self.task_ext_ptr() as *const $task_ext_struct; - assert!(!ptr.is_null()); - &*ptr - } - } - } - - impl $crate::TaskExtMut<$task_ext_struct> for $crate::TaskInner { - fn task_ext_mut(&mut self) -> &mut $task_ext_struct { - unsafe { - let ptr = self.task_ext_ptr() as *mut $task_ext_struct; - assert!(!ptr.is_null()); - &mut *ptr - } - } - } - }; -} diff --git a/arceos/modules/axtask/src/tests.rs b/arceos/modules/axtask/src/tests.rs deleted file mode 100644 index 47a85e83e..000000000 --- a/arceos/modules/axtask/src/tests.rs +++ /dev/null @@ -1,130 +0,0 @@ -use core::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::{Mutex, Once}; - -use crate::{api as axtask, current, WaitQueue}; - -static INIT: Once = Once::new(); -static SERIAL: Mutex<()> = Mutex::new(()); - -#[test] -fn test_sched_fifo() { - let _lock = SERIAL.lock(); - INIT.call_once(axtask::init_scheduler); - - const NUM_TASKS: usize = 10; - static FINISHED_TASKS: AtomicUsize = AtomicUsize::new(0); - - for i in 0..NUM_TASKS { - axtask::spawn_raw( - move || { - println!("sched_fifo: Hello, task {}! ({})", i, current().id_name()); - axtask::yield_now(); - let order = FINISHED_TASKS.fetch_add(1, Ordering::Relaxed); - assert_eq!(order, i); // FIFO scheduler - }, - format!("T{}", i), - 0x1000, - ); - } - - while FINISHED_TASKS.load(Ordering::Relaxed) < NUM_TASKS { - axtask::yield_now(); - } -} - -#[test] -fn test_fp_state_switch() { - let _lock = SERIAL.lock(); - INIT.call_once(axtask::init_scheduler); - - const NUM_TASKS: usize = 5; - const FLOATS: [f64; NUM_TASKS] = [ - 3.141592653589793, - 2.718281828459045, - -1.4142135623730951, - 0.0, - 0.618033988749895, - ]; - static FINISHED_TASKS: AtomicUsize = AtomicUsize::new(0); - - for (i, float) in FLOATS.iter().enumerate() { - axtask::spawn(move || { - let mut value = float + i as f64; - axtask::yield_now(); - value -= i as f64; - - println!("fp_state_switch: Float {} = {}", i, value); - assert!((value - float).abs() < 1e-9); - FINISHED_TASKS.fetch_add(1, Ordering::Relaxed); - }); - } - while FINISHED_TASKS.load(Ordering::Relaxed) < NUM_TASKS { - axtask::yield_now(); - } -} - -#[test] -fn test_wait_queue() { - let _lock = SERIAL.lock(); - INIT.call_once(axtask::init_scheduler); - - const NUM_TASKS: usize = 10; - - static WQ1: WaitQueue = WaitQueue::new(); - static WQ2: WaitQueue = WaitQueue::new(); - static COUNTER: AtomicUsize = AtomicUsize::new(0); - - for _ in 0..NUM_TASKS { - axtask::spawn(move || { - COUNTER.fetch_add(1, Ordering::Relaxed); - println!("wait_queue: task {:?} started", current().id()); - WQ1.notify_one(true); // WQ1.wait_until() - WQ2.wait(); - - assert!(!current().in_wait_queue()); - - COUNTER.fetch_sub(1, Ordering::Relaxed); - println!("wait_queue: task {:?} finished", current().id()); - WQ1.notify_one(true); // WQ1.wait_until() - }); - } - - println!("task {:?} is waiting for tasks to start...", current().id()); - WQ1.wait_until(|| COUNTER.load(Ordering::Relaxed) == NUM_TASKS); - assert_eq!(COUNTER.load(Ordering::Relaxed), NUM_TASKS); - assert!(!current().in_wait_queue()); - WQ2.notify_all(true); // WQ2.wait() - - println!( - "task {:?} is waiting for tasks to finish...", - current().id() - ); - WQ1.wait_until(|| COUNTER.load(Ordering::Relaxed) == 0); - assert_eq!(COUNTER.load(Ordering::Relaxed), 0); - assert!(!current().in_wait_queue()); -} - -#[test] -fn test_task_join() { - let _lock = SERIAL.lock(); - INIT.call_once(axtask::init_scheduler); - - const NUM_TASKS: usize = 10; - let mut tasks = Vec::with_capacity(NUM_TASKS); - - for i in 0..NUM_TASKS { - tasks.push(axtask::spawn_raw( - move || { - println!("task_join: task {}! ({})", i, current().id_name()); - axtask::yield_now(); - axtask::exit(i as _); - }, - format!("T{}", i), - 0x1000, - )); - } - - for i in 0..NUM_TASKS { - assert_eq!(tasks[i].join(), Some(i as _)); - } -} diff --git a/arceos/modules/axtask/src/timers.rs b/arceos/modules/axtask/src/timers.rs deleted file mode 100644 index 1c4a8eed0..000000000 --- a/arceos/modules/axtask/src/timers.rs +++ /dev/null @@ -1,48 +0,0 @@ -use alloc::sync::Arc; -use axhal::time::wall_time; -use kspin::SpinNoIrq; -use lazyinit::LazyInit; -use timer_list::{TimeValue, TimerEvent, TimerList}; - -use crate::{AxTaskRef, RUN_QUEUE}; - -// TODO: per-CPU -static TIMER_LIST: LazyInit>> = LazyInit::new(); - -struct TaskWakeupEvent(AxTaskRef); - -impl TimerEvent for TaskWakeupEvent { - fn callback(self, _now: TimeValue) { - let mut rq = RUN_QUEUE.lock(); - self.0.set_in_timer_list(false); - rq.unblock_task(self.0, true); - } -} - -pub fn set_alarm_wakeup(deadline: TimeValue, task: AxTaskRef) { - let mut timers = TIMER_LIST.lock(); - task.set_in_timer_list(true); - timers.set(deadline, TaskWakeupEvent(task)); -} - -pub fn cancel_alarm(task: &AxTaskRef) { - let mut timers = TIMER_LIST.lock(); - task.set_in_timer_list(false); - timers.cancel(|t| Arc::ptr_eq(&t.0, task)); -} - -pub fn check_events() { - loop { - let now = wall_time(); - let event = TIMER_LIST.lock().expire_one(now); - if let Some((_deadline, event)) = event { - event.callback(now); - } else { - break; - } - } -} - -pub fn init() { - TIMER_LIST.init_once(SpinNoIrq::new(TimerList::new())); -} diff --git a/arceos/modules/axtask/src/wait_queue.rs b/arceos/modules/axtask/src/wait_queue.rs deleted file mode 100644 index d13628ad6..000000000 --- a/arceos/modules/axtask/src/wait_queue.rs +++ /dev/null @@ -1,216 +0,0 @@ -use alloc::collections::VecDeque; -use alloc::sync::Arc; -use kspin::SpinRaw; - -use crate::{AxRunQueue, AxTaskRef, CurrentTask, RUN_QUEUE}; - -/// A queue to store sleeping tasks. -/// -/// # Examples -/// -/// ``` -/// use axtask::WaitQueue; -/// use core::sync::atomic::{AtomicU32, Ordering}; -/// -/// static VALUE: AtomicU32 = AtomicU32::new(0); -/// static WQ: WaitQueue = WaitQueue::new(); -/// -/// axtask::init_scheduler(); -/// // spawn a new task that updates `VALUE` and notifies the main task -/// axtask::spawn(|| { -/// assert_eq!(VALUE.load(Ordering::Relaxed), 0); -/// VALUE.fetch_add(1, Ordering::Relaxed); -/// WQ.notify_one(true); // wake up the main task -/// }); -/// -/// WQ.wait(); // block until `notify()` is called -/// assert_eq!(VALUE.load(Ordering::Relaxed), 1); -/// ``` -pub struct WaitQueue { - queue: SpinRaw>, // we already disabled IRQs when lock the `RUN_QUEUE` -} - -impl WaitQueue { - /// Creates an empty wait queue. - pub const fn new() -> Self { - Self { - queue: SpinRaw::new(VecDeque::new()), - } - } - - /// Creates an empty wait queue with space for at least `capacity` elements. - pub fn with_capacity(capacity: usize) -> Self { - Self { - queue: SpinRaw::new(VecDeque::with_capacity(capacity)), - } - } - - fn cancel_events(&self, curr: CurrentTask) { - // A task can be wake up only one events (timer or `notify()`), remove - // the event from another queue. - if curr.in_wait_queue() { - // wake up by timer (timeout). - // `RUN_QUEUE` is not locked here, so disable IRQs. - let _guard = kernel_guard::IrqSave::new(); - self.queue.lock().retain(|t| !curr.ptr_eq(t)); - curr.set_in_wait_queue(false); - } - #[cfg(feature = "irq")] - if curr.in_timer_list() { - // timeout was set but not triggered (wake up by `WaitQueue::notify()`) - crate::timers::cancel_alarm(curr.as_task_ref()); - } - } - - /// Blocks the current task and put it into the wait queue, until other task - /// notifies it. - pub fn wait(&self) { - RUN_QUEUE.lock().block_current(|task| { - task.set_in_wait_queue(true); - self.queue.lock().push_back(task) - }); - self.cancel_events(crate::current()); - } - - /// Blocks the current task and put it into the wait queue, until the given - /// `condition` becomes true. - /// - /// Note that even other tasks notify this task, it will not wake up until - /// the condition becomes true. - pub fn wait_until(&self, condition: F) - where - F: Fn() -> bool, - { - loop { - let mut rq = RUN_QUEUE.lock(); - if condition() { - break; - } - rq.block_current(|task| { - task.set_in_wait_queue(true); - self.queue.lock().push_back(task); - }); - } - self.cancel_events(crate::current()); - } - - /// Blocks the current task and put it into the wait queue, until other tasks - /// notify it, or the given duration has elapsed. - #[cfg(feature = "irq")] - pub fn wait_timeout(&self, dur: core::time::Duration) -> bool { - let curr = crate::current(); - let deadline = axhal::time::wall_time() + dur; - debug!( - "task wait_timeout: {} deadline={:?}", - curr.id_name(), - deadline - ); - crate::timers::set_alarm_wakeup(deadline, curr.clone()); - - RUN_QUEUE.lock().block_current(|task| { - task.set_in_wait_queue(true); - self.queue.lock().push_back(task) - }); - let timeout = curr.in_wait_queue(); // still in the wait queue, must have timed out - self.cancel_events(curr); - timeout - } - - /// Blocks the current task and put it into the wait queue, until the given - /// `condition` becomes true, or the given duration has elapsed. - /// - /// Note that even other tasks notify this task, it will not wake up until - /// the above conditions are met. - #[cfg(feature = "irq")] - pub fn wait_timeout_until(&self, dur: core::time::Duration, condition: F) -> bool - where - F: Fn() -> bool, - { - let curr = crate::current(); - let deadline = axhal::time::wall_time() + dur; - debug!( - "task wait_timeout: {}, deadline={:?}", - curr.id_name(), - deadline - ); - crate::timers::set_alarm_wakeup(deadline, curr.clone()); - - let mut timeout = true; - while axhal::time::wall_time() < deadline { - let mut rq = RUN_QUEUE.lock(); - if condition() { - timeout = false; - break; - } - rq.block_current(|task| { - task.set_in_wait_queue(true); - self.queue.lock().push_back(task); - }); - } - self.cancel_events(curr); - timeout - } - - /// Wakes up one task in the wait queue, usually the first one. - /// - /// If `resched` is true, the current task will be preempted when the - /// preemption is enabled. - pub fn notify_one(&self, resched: bool) -> bool { - let mut rq = RUN_QUEUE.lock(); - if !self.queue.lock().is_empty() { - self.notify_one_locked(resched, &mut rq) - } else { - false - } - } - - /// Wakes all tasks in the wait queue. - /// - /// If `resched` is true, the current task will be preempted when the - /// preemption is enabled. - pub fn notify_all(&self, resched: bool) { - loop { - let mut rq = RUN_QUEUE.lock(); - if let Some(task) = self.queue.lock().pop_front() { - task.set_in_wait_queue(false); - rq.unblock_task(task, resched); - } else { - break; - } - drop(rq); // we must unlock `RUN_QUEUE` after unlocking `self.queue`. - } - } - - /// Wake up the given task in the wait queue. - /// - /// If `resched` is true, the current task will be preempted when the - /// preemption is enabled. - pub fn notify_task(&mut self, resched: bool, task: &AxTaskRef) -> bool { - let mut rq = RUN_QUEUE.lock(); - let mut wq = self.queue.lock(); - if let Some(index) = wq.iter().position(|t| Arc::ptr_eq(t, task)) { - task.set_in_wait_queue(false); - rq.unblock_task(wq.remove(index).unwrap(), resched); - true - } else { - false - } - } - - pub(crate) fn notify_one_locked(&self, resched: bool, rq: &mut AxRunQueue) -> bool { - if let Some(task) = self.queue.lock().pop_front() { - task.set_in_wait_queue(false); - rq.unblock_task(task, resched); - true - } else { - false - } - } - - pub(crate) fn notify_all_locked(&self, resched: bool, rq: &mut AxRunQueue) { - while let Some(task) = self.queue.lock().pop_front() { - task.set_in_wait_queue(false); - rq.unblock_task(task, resched); - } - } -} diff --git a/arceos/modules/bump_allocator/Cargo.toml b/arceos/modules/bump_allocator/Cargo.toml deleted file mode 100644 index deba6ab8d..000000000 --- a/arceos/modules/bump_allocator/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "bump_allocator" -edition = "2021" -version.workspace = true -authors.workspace = true -license.workspace = true -homepage.workspace = true -documentation.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true - -[dependencies] -allocator = { git = "https://github.com/arceos-org/allocator.git", tag ="v0.1.0", features = ["bitmap"] } diff --git a/arceos/modules/bump_allocator/src/lib.rs b/arceos/modules/bump_allocator/src/lib.rs deleted file mode 100644 index 6c70977bb..000000000 --- a/arceos/modules/bump_allocator/src/lib.rs +++ /dev/null @@ -1,88 +0,0 @@ -#![no_std] - -use allocator::{BaseAllocator, ByteAllocator, PageAllocator}; - -/// Early memory allocator -/// Use it before formal bytes-allocator and pages-allocator can work! -/// This is a double-end memory range: -/// - Alloc bytes forward -/// - Alloc pages backward -/// -/// [ bytes-used | avail-area | pages-used ] -/// | | --> <-- | | -/// start b_pos p_pos end -/// -/// For bytes area, 'count' records number of allocations. -/// When it goes down to ZERO, free bytes-used area. -/// For pages area, it will never be freed! -/// -pub struct EarlyAllocator {} - -impl EarlyAllocator { - pub const fn new() -> Self { - Self {} - } -} - -impl BaseAllocator for EarlyAllocator { - fn init(&mut self, start: usize, size: usize) { - todo!() - } - - fn add_memory(&mut self, start: usize, size: usize) -> allocator::AllocResult { - todo!() - } -} - -impl ByteAllocator for EarlyAllocator { - fn alloc( - &mut self, - layout: core::alloc::Layout, - ) -> allocator::AllocResult> { - todo!() - } - - fn dealloc(&mut self, pos: core::ptr::NonNull, layout: core::alloc::Layout) { - todo!() - } - - fn total_bytes(&self) -> usize { - todo!() - } - - fn used_bytes(&self) -> usize { - todo!() - } - - fn available_bytes(&self) -> usize { - todo!() - } -} - -impl PageAllocator for EarlyAllocator { - const PAGE_SIZE: usize = SIZE; - - fn alloc_pages( - &mut self, - num_pages: usize, - align_pow2: usize, - ) -> allocator::AllocResult { - todo!() - } - - fn dealloc_pages(&mut self, pos: usize, num_pages: usize) { - todo!() - } - - fn total_pages(&self) -> usize { - todo!() - } - - fn used_pages(&self) -> usize { - todo!() - } - - fn available_pages(&self) -> usize { - todo!() - } -} \ No newline at end of file diff --git a/arceos/modules/elf/.cargo-ok b/arceos/modules/elf/.cargo-ok deleted file mode 100644 index 5f8b79583..000000000 --- a/arceos/modules/elf/.cargo-ok +++ /dev/null @@ -1 +0,0 @@ -{"v":1} \ No newline at end of file diff --git a/arceos/modules/elf/.cargo_vcs_info.json b/arceos/modules/elf/.cargo_vcs_info.json deleted file mode 100644 index 632e8d00e..000000000 --- a/arceos/modules/elf/.cargo_vcs_info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "git": { - "sha1": "94d6780552465ebdc3d732f4a32d6bd00f1b8d70" - }, - "path_in_vcs": "" -} \ No newline at end of file diff --git a/arceos/modules/elf/CHANGELOG.md b/arceos/modules/elf/CHANGELOG.md deleted file mode 100644 index 76b4256eb..000000000 --- a/arceos/modules/elf/CHANGELOG.md +++ /dev/null @@ -1,190 +0,0 @@ -# Change Log -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/) - -## [0.7.4] - 2023-11-22 - -### Bug Fixes - -- Fix note parsing for notes with n_namesz == (align * x + 1) - -## [0.7.3] - 2023-10-09 - -### New Features - -- Derive Debug on LittleEndian and BigEndian - -### Misc Improvements - -- Enable #![forbid(unsafe_code)] -- Enable #![deny(missing_debug_implementations)] -- Enable #![warn(rust_2018_idioms)] -- Fix doc comment on file::Class -- Fix README example so it compiles - -## [0.7.2] - 2023-02-15 - -### New Features - -- Implement core::error::Error for ParsingError accessible via a new non-default "nightly" cargo feature -- Add abi constants for note descriptor types (n_type) -- Add C-style struct definitions for various abi structs (Elf[32|64]_Ehdr etc). These aren't used by the parser, but are useful definitions for folks wanting to manually muck with elf bytes. - -### Bug Fixes - -- Fix an 'attempt to shift right with overflow' panic in the GnuHashTable if nshift is wider than the bloom filter word size - -### Misc Improvements - -- Add doc comments for EM_* abi constants -- Tweak formatting and update language for various doc comments - -## [0.7.1] - 2023-01-08 - -### Bug Fixes - -- Fix a divide by zero panic in GnuHashTable.find() for tables with nbloom = 0 - -## [0.7.0] - 2022-11-14 - -### New Features - -- Add new ElfBytes type with better ergonomics for parsing from a &[u8] -- Add GnuHashTable which interprets the contents of a SHT_GNU_HASH section -- Add convenience method section_header_by_name to ElfBytes and ElfStream -- Add GnuBuildIdNote and parsing for NT_GNU_BUILD_ID note contents -- Add GnuAbiTagNote and parsing for NT_GNU_ABI_TAG note contents -- Add ElfBytes::symbol_version_table() to get the GNU extension symbol version table. -- Add ElfBytes::find_common_data() to efficiently discover common ELF structures -- Add a new endian-aware integer parsing trait impl -- Add ParsingTable.is_empty() -- Add abi constants for powerpc and powerpc64 -- Add abi constants for RISC-V -- Add abi constants for x86_64 -- Add abi constants for ARM32 and ARM64 (AARCH64) -- Add abi constant for GNU-extension ELF note name ELF_NOTE_GNU -- Add abi constant for PT_GNU_PROPERTY -- Add abi constants for SHN_ABS and SHN_COMMON -- Add elf::to_str::d_tag_to_str() -- Add elf::to_str::note_abi_tag_os_to_str() - -### Changed Interfaces - -- Rename elf::File -> elf::ElfStream and make it specific to the Read + Seek interface -- Rename gabi -> abi since it also includes extension constants -- Make ELF structures generic across the new endian-aware integer parsing trait EndianParse -- Refactor parsed Note type to be a typed enum -- Rename ElfStream::dynamic_section() -> dynamic() to match ElfBytes -- Change ElfStream::dynamic() to yield a DynamicTable just like in ElfBytes -- Standardize ElfBytes' interfaces for the .dynamic contents to return a DynamicTable -- Export the parsing utilities ParsingTable, ParsingIterator in the public interface -- Refactor section_headers_with_strtab to work with files that have shdrs but no shstrtab -- Remove redundant hash arg from SysVHashTable.find() -- Expose Class in the public interface alongside FileHeader -- Remove opinionated Display impl for file::Class -- Remove section_data_as_symbol_table() from public ElfBytes interface -- Change SymbolVersionTable::new() to take Options instead of Default-empty iterators -- Change ElfStream to parse out the ProgramHeaders into an allocated vec as part of ElfStream::open_stream() -- Change ElfStream to parse out the SectionHeaders into an allocated Vec as part of ElfStream::open_stream() - -### Bug Fixes - -- Properly parse program header table when ehdr.e_phnum > 0xffff -- Fix OOM in ElfStream parsing when parsing corrupted files -- Fix a divide by zero panic in SysVHashTable.find() for empty tables - -### Misc Improvements - -- Add more fuzz testing -- Add some simple parsing smoke tests for the various sample architecture objects -- Add sample object and testing with > 0xff00 section headers -- Add a lot more doc comments to each of the modules - -## [0.6.1] - 2022-11-05 - -### New Features -- Expose Class and Endian in the public interface. These types are exposed in the FileHeader type and so they should also be accessible for users to inspect. - -## [0.6.0] - 2022-11-01 - -### New Features - -- Add fuzz targets for parts of our ELF parsing interface via cargo-fuzz -- Add SysVHashTable which interprets the contents of a SHT_HASH section -- Add StringTable::get_raw() to get an uninterpreted &[u8] -- Add ParsingTable.len() method to get the number of elements in the table -- Add some note n_type constants for GNU extension notes. -- Add default "to_str" feature to get &str for gabi constant names - -### Changed Interfaces - -- Change File::segments() to return a ParsingTable instead of just a ParsingIterator -- Change File's SectionHeader interfaces to provide a ParsingTable instead of just a ParsingIterator -- Remove deprecated File::section_data_for_header() in favor of File::section_data() -- Remove FileHeader wrapper types OSABI, Architecture, and ObjectFileType -- Remove ProgramHeader wrapper types ProgType and ProgFlag -- Remove Symbol wrapper types SymbolType SymbolBind SymbolVis -- Remove wrapper type SectionType -- Remove unhelpful SectionFlag wrapper type -- Remove Display impl for FileHeader, SectionHeader, ProgramHeader, Symbol -- Remove ParseError::UnsupportedElfVersion in favor of more general ParseError::UnsupportedVersion - -### Bug Fixes - -- Fix divide by zero panic when parsing a note with alignment of 0 (Error instead of panic) -- Use checked integer math all over the parsing code (Error instead of panic or overflow) -- Fix note parsing for 8-byte aligned .note.gnu.property sections (Successfully parse instead of Erroring) -- Add size validation when parsing tables with entsizes (Error instead of panic) - -## [0.5.0] - 2022-10-30 - -### New Features - -- Add File::symbol_version_table() interface to get the GNU extension symbol versioning table -- Add Symbol.is_undefined() helper to check if a symbol is defined in this object -- Add File::section_data() which opportunistically parses the CompressionHeader if present - -### Bug Fixes - -- Fix StringTable to return a ParseError on index out of bounds instead of panicking -- Fix File::section_data_as_rels to properly parse Rels (not Relas) - -## [0.4.0] - 2022-10-24 - -### New Features - -- Add .note section and segment parsing -- Add .dynamic section and segment parsing -- Add .rel and .rela section parsing -- Add File::section_headers_with_strtab to get both a header iter and strtab concurrently. - -### Changed Interfaces - -- The ReadBytesAt trait was changed to be implemented for an owned CachedReadBytes. This means that File::open_stream now expects to move-own the CachedReadBytes as opposed to taking a mutable reference. - -## [0.3.1] - 2022-10-21 - -### New Features -- Add File::section_data_for_header() to get raw section data for a given section - -### Bug fixes -- Fix section header table parsing when ehdr.e_shnum > 0xff00 - -## [0.3.0] - 2022-10-20 - -### New Features -- Add a `no_std` option by fully moving the parser over to lazy zero-alloc parsing patterns. - - -[0.7.4]: https://github.com/cole14/rust-elf/compare/v0.7.3...v0.7.4 -[0.7.3]: https://github.com/cole14/rust-elf/compare/v0.7.2...v0.7.3 -[0.7.2]: https://github.com/cole14/rust-elf/compare/v0.7.1...v0.7.2 -[0.7.1]: https://github.com/cole14/rust-elf/compare/v0.7.0...v0.7.1 -[0.7.0]: https://github.com/cole14/rust-elf/compare/v0.6.1...v0.7.0 -[0.6.1]: https://github.com/cole14/rust-elf/compare/v0.6.0...v0.6.1 -[0.6.0]: https://github.com/cole14/rust-elf/compare/v0.5.0...v0.6.0 -[0.5.0]: https://github.com/cole14/rust-elf/compare/v0.4.0...v0.5.0 -[0.4.0]: https://github.com/cole14/rust-elf/compare/v0.3.1...v0.4.0 -[0.3.1]: https://github.com/cole14/rust-elf/compare/v0.3.0...v0.3.1 -[0.3.0]: https://github.com/cole14/rust-elf/compare/v0.2.0...v0.3.0 diff --git a/arceos/modules/elf/COPYRIGHT b/arceos/modules/elf/COPYRIGHT deleted file mode 100644 index 767cb81e4..000000000 --- a/arceos/modules/elf/COPYRIGHT +++ /dev/null @@ -1,12 +0,0 @@ -rust-elf is licensed under either of - - * Apache License, Version 2.0 (LICENSE-APACHE or - http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) - -at your option. - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. diff --git a/arceos/modules/elf/Cargo.toml b/arceos/modules/elf/Cargo.toml deleted file mode 100644 index 11dc49b65..000000000 --- a/arceos/modules/elf/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -edition = "2021" -name = "elf" -version = "0.7.4" -authors = ["Christopher Cole "] -exclude = [ - ".gitignore", - "/.github", - "/sample-objects", -] -description = "A pure-rust library for parsing ELF files" -documentation = "https://docs.rs/elf/latest/elf/" -readme = "README.md" -keywords = [ - "binary", - "elf", - "object", - "parser", -] -categories = [ - "no-std", - "os", - "embedded", -] -license = "MIT/Apache-2.0" -repository = "https://github.com/cole14/rust-elf/" - -[lib] -name = "elf" - -[dependencies] - -[features] -nightly = [] diff --git a/arceos/modules/elf/Cargo.toml.orig b/arceos/modules/elf/Cargo.toml.orig deleted file mode 100644 index b360816c5..000000000 --- a/arceos/modules/elf/Cargo.toml.orig +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "elf" -version = "0.7.4" -authors = ["Christopher Cole "] -license = "MIT/Apache-2.0" -repository = "https://github.com/cole14/rust-elf/" -documentation = "https://docs.rs/elf/latest/elf/" -description = "A pure-rust library for parsing ELF files" -keywords = ["binary", "elf", "object", "parser"] -categories = ["no-std", "os", "embedded"] -exclude = [".gitignore", "/.github", "/sample-objects"] -readme = "README.md" -edition = "2021" - -[lib] -name = "elf" - -[dependencies] - -[features] -default = ["std", "to_str"] -std = [] -to_str = [] -# Enable for nightly feature(error_in_core) to impl core::error::Error on ParseError -nightly = [] diff --git a/arceos/modules/elf/LICENSE-APACHE b/arceos/modules/elf/LICENSE-APACHE deleted file mode 100644 index ebe4b418f..000000000 --- a/arceos/modules/elf/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2016 Christopher Cole - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/arceos/modules/elf/LICENSE-MIT b/arceos/modules/elf/LICENSE-MIT deleted file mode 100644 index cdd6fa3fe..000000000 --- a/arceos/modules/elf/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2016 Christopher Cole - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/arceos/modules/elf/README.md b/arceos/modules/elf/README.md deleted file mode 100644 index eae313f65..000000000 --- a/arceos/modules/elf/README.md +++ /dev/null @@ -1,136 +0,0 @@ -[![](https://img.shields.io/crates/v/elf.svg)](https://crates.io/crates/elf) -[![](https://img.shields.io/crates/d/elf.svg)](https://crates.io/crates/elf) -[![Build Status](https://github.com/cole14/rust-elf/actions/workflows/rust.yml/badge.svg)](https://github.com/cole14/rust-elf/actions) -[![](https://docs.rs/elf/badge.svg)](https://docs.rs/elf/) - -# rust-elf - -The `elf` crate provides a pure-safe-rust interface for reading ELF object files. - -[Documentation](https://docs.rs/elf/) - -# Capabilities - -### ✨ Works in `no_std` environments ✨ -This crate provides an elf parsing interface which does not allocate or use any std -features, so it can be used in `no_std` environments such as kernels and bootloaders. -The no_std variant merely disables the additional stream-oriented `std:: Read + Seek` interface. -All core parsing functionality is the same! - -### ✨ Endian-aware ✨ -This crate handles translating between file and host endianness when -parsing the ELF contents and provides four endian parsing implementations -optimized to support the different common use-cases for an ELF parsing library. -Parsing is generic across the specifications and each trait impl represents a -specification that encapsulates an interface for parsing integers from some -set of allowed byte orderings. - -* `AnyEndian`: Dynamically parsing either byte order at runtime based on the type of ELF object being parsed. -* `BigEndian`/`LittleEndian`: For tools that know they only want to parse a single given byte order known at compile time. -* `NativeEndian`: For tools that know they want to parse the same byte order as the compilation target's byte order. - -When the limited specifications are used, errors are properly returned when asked to parse an ELF file -with an unexpected byte ordering. - -### ✨ Zero-alloc parser ✨ -This crate implements parsing in a way that avoids heap allocations. ELF structures -are parsed and stored on the stack and provided by patterns such as lazily parsed iterators -that yield stack allocated rust types, or lazily parsing tables that only parse out a particular -entry on table.get(index). The structures are copy-converted as needed from the underlying file -data into Rust's native struct representation. - -### ✨ Fuzz Tested ✨ -Various parts of the library are fuzz tested for panics and crashes (see `fuzz/`). - -Memory safety is a core goal, as is providing a safe interface that errors on bad data -over crashing or panicking. Checked integer math is used where appropriate, and ParseErrors are -returned when bad or corrupted ELF structures are encountered. - -### ✨ Uses only safe interfaces ✨ -With memory safety a core goal, this crate contains zero unsafe code blocks of -its own and only uses safe interface methods from core and std, so you can -trust in rust's memory safety guarantees without also having to trust this -library developer as having truly been "right" in why some unsafe block was -safe. 💃 - -Note: I'd love to see this crate be enhanced further once rust provides safe transmutes. - -See: - -### ✨ Some zero-copy interfaces ✨ -The StringTable, for instance, yields `&[u8]` and `&str` backed by the raw string table bytes. - -The `ElfBytes` parser type also does not make raw copies of the underlying file data to back -the parser lazy parser interfaces `ParsingIterator` and `ParsingTable`. They merely wrap byte slices -internally, and yield rust repr values on demand, which does entail copying of the bytes into the -parsed rust-native format. - -Depending on the use-case, it can be more efficient to restructure the raw ELF into different layouts -for more efficient interpretation, say, by re-indexing a flat table into a HashMap. `ParsingIterator`s -make that easy and rustily-intuitive. - -The `ParsingIterator`s are also nice in that you can easily zip/enumerate/filter/collect them -how you wish. Do you know that you want to do multiple passes over pairs from different tables? Just -zip/collect them into another type so you only parse/endian-flip each entry once! - -### ✨ Stream-based lazy i/o interface ✨ -The `ElfStream` parser type takes a `std:: Read + Seek` (such as `std::fs::File`) where ranges of -file contents are read lazily on-demand based on what the user wants to parse. - -This, alongside the bytes-oriented interface, allow you to decide which tradeoffs -you want to make. If you're going to be working with the whole file contents, -then the byte slice approach is probably worthwhile to minimize i/o overhead by -streaming the whole file into memory at once. If you're only going to be -inspecting part of the file, then the `ElfStream` approach would help avoid the -overhead of reading a bunch of unused file data just to parse out a few things, (like -grabbing the `.gnu.note.build-id`) - -### ✨ Tiny library with no dependencies and fast compilation times ✨ -Release-target compilation times on this developer's 2021 m1 macbook are sub-second. - -## Example using `ElfBytes`: - -```rust -use elf::ElfBytes; -use elf::endian::AnyEndian; -use elf::note::Note; -use elf::note::NoteGnuBuildId; -use elf::section::SectionHeader; - -let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so"); -let file_data = std::fs::read(path).expect("Could not read file."); -let slice = file_data.as_slice(); -let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - -// Get the ELF file's build-id -let abi_shdr: SectionHeader = file - .section_header_by_name(".note.gnu.build-id") - .expect("section table should be parseable") - .expect("file should have a .note.ABI-tag section"); - -let notes: Vec = file - .section_data_as_notes(&abi_shdr) - .expect("Should be able to get note section data") - .collect(); -assert_eq!( - notes[0], - Note::GnuBuildId(NoteGnuBuildId( - &[140, 51, 19, 23, 221, 90, 215, 131, 169, 13, - 210, 183, 215, 77, 216, 175, 167, 110, 3, 209])) -); - -// Find lazy-parsing types for the common ELF sections (we want .dynsym, .dynstr, .hash) -let common = file.find_common_data().expect("shdrs should parse"); -let (dynsyms, strtab) = (common.dynsyms.unwrap(), common.dynsyms_strs.unwrap()); -let hash_table = common.sysv_hash.unwrap(); - -// Use the hash table to find a given symbol in it. -let name = b"memset"; -let (sym_idx, sym) = hash_table.find(name, &dynsyms, &strtab) - .expect("hash table and symbols should parse").unwrap(); - -// Verify that we got the same symbol from the hash table we expected -assert_eq!(sym_idx, 2); -assert_eq!(strtab.get(sym.st_name as usize).unwrap(), "memset"); -assert_eq!(sym, dynsyms.get(sym_idx).unwrap()); -``` diff --git a/arceos/modules/elf/src/abi.rs b/arceos/modules/elf/src/abi.rs deleted file mode 100644 index 61ba47f6e..000000000 --- a/arceos/modules/elf/src/abi.rs +++ /dev/null @@ -1,2660 +0,0 @@ -//! Contains ELF constants defined in the ELF gABI and various extensions -// See -// Note: At least in 2022, it seems like the above site is not being updated. Official communication -// occurs on the Generic System V Application Binary Interface mailing list: -// - -// EI_* define indexes into the ELF File Header's e_ident[] byte array. -// We define them as usize in order to use them to easily index into [u8]. - -/// Location of first ELF magic number byte -pub const EI_MAG0: usize = 0; -/// Location of second ELF magic number byte -pub const EI_MAG1: usize = 1; -/// Location of third ELF magic number byte -pub const EI_MAG2: usize = 2; -/// Location of fourth ELF magic number byte -pub const EI_MAG3: usize = 3; -/// Location of ELF class field in ELF file header ident array -pub const EI_CLASS: usize = 4; -/// Location of data format field in ELF file header ident array -pub const EI_DATA: usize = 5; -/// Location of ELF version field in ELF file header ident array -pub const EI_VERSION: usize = 6; -/// Location of OS ABI field in ELF file header ident array -pub const EI_OSABI: usize = 7; -/// Location of ABI version field in ELF file header ident array -pub const EI_ABIVERSION: usize = 8; -/// Start of padding bytes -pub const EI_PAD: usize = 9; -/// Length of ELF file header platform-independent identification fields (e_ident[]) -pub const EI_NIDENT: usize = 16; - -/// ELF magic number byte 1 -pub const ELFMAG0: u8 = 0x7f; -/// ELF magic number byte 2 -pub const ELFMAG1: u8 = 0x45; -/// ELF magic number byte 3 -pub const ELFMAG2: u8 = 0x4c; -/// ELF magic number byte 4 -pub const ELFMAG3: u8 = 0x46; -pub const ELFMAGIC: [u8; 4] = [ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3]; - -// ELFCLASS* define constants for e_ident[EI_CLASS] - -/// Invalid ELF file class -pub const ELFCLASSNONE: u8 = 0; -/// 32-bit ELF file -pub const ELFCLASS32: u8 = 1; -/// 64-bit ELF file -pub const ELFCLASS64: u8 = 2; - -// ELFDATA* define constants for e_ident[EI_DATA] - -/// Invalid ELF data format -pub const ELFDATANONE: u8 = 0; -/// 2's complement values, with the least significant byte occupying the lowest address. -pub const ELFDATA2LSB: u8 = 1; -/// 2's complement values, with the most significant byte occupying the lowest address. -pub const ELFDATA2MSB: u8 = 2; - -// ELFOSABI* define constants for e_ident[EI_OSABI] - -/// No extensions or unspecified -pub const ELFOSABI_NONE: u8 = 0; -/// Alias of unspecified for UNIX System V ABI -pub const ELFOSABI_SYSV: u8 = 0; -/// Hewlett-Packard HP-UX -pub const ELFOSABI_HPUX: u8 = 1; -/// NetBSD -pub const ELFOSABI_NETBSD: u8 = 2; -/// GNU -pub const ELFOSABI_GNU: u8 = 3; -/// Linux historical - alias for ELFOSABI_GNU -pub const ELFOSABI_LINUX: u8 = 3; -/// Sun Solaris -pub const ELFOSABI_SOLARIS: u8 = 6; -/// AIX -pub const ELFOSABI_AIX: u8 = 7; -/// IRIX -pub const ELFOSABI_IRIX: u8 = 8; -/// FreeBSD -pub const ELFOSABI_FREEBSD: u8 = 9; -/// Compaq TRU64 UNIX -pub const ELFOSABI_TRU64: u8 = 10; -/// Novell Modesto -pub const ELFOSABI_MODESTO: u8 = 11; -/// Open BSD -pub const ELFOSABI_OPENBSD: u8 = 12; -/// Open VMS -pub const ELFOSABI_OPENVMS: u8 = 13; -/// Hewlett-Packard Non-Stop Kernel -pub const ELFOSABI_NSK: u8 = 14; -/// Amiga Research OS -pub const ELFOSABI_AROS: u8 = 15; -/// The FenixOS highly scalable multi-core OS -pub const ELFOSABI_FENIXOS: u8 = 16; -/// Nuxi CloudABI -pub const ELFOSABI_CLOUDABI: u8 = 17; -/// Stratus Technologies OpenVOS -pub const ELFOSABI_OPENVOS: u8 = 18; -/// 64-255 Architecture-specific value range - -// ET_* define constants for the ELF File Header's e_type field. -// Represented as Elf32_Half in Elf32_Ehdr and Elf64_Half in Elf64_Ehdr which -// are both are 2-byte unsigned integers with 2-byte alignment - -/// No file type -pub const ET_NONE: u16 = 0; -/// Relocatable file -pub const ET_REL: u16 = 1; -/// Executable file -pub const ET_EXEC: u16 = 2; -/// Shared object file -pub const ET_DYN: u16 = 3; -/// Core file -pub const ET_CORE: u16 = 4; -/// Operating system-specific -pub const ET_LOOS: u16 = 0xfe00; -/// Operating system-specific -pub const ET_HIOS: u16 = 0xfeff; -/// Processor-specific -pub const ET_LOPROC: u16 = 0xff00; -/// Processor-specific -pub const ET_HIPROC: u16 = 0xffff; - -// EM_* define constants for the ELF File Header's e_machine field. -// Represented as Elf32_Half in Elf32_Ehdr and Elf64_Half in Elf64_Ehdr which -// are both 2-byte unsigned integers with 2-byte alignment - -/// No machine -pub const EM_NONE: u16 = 0; -/// AT&T WE 32100 -pub const EM_M32: u16 = 1; -/// SPARC -pub const EM_SPARC: u16 = 2; -/// Intel 80386 -pub const EM_386: u16 = 3; -/// Motorola 68000 -pub const EM_68K: u16 = 4; -/// Motorola 88000 -pub const EM_88K: u16 = 5; -/// Intel MCU -pub const EM_IAMCU: u16 = 6; -/// Intel 80860 -pub const EM_860: u16 = 7; -/// MIPS I Architecture -pub const EM_MIPS: u16 = 8; -/// IBM System/370 Processor -pub const EM_S370: u16 = 9; -/// MIPS RS3000 Little-endian -pub const EM_MIPS_RS3_LE: u16 = 10; -// 11-14 Reserved for future use -/// Hewlett-Packard PA-RISC -pub const EM_PARISC: u16 = 15; -// 16 Reserved for future use -/// Fujitsu VPP500 -pub const EM_VPP500: u16 = 17; -/// Enhanced instruction set SPARC -pub const EM_SPARC32PLUS: u16 = 18; -/// Intel 80960 -pub const EM_960: u16 = 19; -/// PowerPC -pub const EM_PPC: u16 = 20; -/// 64-bit PowerPC -pub const EM_PPC64: u16 = 21; -/// IBM System/390 Processor -pub const EM_S390: u16 = 22; -/// IBM SPU/SPC -pub const EM_SPU: u16 = 23; -// 24-35 Reserved for future use -/// NEC V800 -pub const EM_V800: u16 = 36; -/// Fujitsu FR20 -pub const EM_FR20: u16 = 37; -/// TRW RH-32 -pub const EM_RH32: u16 = 38; -/// Motorola RCE -pub const EM_RCE: u16 = 39; -/// ARM 32-bit architecture (AARCH32) -pub const EM_ARM: u16 = 40; -/// Digital Alpha -pub const EM_ALPHA: u16 = 41; -/// Hitachi SH -pub const EM_SH: u16 = 42; -/// SPARC Version 9 -pub const EM_SPARCV9: u16 = 43; -/// Siemens TriCore embedded processor -pub const EM_TRICORE: u16 = 44; -/// Argonaut RISC Core, Argonaut Technologies Inc. -pub const EM_ARC: u16 = 45; -/// Hitachi H8/300 -pub const EM_H8_300: u16 = 46; -/// Hitachi H8/300H -pub const EM_H8_300H: u16 = 47; -/// Hitachi H8S -pub const EM_H8S: u16 = 48; -/// Hitachi H8/500 -pub const EM_H8_500: u16 = 49; -/// Intel IA-64 processor architecture -pub const EM_IA_64: u16 = 50; -/// Stanford MIPS-X -pub const EM_MIPS_X: u16 = 51; -/// Motorola ColdFire -pub const EM_COLDFIRE: u16 = 52; -/// Motorola M68HC12 -pub const EM_68HC12: u16 = 53; -/// Fujitsu MMA Multimedia Accelerator -pub const EM_MMA: u16 = 54; -/// Siemens PCP -pub const EM_PCP: u16 = 55; -/// Sony nCPU embedded RISC processor -pub const EM_NCPU: u16 = 56; -/// Denso NDR1 microprocessor -pub const EM_NDR1: u16 = 57; -/// Motorola Star*Core processor -pub const EM_STARCORE: u16 = 58; -/// Toyota ME16 processor -pub const EM_ME16: u16 = 59; -/// STMicroelectronics ST100 processor -pub const EM_ST100: u16 = 60; -/// Advanced Logic Corp. TinyJ embedded processor family -pub const EM_TINYJ: u16 = 61; -/// AMD x86-64 architecture -pub const EM_X86_64: u16 = 62; -/// Sony DSP Processor -pub const EM_PDSP: u16 = 63; -/// Digital Equipment Corp. PDP-10 -pub const EM_PDP10: u16 = 64; -/// Digital Equipment Corp. PDP-11 -pub const EM_PDP11: u16 = 65; -/// Siemens FX66 microcontroller -pub const EM_FX66: u16 = 66; -/// STMicroelectronics ST9+ 8/16 bit microcontroller -pub const EM_ST9PLUS: u16 = 67; -/// STMicroelectronics ST7 8-bit microcontroller -pub const EM_ST7: u16 = 68; -/// Motorola MC68HC16 Microcontroller -pub const EM_68HC16: u16 = 69; -/// Motorola MC68HC11 Microcontroller -pub const EM_68HC11: u16 = 70; -/// Motorola MC68HC08 Microcontroller -pub const EM_68HC08: u16 = 71; -/// Motorola MC68HC05 Microcontroller -pub const EM_68HC05: u16 = 72; -/// Silicon Graphics SVx -pub const EM_SVX: u16 = 73; -/// STMicroelectronics ST19 8-bit microcontroller -pub const EM_ST19: u16 = 74; -/// Digital VAX -pub const EM_VAX: u16 = 75; -/// Axis Communications 32-bit embedded processor -pub const EM_CRIS: u16 = 76; -/// Infineon Technologies 32-bit embedded processor -pub const EM_JAVELIN: u16 = 77; -/// Element 14 64-bit DSP Processor -pub const EM_FIREPATH: u16 = 78; -/// LSI Logic 16-bit DSP Processor -pub const EM_ZSP: u16 = 79; -/// Donald Knuth's educational 64-bit processor -pub const EM_MMIX: u16 = 80; -/// Harvard University machine-independent object files -pub const EM_HUANY: u16 = 81; -/// SiTera Prism -pub const EM_PRISM: u16 = 82; -/// Atmel AVR 8-bit microcontroller -pub const EM_AVR: u16 = 83; -/// Fujitsu FR30 -pub const EM_FR30: u16 = 84; -/// Mitsubishi D10V -pub const EM_D10V: u16 = 85; -/// Mitsubishi D30V -pub const EM_D30V: u16 = 86; -/// NEC v850 -pub const EM_V850: u16 = 87; -/// Mitsubishi M32R -pub const EM_M32R: u16 = 88; -/// Matsushita MN10300 -pub const EM_MN10300: u16 = 89; -/// Matsushita MN10200 -pub const EM_MN10200: u16 = 90; -/// picoJava -pub const EM_PJ: u16 = 91; -/// OpenRISC 32-bit embedded processor -pub const EM_OPENRISC: u16 = 92; -/// ARC International ARCompact processor (old spelling/synonym: EM_ARC_A5) -pub const EM_ARC_COMPACT: u16 = 93; -/// Tensilica Xtensa Architecture -pub const EM_XTENSA: u16 = 94; -/// Alphamosaic VideoCore processor -pub const EM_VIDEOCORE: u16 = 95; -/// Thompson Multimedia General Purpose Processor -pub const EM_TMM_GPP: u16 = 96; -/// National Semiconductor 32000 series -pub const EM_NS32K: u16 = 97; -/// Tenor Network TPC processor -pub const EM_TPC: u16 = 98; -/// Trebia SNP 1000 processor -pub const EM_SNP1K: u16 = 99; -/// STMicroelectronics (www.st.com) ST200 microcontroller -pub const EM_ST200: u16 = 100; -/// Ubicom IP2xxx microcontroller family -pub const EM_IP2K: u16 = 101; -/// MAX Processor -pub const EM_MAX: u16 = 102; -/// National Semiconductor CompactRISC microprocessor -pub const EM_CR: u16 = 103; -/// Fujitsu F2MC16 -pub const EM_F2MC16: u16 = 104; -/// Texas Instruments embedded microcontroller msp430 -pub const EM_MSP430: u16 = 105; -/// Analog Devices Blackfin (DSP) processor -pub const EM_BLACKFIN: u16 = 106; -/// S1C33 Family of Seiko Epson processors -pub const EM_SE_C33: u16 = 107; -/// Sharp embedded microprocessor -pub const EM_SEP: u16 = 108; -/// Arca RISC Microprocessor -pub const EM_ARCA: u16 = 109; -/// Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University -pub const EM_UNICORE: u16 = 110; -/// eXcess: 16/32/64-bit configurable embedded CPU -pub const EM_EXCESS: u16 = 111; -/// Icera Semiconductor Inc. Deep Execution Processor -pub const EM_DXP: u16 = 112; -/// Altera Nios II soft-core processor -pub const EM_ALTERA_NIOS2: u16 = 113; -/// National Semiconductor CompactRISC CRX microprocessor -pub const EM_CRX: u16 = 114; -/// Motorola XGATE embedded processor -pub const EM_XGATE: u16 = 115; -/// Infineon C16x/XC16x processor -pub const EM_C166: u16 = 116; -/// Renesas M16C series microprocessors -pub const EM_M16C: u16 = 117; -/// Microchip Technology dsPIC30F Digital Signal Controller -pub const EM_DSPIC30F: u16 = 118; -/// Freescale Communication Engine RISC core -pub const EM_CE: u16 = 119; -/// Renesas M32C series microprocessors -pub const EM_M32C: u16 = 120; -// 121-130 Reserved for future use -/// Altium TSK3000 core -pub const EM_TSK3000: u16 = 131; -/// Freescale RS08 embedded processor -pub const EM_RS08: u16 = 132; -/// Analog Devices SHARC family of 32-bit DSP processors -pub const EM_SHARC: u16 = 133; -/// Cyan Technology eCOG2 microprocessor -pub const EM_ECOG2: u16 = 134; -/// Sunplus S+core7 RISC processor -pub const EM_SCORE7: u16 = 135; -/// New Japan Radio (NJR) 24-bit DSP Processor -pub const EM_DSP24: u16 = 136; -/// Broadcom VideoCore III processor -pub const EM_VIDEOCORE3: u16 = 137; -/// RISC processor for Lattice FPGA architecture -pub const EM_LATTICEMICO32: u16 = 138; -/// Seiko Epson C17 family -pub const EM_SE_C17: u16 = 139; -/// The Texas Instruments TMS320C6000 DSP family -pub const EM_TI_C6000: u16 = 140; -/// The Texas Instruments TMS320C2000 DSP family -pub const EM_TI_C2000: u16 = 141; -/// The Texas Instruments TMS320C55x DSP family -pub const EM_TI_C5500: u16 = 142; -/// Texas Instruments Application Specific RISC Processor, 32bit fetch -pub const EM_TI_ARP32: u16 = 143; -/// Texas Instruments Programmable Realtime Unit -pub const EM_TI_PRU: u16 = 144; -// 145-159 Reserved for future use -/// STMicroelectronics 64bit VLIW Data Signal Processor -pub const EM_MMDSP_PLUS: u16 = 160; -/// Cypress M8C microprocessor -pub const EM_CYPRESS_M8C: u16 = 161; -/// Renesas R32C series microprocessors -pub const EM_R32C: u16 = 162; -/// NXP Semiconductors TriMedia architecture family -pub const EM_TRIMEDIA: u16 = 163; -/// QUALCOMM DSP6 Processor -pub const EM_QDSP6: u16 = 164; -/// Intel 8051 and variants -pub const EM_8051: u16 = 165; -/// STMicroelectronics STxP7x family of configurable and extensible RISC processors -pub const EM_STXP7X: u16 = 166; -/// Andes Technology compact code size embedded RISC processor family -pub const EM_NDS32: u16 = 167; -/// Cyan Technology eCOG1X family -pub const EM_ECOG1: u16 = 168; -/// Cyan Technology eCOG1X family -pub const EM_ECOG1X: u16 = 168; -/// Dallas Semiconductor MAXQ30 Core Micro-controllers -pub const EM_MAXQ30: u16 = 169; -/// New Japan Radio (NJR) 16-bit DSP Processor -pub const EM_XIMO16: u16 = 170; -/// M2000 Reconfigurable RISC Microprocessor -pub const EM_MANIK: u16 = 171; -/// Cray Inc. NV2 vector architecture -pub const EM_CRAYNV2: u16 = 172; -/// Renesas RX family -pub const EM_RX: u16 = 173; -/// Imagination Technologies META processor architecture -pub const EM_METAG: u16 = 174; -/// MCST Elbrus general purpose hardware architecture -pub const EM_MCST_ELBRUS: u16 = 175; -/// Cyan Technology eCOG16 family -pub const EM_ECOG16: u16 = 176; -/// National Semiconductor CompactRISC CR16 16-bit microprocessor -pub const EM_CR16: u16 = 177; -/// Freescale Extended Time Processing Unit -pub const EM_ETPU: u16 = 178; -/// Infineon Technologies SLE9X core -pub const EM_SLE9X: u16 = 179; -/// Intel L10M -pub const EM_L10M: u16 = 180; -/// Intel K10M -pub const EM_K10M: u16 = 181; -// 182 Reserved for future Intel use -/// ARM 64-bit architecture (AARCH64) -pub const EM_AARCH64: u16 = 183; -// 184 Reserved for future ARM use -/// Atmel Corporation 32-bit microprocessor family -pub const EM_AVR32: u16 = 185; -/// STMicroeletronics STM8 8-bit microcontroller -pub const EM_STM8: u16 = 186; -/// Tilera TILE64 multicore architecture family -pub const EM_TILE64: u16 = 187; -/// Tilera TILEPro multicore architecture family -pub const EM_TILEPRO: u16 = 188; -/// Xilinx MicroBlaze 32-bit RISC soft processor core -pub const EM_MICROBLAZE: u16 = 189; -/// NVIDIA CUDA architecture -pub const EM_CUDA: u16 = 190; -/// Tilera TILE-Gx multicore architecture family -pub const EM_TILEGX: u16 = 191; -/// CloudShield architecture family -pub const EM_CLOUDSHIELD: u16 = 192; -/// KIPO-KAIST Core-A 1st generation processor family -pub const EM_COREA_1ST: u16 = 193; -/// KIPO-KAIST Core-A 2nd generation processor family -pub const EM_COREA_2ND: u16 = 194; -/// Synopsys ARCompact V2 -pub const EM_ARC_COMPACT2: u16 = 195; -/// Open8 8-bit RISC soft processor core -pub const EM_OPEN8: u16 = 196; -/// Renesas RL78 family -pub const EM_RL78: u16 = 197; -/// Broadcom VideoCore V processor -pub const EM_VIDEOCORE5: u16 = 198; -/// Renesas 78KOR family -pub const EM_78KOR: u16 = 199; -/// Freescale 56800EX Digital Signal Controller (DSC) -pub const EM_56800EX: u16 = 200; -/// Beyond BA1 CPU architecture -pub const EM_BA1: u16 = 201; -/// Beyond BA2 CPU architecture -pub const EM_BA2: u16 = 202; -/// XMOS xCORE processor family -pub const EM_XCORE: u16 = 203; -/// Microchip 8-bit PIC(r) family -pub const EM_MCHP_PIC: u16 = 204; -/// Reserved by Intel -pub const EM_INTEL205: u16 = 205; -/// Reserved by Intel -pub const EM_INTEL206: u16 = 206; -/// Reserved by Intel -pub const EM_INTEL207: u16 = 207; -/// Reserved by Intel -pub const EM_INTEL208: u16 = 208; -/// Reserved by Intel -pub const EM_INTEL209: u16 = 209; -/// KM211 KM32 32-bit processor -pub const EM_KM32: u16 = 210; -/// KM211 KMX32 32-bit processor -pub const EM_KMX32: u16 = 211; -/// KM211 KMX16 16-bit processor -pub const EM_KMX16: u16 = 212; -/// KM211 KMX8 8-bit processor -pub const EM_KMX8: u16 = 213; -/// KM211 KVARC processor -pub const EM_KVARC: u16 = 214; -/// Paneve CDP architecture family -pub const EM_CDP: u16 = 215; -/// Cognitive Smart Memory Processor -pub const EM_COGE: u16 = 216; -/// Bluechip Systems CoolEngine -pub const EM_COOL: u16 = 217; -/// Nanoradio Optimized RISC -pub const EM_NORC: u16 = 218; -/// CSR Kalimba architecture family -pub const EM_CSR_KALIMBA: u16 = 219; -/// Zilog Z80 -pub const EM_Z80: u16 = 220; -/// Controls and Data Services VISIUMcore processor -pub const EM_VISIUM: u16 = 221; -/// FTDI Chip FT32 high performance 32-bit RISC architecture -pub const EM_FT32: u16 = 222; -/// Moxie processor family -pub const EM_MOXIE: u16 = 223; -/// AMD GPU architecture -pub const EM_AMDGPU: u16 = 224; -/// RISC-V -pub const EM_RISCV: u16 = 243; -/// Linux BPF -pub const EM_BPF: u16 = 247; - -// EV_* define constants for the ELF File Header's e_version field. -// Represented as Elf32_Word in Elf32_Ehdr and Elf64_Word in Elf64_Ehdr which -// are both 4-byte unsigned integers with 4-byte alignment - -/// Invalid version -pub const EV_NONE: u8 = 0; -/// Current version -pub const EV_CURRENT: u8 = 1; - -/// If the number of program headers is greater than or equal to PN_XNUM (0xffff), -/// this member has the value PN_XNUM (0xffff). The actual number of -/// program header table entries is contained in the sh_info field of the -/// section header at index 0. Otherwise, the sh_info member of the initial -/// section header entry contains the value zero. -pub const PN_XNUM: u16 = 0xffff; - -// PF_* define constants for the ELF Program Header's p_flags field. -// Represented as Elf32_Word in Elf32_Ehdr and Elf64_Word in Elf64_Ehdr which -// are both 4-byte unsigned integers with 4-byte alignment - -pub const PF_NONE: u32 = 0; -/// Executable program segment -pub const PF_X: u32 = 1; -/// Writable program segment -pub const PF_W: u32 = 2; -/// Readable program segment -pub const PF_R: u32 = 4; -// All bits included in the PF_MASKOS mask are reserved for operating system-specific semantics. -pub const PF_MASKOS: u32 = 0x0ff00000; -// All bits included in the PF_MASKPROC mask are reserved for processor-specific semantics. -pub const PF_MASKPROC: u32 = 0xf0000000; - -// PT_* define constants for the ELF Program Header's p_type field. -// Represented as Elf32_Word in Elf32_Ehdr and Elf64_Word in Elf64_Ehdr which -// are both 4-byte unsigned integers with 4-byte alignment - -/// Program header table entry unused -pub const PT_NULL: u32 = 0; -/// Loadable program segment -pub const PT_LOAD: u32 = 1; -/// Dynamic linking information -pub const PT_DYNAMIC: u32 = 2; -/// Program interpreter -pub const PT_INTERP: u32 = 3; -/// Auxiliary information -pub const PT_NOTE: u32 = 4; -/// Unused -pub const PT_SHLIB: u32 = 5; -/// The program header table -pub const PT_PHDR: u32 = 6; -/// Thread-local storage segment -pub const PT_TLS: u32 = 7; -/// GCC .eh_frame_hdr segment -pub const PT_GNU_EH_FRAME: u32 = 0x6474e550; -/// Indicates stack executability -pub const PT_GNU_STACK: u32 = 0x6474e551; -/// Read-only after relocation -pub const PT_GNU_RELRO: u32 = 0x6474e552; -/// The segment contains .note.gnu.property section -pub const PT_GNU_PROPERTY: u32 = 0x6474e553; -/// Values between [PT_LOOS, PT_HIOS] in this inclusive range are reserved for -/// operating system-specific semantics. -pub const PT_LOOS: u32 = 0x60000000; -/// Values between [PT_LOOS, PT_HIOS] in this inclusive range are reserved for -/// operating system-specific semantics. -pub const PT_HIOS: u32 = 0x6fffffff; -/// Values between [PT_LOPROC, PT_HIPROC] in this inclusive range are reserved -/// for processor-specific semantics. -pub const PT_LOPROC: u32 = 0x70000000; -/// Values between [PT_LOPROC, PT_HIPROC] in this inclusive range are reserved -/// for processor-specific semantics. -pub const PT_HIPROC: u32 = 0x7fffffff; - -// SHT_* define constants for the ELF Section Header's p_type field. -// Represented as Elf32_Word in Elf32_Ehdr and Elf64_Word in Elf64_Ehdr which -// are both 4-byte unsigned integers with 4-byte alignment - -/// Inactive section with undefined values -pub const SHT_NULL: u32 = 0; -/// Information defined by the program, includes executable code and data -pub const SHT_PROGBITS: u32 = 1; -/// Section data contains a symbol table -pub const SHT_SYMTAB: u32 = 2; -/// Section data contains a string table -pub const SHT_STRTAB: u32 = 3; -/// Section data contains relocation entries with explicit addends -pub const SHT_RELA: u32 = 4; -/// Section data contains a symbol hash table. Must be present for dynamic linking -pub const SHT_HASH: u32 = 5; -/// Section data contains information for dynamic linking -pub const SHT_DYNAMIC: u32 = 6; -/// Section data contains information that marks the file in some way -pub const SHT_NOTE: u32 = 7; -/// Section data occupies no space in the file but otherwise resembles SHT_PROGBITS -pub const SHT_NOBITS: u32 = 8; -/// Section data contains relocation entries without explicit addends -pub const SHT_REL: u32 = 9; -/// Section is reserved but has unspecified semantics -pub const SHT_SHLIB: u32 = 10; -/// Section data contains a minimal set of dynamic linking symbols -pub const SHT_DYNSYM: u32 = 11; -/// Section data contains an array of constructors -pub const SHT_INIT_ARRAY: u32 = 14; -/// Section data contains an array of destructors -pub const SHT_FINI_ARRAY: u32 = 15; -/// Section data contains an array of pre-constructors -pub const SHT_PREINIT_ARRAY: u32 = 16; -/// Section group -pub const SHT_GROUP: u32 = 17; -/// Extended symbol table section index -pub const SHT_SYMTAB_SHNDX: u32 = 18; -/// Values in [SHT_LOOS, SHT_HIOS] are reserved for operating system-specific semantics. -pub const SHT_LOOS: u32 = 0x60000000; -/// Object attributes -pub const SHT_GNU_ATTRIBUTES: u32 = 0x6ffffff5; -/// GNU-style hash section -pub const SHT_GNU_HASH: u32 = 0x6ffffff6; -/// Pre-link library list -pub const SHT_GNU_LIBLIST: u32 = 0x6ffffff7; -/// Version definition section -pub const SHT_GNU_VERDEF: u32 = 0x6ffffffd; -/// Version needs section -pub const SHT_GNU_VERNEED: u32 = 0x6ffffffe; -/// Version symbol table -pub const SHT_GNU_VERSYM: u32 = 0x6fffffff; -/// Values in [SHT_LOOS, SHT_HIOS] are reserved for operating system-specific semantics. -pub const SHT_HIOS: u32 = 0x6fffffff; -/// Values in [SHT_LOPROC, SHT_HIPROC] are reserved for processor-specific semantics. -pub const SHT_LOPROC: u32 = 0x70000000; -/// IA_64 extension bits -pub const SHT_IA_64_EXT: u32 = 0x70000000; // SHT_LOPROC + 0; -/// IA_64 unwind section -pub const SHT_IA_64_UNWIND: u32 = 0x70000001; // SHT_LOPROC + 1; -/// Values in [SHT_LOPROC, SHT_HIPROC] are reserved for processor-specific semantics. -pub const SHT_HIPROC: u32 = 0x7fffffff; -/// Values in [SHT_LOUSER, SHT_HIUSER] are reserved for application-specific semantics. -pub const SHT_LOUSER: u32 = 0x80000000; -/// Values in [SHT_LOUSER, SHT_HIUSER] are reserved for application-specific semantics. -pub const SHT_HIUSER: u32 = 0x8fffffff; - -/// This value marks an undefined, missing, irrelevant, or otherwise meaningless -/// section reference. -pub const SHN_UNDEF: u16 = 0; -/// Symbols with st_shndx=SHN_ABS are absolute and are not affected by relocation. -pub const SHN_ABS: u16 = 0xfff1; -/// Symbols with st_shndx=SHN_COMMON are sometimes used for unallocated C external variables. -pub const SHN_COMMON: u16 = 0xfff2; -pub const SHN_XINDEX: u16 = 0xffff; - -// SHF_* define constants for the ELF Section Header's sh_flags field. -// Represented as Elf32_Word in Elf32_Ehdr and Elf64_Xword in Elf64_Ehdr which -// are both 4-byte and 8-byte unsigned integers, respectively. -// All of the constants are < 32-bits, so we use a u32 to represent these in order -// to make working with them easier. - -/// Empty flags -pub const SHF_NONE: u32 = 0; -/// The section contains data that should be writable during process execution. -pub const SHF_WRITE: u32 = 1; -/// The section occupies memory during process execution. Some control sections -/// do not reside in the memory image of an object file; this attribute is off for -/// those sections. -pub const SHF_ALLOC: u32 = 1 << 1; -/// The section contains executable machine instructions. -pub const SHF_EXECINSTR: u32 = 1 << 2; -/// The data in the section may be merged to eliminate duplication. Unless the -/// SHF_STRINGS flag is also set, the data elements in the section are of a uniform size. -/// The size of each element is specified in the section header's sh_entsize field. If -/// the SHF_STRINGS flag is also set, the data elements consist of null-terminated -/// character strings. The size of each character is specified in the section header's -/// sh_entsize field. -/// -/// Each element in the section is compared against other elements in sections with the -/// same name, type and flags. Elements that would have identical values at program -/// run-time may be merged. Relocations referencing elements of such sections must be -/// resolved to the merged locations of the referenced values. Note that any relocatable -/// values, including values that would result in run-time relocations, must be analyzed -/// to determine whether the run-time values would actually be identical. An -/// ABI-conforming object file may not depend on specific elements being merged, and an -/// ABI-conforming link editor may choose not to merge specific elements. -pub const SHF_MERGE: u32 = 1 << 4; -/// The data elements in the section consist of null-terminated character strings. -/// The size of each character is specified in the section header's sh_entsize field. -pub const SHF_STRINGS: u32 = 1 << 5; -/// The sh_info field of this section header holds a section header table index. -pub const SHF_INFO_LINK: u32 = 1 << 6; -/// This flag adds special ordering requirements for link editors. The requirements -/// apply if the sh_link field of this section's header references another section (the -/// linked-to section). If this section is combined with other sections in the output -/// file, it must appear in the same relative order with respect to those sections, -/// as the linked-to section appears with respect to sections the linked-to section is -/// combined with. -pub const SHF_LINK_ORDER: u32 = 1 << 7; -/// This section requires special OS-specific processing (beyond the standard linking -/// rules) to avoid incorrect behavior. If this section has either an sh_type value or -/// contains sh_flags bits in the OS-specific ranges for those fields, and a link -/// editor processing this section does not recognize those values, then the link editor -/// should reject the object file containing this section with an error. -pub const SHF_OS_NONCONFORMING: u32 = 1 << 8; -/// This section is a member (perhaps the only one) of a section group. The section must -/// be referenced by a section of type SHT_GROUP. The SHF_GROUP flag may be set only for -/// sections contained in relocatable objects (objects with the ELF header e_type member -/// set to ET_REL). -pub const SHF_GROUP: u32 = 1 << 9; -/// This section holds Thread-Local Storage, meaning that each separate execution flow -/// has its own distinct instance of this data. Implementations need not support this flag. -pub const SHF_TLS: u32 = 1 << 10; -/// This flag identifies a section containing compressed data. SHF_COMPRESSED applies only -/// to non-allocable sections, and cannot be used in conjunction with SHF_ALLOC. In -/// addition, SHF_COMPRESSED cannot be applied to sections of type SHT_NOBITS. -/// -/// All relocations to a compressed section specifiy offsets to the uncompressed section -/// data. It is therefore necessary to decompress the section data before relocations can -/// be applied. Each compressed section specifies the algorithm independently. It is -/// permissible for different sections in a given ELF object to employ different -/// compression algorithms. -/// -/// Compressed sections begin with a compression header structure that identifies the -/// compression algorithm. -pub const SHF_COMPRESSED: u32 = 1 << 11; -/// Masked bits are reserved for operating system-specific semantics. -pub const SHF_MASKOS: u32 = 0x0ff00000; -/// Masked bits are reserved for processor-specific semantics. -pub const SHF_MASKPROC: u32 = 0xf0000000; - -// STT_* define constants for the ELF Symbol's st_type (encoded in the st_info field). - -/// Unspecified symbol type -pub const STT_NOTYPE: u8 = 0; -/// Data object symbol -pub const STT_OBJECT: u8 = 1; -/// Code object symbol -pub const STT_FUNC: u8 = 2; -/// Section symbol -pub const STT_SECTION: u8 = 3; -/// File name symbol -pub const STT_FILE: u8 = 4; -/// Common data object symbol -pub const STT_COMMON: u8 = 5; -/// Thread-local data object symbol -pub const STT_TLS: u8 = 6; -/// Indirect code object symbol -pub const STT_GNU_IFUNC: u8 = 10; -/// Values between [STT_LOOS, STT_HIOS] in this inclusive range are reserved for -/// operating system-specific semantics. -pub const STT_LOOS: u8 = 10; -/// Values between [STT_LOOS, STT_HIOS] in this inclusive range are reserved for -/// operating system-specific semantics. -pub const STT_HIOS: u8 = 12; -/// Values between [STT_LOPROC, STT_HIPROC] in this inclusive range are reserved -/// for processor-specific semantics. -pub const STT_LOPROC: u8 = 13; -/// Values between [STT_LOPROC, STT_HIPROC] in this inclusive range are reserved -/// for processor-specific semantics. -pub const STT_HIPROC: u8 = 15; - -// STB_* define constants for the ELF Symbol's st_bind (encoded in the st_info field). - -/// Local symbols are not visible outside the object file containing their -/// definition. Local symbols of the same name may exist in multiple files -/// without interfering with each other. -pub const STB_LOCAL: u8 = 0; -/// Global symbols are visible to all object files being combined. One file's -/// definition of a global symbol will satisfy another file's undefined -/// reference to the same global symbol. -pub const STB_GLOBAL: u8 = 1; -/// Weak symbols resemble global symbols, but their definitions have lower -/// precedence. -pub const STB_WEAK: u8 = 2; -/// Unique symbol -pub const STB_GNU_UNIQUE: u8 = 10; -/// Values between [STB_LOOS, STB_HIOS] in this inclusive range are reserved for -/// operating system-specific semantics. -pub const STB_LOOS: u8 = 10; -/// Values between [STB_LOOS, STB_HIOS] in this inclusive range are reserved for -/// operating system-specific semantics. -pub const STB_HIOS: u8 = 12; -/// Values between [STB_LOPROC, STB_HIPROC] in this inclusive range are reserved -/// for processor-specific semantics. -pub const STB_LOPROC: u8 = 13; -/// Values between [STB_LOPROC, STB_HIPROC] in this inclusive range are reserved -/// for processor-specific semantics. -pub const STB_HIPROC: u8 = 15; - -/// STV_* define constants for the ELF Symbol's st_visibility (encoded in the st_other field). - -/// The visibility of symbols with the STV_DEFAULT attribute is as specified by -/// the symbol's binding type. That is, global and weak symbols are visible -/// outside of their defining component (executable file or shared object). -/// Local symbols are hidden, as described below. Global and weak symbols are -/// also preemptable, that is, they may by preempted by definitions of the same -/// name in another component. -pub const STV_DEFAULT: u8 = 0; -/// The meaning of this visibility attribute may be defined by processor -/// supplements to further constrain hidden symbols. A processor supplement's -/// definition should be such that generic tools can safely treat internal -/// symbols as hidden. -pub const STV_INTERNAL: u8 = 1; -/// A symbol defined in the current component is hidden if its name is not -/// visible to other components. Such a symbol is necessarily protected. This -/// attribute may be used to control the external interface of a component. Note -/// that an object named by such a symbol may still be referenced from another -/// component if its address is passed outside. -pub const STV_HIDDEN: u8 = 2; -/// A symbol defined in the current component is protected if it is visible in -/// other components but not preemptable, meaning that any reference to such a -/// symbol from within the defining component must be resolved to the definition -/// in that component, even if there is a definition in another component that -/// would preempt by the default rules. -pub const STV_PROTECTED: u8 = 3; - -/// An entry with a DT_NULL tag marks the end of the _DYNAMIC array. -pub const DT_NULL: i64 = 0; -/// This element holds the string table offset of a null-terminated string, -/// giving the name of a needed library. The offset is an index into the table -/// recorded in the DT_STRTAB code. The dynamic array may contain multiple -/// entries with this type. These entries' relative order is significant, though -/// their relation to entries of other types is not. -pub const DT_NEEDED: i64 = 1; -/// This element holds the total size, in bytes, of the relocation entries -/// associated with the procedure linkage table. If an entry of type DT_JMPREL -/// is present, a DT_PLTRELSZ must accompany it. -pub const DT_PLTRELSZ: i64 = 2; -/// This element holds an address associated with the procedure linkage table -/// and/or the global offset table. -pub const DT_PLTGOT: i64 = 3; -/// This element holds the address of the symbol hash table. This hash table -/// refers to the symbol table referenced by the DT_SYMTAB element. -pub const DT_HASH: i64 = 4; -/// This element holds the address of the string table. Symbol names, library -/// names, and other strings reside in this table. -pub const DT_STRTAB: i64 = 5; -/// This element holds the address of the symbol table. -pub const DT_SYMTAB: i64 = 6; -/// This element holds the address of a relocation table. Entries in the table -/// have explicit addends, (Rela). An object file may have multiple relocation -/// sections. When building the relocation table for an executable or shared -/// object file, the link editor catenates those sections to form a single -/// table. Although the sections remain independent in the object file, the -/// dynamic linker sees a single table. When the dynamic linker creates the -/// process image for an executable file or adds a shared object to the process -/// image, it reads the relocation table and performs the associated actions. -/// If this element is present, the dynamic structure must also have DT_RELASZ -/// and DT_RELAENT elements. When relocation is mandatory for a file, either -/// DT_RELA or DT_REL may occur (both are permitted but not required). -pub const DT_RELA: i64 = 7; -/// This element holds the total size, in bytes, of the DT_RELA relocation table. -pub const DT_RELASZ: i64 = 8; -/// This element holds the size, in bytes, of the DT_RELA relocation entry. -pub const DT_RELAENT: i64 = 9; -/// This element holds the size, in bytes, of the string table. -pub const DT_STRSZ: i64 = 10; -/// This element holds the size, in bytes, of a symbol table entry. -pub const DT_SYMENT: i64 = 11; -/// This element holds the address of the initialization function. -pub const DT_INIT: i64 = 12; -/// This element holds the address of the termination function. -pub const DT_FINI: i64 = 13; -/// This element holds the string table offset of a null-terminated string, -/// giving the name of the shared object. The offset is an index into the table -/// recorded in the DT_STRTAB entry. -pub const DT_SONAME: i64 = 14; -/// This element holds the string table offset of a null-terminated search -/// library search path string. The offset is an index into the table recorded -/// in the DT_STRTAB entry. Its use has been superseded by DT_RUNPATH. -pub const DT_RPATH: i64 = 15; -/// This element's presence in a shared object library alters the dynamic -/// linker's symbol resolution algorithm for references within the library. -/// Instead of starting a symbol search with the executable file, the dynamic -/// linker starts from the shared object itself. If the shared object fails to -/// supply the referenced symbol, the dynamic linker then searches the -/// executable file and other shared objects as usual. Its use has been -/// superseded by the DF_SYMBOLIC flag. -pub const DT_SYMBOLIC: i64 = 16; -/// This element is similar to DT_RELA, except its table has implicit addends (Rel). -/// If this element is present, the dynamic structure must also have DT_RELSZ -/// and DT_RELENT elements. -pub const DT_REL: i64 = 17; -/// This element holds the total size, in bytes, of the DT_REL relocation table. -pub const DT_RELSZ: i64 = 18; -/// This element holds the size, in bytes, of the DT_REL relocation entry. -pub const DT_RELENT: i64 = 19; -/// This member specifies the type of relocation entry to which the procedure -/// linkage table refers. The d_val member holds DT_REL or DT_RELA, as -/// appropriate. All relocations in a procedure linkage table must use the same -/// relocation. -pub const DT_PLTREL: i64 = 20; -/// This member is used for debugging. Its contents are not specified for the -/// ABI; programs that access this entry are not ABI-conforming. -pub const DT_DEBUG: i64 = 21; -/// This member's absence signifies that no relocation entry should cause a -/// modification to a non-writable segment, as specified by the segment -/// permissions in the program header table. If this member is present, one or -/// more relocation entries might request modifications to a non-writable -/// segment, and the dynamic linker can prepare accordingly. Its use has been -/// superseded by the DF_TEXTREL flag. -pub const DT_TEXTREL: i64 = 22; -/// If present, this entry's d_ptr member holds the address of relocation -/// entries associated solely with the procedure linkage table. Separating these -/// relocation entries lets the dynamic linker ignore them during process -/// initialization, if lazy binding is enabled. If this entry is present, the -/// related entries of types DT_PLTRELSZ and DT_PLTREL must also be present. -pub const DT_JMPREL: i64 = 23; -/// If present in a shared object or executable, this entry instructs the -/// dynamic linker to process all relocations for the object containing this -/// entry before transferring control to the program. The presence of this entry -/// takes precedence over a directive to use lazy binding for this object when -/// specified through the environment or via dlopen(BA_LIB). Its use has been -/// superseded by the DF_BIND_NOW flag. -pub const DT_BIND_NOW: i64 = 24; -/// This element holds the address of the array of pointers to initialization functions. -pub const DT_INIT_ARRAY: i64 = 25; -/// This element holds the address of the array of pointers to termination functions. -pub const DT_FINI_ARRAY: i64 = 26; -/// This element holds the size in bytes of the array of initialization -/// functions pointed to by the DT_INIT_ARRAY entry. If an object has a -/// DT_INIT_ARRAY entry, it must also have a DT_INIT_ARRAYSZ entry. -pub const DT_INIT_ARRAYSZ: i64 = 27; -/// This element holds the size in bytes of the array of termination functions -/// pointed to by the DT_FINI_ARRAY entry. If an object has a DT_FINI_ARRAY -/// entry, it must also have a DT_FINI_ARRAYSZ entry. -pub const DT_FINI_ARRAYSZ: i64 = 28; -/// This element holds the string table offset of a null-terminated library -/// search path string. The offset is an index into the table recorded in the -/// DT_STRTAB entry. -pub const DT_RUNPATH: i64 = 29; -/// This element holds flag values specific to the object being loaded. Each -/// flag value will have the name DF_flag_name. Defined values and their -/// meanings are described below. All other values are reserved. -pub const DT_FLAGS: i64 = 30; -/// This element holds the address of the array of pointers to -/// pre-initialization functions. The DT_PREINIT_ARRAY table is processed only -/// in an executable file; it is ignored if contained in a shared object. -pub const DT_PREINIT_ARRAY: i64 = 32; -/// This element holds the size in bytes of the array of pre-initialization -/// functions pointed to by the DT_PREINIT_ARRAY entry. If an object has a -/// DT_PREINIT_ARRAY entry, it must also have a DT_PREINIT_ARRAYSZ entry. As -/// with DT_PREINIT_ARRAY, this entry is ignored if it appears in a shared -/// object. -pub const DT_PREINIT_ARRAYSZ: i64 = 33; -/// This element holds the address of the SHT_SYMTAB_SHNDX section associated -/// with the dynamic symbol table referenced by the DT_SYMTAB element. -pub const DT_SYMTAB_SHNDX: i64 = 34; -/// Guile offset of GC roots -pub const DT_GUILE_GC_ROOT: i64 = 0x37146000; -/// Guile size in machine words of GC roots -pub const DT_GUILE_GC_ROOT_SZ: i64 = 0x37146001; -/// Guile address of entry thunk -pub const DT_GUILE_ENTRY: i64 = 0x37146002; -/// Guile bytecode version -pub const DT_GUILE_VM_VERSION: i64 = 0x37146003; -/// Guile frame maps -pub const DT_GUILE_FRAME_MAPS: i64 = 0x37146004; -/// Values in [DT_LOOS, DT_HIOS] are reserved for operating system-specific semantics. -pub const DT_LOOS: i64 = 0x6000000D; -/// Prelinking timestamp -pub const DT_GNU_PRELINKED: i64 = 0x6ffffdf5; -/// Size of conflict section -pub const DT_GNU_CONFLICTSZ: i64 = 0x6ffffdf6; -/// Size of library list -pub const DT_GNU_LIBLISTSZ: i64 = 0x6ffffdf7; -pub const DT_CHECKSUM: i64 = 0x6ffffdf8; -pub const DT_PLTPADSZ: i64 = 0x6ffffdf9; -pub const DT_MOVEENT: i64 = 0x6ffffdfa; -pub const DT_MOVESZ: i64 = 0x6ffffdfb; -/// Feature selection (DTF_*) -pub const DT_FEATURE_1: i64 = 0x6ffffdfc; -/// Flags for DT_* entries, effecting the following DT_* entry -pub const DT_POSFLAG_1: i64 = 0x6ffffdfd; -/// Size of syminfo table (in bytes) -pub const DT_SYMINSZ: i64 = 0x6ffffdfe; -/// Entry size of syminfo table -pub const DT_SYMINENT: i64 = 0x6ffffdff; -/// GNU-style hash table -pub const DT_GNU_HASH: i64 = 0x6ffffef5; -pub const DT_TLSDESC_PLT: i64 = 0x6ffffef6; -pub const DT_TLSDESC_GOT: i64 = 0x6ffffef7; -/// Start of conflict section -pub const DT_GNU_CONFLICT: i64 = 0x6ffffef8; -/// Library list -pub const DT_GNU_LIBLIST: i64 = 0x6ffffef9; -/// Configuration information -pub const DT_CONFIG: i64 = 0x6ffffefa; -/// Dependency auditing -pub const DT_DEPAUDIT: i64 = 0x6ffffefb; -/// Object auditing -pub const DT_AUDIT: i64 = 0x6ffffefc; -/// PLT padding -pub const DT_PLTPAD: i64 = 0x6ffffefd; -/// Move table -pub const DT_MOVETAB: i64 = 0x6ffffefe; -/// Syminfo table -pub const DT_SYMINFO: i64 = 0x6ffffeff; -pub const DT_VERSYM: i64 = 0x6ffffff0; -pub const DT_RELACOUNT: i64 = 0x6ffffff9; -pub const DT_RELCOUNT: i64 = 0x6ffffffa; -/// State flags, see DF_1_* below. -pub const DT_FLAGS_1: i64 = 0x6ffffffb; -/// Address of version definition table -pub const DT_VERDEF: i64 = 0x6ffffffc; -/// Number of version definitions -pub const DT_VERDEFNUM: i64 = 0x6ffffffd; -/// Address of table with needed versions -pub const DT_VERNEED: i64 = 0x6ffffffe; -/// Number of needed versions -pub const DT_VERNEEDNUM: i64 = 0x6fffffff; -/// Values in [DT_LOOS, DT_HIOS] are reserved for operating system-specific semantics. -pub const DT_HIOS: i64 = 0x6ffff000; -/// Values in [DT_LOPROC, DT_HIPROC] are reserved for processor-specific semantics. -pub const DT_LOPROC: i64 = 0x70000000; -/// Values in [DT_LOPROC, DT_HIPROC] are reserved for processor-specific semantics. -pub const DT_HIPROC: i64 = 0x7fffffff; - -/// This flag signifies that the object being loaded may make reference to the -/// $ORIGIN substitution string. The dynamic linker must determine the pathname -/// of the object containing this entry when the object is loaded. -pub const DF_ORIGIN: i64 = 0x1; -/// If this flag is set in a shared object library, the dynamic linker's symbol -/// resolution algorithm for references within the library is changed. Instead -/// of starting a symbol search with the executable file, the dynamic linker -/// starts from the shared object itself. If the shared object fails to supply -/// the referenced symbol, the dynamic linker then searches the executable file -/// and other shared objects as usual. -pub const DF_SYMBOLIC: i64 = 0x2; -/// If this flag is not set, no relocation entry should cause a modification to -/// a non-writable segment, as specified by the segment permissions in the -/// program header table. If this flag is set, one or more relocation entries -/// might request modifications to a non-writable segment, and the dynamic -/// linker can prepare accordingly. -pub const DF_TEXTREL: i64 = 0x4; -/// If set in a shared object or executable, this flag instructs the dynamic -/// linker to process all relocations for the object containing this entry -/// before transferring control to the program. The presence of this entry takes -/// precedence over a directive to use lazy binding for this object when -/// specified through the environment or via dlopen(BA_LIB). -pub const DF_BIND_NOW: i64 = 0x8; -/// If set in a shared object or executable, this flag instructs the dynamic -/// linker to reject attempts to load this file dynamically. It indicates that -/// the shared object or executable contains code using a static thread-local -/// storage scheme. Implementations need not support any form of thread-local -/// storage. -pub const DF_STATIC_TLS: i64 = 0x10; - -// State flags selectable in Dyn.d_val() of the DT_FLAGS_1 entries in the dynamic section - -/// Set RTLD_NOW for this object -pub const DF_1_NOW: i64 = 0x00000001; -/// Set RTLD_GLOBAL for this object -pub const DF_1_GLOBAL: i64 = 0x00000002; -/// Set RTLD_GROUP for this object -pub const DF_1_GROUP: i64 = 0x00000004; -/// Set RTLD_NODELETE for this object -pub const DF_1_NODELETE: i64 = 0x00000008; -/// Trigger filtee loading at runtime -pub const DF_1_LOADFLTR: i64 = 0x00000010; -/// Set RTLD_INITFIRST for this object -pub const DF_1_INITFIRST: i64 = 0x00000020; -/// Set RTLD_NOOPEN for this object -pub const DF_1_NOOPEN: i64 = 0x00000040; -/// $ORIGIN must be handled -pub const DF_1_ORIGIN: i64 = 0x00000080; -/// Direct binding enabled -pub const DF_1_DIRECT: i64 = 0x00000100; -pub const DF_1_TRANS: i64 = 0x00000200; -/// Object is used to interpose -pub const DF_1_INTERPOSE: i64 = 0x00000400; -/// Ignore default lib search path -pub const DF_1_NODEFLIB: i64 = 0x00000800; -/// Object can't be dldump'ed -pub const DF_1_NODUMP: i64 = 0x00001000; -/// Configuration alternative created -pub const DF_1_CONFALT: i64 = 0x00002000; -/// Filtee terminates filters search -pub const DF_1_ENDFILTEE: i64 = 0x00004000; -/// Disp reloc applied at build time -pub const DF_1_DISPRELDNE: i64 = 0x00008000; -/// Disp reloc applied at run-time -pub const DF_1_DISPRELPND: i64 = 0x00010000; -/// Object has no-direct binding -pub const DF_1_NODIRECT: i64 = 0x00020000; -pub const DF_1_IGNMULDEF: i64 = 0x00040000; -pub const DF_1_NOKSYMS: i64 = 0x00080000; -pub const DF_1_NOHDR: i64 = 0x00100000; -/// Object is modified after built -pub const DF_1_EDITED: i64 = 0x00200000; -pub const DF_1_NORELOC: i64 = 0x00400000; -/// Object has individual interposers -pub const DF_1_SYMINTPOSE: i64 = 0x00800000; -/// Global auditing required -pub const DF_1_GLOBAUDIT: i64 = 0x01000000; -/// Singleton symbols are used -pub const DF_1_SINGLETON: i64 = 0x02000000; -pub const DF_1_STUB: i64 = 0x04000000; -pub const DF_1_PIE: i64 = 0x08000000; -pub const DF_1_KMOD: i64 = 0x10000000; -pub const DF_1_WEAKFILTER: i64 = 0x20000000; -pub const DF_1_NOCOMMON: i64 = 0x40000000; - -// Flags for the feature selection in DT_FEATURE_1 -pub const DTF_1_PARINIT: i64 = 0x00000001; -pub const DTF_1_CONFEXP: i64 = 0x00000002; - -// Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry -/// Lazyload following object -pub const DF_P1_LAZYLOAD: i64 = 0x00000001; -/// Symbols from next object are not generally available -pub const DF_P1_GROUPPERM: i64 = 0x00000002; - -// .gnu.version index reserved values -/// Symbol is local -pub const VER_NDX_LOCAL: u16 = 0; -/// Symbol is global -pub const VER_NDX_GLOBAL: u16 = 1; -/// .gnu.version index mask -pub const VER_NDX_VERSION: u16 = 0x7fff; -/// Symbol is hidden -pub const VER_NDX_HIDDEN: u16 = 0x8000; - -// .gnu.version_d VerDef.vd_version reserved values -/// Only defined valid vd_version value -pub const VER_DEF_CURRENT: u16 = 1; - -// .gnu.version_r VerNeed.vn_version reserved values -/// Only defined valid vn_version value -pub const VER_NEED_CURRENT: u16 = 1; - -// Bit flags which appear in vd_flags of VerDef and vna_flags of VerNeedAux. -pub const VER_FLG_BASE: u16 = 0x1; -pub const VER_FLG_WEAK: u16 = 0x2; -pub const VER_FLG_INFO: u16 = 0x4; - -/// ZLIB/DEFLATE -pub const ELFCOMPRESS_ZLIB: u32 = 1; -/// zstd algorithm -pub const ELFCOMPRESS_ZSTD: u32 = 2; -/// Values in [ELFCOMPRESS_LOOS, ELFCOMPRESS_HIOS] are reserved for operating system-specific semantics. -pub const ELFCOMPRESS_LOOS: u32 = 0x60000000; -/// Values in [ELFCOMPRESS_LOOS, ELFCOMPRESS_HIOS] are reserved for operating system-specific semantics. -pub const ELFCOMPRESS_HIOS: u32 = 0x6fffffff; -/// Values in [ELFCOMPRESS_LOPROC, ELFCOMPRESS_HIPROC] are reserved for processor-specific semantics. -pub const ELFCOMPRESS_LOPROC: u32 = 0x70000000; -/// Values in [ELFCOMPRESS_LOPROC, ELFCOMPRESS_HIPROC] are reserved for processor-specific semantics. -pub const ELFCOMPRESS_HIPROC: u32 = 0x7fffffff; - -/// GNU-extension notes have this name -pub const ELF_NOTE_GNU: &str = "GNU"; - -// Note header descriptor types constants (n_type) - -/// Contains copy of prstatus struct -pub const NT_PRSTATUS: u64 = 1; -/// Contains copy of fpregset struct -pub const NT_PRFPREG: u64 = 2; -/// Contains copy of fpregset struct -pub const NT_FPREGSET: u64 = 2; -/// Contains copy of prpsinfo struct -pub const NT_PRPSINFO: u64 = 3; -/// Contains copy of prxregset struct -pub const NT_PRXREG: u64 = 4; -/// Contains copy of task structure -pub const NT_TASKSTRUCT: u64 = 4; -/// String from sysinfo(SI_PLATFORM) -pub const NT_PLATFORM: u64 = 5; -/// Contains copy of auxv array -pub const NT_AUXV: u64 = 6; -/// Contains copy of gwindows struct -pub const NT_GWINDOWS: u64 = 7; -/// Contains copy of asrset struct -pub const NT_ASRS: u64 = 8; -/// Contains copy of pstatus struct -pub const NT_PSTATUS: u64 = 10; -/// Contains copy of psinfo struct -pub const NT_PSINFO: u64 = 13; -/// Contains copy of prcred struct -pub const NT_PRCRED: u64 = 14; -/// Contains copy of utsname struct -pub const NT_UTSNAME: u64 = 15; -/// Contains copy of lwpstatus struct -pub const NT_LWPSTATUS: u64 = 16; -/// Contains copy of lwpinfo struct -pub const NT_LWPSINFO: u64 = 17; -/// Contains copy of fprxregset struct -pub const NT_PRFPXREG: u64 = 20; -/// Contains copy of siginfo_t, size might increase -pub const NT_SIGINFO: u64 = 0x53494749; -/// Contains information about mapped files -pub const NT_FILE: u64 = 0x46494c45; -/// Contains copy of user_fxsr_struct -pub const NT_PRXFPREG: u64 = 0x46e62b7f; -/// /// PowerPC Altivec/VMX registers -pub const NT_PPC_VMX: u64 = 0x100; -/// PowerPC SPE/EVR registers -pub const NT_PPC_SPE: u64 = 0x101; -/// PowerPC VSX registers -pub const NT_PPC_VSX: u64 = 0x102; -/// Target Address Register -pub const NT_PPC_TAR: u64 = 0x103; -/// Program Priority Register -pub const NT_PPC_PPR: u64 = 0x104; -/// Data Stream Control Register -pub const NT_PPC_DSCR: u64 = 0x105; -/// Event Based Branch Registers -pub const NT_PPC_EBB: u64 = 0x106; -/// Performance Monitor Registers -pub const NT_PPC_PMU: u64 = 0x107; -/// TM checkpointed GPR Registers -pub const NT_PPC_TM_CGPR: u64 = 0x108; -/// TM checkpointed FPR Registers -pub const NT_PPC_TM_CFPR: u64 = 0x109; -/// TM checkpointed VMX Registers -pub const NT_PPC_TM_CVMX: u64 = 0x10a; -/// TM checkpointed VSX Registers -pub const NT_PPC_TM_CVSX: u64 = 0x10b; -/// TM Special Purpose Registers -pub const NT_PPC_TM_SPR: u64 = 0x10c; -/// TM checkpointed Target Address Register -pub const NT_PPC_TM_CTAR: u64 = 0x10d; -/// TM checkpointed Program Priority Register -pub const NT_PPC_TM_CPPR: u64 = 0x10e; -/// TM checkpointed Data Stream Control Register -pub const NT_PPC_TM_CDSCR: u64 = 0x10f; -/// Memory Protection Keys registers -pub const NT_PPC_PKEY: u64 = 0x110; -/// i386 TLS slots (struct user_desc) -pub const NT_386_TLS: u64 = 0x200; -/// x86 io permission bitmap (1=deny) -pub const NT_386_IOPERM: u64 = 0x201; -/// x86 extended state using xsave -pub const NT_X86_XSTATE: u64 = 0x202; -/// ARM VFP/NEON registers -pub const NT_ARM_VFP: u64 = 0x400; -/// ARM TLS register -pub const NT_ARM_TLS: u64 = 0x401; -/// ARM hardware breakpoint registers -pub const NT_ARM_HW_BREAK: u64 = 0x402; -/// ARM hardware watchpoint registers -pub const NT_ARM_HW_WATCH: u64 = 0x403; -/// ARM system call number -pub const NT_ARM_SYSTEM_CALL: u64 = 0x404; -/// ARM Scalable Vector Extension registers -pub const NT_ARM_SVE: u64 = 0x405; -/// ARM pointer authentication code masks -pub const NT_ARM_PAC_MASK: u64 = 0x406; -/// ARM pointer authentication address keys -pub const NT_ARM_PACA_KEYS: u64 = 0x407; -/// ARM pointer authentication generic key -pub const NT_ARM_PACG_KEYS: u64 = 0x408; -/// AArch64 tagged address control. -pub const NT_ARM_TAGGED_ADDR_CTRL: u64 = 0x409; -/// AArch64 pointer authentication enabled keys -pub const NT_ARM_PAC_ENABLED_KEYS: u64 = 0x40a; -/// Vmcore Device Dump Note -pub const NT_VMCOREDD: u64 = 0x700; - -/// ABI information -/// The descriptor consists of words: -/// word 0: OS descriptor -/// word 1: major version of the ABI -/// word 2: minor version of the ABI -/// word 3: subminor version of the ABI -pub const NT_GNU_ABI_TAG: u64 = 1; -/// Synthetic hwcap information -pub const NT_GNU_HWCAP: u64 = 2; -/// Build ID bits as generated by ld --build-id. -pub const NT_GNU_BUILD_ID: u64 = 3; -/// Version note generated by GNU gold containing a version string -pub const NT_GNU_GOLD_VERSION: u64 = 4; -/// Program property note which describes special handling requirements for linker and run-time loader. -pub const NT_GNU_PROPERTY_TYPE_0: u64 = 5; - -// These values can appear in word 0 of an NT_GNU_ABI_TAG note section entry. -pub const ELF_NOTE_GNU_ABI_TAG_OS_LINUX: u32 = 0; -pub const ELF_NOTE_GNU_ABI_TAG_OS_GNU: u32 = 1; -pub const ELF_NOTE_GNU_ABI_TAG_OS_SOLARIS2: u32 = 2; -pub const ELF_NOTE_GNU_ABI_TAG_OS_FREEBSD: u32 = 3; - -// _ ____ __ __ -// / \ | _ \| \/ | -// / _ \ | |_) | |\/| | -// / ___ \| _ <| | | | -// /_/ \_\_| \_\_| |_| -// -// ARM-specific declarations (ABI v5) -// See: https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst -// See: https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst - -/// Set in executable file headers (e_type = ET_EXEC or ET_DYN) to note explicitly that the -/// executable file was built to conform to the software floating-point procedure-call standard -/// (the base standard). If both EF_ARM_ABI_FLOAT_XXXX bits are clear, conformance to the base -/// procedure-call standard is implied. -pub const EF_ARM_ABI_FLOAT_SOFT: u32 = 0x200; -/// Compatible with legacy (pre version 5) gcc use as EF_ARM_SOFT_FLOAT -pub const EF_ARM_SOFT_FLOAT: u32 = EF_ARM_ABI_FLOAT_SOFT; -/// Set in executable file headers (e_type = ET_EXEC or ET_DYN) to note that the executable file -/// was built to conform to the hardware floating-point procedure-call standard. -pub const EF_ARM_ABI_FLOAT_HARD: u32 = 0x400; -/// Compatible with legacy (pre version 5) gcc use as EF_ARM_VFP_FLOAT. -pub const EF_ARM_VFP_FLOAT: u32 = EF_ARM_ABI_FLOAT_HARD; - -/// The ELF file contains BE-8 code, suitable for execution on an Arm Architecture v6 processor. -/// This flag must only be set on an executable file. -pub const EF_ARM_BE8: u32 = 0x00800000; - -/// Legacy code (ABI version 4 and earlier) generated by gcc-arm-xxx might use these bits. -pub const EF_ARM_GCCMASK: u32 = 0x00400FFF; - -/// This masks an 8-bit version number, the version of the ABI to which this ELF -/// file conforms. This ABI is version 5. A value of 0 denotes unknown conformance. -pub const EF_ARM_EABIMASK: u32 = 0xFF000000; -pub const EF_ARM_EABI_UNKNOWN: u32 = 0x00000000; -pub const EF_ARM_EABI_VER1: u32 = 0x01000000; -pub const EF_ARM_EABI_VER2: u32 = 0x02000000; -pub const EF_ARM_EABI_VER3: u32 = 0x03000000; -pub const EF_ARM_EABI_VER4: u32 = 0x04000000; -pub const EF_ARM_EABI_VER5: u32 = 0x05000000; - -/// Section contains index information for exception unwinding -pub const SHT_ARM_EXIDX: u32 = 0x70000001; -/// BPABI DLL dynamic linking pre-emption map -pub const SHT_ARM_PREEMPTMAP: u32 = 0x70000002; -/// Object file compatibility attributes -pub const SHT_ARM_ATTRIBUTES: u32 = 0x70000003; -/// See -pub const SHT_ARM_DEBUGOVERLAY: u32 = 0x70000004; -/// See -pub const SHT_ARM_OVERLAYSECTION: u32 = 0x70000005; - -/// The contents of this section contains only program instructions and no program data. -/// -/// If any section contained by a segment does not have the SHF_ARM_PURECODE -/// section flag set, the PF_R segment flag must be set in the program header -/// for the segment. If all sections contained by a segment have the -/// SHF_ARM_PURECODE section flag, a linker may optionally clear the PF_R -/// segment flag in the program header of the segment, to signal to the runtime -/// that the program does not rely on being able to read that segment. -pub const SHF_ARM_PURECODE: u64 = 0x20000000; - -/// Architecture compatibility information. -/// -/// A segment of type PT_ARM_ARCHEXT contains information describing the -/// platform capabilities required by the executable file. The segment is -/// optional, but if present it must appear before segment of type PT_LOAD. -pub const PT_ARM_ARCHEXT: u32 = 0x70000000; -/// alias for unwind -pub const PT_ARM_EXIDX: u32 = 0x70000001; -/// Exception unwind tables -pub const PT_ARM_UNWIND: u32 = 0x70000001; - -// Contents of a PT_ARM_ARCHEXT segment shall contain at least one 32-bit word with meanings: -/// Masks bits describing the format of data in subsequent words. -pub const PT_ARM_ARCHEXT_FMTMSK: u32 = 0xff000000; -/// There are no additional words of data. However, if EF_OSABI is non-zero, the -/// relevant platform ABI may define additional data that follows the initial word. -pub const PT_ARM_ARCHEXT_FMT_OS: u32 = 0x00000000; -/// See -/// and -pub const PT_ARM_ARCHEXT_FMT_ABI: u32 = 0x01000000; - -/// Masks bits describing the architecture profile required by the executable. -pub const PT_ARM_ARCHEXT_PROFMSK: u32 = 0x00ff0000; -/// The architecture has no profile variants, or the image has no profile-specific constraints -pub const PT_ARM_ARCHEXT_PROF_NONE: u32 = 0x00000000; -/// (‘A’<<16) The executable file requires the Application profile -pub const PT_ARM_ARCHEXT_PROF_ARM: u32 = 0x00410000; -/// (‘R’<<16) The executable file requires the Real-Time profile -pub const PT_ARM_ARCHEXT_PROF_RT: u32 = 0x00520000; -/// (‘M’<<16) The executable file requires the Microcontroller profile -pub const PT_ARM_ARCHEXT_PROF_MC: u32 = 0x004D0000; -/// (‘S’<<16) The executable file requires the ‘classic’ (‘A’ or ‘R’ profile) exception model. -pub const PT_ARM_ARCHEXT_PROF_CLASSIC: u32 = 0x00530000; - -/// Masks bits describing the base architecture required by the executable. -pub const PT_ARM_ARCHEXT_ARCHMSK: u32 = 0x000000ff; -/// The needed architecture is unknown or specified in some other way -pub const PT_ARM_ARCHEXT_ARCH_UNKN: u32 = 0x00; -/// Architecture v4 -pub const PT_ARM_ARCHEXT_ARCHV4: u32 = 0x01; -/// Architecture v4T -pub const PT_ARM_ARCHEXT_ARCHV4T: u32 = 0x02; -/// Architecture v5T -pub const PT_ARM_ARCHEXT_ARCHV5T: u32 = 0x03; -/// Architecture v5TE -pub const PT_ARM_ARCHEXT_ARCHV5TE: u32 = 0x04; -/// Architecture v5TEJ -pub const PT_ARM_ARCHEXT_ARCHV5TEJ: u32 = 0x05; -/// Architecture v6 -pub const PT_ARM_ARCHEXT_ARCHV6: u32 = 0x06; -/// Architecture v6KZ -pub const PT_ARM_ARCHEXT_ARCHV6KZ: u32 = 0x07; -/// Architecture v6T2 -pub const PT_ARM_ARCHEXT_ARCHV6T2: u32 = 0x08; -/// Architecture v6K -pub const PT_ARM_ARCHEXT_ARCHV6K: u32 = 0x09; -/// Architecture v7 (in this case the architecture profile may also be -/// required to fully specify the needed execution environment). -pub const PT_ARM_ARCHEXT_ARCHV7: u32 = 0x0A; -/// Architecture v6M (e.g. Cortex-M0) -pub const PT_ARM_ARCHEXT_ARCHV6M: u32 = 0x0B; -/// Architecture v6S-M (e.g. Cortex-M0) -pub const PT_ARM_ARCHEXT_ARCHV6SM: u32 = 0x0C; -/// Architecture v7E-M -pub const PT_ARM_ARCHEXT_ARCHV7EM: u32 = 0x0D; - -/// gives the number of entries in the dynamic symbol table, including the initial dummy symbol -pub const DT_ARM_SYMTABSZ: i64 = 0x70000001; -/// holds the address of the pre-emption map for platforms that use the DLL static binding mode -pub const DT_ARM_PREEMPTMAP: i64 = 0x70000002; - -// ARM relocs -// -// * S (when used on its own) is the address of the symbol. -// * A is the addend for the relocation. -// * P is the address of the place being relocated (derived from r_offset). -// * Pa is the adjusted address of the place being relocated, defined as (P & 0xFFFFFFFC). -// * T is 1 if the target symbol S has type STT_FUNC and the symbol addresses a Thumb instruction; 0 otherwise. -// * B(S) is the addressing origin of the output segment defining the symbol S. -// The origin is not required to be the base address of the segment. This value must always be word-aligned. -// * GOT_ORG is the addressing origin of the Global Offset Table (the indirection table for imported data addresses). -// This value must always be word-aligned. -// * GOT(S) is the address of the GOT entry for the symbol S - -/// no reloc -pub const R_ARM_NONE: u32 = 0; -/// Deprecated PC relative 26 bit branch. `((S + A) | T) – P` -pub const R_ARM_PC24: u32 = 1; -/// Direct 32 bit. `(S + A) | T` -pub const R_ARM_ABS32: u32 = 2; -/// PC relative 32 bit. `((S + A) | T) | – P` -pub const R_ARM_REL32: u32 = 3; -/// `S + A – P` -pub const R_ARM_LDR_PC_G0: u32 = 4; -/// Direct 16 bit. `S + A` -pub const R_ARM_ABS16: u32 = 5; -/// Direct 12 bit. `S + A` -pub const R_ARM_ABS12: u32 = 6; -/// Direct & 0x7C `(LDR, STR). S + A` -pub const R_ARM_THM_ABS5: u32 = 7; -/// Direct 8 bit. `S + A` -pub const R_ARM_ABS8: u32 = 8; -/// `((S + A) | T) – B(S)` -pub const R_ARM_SBREL32: u32 = 9; -/// PC relative 24 bit (Thumb32 BL). `((S + A) | T) – P` -pub const R_ARM_THM_CALL: u32 = 10; -/// PC relative & 0x3FC (Thumb16 LDR, ADD, ADR). `S + A – Pa` -pub const R_ARM_THM_PC8: u32 = 11; -pub const R_ARM_BREL_ADJ: u32 = 12; -/// dynamic reloc -pub const R_ARM_TLS_DESC: u32 = 13; -/// obsolete/reserved -pub const R_ARM_THM_SWI8: u32 = 14; -/// obsolete/reserved -pub const R_ARM_XPC25: u32 = 15; -/// obsolete/reserved -pub const R_ARM_THM_XPC22: u32 = 16; -/// ID of module containing symbol. -pub const R_ARM_TLS_DTPMOD32: u32 = 17; -/// Offset in TLS block. `S + A – TLS` -pub const R_ARM_TLS_DTPOFF32: u32 = 18; -/// Offset in static TLS block. `S + A – Tp` -pub const R_ARM_TLS_TPOFF32: u32 = 19; -/// dynamic reloc Copy symbol at runtime. -pub const R_ARM_COPY: u32 = 20; -/// Create GOT entry. `(S + A) | T` -pub const R_ARM_GLOB_DAT: u32 = 21; -/// Create PLT entry. `(S + A) | T` -pub const R_ARM_JUMP_SLOT: u32 = 22; -/// Adjust by program base. `B(S) + A` -pub const R_ARM_RELATIVE: u32 = 23; -/// 32 bit offset to GOT. `((S + A) | T) – GOT_ORG` -pub const R_ARM_GOTOFF32: u32 = 24; -/// 32 bit PC relative offset to GOT. `B(S) + A – P` -pub const R_ARM_BASE_PREL: u32 = 25; -/// 32 bit GOT entry. `GOT(S) + A – GOT_ORG` -pub const R_ARM_BASE_BREL: u32 = 26; -/// Deprecated, 32 bit PLT address. -pub const R_ARM_PLT32: u32 = 27; -/// PC relative 24 bit (BL, BLX). `((S + A) | T) – P` -pub const R_ARM_CALL: u32 = 28; -/// PC relative 24 bit (B, BL{cond}). `((S + A) | T) – P` -pub const R_ARM_JUMP24: u32 = 29; -/// PC relative 24 bit (Thumb32 B.W). `((S + A) | T) – P` -pub const R_ARM_THM_JUMP24: u32 = 30; -/// Adjust by program base. `B(S) + A` -pub const R_ARM_BASE_ABS: u32 = 31; -/// Obsolete. -pub const R_ARM_ALU_PCREL_7_0: u32 = 32; -/// Obsolete. -pub const R_ARM_ALU_PCREL_15_8: u32 = 33; -/// Obsolete. -pub const R_ARM_ALU_PCREL_23_15: u32 = 34; -/// Deprecated, prog. base relative. -pub const R_ARM_LDR_SBREL_11_0: u32 = 35; -/// Deprecated, prog. base relative. -pub const R_ARM_ALU_SBREL_19_12: u32 = 36; -/// Deprecated, prog. base relative. -pub const R_ARM_ALU_SBREL_27_20: u32 = 37; -pub const R_ARM_TARGET1: u32 = 38; -/// Program base relative. `((S + A) | T) – B(S)` -pub const R_ARM_SBREL31: u32 = 39; -pub const R_ARM_V4BX: u32 = 40; -pub const R_ARM_TARGET2: u32 = 41; -/// 32 bit PC relative. `((S + A) | T) – P` -pub const R_ARM_PREL31: u32 = 42; -/// Direct 16-bit (MOVW). `(S + A) | T` -pub const R_ARM_MOVW_ABS_NC: u32 = 43; -/// Direct high 16-bit (MOVT). `S + A` -pub const R_ARM_MOVT_ABS: u32 = 44; -/// PC relative 16-bit (MOVW). `((S + A) | T) – P` -pub const R_ARM_MOVW_PREL_NC: u32 = 45; -/// PC relative (MOVT). `S + A - P` -pub const R_ARM_MOVT_PREL: u32 = 46; -/// Direct 16 bit (Thumb32 MOVW). `(S + A) | T` -pub const R_ARM_THM_MOVW_ABS_NC: u32 = 47; -/// Direct high 16 bit (Thumb32 MOVT). `S + A` -pub const R_ARM_THM_MOVT_ABS: u32 = 48; -/// PC relative 16 bit (Thumb32 MOVW). `((S + A) | T) – P` -pub const R_ARM_THM_MOVW_PREL_NC: u32 = 49; -/// PC relative high 16 bit (Thumb32 MOVT). `S + A – P` -pub const R_ARM_THM_MOVT_PREL: u32 = 50; -/// PC relative 20 bit (Thumb32 B{cond}.W). `((S + A) | T) – P` -pub const R_ARM_THM_JUMP19: u32 = 51; -/// PC relative X & 0x7E (Thumb16 CBZ, CBNZ). `S + A – P` -pub const R_ARM_THM_JUMP6: u32 = 52; -/// PC relative 12 bit (Thumb32 ADR.W). `((S + A) | T) – Pa` -pub const R_ARM_THM_ALU_PREL_11_0: u32 = 53; -/// PC relative 12 bit (Thumb32 LDR{D,SB,H,SH}). `S + A – Pa` -pub const R_ARM_THM_PC12: u32 = 54; -/// Direct 32-bit. `S + A` -pub const R_ARM_ABS32_NOI: u32 = 55; -/// PC relative 32-bit. `S + A - P` -pub const R_ARM_REL32_NOI: u32 = 56; -/// PC relative (ADD, SUB). `((S + A) | T) – P` -pub const R_ARM_ALU_PC_G0_NC: u32 = 57; -/// PC relative (ADD, SUB). `((S + A) | T) – P` -pub const R_ARM_ALU_PC_G0: u32 = 58; -/// PC relative (ADD, SUB). `((S + A) | T) – P` -pub const R_ARM_ALU_PC_G1_NC: u32 = 59; -/// PC relative (ADD, SUB). `((S + A) | T) – P` -pub const R_ARM_ALU_PC_G1: u32 = 60; -/// PC relative (ADD, SUB). `((S + A) | T) – P` -pub const R_ARM_ALU_PC_G2: u32 = 61; -/// PC relative (LDR,STR,LDRB,STRB). `S + A – P` -pub const R_ARM_LDR_PC_G1: u32 = 62; -/// PC relative (LDR,STR,LDRB,STRB). `S + A – P` -pub const R_ARM_LDR_PC_G2: u32 = 63; -/// PC relative (STR{D,H}, LDR{D,SB,H,SH}). `S + A – P` -pub const R_ARM_LDRS_PC_G0: u32 = 64; -/// PC relative (STR{D,H}, LDR{D,SB,H,SH}). `S + A – P` -pub const R_ARM_LDRS_PC_G1: u32 = 65; -/// PC relative (STR{D,H}, LDR{D,SB,H,SH}). `S + A – P` -pub const R_ARM_LDRS_PC_G2: u32 = 66; -/// PC relative (LDC, STC). `S + A – P` -pub const R_ARM_LDC_PC_G0: u32 = 67; -/// PC relative (LDC, STC). `S + A – P` -pub const R_ARM_LDC_PC_G1: u32 = 68; -/// PC relative (LDC, STC). `S + A – P` -pub const R_ARM_LDC_PC_G2: u32 = 69; -/// Program base relative (ADD,SUB). `((S + A) | T) – B(S)` -pub const R_ARM_ALU_SB_G0_NC: u32 = 70; -/// Program base relative (ADD,SUB). `((S + A) | T) – B(S)` -pub const R_ARM_ALU_SB_G0: u32 = 71; -/// Program base relative (ADD,SUB). `((S + A) | T) – B(S)` -pub const R_ARM_ALU_SB_G1_NC: u32 = 72; -/// Program base relative (ADD,SUB). `((S + A) | T) – B(S)` -pub const R_ARM_ALU_SB_G1: u32 = 73; -/// Program base relative (ADD,SUB). `((S + A) | T) – B(S)` -pub const R_ARM_ALU_SB_G2: u32 = 74; -/// Program base relative (LDR, STR, LDRB, STRB). `S + A – B(S)` -pub const R_ARM_LDR_SB_G0: u32 = 75; -/// Program base relative (LDR, STR, LDRB, STRB). `S + A – B(S)` -pub const R_ARM_LDR_SB_G1: u32 = 76; -/// Program base relative (LDR, STR, LDRB, STRB). `S + A – B(S)` -pub const R_ARM_LDR_SB_G2: u32 = 77; -/// Program base relative (LDR, STR, LDRB, STRB). `S + A – B(S)` -pub const R_ARM_LDRS_SB_G0: u32 = 78; -/// Program base relative (LDR, STR, LDRB, STRB). `S + A – B(S)` -pub const R_ARM_LDRS_SB_G1: u32 = 79; -/// Program base relative (LDR, STR, LDRB, STRB). `S + A – B(S)` -pub const R_ARM_LDRS_SB_G2: u32 = 80; -/// Program base relative (LDC,STC). `S + A – B(S)` -pub const R_ARM_LDC_SB_G0: u32 = 81; -/// Program base relative (LDC,STC). `S + A – B(S)` -pub const R_ARM_LDC_SB_G1: u32 = 82; -/// Program base relative (LDC,STC). `S + A – B(S)` -pub const R_ARM_LDC_SB_G2: u32 = 83; -/// Program base relative 16 bit (MOVW). `((S + A) | T) – B(S)` -pub const R_ARM_MOVW_BREL_NC: u32 = 84; -/// Program base relative high 16 bit (MOVT). `S + A – B(S)` -pub const R_ARM_MOVT_BREL: u32 = 85; -/// Program base relative 16 bit (MOVW). `((S + A) | T) – B(S)` -pub const R_ARM_MOVW_BREL: u32 = 86; -/// Program base relative 16 bit (Thumb32 MOVW). `((S + A) | T) – B(S)` -pub const R_ARM_THM_MOVW_BREL_NC: u32 = 87; -/// Program base relative high 16 bit (Thumb32 MOVT). `S + A – B(S)` -pub const R_ARM_THM_MOVT_BREL: u32 = 88; -/// Program base relative 16 bit (Thumb32 MOVW). `((S + A) | T) – B(S)` -pub const R_ARM_THM_MOVW_BREL: u32 = 89; -pub const R_ARM_TLS_GOTDESC: u32 = 90; -pub const R_ARM_TLS_CALL: u32 = 91; -/// TLS relaxation. -pub const R_ARM_TLS_DESCSEQ: u32 = 92; -pub const R_ARM_THM_TLS_CALL: u32 = 93; -/// `PLT(S) + A` -pub const R_ARM_PLT32_ABS: u32 = 94; -/// GOT entry. `GOT(S) + A` -pub const R_ARM_GOT_ABS: u32 = 95; -/// PC relative GOT entry. `GOT(S) + A – P` -pub const R_ARM_GOT_PREL: u32 = 96; -/// GOT entry relative to GOT origin (LDR). `GOT(S) + A – GOT_ORG` -pub const R_ARM_GOT_BREL12: u32 = 97; -/// 12 bit, GOT entry relative to GOT origin (LDR, STR). `S + A – GOT_ORG` -pub const R_ARM_GOTOFF12: u32 = 98; -pub const R_ARM_GOTRELAX: u32 = 99; -pub const R_ARM_GNU_VTENTRY: u32 = 100; -pub const R_ARM_GNU_VTINHERIT: u32 = 101; -/// PC relative & 0xFFE (Thumb16 B). `S + A – P` -pub const R_ARM_THM_JUMP11: u32 = 102; -/// PC relative & 0x1FE (Thumb16 B/B{cond}). `S + A – P` -pub const R_ARM_THM_JUMP8: u32 = 103; -/// PC-rel 32 bit for global dynamic thread local data. `GOT(S) + A – P` -pub const R_ARM_TLS_GD32: u32 = 104; -/// PC-rel 32 bit for local dynamic thread local data. `GOT(S) + A – P` -pub const R_ARM_TLS_LDM32: u32 = 105; -/// 32 bit offset relative to TLS block. `S + A – TLS` -pub const R_ARM_TLS_LDO32: u32 = 106; -/// PC-rel 32 bit for GOT entry of static TLS block offset. `GOT(S) + A – P` -pub const R_ARM_TLS_IE32: u32 = 107; -/// 32 bit offset relative to static TLS block. `S + A – tp` -pub const R_ARM_TLS_LE32: u32 = 108; -/// 12 bit relative to TLS block (LDR, STR). `S + A – TLS` -pub const R_ARM_TLS_LDO12: u32 = 109; -/// 12 bit relative to static TLS block (LDR, STR). `S + A – tp` -pub const R_ARM_TLS_LE12: u32 = 110; -/// 12 bit GOT entry relative to GOT origin (LDR). `GOT(S) + A – GOT_ORG` -pub const R_ARM_TLS_IE12GP: u32 = 111; -/// Obsolete. -pub const R_ARM_ME_TOO: u32 = 128; -pub const R_ARM_THM_TLS_DESCSEQ16: u32 = 129; -pub const R_ARM_THM_TLS_DESCSEQ32: u32 = 130; -/// GOT entry relative to GOT origin, 12 bit (Thumb32 LDR). `GOT(S) + A – GOT_ORG` -pub const R_ARM_THM_GOT_BREL12: u32 = 131; -/// Static Thumb16 `(S + A) | T` -pub const R_ARM_THM_ALU_ABS_G0_NC: u32 = 132; -/// Static Thumb16 `S + A` -pub const R_ARM_THM_ALU_ABS_G1_NC: u32 = 133; -/// Static Thumb16 `S + A` -pub const R_ARM_THM_ALU_ABS_G2_NC: u32 = 134; -/// Static Thumb16 `S + A` -pub const R_ARM_THM_ALU_ABS_G3: u32 = 135; -/// Static Arm `((S + A) | T) – P` -pub const R_ARM_THM_BF16: u32 = 136; -/// Static Arm `((S + A) | T) – P` -pub const R_ARM_THM_BF12: u32 = 137; -/// Static Arm `((S + A) | T) – P` -pub const R_ARM_THM_BF18: u32 = 138; -pub const R_ARM_IRELATIVE: u32 = 160; - -/// Object file compatibility attributes -pub const SHT_AARCH64_ATTRIBUTES: u32 = 0x70000003; -pub const SHT_AARCH64_ATTRIBUTES_SECTION_NAME: &str = ".ARM.attributes"; - -/// Architecture compatibility information. -/// -/// A segment of type PT_AARCH64_ARCHEXT (if present) contains information -/// describing the architecture capabilities required by the executable file. -/// Not all platform ABIs require this segment; the Linux ABI does not. If the -/// segment is present it must appear before segment of type PT_LOAD. -pub const PT_AARCH64_ARCHEXT: u32 = 0x70000000; -/// (if present) describes the location of a program’s exception unwind tables. -pub const PT_AARCH64_UNWIND: u32 = 0x70000001; -/// Reserved for MTE memory tag data dumps in core files -/// (if present) hold MTE memory tags for a particular memory range. -/// At present they are defined for core dump files of type ET_CORE -/// See -pub const PT_AARCH64_MEMTAG_MTE: u32 = 0x70000002; - -/// The function associated with the symbol may follow a variant procedure call -/// standard with different register usage convention. -/// Found in Symbol's st_other field -pub const STO_AARCH64_VARIANT_PCS: u8 = 0x80; - -pub const GNU_PROPERTY_AARCH64_FEATURE_1_AND: u32 = 0xc0000000; -pub const GNU_PROPERTY_AARCH64_FEATURE_1_BTI: u32 = 0x1; -pub const GNU_PROPERTY_AARCH64_FEATURE_1_PAC: u32 = 0x2; - -// AArch64 specific values for the Dyn d_tag field. -/// indicates PLTs enabled with Branch Target Identification mechanism -pub const DT_AARCH64_BTI_PLT: i64 = 0x70000001; -/// indicates PLTs enabled with Pointer Authentication. -pub const DT_AARCH64_PAC_PLT: i64 = 0x70000003; -/// must be present if there are R_{CLS}_JUMP_SLOT relocations that reference -/// symbols marked with the STO_AARCH64_VARIANT_PCS flag set in their st_other field -pub const DT_AARCH64_VARIANT_PCS: i64 = 0x70000005; - -/// No relocation. -pub const R_AARCH64_NONE: u32 = 0; -/// Direct 32 bit. -pub const R_AARCH64_P32_ABS32: u32 = 1; -/// Copy symbol at runtime. -pub const R_AARCH64_P32_COPY: u32 = 180; -/// Create GOT entry. -pub const R_AARCH64_P32_GLOB_DAT: u32 = 181; -/// Create PLT entry. -pub const R_AARCH64_P32_JUMP_SLOT: u32 = 182; -/// Adjust by program base. -pub const R_AARCH64_P32_RELATIVE: u32 = 183; -/// Module number, 32 bit. -pub const R_AARCH64_P32_TLS_DTPMOD: u32 = 184; -/// Module-relative offset, 32 bit. -pub const R_AARCH64_P32_TLS_DTPREL: u32 = 185; -/// TP-relative offset, 32 bit. -pub const R_AARCH64_P32_TLS_TPREL: u32 = 186; -/// TLS Descriptor. -pub const R_AARCH64_P32_TLSDESC: u32 = 187; -/// STT_GNU_IFUNC relocation -pub const R_AARCH64_P32_IRELATIVE: u32 = 188; -/// Direct 64 bit. -pub const R_AARCH64_ABS64: u32 = 257; -/// Direct 32 bit. -pub const R_AARCH64_ABS32: u32 = 258; -/// Direct 16-bit. -pub const R_AARCH64_ABS16: u32 = 259; -/// PC-relative 64-bit. -pub const R_AARCH64_PREL64: u32 = 260; -/// PC-relative 32-bit. -pub const R_AARCH64_PREL32: u32 = 261; -/// PC-relative 16-bit. -pub const R_AARCH64_PREL16: u32 = 262; -/// Dir. MOVZ imm. from bits 15:0. -pub const R_AARCH64_MOVW_UABS_G0: u32 = 263; -/// Likewise for MOVK; no check. -pub const R_AARCH64_MOVW_UABS_G0_NC: u32 = 264; -/// Dir. MOVZ imm. from bits 31:16. -pub const R_AARCH64_MOVW_UABS_G1: u32 = 265; -/// Likewise for MOVK; no check. -pub const R_AARCH64_MOVW_UABS_G1_NC: u32 = 266; -/// Dir. MOVZ imm. from bits 47:32. -pub const R_AARCH64_MOVW_UABS_G2: u32 = 267; -/// Likewise for MOVK; no check. -pub const R_AARCH64_MOVW_UABS_G2_NC: u32 = 268; -/// Dir. MOV{K,Z} imm. from 63:48. -pub const R_AARCH64_MOVW_UABS_G3: u32 = 269; -/// Dir. MOV{N,Z} imm. from 15:0. -pub const R_AARCH64_MOVW_SABS_G0: u32 = 270; -/// Dir. MOV{N,Z} imm. from 31:16. -pub const R_AARCH64_MOVW_SABS_G1: u32 = 271; -/// Dir. MOV{N,Z} imm. from 47:32. -pub const R_AARCH64_MOVW_SABS_G2: u32 = 272; -/// PC-rel. LD imm. from bits 20:2. -pub const R_AARCH64_LD_PREL_LO19: u32 = 273; -/// PC-rel. ADR imm. from bits 20:0. -pub const R_AARCH64_ADR_PREL_LO21: u32 = 274; -/// Page-rel. ADRP imm. from 32:12. -pub const R_AARCH64_ADR_PREL_PG_HI21: u32 = 275; -/// Likewise; no overflow check. -pub const R_AARCH64_ADR_PREL_PG_HI21_NC: u32 = 276; -/// Dir. ADD imm. from bits 11:0. -pub const R_AARCH64_ADD_ABS_LO12_NC: u32 = 277; -/// Likewise for LD/ST; no check. -pub const R_AARCH64_LDST8_ABS_LO12_NC: u32 = 278; -/// PC-rel. TBZ/TBNZ imm. from 15:2. -pub const R_AARCH64_TSTBR14: u32 = 279; -/// PC-rel. cond. br. imm. from 20:2. -pub const R_AARCH64_CONDBR19: u32 = 280; -/// PC-rel. B imm. from bits 27:2. -pub const R_AARCH64_JUMP26: u32 = 282; -/// Likewise for CALL. -pub const R_AARCH64_CALL26: u32 = 283; -/// Dir. ADD imm. from bits 11:1. -pub const R_AARCH64_LDST16_ABS_LO12_NC: u32 = 284; -/// Likewise for bits 11:2. -pub const R_AARCH64_LDST32_ABS_LO12_NC: u32 = 285; -/// Likewise for bits 11:3. -pub const R_AARCH64_LDST64_ABS_LO12_NC: u32 = 286; -/// PC-rel. MOV{N,Z} imm. from 15:0. -pub const R_AARCH64_MOVW_PREL_G0: u32 = 287; -/// Likewise for MOVK; no check. -pub const R_AARCH64_MOVW_PREL_G0_NC: u32 = 288; -/// PC-rel. MOV{N,Z} imm. from 31:16. -pub const R_AARCH64_MOVW_PREL_G1: u32 = 289; -/// Likewise for MOVK; no check. -pub const R_AARCH64_MOVW_PREL_G1_NC: u32 = 290; -/// PC-rel. MOV{N,Z} imm. from 47:32. -pub const R_AARCH64_MOVW_PREL_G2: u32 = 291; -/// Likewise for MOVK; no check. -pub const R_AARCH64_MOVW_PREL_G2_NC: u32 = 292; -/// PC-rel. MOV{N,Z} imm. from 63:48. -pub const R_AARCH64_MOVW_PREL_G3: u32 = 293; -/// Dir. ADD imm. from bits 11:4. -pub const R_AARCH64_LDST128_ABS_LO12_NC: u32 = 299; -/// GOT-rel. off. MOV{N,Z} imm. 15:0. -pub const R_AARCH64_MOVW_GOTOFF_G0: u32 = 300; -/// Likewise for MOVK; no check. -pub const R_AARCH64_MOVW_GOTOFF_G0_NC: u32 = 301; -/// GOT-rel. o. MOV{N,Z} imm. 31:16. -pub const R_AARCH64_MOVW_GOTOFF_G1: u32 = 302; -/// Likewise for MOVK; no check. -pub const R_AARCH64_MOVW_GOTOFF_G1_NC: u32 = 303; -/// GOT-rel. o. MOV{N,Z} imm. 47:32. -pub const R_AARCH64_MOVW_GOTOFF_G2: u32 = 304; -/// Likewise for MOVK; no check. -pub const R_AARCH64_MOVW_GOTOFF_G2_NC: u32 = 305; -/// GOT-rel. o. MOV{N,Z} imm. 63:48. -pub const R_AARCH64_MOVW_GOTOFF_G3: u32 = 306; -/// GOT-relative 64-bit. -pub const R_AARCH64_GOTREL64: u32 = 307; -/// GOT-relative 32-bit. -pub const R_AARCH64_GOTREL32: u32 = 308; -/// PC-rel. GOT off. load imm. 20:2. -pub const R_AARCH64_GOT_LD_PREL19: u32 = 309; -/// GOT-rel. off. LD/ST imm. 14:3. -pub const R_AARCH64_LD64_GOTOFF_LO15: u32 = 310; -/// P-page-rel. GOT off. ADRP: u32 = 32:12. -pub const R_AARCH64_ADR_GOT_PAGE: u32 = 311; -/// Dir. GOT off. LD/ST imm. 11:3. -pub const R_AARCH64_LD64_GOT_LO12_NC: u32 = 312; -/// GOT-page-rel. GOT off. LD/ST: u32 = 14:3 -pub const R_AARCH64_LD64_GOTPAGE_LO15: u32 = 313; -/// PC-relative ADR imm. 20:0. -pub const R_AARCH64_TLSGD_ADR_PREL21: u32 = 512; -/// page-rel. ADRP imm. 32:12. -pub const R_AARCH64_TLSGD_ADR_PAGE21: u32 = 513; -/// direct ADD imm. from 11:0. -pub const R_AARCH64_TLSGD_ADD_LO12_NC: u32 = 514; -/// GOT-rel. MOV{N,Z} 31:16. -pub const R_AARCH64_TLSGD_MOVW_G1: u32 = 515; -/// GOT-rel. MOVK imm. 15:0. -pub const R_AARCH64_TLSGD_MOVW_G0_NC: u32 = 516; -/// Like 512; local dynamic model. -pub const R_AARCH64_TLSLD_ADR_PREL21: u32 = 517; -/// Like 513; local dynamic model. -pub const R_AARCH64_TLSLD_ADR_PAGE21: u32 = 518; -/// Like 514; local dynamic model. -pub const R_AARCH64_TLSLD_ADD_LO12_NC: u32 = 519; -/// Like 515; local dynamic model. -pub const R_AARCH64_TLSLD_MOVW_G1: u32 = 520; -/// Like 516; local dynamic model. -pub const R_AARCH64_TLSLD_MOVW_G0_NC: u32 = 521; -/// TLS PC-rel. load imm. 20:2. -pub const R_AARCH64_TLSLD_LD_PREL19: u32 = 522; -/// TLS DTP-rel. MOV{N,Z} 47:32. -pub const R_AARCH64_TLSLD_MOVW_DTPREL_G2: u32 = 523; -/// TLS DTP-rel. MOV{N,Z} 31:16. -pub const R_AARCH64_TLSLD_MOVW_DTPREL_G1: u32 = 524; -/// Likewise; MOVK; no check. -pub const R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC: u32 = 525; -/// TLS DTP-rel. MOV{N,Z} 15:0. -pub const R_AARCH64_TLSLD_MOVW_DTPREL_G0: u32 = 526; -/// Likewise; MOVK; no check. -pub const R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: u32 = 527; -/// DTP-rel. ADD imm. from 23:12. -pub const R_AARCH64_TLSLD_ADD_DTPREL_HI12: u32 = 528; -/// DTP-rel. ADD imm. from 11:0. -pub const R_AARCH64_TLSLD_ADD_DTPREL_LO12: u32 = 529; -/// Likewise; no ovfl. check. -pub const R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: u32 = 530; -/// DTP-rel. LD/ST imm. 11:0. -pub const R_AARCH64_TLSLD_LDST8_DTPREL_LO12: u32 = 531; -/// Likewise; no check. -pub const R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC: u32 = 532; -/// DTP-rel. LD/ST imm. 11:1. -pub const R_AARCH64_TLSLD_LDST16_DTPREL_LO12: u32 = 533; -/// Likewise; no check. -pub const R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC: u32 = 534; -/// DTP-rel. LD/ST imm. 11:2. -pub const R_AARCH64_TLSLD_LDST32_DTPREL_LO12: u32 = 535; -/// Likewise; no check. -pub const R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC: u32 = 536; -/// DTP-rel. LD/ST imm. 11:3. -pub const R_AARCH64_TLSLD_LDST64_DTPREL_LO12: u32 = 537; -/// Likewise; no check. -pub const R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC: u32 = 538; -/// GOT-rel. MOV{N,Z} 31:16. -pub const R_AARCH64_TLSIE_MOVW_GOTTPREL_G1: u32 = 539; -/// GOT-rel. MOVK: u32 = 15:0. -pub const R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC: u32 = 540; -/// Page-rel. ADRP: u32 = 32:12. -pub const R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: u32 = 541; -/// Direct LD off. 11:3. -pub const R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: u32 = 542; -/// PC-rel. load imm. 20:2. -pub const R_AARCH64_TLSIE_LD_GOTTPREL_PREL19: u32 = 543; -/// TLS TP-rel. MOV{N,Z} 47:32. -pub const R_AARCH64_TLSLE_MOVW_TPREL_G2: u32 = 544; -/// TLS TP-rel. MOV{N,Z} 31:16. -pub const R_AARCH64_TLSLE_MOVW_TPREL_G1: u32 = 545; -/// Likewise; MOVK; no check. -pub const R_AARCH64_TLSLE_MOVW_TPREL_G1_NC: u32 = 546; -/// TLS TP-rel. MOV{N,Z} 15:0. -pub const R_AARCH64_TLSLE_MOVW_TPREL_G0: u32 = 547; -/// Likewise; MOVK; no check. -pub const R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: u32 = 548; -/// TP-rel. ADD imm. 23:12. -pub const R_AARCH64_TLSLE_ADD_TPREL_HI12: u32 = 549; -/// TP-rel. ADD imm. 11:0. -pub const R_AARCH64_TLSLE_ADD_TPREL_LO12: u32 = 550; -/// Likewise; no ovfl. check. -pub const R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: u32 = 551; -/// TP-rel. LD/ST off. 11:0. -pub const R_AARCH64_TLSLE_LDST8_TPREL_LO12: u32 = 552; -/// Likewise; no ovfl. check. -pub const R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: u32 = 553; -/// TP-rel. LD/ST off. 11:1. -pub const R_AARCH64_TLSLE_LDST16_TPREL_LO12: u32 = 554; -/// Likewise; no check. -pub const R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: u32 = 555; -/// TP-rel. LD/ST off. 11:2. -pub const R_AARCH64_TLSLE_LDST32_TPREL_LO12: u32 = 556; -/// Likewise; no check. -pub const R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: u32 = 557; -/// TP-rel. LD/ST off. 11:3. -pub const R_AARCH64_TLSLE_LDST64_TPREL_LO12: u32 = 558; -/// Likewise; no check. -pub const R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: u32 = 559; -/// PC-rel. load immediate 20:2. -pub const R_AARCH64_TLSDESC_LD_PREL19: u32 = 560; -/// PC-rel. ADR immediate 20:0. -pub const R_AARCH64_TLSDESC_ADR_PREL21: u32 = 561; -/// Page-rel. ADRP imm. 32:12. -pub const R_AARCH64_TLSDESC_ADR_PAGE21: u32 = 562; -/// Direct LD off. from 11:3. -pub const R_AARCH64_TLSDESC_LD64_LO12: u32 = 563; -/// Direct ADD imm. from 11:0. -pub const R_AARCH64_TLSDESC_ADD_LO12: u32 = 564; -/// GOT-rel. MOV{N,Z} imm. 31:16. -pub const R_AARCH64_TLSDESC_OFF_G1: u32 = 565; -/// GOT-rel. MOVK imm. 15:0; no ck. -pub const R_AARCH64_TLSDESC_OFF_G0_NC: u32 = 566; -/// Relax LDR. -pub const R_AARCH64_TLSDESC_LDR: u32 = 567; -/// Relax ADD. -pub const R_AARCH64_TLSDESC_ADD: u32 = 568; -/// Relax BLR. -pub const R_AARCH64_TLSDESC_CALL: u32 = 569; -/// TP-rel. LD/ST off. 11:4. -pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12: u32 = 570; -/// Likewise; no check. -pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: u32 = 571; -/// DTP-rel. LD/ST imm. 11:4. -pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12: u32 = 572; -/// Likewise; no check. -pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC: u32 = 573; -/// Copy symbol at runtime. -pub const R_AARCH64_COPY: u32 = 1024; -/// Create GOT entry. -pub const R_AARCH64_GLOB_DAT: u32 = 1025; -/// Create PLT entry. -pub const R_AARCH64_JUMP_SLOT: u32 = 1026; -/// Adjust by program base. -pub const R_AARCH64_RELATIVE: u32 = 1027; -/// Module number, 64 bit. -pub const R_AARCH64_TLS_DTPMOD: u32 = 1028; -/// Module-relative offset, 64 bit. -pub const R_AARCH64_TLS_DTPREL: u32 = 1029; -/// TP-relative offset, 64 bit. -pub const R_AARCH64_TLS_TPREL: u32 = 1030; -/// TLS Descriptor. -pub const R_AARCH64_TLSDESC: u32 = 1031; -/// STT_GNU_IFUNC relocation. -pub const R_AARCH64_IRELATIVE: u32 = 1032; - -// ____ ____ ____ -// | _ \ _____ _____ _ __| _ \ / ___| -// | |_) / _ \ \ /\ / / _ \ '__| |_) | | -// | __/ (_) \ V V / __/ | | __/| |___ -// |_| \___/ \_/\_/ \___|_| |_| \____| -// -// See: https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#ELF-HEAD - -/// PowerPC embedded flag -pub const EF_PPC_EMB: u32 = 0x80000000; -/// PowerPC -mrelocatable flag -pub const EF_PPC_RELOCATABLE: u32 = 0x00010000; -/// PowerPC -mrelocatable-lib flag -pub const EF_PPC_RELOCATABLE_LIB: u32 = 0x00008000; - -// PowerPC relocations types -pub const R_PPC_NONE: u32 = 0; -/// 32bit absolute address -pub const R_PPC_ADDR32: u32 = 1; -/// 26bit address, 2 bits ignored. -pub const R_PPC_ADDR24: u32 = 2; -/// 16bit absolute address -pub const R_PPC_ADDR16: u32 = 3; -/// lower 16bit of absolute address -pub const R_PPC_ADDR16_LO: u32 = 4; -/// high 16bit of absolute address -pub const R_PPC_ADDR16_HI: u32 = 5; -/// adjusted high 16bit -pub const R_PPC_ADDR16_HA: u32 = 6; -/// 16bit address, 2 bits ignored -pub const R_PPC_ADDR14: u32 = 7; -pub const R_PPC_ADDR14_BRTAKEN: u32 = 8; -pub const R_PPC_ADDR14_BRNTAKEN: u32 = 9; -/// PC relative 26 bit -pub const R_PPC_REL24: u32 = 10; -/// PC relative 16 bit -pub const R_PPC_REL14: u32 = 11; -pub const R_PPC_REL14_BRTAKEN: u32 = 12; -pub const R_PPC_REL14_BRNTAKEN: u32 = 13; -pub const R_PPC_GOT16: u32 = 14; -pub const R_PPC_GOT16_LO: u32 = 15; -pub const R_PPC_GOT16_HI: u32 = 16; -pub const R_PPC_GOT16_HA: u32 = 17; -pub const R_PPC_PLTREL24: u32 = 18; -pub const R_PPC_COPY: u32 = 19; -pub const R_PPC_GLOB_DAT: u32 = 20; -pub const R_PPC_JMP_SLOT: u32 = 21; -pub const R_PPC_RELATIVE: u32 = 22; -pub const R_PPC_LOCAL24PC: u32 = 23; -pub const R_PPC_UADDR32: u32 = 24; -pub const R_PPC_UADDR16: u32 = 25; -pub const R_PPC_REL32: u32 = 26; -pub const R_PPC_PLT32: u32 = 27; -pub const R_PPC_PLTREL32: u32 = 28; -pub const R_PPC_PLT16_LO: u32 = 29; -pub const R_PPC_PLT16_HI: u32 = 30; -pub const R_PPC_PLT16_HA: u32 = 31; -pub const R_PPC_SDAREL16: u32 = 32; -pub const R_PPC_SECTOFF: u32 = 33; -pub const R_PPC_SECTOFF_LO: u32 = 34; -pub const R_PPC_SECTOFF_HI: u32 = 35; -pub const R_PPC_SECTOFF_HA: u32 = 36; - -/// (sym+add)@tls -pub const R_PPC_TLS: u32 = 67; -/// (sym+add)@dtpmod -pub const R_PPC_DTPMOD32: u32 = 68; -/// (sym+add)@tprel -pub const R_PPC_TPREL16: u32 = 69; -/// (sym+add)@tprel@l -pub const R_PPC_TPREL16_LO: u32 = 70; -/// (sym+add)@tprel@h -pub const R_PPC_TPREL16_HI: u32 = 71; -/// (sym+add)@tprel@ha -pub const R_PPC_TPREL16_HA: u32 = 72; -/// (sym+add)@tprel -pub const R_PPC_TPREL32: u32 = 73; -/// (sym+add)@dtprel -pub const R_PPC_DTPREL16: u32 = 74; -/// (sym+add)@dtprel@l -pub const R_PPC_DTPREL16_LO: u32 = 75; -/// (sym+add)@dtprel@h -pub const R_PPC_DTPREL16_HI: u32 = 76; -/// (sym+add)@dtprel@ha -pub const R_PPC_DTPREL16_HA: u32 = 77; -/// (sym+add)@dtprel -pub const R_PPC_DTPREL32: u32 = 78; -/// (sym+add)@got@tlsgd -pub const R_PPC_GOT_TLSGD16: u32 = 79; -/// (sym+add)@got@tlsgd@l -pub const R_PPC_GOT_TLSGD16_LO: u32 = 80; -/// (sym+add)@got@tlsgd@h -pub const R_PPC_GOT_TLSGD16_HI: u32 = 81; -/// (sym+add)@got@tlsgd@ha -pub const R_PPC_GOT_TLSGD16_HA: u32 = 82; -/// (sym+add)@got@tlsld -pub const R_PPC_GOT_TLSLD16: u32 = 83; -/// (sym+add)@got@tlsld@l -pub const R_PPC_GOT_TLSLD16_LO: u32 = 84; -/// (sym+add)@got@tlsld@h -pub const R_PPC_GOT_TLSLD16_HI: u32 = 85; -/// (sym+add)@got@tlsld@ha -pub const R_PPC_GOT_TLSLD16_HA: u32 = 86; -/// (sym+add)@got@tprel -pub const R_PPC_GOT_TPREL16: u32 = 87; -/// (sym+add)@got@tprel@l -pub const R_PPC_GOT_TPREL16_LO: u32 = 88; -/// (sym+add)@got@tprel@h -pub const R_PPC_GOT_TPREL16_HI: u32 = 89; -/// (sym+add)@got@tprel@ha -pub const R_PPC_GOT_TPREL16_HA: u32 = 90; -/// (sym+add)@got@dtprel -pub const R_PPC_GOT_DTPREL16: u32 = 91; -/// (sym+add)@got@dtprel@l -pub const R_PPC_GOT_DTPREL16_LO: u32 = 92; -/// (sym+add)@got@dtprel@h -pub const R_PPC_GOT_DTPREL16_HI: u32 = 93; -/// (sym+add)@got@dtprel@ha -pub const R_PPC_GOT_DTPREL16_HA: u32 = 94; -/// (sym+add)@tlsgd -pub const R_PPC_TLSGD: u32 = 95; -/// (sym+add)@tlsld -pub const R_PPC_TLSLD: u32 = 96; - -// The remaining relocs are from the Embedded ELF ABI, and are not in the SVR4 ELF ABI. -pub const R_PPC_EMB_NADDR32: u32 = 101; -pub const R_PPC_EMB_NADDR16: u32 = 102; -pub const R_PPC_EMB_NADDR16_LO: u32 = 103; -pub const R_PPC_EMB_NADDR16_HI: u32 = 104; -pub const R_PPC_EMB_NADDR16_HA: u32 = 105; -pub const R_PPC_EMB_SDAI16: u32 = 106; -pub const R_PPC_EMB_SDA2I16: u32 = 107; -pub const R_PPC_EMB_SDA2REL: u32 = 108; -/// 16 bit offset in SDA -pub const R_PPC_EMB_SDA21: u32 = 109; -pub const R_PPC_EMB_MRKREF: u32 = 110; -pub const R_PPC_EMB_RELSEC16: u32 = 111; -pub const R_PPC_EMB_RELST_LO: u32 = 112; -pub const R_PPC_EMB_RELST_HI: u32 = 113; -pub const R_PPC_EMB_RELST_HA: u32 = 114; -pub const R_PPC_EMB_BIT_FLD: u32 = 115; -pub const R_PPC_EMB_RELSDA: u32 = 116; - -/// like EMB_SDA21, but lower 16 bit -pub const R_PPC_DIAB_SDA21_LO: u32 = 180; -/// like EMB_SDA21, but high 16 bit -pub const R_PPC_DIAB_SDA21_HI: u32 = 181; -/// like EMB_SDA21, adjusted high 16 -pub const R_PPC_DIAB_SDA21_HA: u32 = 182; -/// like EMB_RELSDA, but lower 16 bit -pub const R_PPC_DIAB_RELSDA_LO: u32 = 183; -/// like EMB_RELSDA, but high 16 bit -pub const R_PPC_DIAB_RELSDA_HI: u32 = 184; -/// like EMB_RELSDA, adjusted high 16 -pub const R_PPC_DIAB_RELSDA_HA: u32 = 185; - -// GNU extension to support local ifunc. -pub const R_PPC_IRELATIVE: u32 = 248; - -// GNU relocs used in PIC code sequences. -/// (sym+add-.) -pub const R_PPC_REL16: u32 = 249; -/// (sym+add-.)@l -pub const R_PPC_REL16_LO: u32 = 250; -/// (sym+add-.)@h -pub const R_PPC_REL16_HI: u32 = 251; -/// (sym+add-.)@ha -pub const R_PPC_REL16_HA: u32 = 252; - -/// This is a phony reloc to handle any old fashioned TOC16 references that may still be in object files. -pub const R_PPC_TOC16: u32 = 255; - -// PowerPC specific values for the Dyn d_tag field. -pub const DT_PPC_GOT: i64 = 0x70000000; -pub const DT_PPC_OPT: i64 = 0x70000001; - -/// PowerPC specific values for the DT_PPC_OPT Dyn entry. -pub const PPC_OPT_TLS: u64 = 1; - -// e_flags bits specifying ABI. -// 1 for original function descriptor using ABI, -// 2 for revised ABI without function descriptors, -// 0 for unspecified or not using any features affected by the differences. -pub const EF_PPC64_ABI: u32 = 3; - -// PowerPC64 specific values for the Dyn d_tag field. -pub const DT_PPC64_GLINK: i64 = 0x70000000; -pub const DT_PPC64_OPD: i64 = 0x70000001; -pub const DT_PPC64_OPDSZ: i64 = 0x70000002; -pub const DT_PPC64_OPT: i64 = 0x70000003; - -// PowerPC64 specific bits in the DT_PPC64_OPT Dyn entry. -pub const PPC64_OPT_TLS: u64 = 1; -pub const PPC64_OPT_MULTI_TOC: u64 = 2; -pub const PPC64_OPT_LOCALENTRY: u64 = 4; - -// PowerPC64 specific values for the Elf64_Sym st_other field. -pub const STO_PPC64_LOCAL_BIT: u8 = 5; -pub const STO_PPC64_LOCAL_MASK: u8 = 7 << STO_PPC64_LOCAL_BIT; - -// Relocation types -// -// A Represents the addend used to compute the value of the relocatable field. -// B Represents the base address at which a shared object has been loaded into memory during execution. -// G Represents the offset into the global offset table, relative to -// the TOC base, at which the address of the relocation entry's symbol -// plus addend will reside during execution. -// L Represents the section offset or address of the procedure linkage -// table entry for the symbol plus addend. -// M Similar to G, except that the address which is stored may be the -// address of the procedure linkage table entry for the symbol. -// P Represents the place (section offset or address) of the storage -// unit being relocated (computed using r_offset). -// R Represents the offset of the symbol within the section in which -// the symbol is defined (its section-relative address). -// S Represents the value of the symbol whose index resides in the relocation entry. - -/// none -pub const R_PPC64_NONE: u32 = 0; -/// `S + A` -pub const R_PPC64_ADDR32: u32 = 1; -/// `(S + A) >> 2` -pub const R_PPC64_ADDR24: u32 = 2; -/// `S + A` -pub const R_PPC64_ADDR16: u32 = 3; -/// `#lo(S + A)` -pub const R_PPC64_ADDR16_LO: u32 = 4; -/// `#hi(S + A)` -pub const R_PPC64_ADDR16_HI: u32 = 5; -/// `#ha(S + A)` -pub const R_PPC64_ADDR16_HA: u32 = 6; -/// `(S + A) >> 2` -pub const R_PPC64_ADDR14: u32 = 7; -/// `(S + A) >> 2` -pub const R_PPC64_ADDR14_BRTAKEN: u32 = 8; -/// `(S + A) >> 2` -pub const R_PPC64_ADDR14_BRNTAKEN: u32 = 9; -/// `(S + A - P) >> 2` -pub const R_PPC64_REL24: u32 = 10; -/// `(S + A - P) >> 2` -pub const R_PPC64_REL14: u32 = 11; -/// `(S + A - P) >> 2` -pub const R_PPC64_REL14_BRTAKEN: u32 = 12; -/// `(S + A - P) >> 2` -pub const R_PPC64_REL14_BRNTAKEN: u32 = 13; -/// `G` -pub const R_PPC64_GOT16: u32 = 14; -/// `#lo(G)` -pub const R_PPC64_GOT16_LO: u32 = 15; -/// `#hi(G)` -pub const R_PPC64_GOT16_HI: u32 = 16; -/// `#ha(G)` -pub const R_PPC64_GOT16_HA: u32 = 17; -/// none -pub const R_PPC64_COPY: u32 = 19; -/// `S + A` -pub const R_PPC64_GLOB_DAT: u32 = 20; -/// see below -pub const R_PPC64_JMP_SLOT: u32 = 21; -/// `B + A` -pub const R_PPC64_RELATIVE: u32 = 22; -/// `S + A` -pub const R_PPC64_UADDR32: u32 = 24; -/// `S + A` -pub const R_PPC64_UADDR16: u32 = 25; -/// `S + A - P` -pub const R_PPC64_REL32: u32 = 26; -/// `L` -pub const R_PPC64_PLT32: u32 = 27; -/// `L - P` -pub const R_PPC64_PLTREL32: u32 = 28; -/// `#lo(L)` -pub const R_PPC64_PLT16_LO: u32 = 29; -/// `#hi(L)` -pub const R_PPC64_PLT16_HI: u32 = 30; -/// `#ha(L)` -pub const R_PPC64_PLT16_HA: u32 = 31; -/// `R + A` -pub const R_PPC64_SECTOFF: u32 = 33; -/// `#lo(R + A)` -pub const R_PPC64_SECTOFF_LO: u32 = 34; -/// `#hi(R + A)` -pub const R_PPC64_SECTOFF_HI: u32 = 35; -/// `#ha(R + A)` -pub const R_PPC64_SECTOFF_HA: u32 = 36; -/// `(S + A - P) >> 2` -pub const R_PPC64_ADDR30: u32 = 37; -/// `S + A` -pub const R_PPC64_ADDR64: u32 = 38; -/// `#higher(S + A)` -pub const R_PPC64_ADDR16_HIGHER: u32 = 39; -/// `#highera(S + A)` -pub const R_PPC64_ADDR16_HIGHERA: u32 = 40; -/// `#highest(S + A)` -pub const R_PPC64_ADDR16_HIGHEST: u32 = 41; -/// `#highesta(S + A)` -pub const R_PPC64_ADDR16_HIGHESTA: u32 = 42; -/// `S + A` -pub const R_PPC64_UADDR64: u32 = 43; -/// `S + A - P` -pub const R_PPC64_REL64: u32 = 44; -/// `L` -pub const R_PPC64_PLT64: u32 = 45; -/// `L - P` -pub const R_PPC64_PLTREL64: u32 = 46; -/// `S + A - .TOC.` -pub const R_PPC64_TOC16: u32 = 47; -/// `#lo(S + A - .TOC.)` -pub const R_PPC64_TOC16_LO: u32 = 48; -/// `#hi(S + A - .TOC.)` -pub const R_PPC64_TOC16_HI: u32 = 49; -/// `#ha(S + A - .TOC.)` -pub const R_PPC64_TOC16_HA: u32 = 50; -/// `.TOC.` -pub const R_PPC64_TOC: u32 = 51; -/// `M` -pub const R_PPC64_PLTGOT16: u32 = 52; -/// `#lo(M)` -pub const R_PPC64_PLTGOT16_LO: u32 = 53; -/// `#hi(M)` -pub const R_PPC64_PLTGOT16_HI: u32 = 54; -/// `#ha(M)` -pub const R_PPC64_PLTGOT16_HA: u32 = 55; -/// `(S + A) >> 2` -pub const R_PPC64_ADDR16_DS: u32 = 56; -/// `#lo(S + A) >> 2` -pub const R_PPC64_ADDR16_LO_DS: u32 = 57; -/// `G >> 2` -pub const R_PPC64_GOT16_DS: u32 = 58; -/// `#lo(G) >> 2` -pub const R_PPC64_GOT16_LO_DS: u32 = 59; -/// `#lo(L) >> 2` -pub const R_PPC64_PLT16_LO_DS: u32 = 60; -/// `(R + A) >> 2` -pub const R_PPC64_SECTOFF_DS: u32 = 61; -/// `#lo(R + A) >> 2` -pub const R_PPC64_SECTOFF_LO_DS: u32 = 62; -/// `(S + A - .TOC.) >> 2` -pub const R_PPC64_TOC16_DS: u32 = 63; -/// `#lo(S + A - .TOC.) >> 2` -pub const R_PPC64_TOC16_LO_DS: u32 = 64; -/// `M >> 2` -pub const R_PPC64_PLTGOT16_DS: u32 = 65; -/// `#lo(M) >> 2` -pub const R_PPC64_PLTGOT16_LO_DS: u32 = 66; -/// none -pub const R_PPC64_TLS: u32 = 67; -/// `@dtpmod` -pub const R_PPC64_DTPMOD64: u32 = 68; -/// `@tprel` -pub const R_PPC64_TPREL16: u32 = 69; -/// `#lo(@tprel)` -pub const R_PPC64_TPREL16_LO: u32 = 60; -/// `#hi(@tprel)` -pub const R_PPC64_TPREL16_HI: u32 = 71; -/// `#ha(@tprel)` -pub const R_PPC64_TPREL16_HA: u32 = 72; -/// `@tprel` -pub const R_PPC64_TPREL64: u32 = 73; -/// `@dtprel` -pub const R_PPC64_DTPREL16: u32 = 74; -/// `#lo(@dtprel)` -pub const R_PPC64_DTPREL16_LO: u32 = 75; -/// `#hi(@dtprel)` -pub const R_PPC64_DTPREL16_HI: u32 = 76; -/// `#ha(@dtprel)` -pub const R_PPC64_DTPREL16_HA: u32 = 77; -/// `@dtprel` -pub const R_PPC64_DTPREL64: u32 = 78; -/// `@got@tlsgd` -pub const R_PPC64_GOT_TLSGD16: u32 = 79; -/// `#lo(@got@tlsgd)` -pub const R_PPC64_GOT_TLSGD16_LO: u32 = 80; -/// `#hi(@got@tlsgd)` -pub const R_PPC64_GOT_TLSGD16_HI: u32 = 81; -/// `#ha(@got@tlsgd)` -pub const R_PPC64_GOT_TLSGD16_HA: u32 = 82; -/// `@got@tlsld` -pub const R_PPC64_GOT_TLSLD16: u32 = 83; -/// `#lo(@got@tlsld)` -pub const R_PPC64_GOT_TLSLD16_LO: u32 = 84; -/// `#hi(@got@tlsld)` -pub const R_PPC64_GOT_TLSLD16_HI: u32 = 85; -/// `#ha(@got@tlsld)` -pub const R_PPC64_GOT_TLSLD16_HA: u32 = 86; -/// `@got@tprel` -pub const R_PPC64_GOT_TPREL16_DS: u32 = 87; -/// `#lo(@got@tprel)` -pub const R_PPC64_GOT_TPREL16_LO_DS: u32 = 88; -/// `#hi(@got@tprel)` -pub const R_PPC64_GOT_TPREL16_HI: u32 = 89; -/// `#ha(@got@tprel)` -pub const R_PPC64_GOT_TPREL16_HA: u32 = 90; -/// `@got@dtprel` -pub const R_PPC64_GOT_DTPREL16_DS: u32 = 91; -/// `#lo(@got@dtprel)` -pub const R_PPC64_GOT_DTPREL16_LO_DS: u32 = 92; -/// `#hi(@got@dtprel)` -pub const R_PPC64_GOT_DTPREL16_HI: u32 = 93; -/// `#ha(@got@dtprel)` -pub const R_PPC64_GOT_DTPREL16_HA: u32 = 94; -/// `@tprel` -pub const R_PPC64_TPREL16_DS: u32 = 95; -/// `#lo(@tprel)` -pub const R_PPC64_TPREL16_LO_DS: u32 = 96; -/// `#higher(@tprel)` -pub const R_PPC64_TPREL16_HIGHER: u32 = 97; -/// `#highera(@tprel)` -pub const R_PPC64_TPREL16_HIGHERA: u32 = 98; -/// `#highest(@tprel)` -pub const R_PPC64_TPREL16_HIGHEST: u32 = 99; -/// `#highesta(@tprel)` -pub const R_PPC64_TPREL16_HIGHESTA: u32 = 100; -/// `@dtprel` -pub const R_PPC64_DTPREL16_DS: u32 = 101; -/// `#lo(@dtprel)` -pub const R_PPC64_DTPREL16_LO_DS: u32 = 102; -/// `#higher(@dtprel)` -pub const R_PPC64_DTPREL16_HIGHER: u32 = 103; -/// `#highera(@dtprel)` -pub const R_PPC64_DTPREL16_HIGHERA: u32 = 104; -/// `#highest(@dtprel)` -pub const R_PPC64_DTPREL16_HIGHEST: u32 = 105; -/// `#highesta(@dtprel)` -pub const R_PPC64_DTPREL16_HIGHESTA: u32 = 106; -/// `(sym+add)@tlsgd` -pub const R_PPC64_TLSGD: u32 = 107; -/// `(sym+add)@tlsld` -pub const R_PPC64_TLSLD: u32 = 108; -pub const R_PPC64_TOCSAVE: u32 = 109; -pub const R_PPC64_ADDR16_HIGH: u32 = 110; -pub const R_PPC64_ADDR16_HIGHA: u32 = 111; -pub const R_PPC64_TPREL16_HIGH: u32 = 112; -pub const R_PPC64_TPREL16_HIGHA: u32 = 113; -pub const R_PPC64_DTPREL16_HIGH: u32 = 114; -pub const R_PPC64_DTPREL16_HIGHA: u32 = 115; - -// GNU extension to support local ifunc. -pub const R_PPC64_JMP_IREL: u32 = 247; -pub const R_PPC64_IRELATIVE: u32 = 248; -/// `(sym+add-.)` -pub const R_PPC64_REL16: u32 = 249; -/// `(sym+add-.)@l` -pub const R_PPC64_REL16_LO: u32 = 250; -/// `(sym+add-.)@h` -pub const R_PPC64_REL16_HI: u32 = 251; -/// `(sym+add-.)@ha` -pub const R_PPC64_REL16_HA: u32 = 252; - -// ____ ___ ____ ____ __ __ -// | _ \|_ _/ ___| / ___| \ \ / / -// | |_) || |\___ \| | ____\ \ / / -// | _ < | | ___) | |__|_____\ V / -// |_| \_\___|____/ \____| \_/ -// -// See: https://github.com/riscv-non-isa/riscv-elf-psabi-doc - -/// This bit is set when the binary targets the C ABI. -pub const EF_RISCV_RVC: u32 = 0x0001; -pub const EF_RISCV_FLOAT_ABI_SOFT: u32 = 0x0000; -pub const EF_RISCV_FLOAT_ABI_SINGLE: u32 = 0x0002; -pub const EF_RISCV_FLOAT_ABI_DOUBLE: u32 = 0x0004; -pub const EF_RISCV_FLOAT_ABI_QUAD: u32 = 0x0006; -/// This is used as a mask to test for one of the above floating-point ABIs, -/// e.g., (e_flags & EF_RISCV_FLOAT_ABI) == EF_RISCV_FLOAT_ABI_DOUBLE. -pub const EF_RISCV_FLOAT_ABI_MASK: u32 = 0x0006; -/// This bit is set when the binary targets the E ABI. -pub const EF_RISCV_RVE: u32 = 0x0008; -/// This bit is set when the binary requires the RVTSO memory consistency model. -pub const EF_RISCV_TSO: u32 = 0x0010; - -pub const SHT_RISCV_ATTRIBUTES: u32 = 0x70000003; // SHT_LOPROC + 3; -pub const SHT_RISCV_ATTRIBUTES_SECTION_NAME: &str = ".riscv.attributes"; - -pub const PT_RISCV_ATTRIBUTES: u32 = 0x70000003; - -/// Any functions that use registers in a way that is incompatible with the -/// calling convention of the ABI in use must be annotated with STO_RISCV_VARIANT_CC -pub const STO_RISCV_VARIANT_CC: u8 = 0x80; - -/// An object must have the dynamic tag DT_RISCV_VARIANT_CC if it has one or more R_RISCV_JUMP_SLOT -/// relocations against symbols with the STO_RISCV_VARIANT_CC attribute. -pub const DT_RISCV_VARIANT_CC: i64 = 0x70000001; - -// RISC-V relocation types -// -// A Addend field in the relocation entry associated with the symbol -// B Base address of a shared object loaded into memory -// G Offset of the symbol into the GOT (Global Offset Table) -// GOT Address of the GOT (Global Offset Table) -// P Position of the relocation -// S Value of the symbol in the symbol table -// V Value at the position of the relocation -// GP Value of __global_pointer$ symbol -// TLSMODULE TLS module index for the object containing the symbol -// TLSOFFSET TLS static block offset (relative to tp) for the object containing the symbol - -pub const R_RISCV_NONE: u32 = 0; -/// 32-bit relocation: `S + A` -pub const R_RISCV_32: u32 = 1; -/// 64-bit relocation: `S + A` -pub const R_RISCV_64: u32 = 2; -/// Adjust a link address (A) to its load address: `(B + A).` -pub const R_RISCV_RELATIVE: u32 = 3; -/// Must be in executable; not allowed in shared library -pub const R_RISCV_COPY: u32 = 4; -/// Indicates the symbol associated with a PLT entry: `S` -pub const R_RISCV_JUMP_SLOT: u32 = 5; -/// `TLSMODULE` -pub const R_RISCV_TLS_DTPMOD32: u32 = 6; -/// `TLSMODULE` -pub const R_RISCV_TLS_DTPMOD64: u32 = 7; -/// `S + A - TLS_DTV_OFFSET` -pub const R_RISCV_TLS_DTPREL32: u32 = 8; -/// `S + A - TLS_DTV_OFFSET` -pub const R_RISCV_TLS_DTPREL64: u32 = 9; -/// `S + A + TLSOFFSET` -pub const R_RISCV_TLS_TPREL32: u32 = 10; -/// `S + A + TLSOFFSET` -pub const R_RISCV_TLS_TPREL64: u32 = 11; -/// 12-bit PC-relative branch offset `S + A - P` -pub const R_RISCV_BRANCH: u32 = 16; -/// 20-bit PC-relative jump offset `S + A - P` -pub const R_RISCV_JAL: u32 = 17; -/// Deprecated, please use CALL_PLT instead 32-bit PC-relative function call, macros call, tail: `S + A - P` -pub const R_RISCV_CALL: u32 = 18; -/// 32-bit PC-relative function call, macros call, tail (PIC): `S + A - P` -pub const R_RISCV_CALL_PLT: u32 = 19; -/// High 20 bits of 32-bit PC-relative GOT access, %got_pcrel_hi(symbol): `G + GOT + A - P` -pub const R_RISCV_GOT_HI20: u32 = 20; -/// High 20 bits of 32-bit PC-relative TLS IE GOT access, macro la.tls.ie -pub const R_RISCV_TLS_GOT_HI20: u32 = 21; -/// High 20 bits of 32-bit PC-relative TLS GD GOT reference, macro la.tls.gd -pub const R_RISCV_TLS_GD_HI20: u32 = 22; -/// High 20 bits of 32-bit PC-relative reference, %pcrel_hi(symbol): `S + A - P` -pub const R_RISCV_PCREL_HI20: u32 = 23; -/// Low 12 bits of a 32-bit PC-relative, %pcrel_lo(address of %pcrel_hi), the addend must be 0: `S - P` -pub const R_RISCV_PCREL_LO12_I: u32 = 24; -/// Low 12 bits of a 32-bit PC-relative, %pcrel_lo(address of %pcrel_hi), the addend must be 0: `S - P` -pub const R_RISCV_PCREL_LO12_S: u32 = 25; -/// High 20 bits of 32-bit absolute address, %hi(symbol): `S + A` -pub const R_RISCV_HI20: u32 = 26; -/// Low 12 bits of 32-bit absolute address, %lo(symbol): `S + A` -pub const R_RISCV_LO12_I: u32 = 27; -/// Low 12 bits of 32-bit absolute address, %lo(symbol): `S + A` -pub const R_RISCV_LO12_S: u32 = 28; -/// High 20 bits of TLS LE thread pointer offset, `%tprel_hi(symbol)` -pub const R_RISCV_TPREL_HI20: u32 = 29; -/// Low 12 bits of TLS LE thread pointer offset, `%tprel_lo(symbol)` -pub const R_RISCV_TPREL_LO12_I: u32 = 30; -/// Low 12 bits of TLS LE thread pointer offset, `%tprel_lo(symbol)` -pub const R_RISCV_TPREL_LO12_S: u32 = 31; -/// TLS LE thread pointer usage, `%tprel_add(symbol)` -pub const R_RISCV_TPREL_ADD: u32 = 32; -/// 8-bit label addition: `V + S + A` -pub const R_RISCV_ADD8: u32 = 33; -/// 16-bit label addition: `V + S + A` -pub const R_RISCV_ADD16: u32 = 34; -/// 32-bit label addition: `V + S + A` -pub const R_RISCV_ADD32: u32 = 35; -/// 64-bit label addition: `V + S + A` -pub const R_RISCV_ADD64: u32 = 36; -/// 8-bit label subtraction: `V - S - A` -pub const R_RISCV_SUB8: u32 = 37; -/// 16-bit label subtraction: `V - S - A` -pub const R_RISCV_SUB16: u32 = 38; -/// 32-bit label subtraction: `V - S - A` -pub const R_RISCV_SUB32: u32 = 39; -/// 64-bit label subtraction: `V - S - A` -pub const R_RISCV_SUB64: u32 = 40; -/// Alignment statement. The addend indicates the number of bytes occupied by -/// nop instructions at the relocation offset. The alignment boundary is -/// specified by the addend rounded up to the next power of two. -pub const R_RISCV_ALIGN: u32 = 43; -/// 8-bit PC-relative branch offset: `S + A - P` -pub const R_RISCV_RVC_BRANCH: u32 = 44; -/// 11-bit PC-relative jump offset: `S + A - P` -pub const R_RISCV_RVC_JUMP: u32 = 45; -/// High 6 bits of 18-bit absolute address: `S + A` -pub const R_RISCV_RVC_LUI: u32 = 46; -/// Instruction can be relaxed, paired with a normal relocation at the same address -pub const R_RISCV_RELAX: u32 = 51; -/// Local label subtraction: `V - S - A` -pub const R_RISCV_SUB6: u32 = 52; -/// Local label assignment: `S + A` -pub const R_RISCV_SET6: u32 = 53; -/// Local label assignment: `S + A` -pub const R_RISCV_SET8: u32 = 54; -/// Local label assignment: `S + A` -pub const R_RISCV_SET16: u32 = 55; -/// Local label assignment: `S + A` -pub const R_RISCV_SET32: u32 = 56; -/// 32-bit PC relative: `S + A - P` -pub const R_RISCV_32_PCREL: u32 = 57; -/// Relocation against a non-preemptible ifunc symbolifunc_resolver: `(B + A)` -pub const R_RISCV_IRELATIVE: u32 = 58; - -// ___ __ __ _ _ -// __ _( _ ) / /_ / /_ | || | -// \ \/ / _ \| '_ \ | '_ \| || |_ -// > < (_) | (_) | | (_) |__ _| -// /_/\_\___/ \___/___\___/ |_| -// |_____| -// -// See: https://gitlab.com/x86-psABIs/x86-64-ABI - -/// If an object file section does not have this flag set, then it may not hold -/// more than 2GB and can be freely referred to in objects using smaller code models. -pub const SHF_X86_64_LARGE: u64 = 0x10000000; - -/// This section contains unwind function table entries for stack unwinding. -pub const SHT_X86_64_UNWIND: u32 = 0x70000001; // SHT_LOPROC + 1; - -// x86_64 reloc types -// -// A Represents the addend used to compute the value of the relocatable field. -// B Represents the base address at which a shared object has been loaded into memory -// during execution. Generally, a shared object is built with a 0 base virtual address, -// but the execution address will be different. -// G Represents the offset into the global offset table at which the relocation entry’s symbol -// will reside during execution. -// GOT Represents the address of the global offset table. -// L Represents the place (section offset or address) of the Procedure Linkage Table entry for a symbol. -// P Represents the place (section offset or address) of the storage unit being relocated (computed using r_offset). -// S Represents the value of the symbol whose index resides in the relocation entry. -// Z Represents the size of the symbol whose index resides in the relocation entry. - -pub const R_X86_64_NONE: u32 = 0; -/// `S + A` -pub const R_X86_64_64: u32 = 1; -/// `S + A - P` -pub const R_X86_64_PC32: u32 = 2; -/// `G + A` -pub const R_X86_64_GOT32: u32 = 3; -/// `L + A - P` -pub const R_X86_64_PLT32: u32 = 4; -pub const R_X86_64_COPY: u32 = 5; -/// `S` -pub const R_X86_64_GLOB_DAT: u32 = 6; -/// `S` -pub const R_X86_64_JUMP_SLOT: u32 = 7; -/// `B + A` -pub const R_X86_64_RELATIVE: u32 = 8; -/// `G + GOT + A - P` -pub const R_X86_64_GOTPCREL: u32 = 9; -/// `S + A` -pub const R_X86_64_32: u32 = 10; -/// `S + A` -pub const R_X86_64_32S: u32 = 11; -/// `S + A` -pub const R_X86_64_16: u32 = 12; -/// `S + A - P` -pub const R_X86_64_PC16: u32 = 13; -/// `S + A` -pub const R_X86_64_8: u32 = 14; -/// `S + A - P` -pub const R_X86_64_PC8: u32 = 15; -pub const R_X86_64_DTPMOD64: u32 = 16; -pub const R_X86_64_DTPOFF64: u32 = 17; -pub const R_X86_64_TPOFF64: u32 = 18; -pub const R_X86_64_TLSGD: u32 = 19; -pub const R_X86_64_TLSLD: u32 = 20; -pub const R_X86_64_DTPOFF32: u32 = 21; -pub const R_X86_64_GOTTPOFF: u32 = 22; -pub const R_X86_64_TPOFF32: u32 = 23; -/// `S + A - P` -pub const R_X86_64_PC64: u32 = 24; -/// `S + A - GOT` -pub const R_X86_64_GOTOFF64: u32 = 25; -/// `GOT + A - P` -pub const R_X86_64_GOTPC32: u32 = 26; -/// `G + A` -pub const R_X86_64_GOT64: u32 = 27; -/// `G + GOT - P + A` -pub const R_X86_64_GOTPCREL64: u32 = 28; -/// `GOT - P + A` -pub const R_X86_64_GOTPC64: u32 = 29; -/// `L - GOT + A` -pub const R_X86_64_PLTOFF64: u32 = 31; -/// `Z + A` -pub const R_X86_64_SIZE32: u32 = 32; -/// `Z + A` -pub const R_X86_64_SIZE64: u32 = 33; -pub const R_X86_64_GOTPC32_TLSDESC: u32 = 34; -pub const R_X86_64_TLSDESC_CALL: u32 = 35; -pub const R_X86_64_TLSDESC: u32 = 36; -/// `indirect (B + A)` -pub const R_X86_64_IRELATIVE: u32 = 37; -/// `B + A` -pub const R_X86_64_RELATIVE64: u32 = 38; -/// `G + GOT + A - P` -pub const R_X86_64_GOTPCRELX: u32 = 41; -/// `G + GOT + A - P` -pub const R_X86_64_REX_GOTPCRELX: u32 = 42; diff --git a/arceos/modules/elf/src/compression.rs b/arceos/modules/elf/src/compression.rs deleted file mode 100644 index 1e11fdb6f..000000000 --- a/arceos/modules/elf/src/compression.rs +++ /dev/null @@ -1,153 +0,0 @@ -//! Parsing [CompressionHeader] from compressed ELF sections -//! -//! Note: This library does not provide any decompression functionality, but -//! does expose parsed ELF compression headers alongside the raw compressed data. -//! -//! It is up to users of the library to choose the decompression library of -//! their choice when dealing with compressed section contents. -use crate::endian::EndianParse; -use crate::file::Class; -use crate::parse::{ParseAt, ParseError}; - -/// C-style 32-bit ELF Compression Header definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf32_Chdr { - pub ch_type: u32, - pub ch_size: u32, - pub ch_addralign: u32, -} - -/// C-style 64-bit ELF Compression Header definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf64_Chdr { - pub ch_type: u32, - pub ch_reserved: u32, - pub ch_size: u64, - pub ch_addralign: u64, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CompressionHeader { - pub ch_type: u32, - pub ch_size: u64, - pub ch_addralign: u64, -} - -impl ParseAt for CompressionHeader { - fn parse_at( - endian: E, - class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - match class { - Class::ELF32 => Ok(CompressionHeader { - ch_type: endian.parse_u32_at(offset, data)?, - ch_size: endian.parse_u32_at(offset, data)? as u64, - ch_addralign: endian.parse_u32_at(offset, data)? as u64, - }), - Class::ELF64 => { - let ch_type = endian.parse_u32_at(offset, data)?; - let _ch_reserved = endian.parse_u32_at(offset, data)?; - Ok(CompressionHeader { - ch_type, - ch_size: endian.parse_u64_at(offset, data)?, - ch_addralign: endian.parse_u64_at(offset, data)?, - }) - } - } - } - - #[inline] - fn size_for(class: Class) -> usize { - match class { - Class::ELF32 => 12, - Class::ELF64 => 24, - } - } -} - -#[cfg(test)] -mod parse_tests { - use super::*; - use crate::endian::{BigEndian, LittleEndian}; - use crate::parse::{test_parse_for, test_parse_fuzz_too_short}; - - #[test] - fn parse_chdr32_lsb() { - test_parse_for( - LittleEndian, - Class::ELF32, - CompressionHeader { - ch_type: 0x03020100, - ch_size: 0x07060504, - ch_addralign: 0x0B0A0908, - }, - ); - } - - #[test] - fn parse_chdr32_msb() { - test_parse_for( - BigEndian, - Class::ELF32, - CompressionHeader { - ch_type: 0x00010203, - ch_size: 0x04050607, - ch_addralign: 0x08090A0B, - }, - ); - } - - #[test] - fn parse_chdr64_lsb() { - test_parse_for( - LittleEndian, - Class::ELF64, - CompressionHeader { - ch_type: 0x03020100, - ch_size: 0x0F0E0D0C0B0A0908, - ch_addralign: 0x1716151413121110, - }, - ); - } - - #[test] - fn parse_chdr64_msb() { - test_parse_for( - BigEndian, - Class::ELF64, - CompressionHeader { - ch_type: 0x00010203, - ch_size: 0x08090A0B0C0D0E0F, - ch_addralign: 0x1011121314151617, - }, - ); - } - - #[test] - fn parse_chdr32_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, CompressionHeader>(LittleEndian, Class::ELF32); - } - - #[test] - fn parse_chdr32_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, CompressionHeader>(BigEndian, Class::ELF32); - } - - #[test] - fn parse_chdr64_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, CompressionHeader>(LittleEndian, Class::ELF64); - } - - #[test] - fn parse_chdr64_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, CompressionHeader>(BigEndian, Class::ELF64); - } -} diff --git a/arceos/modules/elf/src/dynamic.rs b/arceos/modules/elf/src/dynamic.rs deleted file mode 100644 index af88f46dd..000000000 --- a/arceos/modules/elf/src/dynamic.rs +++ /dev/null @@ -1,147 +0,0 @@ -//! Parsing `.dynamic` section or [PT_DYNAMIC](crate::abi::PT_DYNAMIC) segment contents -use crate::endian::EndianParse; -use crate::file::Class; -use crate::parse::{ParseAt, ParseError, ParsingTable}; - -pub type DynamicTable<'data, E> = ParsingTable<'data, E, Dyn>; - -/// C-style 32-bit ELF Dynamic section entry definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf32_Dyn { - pub d_tag: i32, - // union of both {d_val, d_ptr} - pub d_un: u32, -} - -/// C-style 64-bit ELF Dynamic section entry definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf64_Dyn { - pub d_tag: i64, - // union of both {d_val, d_ptr} - pub d_un: u64, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Dyn { - pub d_tag: i64, - pub(super) d_un: u64, -} - -impl Dyn { - pub fn d_val(self) -> u64 { - self.d_un - } - - pub fn d_ptr(self) -> u64 { - self.d_un - } -} - -impl ParseAt for Dyn { - fn parse_at( - endian: E, - class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - match class { - Class::ELF32 => Ok(Dyn { - d_tag: endian.parse_i32_at(offset, data)? as i64, - d_un: endian.parse_u32_at(offset, data)? as u64, - }), - Class::ELF64 => Ok(Dyn { - d_tag: endian.parse_i64_at(offset, data)?, - d_un: endian.parse_u64_at(offset, data)?, - }), - } - } - - #[inline] - fn size_for(class: Class) -> usize { - match class { - Class::ELF32 => 8, - Class::ELF64 => 16, - } - } -} - -#[cfg(test)] -mod parse_tests { - use super::*; - use crate::endian::{BigEndian, LittleEndian}; - use crate::parse::{test_parse_for, test_parse_fuzz_too_short}; - - #[test] - fn parse_dyn32_lsb() { - test_parse_for( - LittleEndian, - Class::ELF32, - Dyn { - d_tag: 0x03020100, - d_un: 0x07060504, - }, - ); - } - - #[test] - fn parse_dyn32_msb() { - test_parse_for( - BigEndian, - Class::ELF32, - Dyn { - d_tag: 0x00010203, - d_un: 0x04050607, - }, - ); - } - - #[test] - fn parse_dyn64_lsb() { - test_parse_for( - LittleEndian, - Class::ELF64, - Dyn { - d_tag: 0x0706050403020100, - d_un: 0x0F0E0D0C0B0A0908, - }, - ); - } - - #[test] - fn parse_dyn64_msb() { - test_parse_for( - BigEndian, - Class::ELF64, - Dyn { - d_tag: 0x0001020304050607, - d_un: 0x08090A0B0C0D0E0F, - }, - ); - } - - #[test] - fn parse_dyn32_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Dyn>(LittleEndian, Class::ELF32); - } - - #[test] - fn parse_dyn32_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Dyn>(BigEndian, Class::ELF32); - } - - #[test] - fn parse_dyn64_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Dyn>(LittleEndian, Class::ELF64); - } - - #[test] - fn parse_dyn64_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Dyn>(BigEndian, Class::ELF64); - } -} diff --git a/arceos/modules/elf/src/elf_bytes.rs b/arceos/modules/elf/src/elf_bytes.rs deleted file mode 100644 index 30975e047..000000000 --- a/arceos/modules/elf/src/elf_bytes.rs +++ /dev/null @@ -1,1594 +0,0 @@ -use crate::abi; -use crate::compression::CompressionHeader; -use crate::dynamic::{Dyn, DynamicTable}; -use crate::endian::EndianParse; -use crate::file::{parse_ident, Class, FileHeader}; -use crate::gnu_symver::{ - SymbolVersionTable, VerDefIterator, VerNeedIterator, VersionIndex, VersionIndexTable, -}; -use crate::hash::{GnuHashTable, SysVHashTable}; -use crate::note::NoteIterator; -use crate::parse::{ParseAt, ParseError, ReadBytesExt}; -use crate::relocation::{RelIterator, RelaIterator}; -use crate::section::{SectionHeader, SectionHeaderTable}; -use crate::segment::{ProgramHeader, SegmentTable}; -use crate::string_table::StringTable; -use crate::symbol::{Symbol, SymbolTable}; - -// _____ _ _____ ____ _ -// | ____| | | ___| __ ) _ _| |_ ___ ___ -// | _| | | | |_ | _ \| | | | __/ _ \/ __| -// | |___| |___| _| | |_) | |_| | || __/\__ \ -// |_____|_____|_| |____/ \__, |\__\___||___/ -// |___/ -// - -/// This type encapsulates the bytes-oriented interface for parsing ELF objects from `&[u8]`. -/// -/// This parser is no_std and zero-alloc, returning lazy-parsing interfaces wrapped around -/// subslices of the provided ELF bytes `&[u8]`. The various ELF structures are -/// parsed on-demand into a native Rust representation. -/// -/// Example usage: -/// ``` -/// use elf::abi::PT_LOAD; -/// use elf::endian::AnyEndian; -/// use elf::ElfBytes; -/// use elf::segment::ProgramHeader; -/// -/// let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so"); -/// let file_data = std::fs::read(path).unwrap(); -/// -/// let slice = file_data.as_slice(); -/// let file = ElfBytes::::minimal_parse(slice).unwrap(); -/// -/// // Get all the common ELF sections (if any). We have a lot of ELF work to do! -/// let common_sections = file.find_common_data().unwrap(); -/// // ... do some stuff with the symtab, dynsyms etc -/// -/// // It can also yield iterators on which we can do normal iterator things, like filtering -/// // for all the segments of a specific type. Parsing is done on each iter.next() call, so -/// // if you end iteration early, it won't parse the rest of the table. -/// let first_load_phdr: Option = file.segments().unwrap() -/// .iter() -/// .find(|phdr|{phdr.p_type == PT_LOAD}); -/// println!("First load segment is at: {}", first_load_phdr.unwrap().p_vaddr); -/// -/// // Or if you do things like this to get a vec of only the PT_LOAD segments. -/// let all_load_phdrs: Vec = file.segments().unwrap() -/// .iter() -/// .filter(|phdr|{phdr.p_type == PT_LOAD}) -/// .collect(); -/// println!("There are {} PT_LOAD segments", all_load_phdrs.len()); -/// ``` -#[derive(Debug)] -pub struct ElfBytes<'data, E: EndianParse> { - pub ehdr: FileHeader, - data: &'data [u8], - shdrs: Option>, - phdrs: Option>, -} - -/// Find the location (if any) of the section headers in the given data buffer and take a -/// subslice of their data and wrap it in a lazy-parsing SectionHeaderTable. -/// If shnum > SHN_LORESERVE (0xff00), then this will additionally parse out shdr[0] to calculate -/// the full table size, but all other parsing of SectionHeaders is deferred. -fn find_shdrs<'data, E: EndianParse>( - ehdr: &FileHeader, - data: &'data [u8], -) -> Result>, ParseError> { - // It's Ok to have no section headers - if ehdr.e_shoff == 0 { - return Ok(None); - } - - // If the number of sections is greater than or equal to SHN_LORESERVE (0xff00), - // e_shnum is zero and the actual number of section header table entries - // is contained in the sh_size field of the section header at index 0. - let shoff: usize = ehdr.e_shoff.try_into()?; - let mut shnum = ehdr.e_shnum as usize; - if shnum == 0 { - let mut offset = shoff; - let shdr0 = SectionHeader::parse_at(ehdr.endianness, ehdr.class, &mut offset, data)?; - shnum = shdr0.sh_size.try_into()?; - } - - // Validate shentsize before trying to read the table so that we can error early for corrupted files - let entsize = SectionHeader::validate_entsize(ehdr.class, ehdr.e_shentsize as usize)?; - - let size = entsize - .checked_mul(shnum) - .ok_or(ParseError::IntegerOverflow)?; - let end = shoff.checked_add(size).ok_or(ParseError::IntegerOverflow)?; - let buf = data.get_bytes(shoff..end)?; - Ok(Some(SectionHeaderTable::new( - ehdr.endianness, - ehdr.class, - buf, - ))) -} - -/// Find the location (if any) of the program headers in the given data buffer and take a -/// subslice of their data and wrap it in a lazy-parsing SegmentTable. -fn find_phdrs<'data, E: EndianParse>( - ehdr: &FileHeader, - data: &'data [u8], -) -> Result>, ParseError> { - // It's Ok to have no program headers - if ehdr.e_phoff == 0 { - return Ok(None); - } - - // If the number of segments is greater than or equal to PN_XNUM (0xffff), - // e_phnum is set to PN_XNUM, and the actual number of program header table - // entries is contained in the sh_info field of the section header at index 0. - let mut phnum = ehdr.e_phnum as usize; - if phnum == abi::PN_XNUM as usize { - let shoff: usize = ehdr.e_shoff.try_into()?; - let mut offset = shoff; - let shdr0 = SectionHeader::parse_at(ehdr.endianness, ehdr.class, &mut offset, data)?; - phnum = shdr0.sh_info.try_into()?; - } - - // Validate phentsize before trying to read the table so that we can error early for corrupted files - let entsize = ProgramHeader::validate_entsize(ehdr.class, ehdr.e_phentsize as usize)?; - - let phoff: usize = ehdr.e_phoff.try_into()?; - let size = entsize - .checked_mul(phnum) - .ok_or(ParseError::IntegerOverflow)?; - let end = phoff.checked_add(size).ok_or(ParseError::IntegerOverflow)?; - let buf = data.get_bytes(phoff..end)?; - Ok(Some(SegmentTable::new(ehdr.endianness, ehdr.class, buf))) -} - -/// This struct collects the common sections found in ELF objects -#[derive(Debug, Default)] -pub struct CommonElfData<'data, E: EndianParse> { - /// .symtab section - pub symtab: Option>, - /// strtab for .symtab - pub symtab_strs: Option>, - - /// .dynsym section - pub dynsyms: Option>, - /// strtab for .dynsym - pub dynsyms_strs: Option>, - - /// .dynamic section or PT_DYNAMIC segment (both point to the same table) - pub dynamic: Option>, - - /// .hash section - pub sysv_hash: Option>, - - /// .gnu.hash section - pub gnu_hash: Option>, -} - -impl<'data, E: EndianParse> ElfBytes<'data, E> { - /// Do the minimal parsing work to get an [ElfBytes] handle from a byte slice containing an ELF object. - /// - /// This parses the ELF [FileHeader], and locates (but does not parse) the - /// Section Header Table and Segment Table. - /// - // N.B. I thought about calling this "sparse_parse", but it felt too silly for a serious lib like this - pub fn minimal_parse(data: &'data [u8]) -> Result { - let ident_buf = data.get_bytes(0..abi::EI_NIDENT)?; - let ident = parse_ident(ident_buf)?; - - let tail_start = abi::EI_NIDENT; - let tail_end = match ident.1 { - Class::ELF32 => tail_start + crate::file::ELF32_EHDR_TAILSIZE, - Class::ELF64 => tail_start + crate::file::ELF64_EHDR_TAILSIZE, - }; - let tail_buf = data.get_bytes(tail_start..tail_end)?; - - let ehdr = FileHeader::parse_tail(ident, tail_buf)?; - - let shdrs = find_shdrs(&ehdr, data)?; - let phdrs = find_phdrs(&ehdr, data)?; - Ok(ElfBytes { - ehdr, - data, - shdrs, - phdrs, - }) - } - - pub fn parse_elf_header(data: &'data [u8]) -> Result, ParseError> { - let ident_buf = data.get_bytes(0..abi::EI_NIDENT)?; - let ident = parse_ident::(ident_buf)?; - - let tail_start = abi::EI_NIDENT; - let tail_end = match ident.1 { - Class::ELF32 => tail_start + crate::file::ELF32_EHDR_TAILSIZE, - Class::ELF64 => tail_start + crate::file::ELF64_EHDR_TAILSIZE, - }; - let tail_buf = data.get_bytes(tail_start..tail_end)?; - - FileHeader::parse_tail(ident, tail_buf) - } - - /// Get this Elf object's zero-alloc lazy-parsing [SegmentTable] (if any). - /// - /// This table parses [ProgramHeader]s on demand and does not make any internal heap allocations - /// when parsing. - pub fn segments(&self) -> Option> { - self.phdrs - } - - /// Get this Elf object's zero-alloc lazy-parsing [SectionHeaderTable] (if any). - /// - /// This table parses [SectionHeader]s on demand and does not make any internal heap allocations - /// when parsing. - pub fn section_headers(&self) -> Option> { - self.shdrs - } - - /// Get this ELF object's [SectionHeaderTable] alongside its corresponding [StringTable]. - /// - /// This is useful if you want to know the string name of sections. - /// - /// Example usage: - /// ``` - /// use std::collections::HashMap; - /// use elf::endian::AnyEndian; - /// use elf::ElfBytes; - /// use elf::note::Note; - /// use elf::note::NoteGnuBuildId; - /// use elf::section::SectionHeader; - /// - /// let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so"); - /// let file_data = std::fs::read(path).unwrap(); - /// - /// let slice = file_data.as_slice(); - /// let file = ElfBytes::::minimal_parse(slice).unwrap(); - /// - /// // Get the section header table alongside its string table - /// let (shdrs_opt, strtab_opt) = file - /// .section_headers_with_strtab() - /// .expect("shdrs offsets should be valid"); - /// let (shdrs, strtab) = ( - /// shdrs_opt.expect("Should have shdrs"), - /// strtab_opt.expect("Should have strtab") - /// ); - /// - /// // Parse the shdrs and collect them into a map keyed on their zero-copied name - /// let with_names: HashMap<&str, SectionHeader> = shdrs - /// .iter() - /// .map(|shdr| { - /// ( - /// strtab.get(shdr.sh_name as usize).expect("Failed to get section name"), - /// shdr, - /// ) - /// }) - /// .collect(); - /// - /// // Get the zero-copy parsed type for the the build id note - /// let build_id_note_shdr: &SectionHeader = with_names - /// .get(".note.gnu.build-id") - /// .expect("Should have build id note section"); - /// let notes: Vec<_> = file - /// .section_data_as_notes(build_id_note_shdr) - /// .expect("Should be able to get note section data") - /// .collect(); - /// println!("{:?}", notes[0]); - /// ``` - pub fn section_headers_with_strtab( - &self, - ) -> Result< - ( - Option>, - Option>, - ), - ParseError, - > { - // It's Ok to have no section headers - let shdrs = match self.section_headers() { - Some(shdrs) => shdrs, - None => { - return Ok((None, None)); - } - }; - - // It's Ok to not have a string table - if self.ehdr.e_shstrndx == abi::SHN_UNDEF { - return Ok((Some(shdrs), None)); - } - - // If the section name string table section index is greater than or - // equal to SHN_LORESERVE (0xff00), e_shstrndx has the value SHN_XINDEX - // (0xffff) and the actual index of the section name string table section - // is contained in the sh_link field of the section header at index 0. - let mut shstrndx = self.ehdr.e_shstrndx as usize; - if self.ehdr.e_shstrndx == abi::SHN_XINDEX { - let shdr_0 = shdrs.get(0)?; - shstrndx = shdr_0.sh_link as usize; - } - - let strtab = shdrs.get(shstrndx)?; - let (strtab_start, strtab_end) = strtab.get_data_range()?; - let strtab_buf = self.data.get_bytes(strtab_start..strtab_end)?; - Ok((Some(shdrs), Some(StringTable::new(strtab_buf)))) - } - - /// Parse section headers until one is found with the given name - /// - /// Example to get the ELF file's ABI-tag note - /// ``` - /// use elf::ElfBytes; - /// use elf::endian::AnyEndian; - /// use elf::section::SectionHeader; - /// use elf::note::Note; - /// use elf::note::NoteGnuAbiTag; - /// - /// let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - /// let file_data = std::fs::read(path).unwrap(); - /// let slice = file_data.as_slice(); - /// let file = ElfBytes::::minimal_parse(slice).unwrap(); - /// - /// let shdr: SectionHeader = file - /// .section_header_by_name(".note.ABI-tag") - /// .expect("section table should be parseable") - /// .expect("file should have a .note.ABI-tag section"); - /// - /// let notes: Vec<_> = file - /// .section_data_as_notes(&shdr) - /// .expect("Should be able to get note section data") - /// .collect(); - /// assert_eq!( - /// notes[0], - /// Note::GnuAbiTag(NoteGnuAbiTag { - /// os: 0, - /// major: 2, - /// minor: 6, - /// subminor: 32 - /// })); - /// ``` - pub fn section_header_by_name(&self, name: &str) -> Result, ParseError> { - let (shdrs, strtab) = match self.section_headers_with_strtab()? { - (Some(shdrs), Some(strtab)) => (shdrs, strtab), - _ => { - // If we don't have shdrs, or don't have a strtab, we can't find a section by its name - return Ok(None); - } - }; - - Ok(shdrs.iter().find(|shdr| { - let sh_name = match strtab.get(shdr.sh_name as usize) { - Ok(name) => name, - _ => { - return false; - } - }; - name == sh_name - })) - } - - /// Efficiently locate the set of common sections found in ELF files by doing a single iteration - /// over the SectionHeaders table. - /// - /// This is useful for those who know they're going to be accessing multiple common sections, like - /// symbol tables, string tables. Many of these can also be accessed by the more targeted - /// helpers like [ElfBytes::symbol_table] or [ElfBytes::dynamic], though those each do their own - /// internal searches through the shdrs to find the section. - pub fn find_common_data(&self) -> Result, ParseError> { - let mut result: CommonElfData<'data, E> = CommonElfData::default(); - - // Iterate once over the shdrs to collect up any known sections - if let Some(shdrs) = self.shdrs { - for shdr in shdrs.iter() { - match shdr.sh_type { - abi::SHT_SYMTAB => { - let strtab_shdr = shdrs.get(shdr.sh_link as usize)?; - let (symtab, strtab) = - self.section_data_as_symbol_table(&shdr, &strtab_shdr)?; - - result.symtab = Some(symtab); - result.symtab_strs = Some(strtab); - } - abi::SHT_DYNSYM => { - let strtab_shdr = shdrs.get(shdr.sh_link as usize)?; - let (symtab, strtab) = - self.section_data_as_symbol_table(&shdr, &strtab_shdr)?; - - result.dynsyms = Some(symtab); - result.dynsyms_strs = Some(strtab); - } - abi::SHT_DYNAMIC => { - result.dynamic = Some(self.section_data_as_dynamic(&shdr)?); - } - abi::SHT_HASH => { - let (start, end) = shdr.get_data_range()?; - let buf = self.data.get_bytes(start..end)?; - result.sysv_hash = Some(SysVHashTable::new( - self.ehdr.endianness, - self.ehdr.class, - buf, - )?); - } - abi::SHT_GNU_HASH => { - let (start, end) = shdr.get_data_range()?; - let buf = self.data.get_bytes(start..end)?; - result.gnu_hash = Some(GnuHashTable::new( - self.ehdr.endianness, - self.ehdr.class, - buf, - )?); - } - _ => { - continue; - } - } - } - } - - // If we didn't find SHT_DYNAMIC from the section headers, try the program headers - if result.dynamic.is_none() { - if let Some(phdrs) = self.phdrs { - if let Some(dyn_phdr) = phdrs.iter().find(|phdr| phdr.p_type == abi::PT_DYNAMIC) { - let (start, end) = dyn_phdr.get_file_data_range()?; - let buf = self.data.get_bytes(start..end)?; - result.dynamic = Some(DynamicTable::new( - self.ehdr.endianness, - self.ehdr.class, - buf, - )); - } - } - } - - Ok(result) - } - - /// Get the section data for a given [SectionHeader], alongside an optional compression context. - /// - /// This library does not do any decompression for the user, but merely returns the raw compressed - /// section data if the section is compressed alongside its ELF compression structure describing the - /// compression algorithm used. - /// - /// Users who wish to work with compressed sections must pick their compression library of choice - /// and do the decompression themselves. The only two options supported by the ELF spec for section - /// compression are: [abi::ELFCOMPRESS_ZLIB] and [abi::ELFCOMPRESS_ZSTD]. - pub fn section_data( - &self, - shdr: &SectionHeader, - ) -> Result<(&'data [u8], Option), ParseError> { - if shdr.sh_type == abi::SHT_NOBITS { - return Ok((&[], None)); - } - - let (start, end) = shdr.get_data_range()?; - let buf = self.data.get_bytes(start..end)?; - - if shdr.sh_flags & abi::SHF_COMPRESSED as u64 == 0 { - Ok((buf, None)) - } else { - let mut offset = 0; - let chdr = CompressionHeader::parse_at( - self.ehdr.endianness, - self.ehdr.class, - &mut offset, - buf, - )?; - let compressed_buf = buf.get(offset..).ok_or(ParseError::SliceReadError(( - offset, - shdr.sh_size.try_into()?, - )))?; - Ok((compressed_buf, Some(chdr))) - } - } - - /// Get the section data for a given [SectionHeader], and interpret it as a [StringTable] - /// - /// Returns a ParseError if the section is not of type [abi::SHT_STRTAB] - pub fn section_data_as_strtab( - &self, - shdr: &SectionHeader, - ) -> Result, ParseError> { - if shdr.sh_type != abi::SHT_STRTAB { - return Err(ParseError::UnexpectedSectionType(( - shdr.sh_type, - abi::SHT_STRTAB, - ))); - } - - let (buf, _) = self.section_data(shdr)?; - Ok(StringTable::new(buf)) - } - - /// Get the section data for a given [SectionHeader], and interpret it as an - /// iterator over no-addend relocations [Rel](crate::relocation::Rel) - /// - /// Returns a ParseError if the section is not of type [abi::SHT_REL] - pub fn section_data_as_rels( - &self, - shdr: &SectionHeader, - ) -> Result, ParseError> { - if shdr.sh_type != abi::SHT_REL { - return Err(ParseError::UnexpectedSectionType(( - shdr.sh_type, - abi::SHT_REL, - ))); - } - - let (buf, _) = self.section_data(shdr)?; - Ok(RelIterator::new(self.ehdr.endianness, self.ehdr.class, buf)) - } - - /// Get the section data for a given [SectionHeader], and interpret it as an - /// iterator over relocations with addends [Rela](crate::relocation::Rela) - /// - /// Returns a ParseError if the section is not of type [abi::SHT_RELA] - pub fn section_data_as_relas( - &self, - shdr: &SectionHeader, - ) -> Result, ParseError> { - if shdr.sh_type != abi::SHT_RELA { - return Err(ParseError::UnexpectedSectionType(( - shdr.sh_type, - abi::SHT_RELA, - ))); - } - - let (buf, _) = self.section_data(shdr)?; - Ok(RelaIterator::new( - self.ehdr.endianness, - self.ehdr.class, - buf, - )) - } - - /// Get the section data for a given [SectionHeader], and interpret it as an - /// iterator over [Note](crate::note::Note)s - /// - /// Returns a ParseError if the section is not of type [abi::SHT_NOTE] - pub fn section_data_as_notes( - &self, - shdr: &SectionHeader, - ) -> Result, ParseError> { - if shdr.sh_type != abi::SHT_NOTE { - return Err(ParseError::UnexpectedSectionType(( - shdr.sh_type, - abi::SHT_NOTE, - ))); - } - - let (buf, _) = self.section_data(shdr)?; - Ok(NoteIterator::new( - self.ehdr.endianness, - self.ehdr.class, - shdr.sh_addralign as usize, - buf, - )) - } - - /// Internal helper to get the section data for an SHT_DYNAMIC section as a .dynamic section table. - /// See [ElfBytes::dynamic] or [ElfBytes::find_common_data] for the public interface - fn section_data_as_dynamic( - &self, - shdr: &SectionHeader, - ) -> Result, ParseError> { - if shdr.sh_type != abi::SHT_DYNAMIC { - return Err(ParseError::UnexpectedSectionType(( - shdr.sh_type, - abi::SHT_DYNAMIC, - ))); - } - - // Validate entsize before trying to read the table so that we can error early for corrupted files - Dyn::validate_entsize(self.ehdr.class, shdr.sh_entsize.try_into()?)?; - let (buf, _) = self.section_data(shdr)?; - Ok(DynamicTable::new( - self.ehdr.endianness, - self.ehdr.class, - buf, - )) - } - - /// Get the segment's file data for a given segment/[ProgramHeader]. - /// - /// This is the segment's data as found in the file. - pub fn segment_data(&self, phdr: &ProgramHeader) -> Result<&'data [u8], ParseError> { - let (start, end) = phdr.get_file_data_range()?; - self.data.get_bytes(start..end) - } - - /// Get the segment's file data for a given [ProgramHeader], and interpret it as an - /// iterator over [Note](crate::note::Note)s - /// - /// Returns a ParseError if the section is not of type [abi::PT_NOTE] - pub fn segment_data_as_notes( - &self, - phdr: &ProgramHeader, - ) -> Result, ParseError> { - if phdr.p_type != abi::PT_NOTE { - return Err(ParseError::UnexpectedSegmentType(( - phdr.p_type, - abi::PT_NOTE, - ))); - } - - let buf = self.segment_data(phdr)?; - Ok(NoteIterator::new( - self.ehdr.endianness, - self.ehdr.class, - phdr.p_align as usize, - buf, - )) - } - - /// Get the .dynamic section or [abi::PT_DYNAMIC] segment contents. - pub fn dynamic(&self) -> Result>, ParseError> { - // If we have section headers, look for the SHT_DYNAMIC section - if let Some(shdrs) = self.section_headers() { - if let Some(shdr) = shdrs.iter().find(|shdr| shdr.sh_type == abi::SHT_DYNAMIC) { - return Ok(Some(self.section_data_as_dynamic(&shdr)?)); - } - // Otherwise, look up the PT_DYNAMIC segment (if any) - } else if let Some(phdrs) = self.segments() { - if let Some(phdr) = phdrs.iter().find(|phdr| phdr.p_type == abi::PT_DYNAMIC) { - let (start, end) = phdr.get_file_data_range()?; - let buf = self.data.get_bytes(start..end)?; - return Ok(Some(DynamicTable::new( - self.ehdr.endianness, - self.ehdr.class, - buf, - ))); - } - } - - Ok(None) - } - - /// Helper method to get the section data for a given pair of [SectionHeader] for the symbol - /// table and its linked strtab, and interpret them as [SymbolTable] and [StringTable]. - fn section_data_as_symbol_table( - &self, - shdr: &SectionHeader, - strtab_shdr: &SectionHeader, - ) -> Result<(SymbolTable<'data, E>, StringTable<'data>), ParseError> { - // Validate entsize before trying to read the table so that we can error early for corrupted files - Symbol::validate_entsize(self.ehdr.class, shdr.sh_entsize.try_into()?)?; - - // Load the section bytes for the symtab - // (we want immutable references to both the symtab and its strtab concurrently) - let (symtab_start, symtab_end) = shdr.get_data_range()?; - let symtab_buf = self.data.get_bytes(symtab_start..symtab_end)?; - - // Load the section bytes for the strtab - // (we want immutable references to both the symtab and its strtab concurrently) - let (strtab_start, strtab_end) = strtab_shdr.get_data_range()?; - let strtab_buf = self.data.get_bytes(strtab_start..strtab_end)?; - - let symtab = SymbolTable::new(self.ehdr.endianness, self.ehdr.class, symtab_buf); - let strtab = StringTable::new(strtab_buf); - Ok((symtab, strtab)) - } - - /// Get the ELF file's `.symtab` and associated strtab (if any) - pub fn symbol_table( - &self, - ) -> Result, StringTable<'data>)>, ParseError> { - let shdrs = match self.section_headers() { - Some(shdrs) => shdrs, - None => { - return Ok(None); - } - }; - - // Get the symtab header for the symtab. The GABI states there can be zero or one per ELF file. - let symtab_shdr = match shdrs.iter().find(|shdr| shdr.sh_type == abi::SHT_SYMTAB) { - Some(shdr) => shdr, - None => { - return Ok(None); - } - }; - - let strtab_shdr = shdrs.get(symtab_shdr.sh_link as usize)?; - Ok(Some(self.section_data_as_symbol_table( - &symtab_shdr, - &strtab_shdr, - )?)) - } - - /// Get the ELF file's `.dynsym` and associated strtab (if any) - pub fn dynamic_symbol_table( - &self, - ) -> Result, StringTable<'data>)>, ParseError> { - let shdrs = match self.section_headers() { - Some(shdrs) => shdrs, - None => { - return Ok(None); - } - }; - - // Get the symtab header for the symtab. The GABI states there can be zero or one per ELF file. - let symtab_shdr = match shdrs.iter().find(|shdr| shdr.sh_type == abi::SHT_DYNSYM) { - Some(shdr) => shdr, - None => { - return Ok(None); - } - }; - - let strtab_shdr = shdrs.get(symtab_shdr.sh_link as usize)?; - Ok(Some(self.section_data_as_symbol_table( - &symtab_shdr, - &strtab_shdr, - )?)) - } - - /// Locate the section data for the various GNU Symbol Versioning sections (if any) - /// and return them in a [SymbolVersionTable] that which can interpret them in-place to - /// yield [SymbolRequirement](crate::gnu_symver::SymbolRequirement)s - /// and [SymbolDefinition](crate::gnu_symver::SymbolDefinition)s - /// - /// This is a GNU extension and not all objects use symbol versioning. - /// Returns an empty Option if the object does not use symbol versioning. - pub fn symbol_version_table(&self) -> Result>, ParseError> { - // No sections means no GNU symbol versioning sections, which is ok - let shdrs = match self.section_headers() { - Some(shdrs) => shdrs, - None => { - return Ok(None); - } - }; - - let mut versym_opt: Option = None; - let mut needs_opt: Option = None; - let mut defs_opt: Option = None; - // Find the GNU Symbol versioning sections (if any) - for shdr in shdrs.iter() { - if shdr.sh_type == abi::SHT_GNU_VERSYM { - versym_opt = Some(shdr); - } else if shdr.sh_type == abi::SHT_GNU_VERNEED { - needs_opt = Some(shdr); - } else if shdr.sh_type == abi::SHT_GNU_VERDEF { - defs_opt = Some(shdr); - } - - // If we've found all three sections, then we're done - if versym_opt.is_some() && needs_opt.is_some() && defs_opt.is_some() { - break; - } - } - - let versym_shdr = match versym_opt { - Some(shdr) => shdr, - // No VERSYM section means the object doesn't use symbol versioning, which is ok. - None => { - return Ok(None); - } - }; - - // Load the versym table - // Validate VERSYM entsize before trying to read the table so that we can error early for corrupted files - VersionIndex::validate_entsize(self.ehdr.class, versym_shdr.sh_entsize.try_into()?)?; - let (versym_start, versym_end) = versym_shdr.get_data_range()?; - let version_ids = VersionIndexTable::new( - self.ehdr.endianness, - self.ehdr.class, - self.data.get_bytes(versym_start..versym_end)?, - ); - - // Wrap the VERNEED section and strings data in an iterator and string table (if any) - let verneeds = match needs_opt { - Some(shdr) => { - let (start, end) = shdr.get_data_range()?; - let needs_buf = self.data.get_bytes(start..end)?; - - let strs_shdr = shdrs.get(shdr.sh_link as usize)?; - let (strs_start, strs_end) = strs_shdr.get_data_range()?; - let strs_buf = self.data.get_bytes(strs_start..strs_end)?; - - Some(( - VerNeedIterator::new( - self.ehdr.endianness, - self.ehdr.class, - shdr.sh_info as u64, - 0, - needs_buf, - ), - StringTable::new(strs_buf), - )) - } - // It's possible to have symbol versioning with no NEEDs if we're an object that only - // exports defined symbols. - None => None, - }; - - // Wrap the VERDEF section and strings data in an iterator and string table (if any) - let verdefs = match defs_opt { - Some(shdr) => { - let (start, end) = shdr.get_data_range()?; - let defs_buf = self.data.get_bytes(start..end)?; - - let strs_shdr = shdrs.get(shdr.sh_link as usize)?; - let (strs_start, strs_end) = strs_shdr.get_data_range()?; - let strs_buf = self.data.get_bytes(strs_start..strs_end)?; - - Some(( - VerDefIterator::new( - self.ehdr.endianness, - self.ehdr.class, - shdr.sh_info as u64, - 0, - defs_buf, - ), - StringTable::new(strs_buf), - )) - } - // It's possible to have symbol versioning with no NEEDs if we're an object that only - // exports defined symbols. - None => None, - }; - - // whew, we're done here! - Ok(Some(SymbolVersionTable::new( - version_ids, - verneeds, - verdefs, - ))) - } -} - -// _ _ -// | |_ ___ ___| |_ ___ -// | __/ _ \/ __| __/ __| -// | || __/\__ \ |_\__ \ -// \__\___||___/\__|___/ -// - -#[cfg(test)] -mod interface_tests { - use super::*; - use crate::abi::{SHT_GNU_HASH, SHT_NOBITS, SHT_NOTE, SHT_NULL, SHT_REL, SHT_RELA, SHT_STRTAB}; - use crate::dynamic::Dyn; - use crate::endian::AnyEndian; - use crate::hash::sysv_hash; - use crate::note::{Note, NoteGnuAbiTag, NoteGnuBuildId}; - use crate::relocation::Rela; - use crate::segment::ProgramHeader; - - #[test] - fn simultaenous_segments_parsing() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - // With the bytes interface, we should be able to get multiple lazy-parsing types concurrently, - // since the trait is implemented for shared references. - // - // Get the segment table - let iter = file.segments().expect("File should have a segment table"); - - // Concurrently get the segment table again as an iterator and collect the headers into a vec - let segments: Vec = file - .segments() - .expect("File should have a segment table") - .iter() - .collect(); - - let expected_phdr = ProgramHeader { - p_type: abi::PT_PHDR, - p_offset: 64, - p_vaddr: 4194368, - p_paddr: 4194368, - p_filesz: 448, - p_memsz: 448, - p_flags: 5, - p_align: 8, - }; - - // Assert we parsed the first header correctly - assert_eq!(segments[0], expected_phdr); - - // Now use the original lazy-parsing table to parse out the first entry - assert_eq!( - iter.get(0).expect("should be able to parse phdr"), - expected_phdr - ) - } - - #[test] - fn segments() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let segments: Vec = file - .segments() - .expect("File should have a segment table") - .iter() - .collect(); - assert_eq!( - segments[0], - ProgramHeader { - p_type: abi::PT_PHDR, - p_offset: 64, - p_vaddr: 4194368, - p_paddr: 4194368, - p_filesz: 448, - p_memsz: 448, - p_flags: 5, - p_align: 8, - } - ); - } - - #[test] - fn segments_phnum_in_shdr0() { - let path = std::path::PathBuf::from("sample-objects/phnum.m68k.so"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let segments: Vec = file - .segments() - .expect("File should have a segment table") - .iter() - .collect(); - assert_eq!( - segments[0], - ProgramHeader { - p_type: abi::PT_PHDR, - p_offset: 92, - p_vaddr: 0, - p_paddr: 0, - p_filesz: 32, - p_memsz: 32, - p_flags: 0x20003, - p_align: 0x40000, - } - ); - } - - #[test] - fn section_headers() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let shdrs = file - .section_headers() - .expect("File should have a section table"); - - let shdrs_vec: Vec = shdrs.iter().collect(); - - assert_eq!(shdrs_vec[4].sh_type, SHT_GNU_HASH); - } - - #[test] - fn section_headers_with_strtab() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let (shdrs, strtab) = file - .section_headers_with_strtab() - .expect("shdrs should be parsable"); - let (shdrs, strtab) = (shdrs.unwrap(), strtab.unwrap()); - - let with_names: Vec<(&str, SectionHeader)> = shdrs - .iter() - .map(|shdr| { - ( - strtab - .get(shdr.sh_name as usize) - .expect("Failed to get section name"), - shdr, - ) - }) - .collect(); - - let (name, shdr) = with_names[4]; - assert_eq!(name, ".gnu.hash"); - assert_eq!(shdr.sh_type, abi::SHT_GNU_HASH); - } - - #[test] - fn shnum_and_shstrndx_in_shdr0() { - let path = std::path::PathBuf::from("sample-objects/shnum.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).unwrap(); - - let (shdrs, strtab) = file - .section_headers_with_strtab() - .expect("shdrs should be parsable"); - let (shdrs, strtab) = (shdrs.unwrap(), strtab.unwrap()); - - let shdrs_len = shdrs.len(); - assert_eq!(shdrs_len, 0xFF15); - - let shdr = shdrs.get(shdrs_len - 1).unwrap(); - let name = strtab - .get(shdr.sh_name as usize) - .expect("Failed to get section name"); - - assert_eq!(name, ".shstrtab"); - assert_eq!(shdr.sh_type, abi::SHT_STRTAB); - } - - #[test] - fn section_header_by_name() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let shdr = file - .section_header_by_name(".gnu.hash") - .expect("section table should be parseable") - .expect("file should have .gnu.hash section"); - - assert_eq!(shdr.sh_type, SHT_GNU_HASH); - - let shdr = file - .section_header_by_name(".not.found") - .expect("section table should be parseable"); - - assert_eq!(shdr, None); - } - - #[test] - fn find_common_data() { - let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let elf_scns = file.find_common_data().expect("file should parse"); - - // hello.so should find everything - assert!(elf_scns.symtab.is_some()); - assert!(elf_scns.symtab_strs.is_some()); - assert!(elf_scns.dynsyms.is_some()); - assert!(elf_scns.dynsyms_strs.is_some()); - assert!(elf_scns.dynamic.is_some()); - assert!(elf_scns.sysv_hash.is_some()); - assert!(elf_scns.gnu_hash.is_some()); - } - - #[test] - fn section_data() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let shdr = file - .section_headers() - .expect("File should have section table") - .get(26) - .expect("shdr should be parsable"); - - assert_eq!(shdr.sh_type, SHT_NOBITS); - - let (data, chdr) = file - .section_data(&shdr) - .expect("Failed to get section data"); - - assert_eq!(chdr, None); - assert_eq!(data, &[]); - } - - // Test all the different section_data_as* with a section of the wrong type - #[test] - fn section_data_as_wrong_type() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - // Section 0 is SHT_NULL, so all of the section_data_as* should error on it - let shdr = file - .section_headers() - .expect("File should have section table") - .get(0) - .expect("shdr should be parsable"); - - let err = file - .section_data_as_strtab(&shdr) - .expect_err("shdr0 should be the wrong type"); - assert!( - matches!( - err, - ParseError::UnexpectedSectionType((SHT_NULL, SHT_STRTAB)) - ), - "Unexpected Error type found: {err}" - ); - - let err = file - .section_data_as_rels(&shdr) - .expect_err("shdr0 should be the wrong type"); - assert!( - matches!(err, ParseError::UnexpectedSectionType((SHT_NULL, SHT_REL))), - "Unexpected Error type found: {err}" - ); - - let err = file - .section_data_as_relas(&shdr) - .expect_err("shdr0 should be the wrong type"); - assert!( - matches!(err, ParseError::UnexpectedSectionType((SHT_NULL, SHT_RELA))), - "Unexpected Error type found: {err}" - ); - - let err = file - .section_data_as_notes(&shdr) - .expect_err("shdr0 should be the wrong type"); - assert!( - matches!(err, ParseError::UnexpectedSectionType((SHT_NULL, SHT_NOTE))), - "Unexpected Error type found: {err}" - ); - } - - #[test] - fn section_data_as_strtab() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let shdr = file - .section_headers() - .expect("File should have section table") - .get(file.ehdr.e_shstrndx as usize) - .expect("shdr should be parsable"); - - let strtab = file - .section_data_as_strtab(&shdr) - .expect("Failed to read strtab"); - - assert_eq!( - strtab.get(1).expect("Failed to get strtab entry"), - ".symtab" - ); - } - - #[test] - fn section_data_as_relas() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let shdr = file - .section_headers() - .expect("File should have section table") - .get(10) - .expect("Failed to get rela shdr"); - - let mut relas = file - .section_data_as_relas(&shdr) - .expect("Failed to read relas section"); - assert_eq!( - relas.next().expect("Failed to get rela entry"), - Rela { - r_offset: 6293704, - r_sym: 1, - r_type: 7, - r_addend: 0, - } - ); - assert_eq!( - relas.next().expect("Failed to get rela entry"), - Rela { - r_offset: 6293712, - r_sym: 2, - r_type: 7, - r_addend: 0, - } - ); - assert!(relas.next().is_none()); - } - - #[test] - fn section_data_as_notes() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let shdr = file - .section_headers() - .expect("File should have section table") - .get(2) - .expect("Failed to get note shdr"); - - let mut notes = file - .section_data_as_notes(&shdr) - .expect("Failed to read note section"); - assert_eq!( - notes.next().expect("Failed to get first note"), - Note::GnuAbiTag(NoteGnuAbiTag { - os: 0, - major: 2, - minor: 6, - subminor: 32 - }) - ); - assert!(notes.next().is_none()); - } - - #[test] - fn segment_data_as_notes() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let phdr = file - .segments() - .expect("File should have segmetn table") - .get(5) - .expect("Failed to get notes phdr"); - - let mut notes = file - .segment_data_as_notes(&phdr) - .expect("Failed to read notes segment"); - assert_eq!( - notes.next().expect("Failed to get first note"), - Note::GnuAbiTag(NoteGnuAbiTag { - os: 0, - major: 2, - minor: 6, - subminor: 32 - }) - ); - assert_eq!( - notes.next().expect("Failed to get second note"), - Note::GnuBuildId(NoteGnuBuildId(&[ - 119, 65, 159, 13, 165, 16, 131, 12, 87, 167, 200, 204, 176, 238, 133, 95, 238, 211, - 118, 163 - ])) - ); - assert!(notes.next().is_none()); - } - - #[test] - fn dynamic() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let mut dynamic = file - .dynamic() - .expect("Failed to parse .dynamic") - .expect("Failed to find .dynamic") - .iter(); - assert_eq!( - dynamic.next().expect("Failed to get dyn entry"), - Dyn { - d_tag: abi::DT_NEEDED, - d_un: 1 - } - ); - assert_eq!( - dynamic.next().expect("Failed to get dyn entry"), - Dyn { - d_tag: abi::DT_INIT, - d_un: 4195216 - } - ); - } - - #[test] - fn symbol_table() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let (symtab, strtab) = file - .symbol_table() - .expect("Failed to read symbol table") - .expect("Failed to find symbol table"); - let symbol = symtab.get(30).expect("Failed to get symbol"); - assert_eq!( - symbol, - Symbol { - st_name: 19, - st_value: 6293200, - st_size: 0, - st_shndx: 21, - st_info: 1, - st_other: 0, - } - ); - assert_eq!( - strtab - .get(symbol.st_name as usize) - .expect("Failed to get name from strtab"), - "__JCR_LIST__" - ); - } - - #[test] - fn dynamic_symbol_table() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let (symtab, strtab) = file - .dynamic_symbol_table() - .expect("Failed to read symbol table") - .expect("Failed to find symbol table"); - let symbol = symtab.get(1).expect("Failed to get symbol"); - assert_eq!( - symbol, - Symbol { - st_name: 11, - st_value: 0, - st_size: 0, - st_shndx: 0, - st_info: 18, - st_other: 0, - } - ); - assert_eq!( - strtab - .get(symbol.st_name as usize) - .expect("Failed to get name from strtab"), - "memset" - ); - } - - #[test] - fn symbol_version_table() { - let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - let vst = file - .symbol_version_table() - .expect("Failed to parse GNU symbol versions") - .expect("Failed to find GNU symbol versions"); - - let req = vst - .get_requirement(2) - .expect("Failed to parse NEED") - .expect("Failed to find NEED"); - assert_eq!(req.file, "libc.so.6"); - assert_eq!(req.name, "GLIBC_2.2.5"); - assert_eq!(req.hash, 0x9691A75); - - let req = vst.get_requirement(3).expect("Failed to parse NEED"); - assert!(req.is_none()); - - let req = vst.get_requirement(4).expect("Failed to parse NEED"); - assert!(req.is_none()); - - let req = vst - .get_requirement(5) - .expect("Failed to parse NEED") - .expect("Failed to find NEED"); - assert_eq!(req.file, "libc.so.6"); - assert_eq!(req.name, "GLIBC_2.2.5"); - assert_eq!(req.hash, 0x9691A75); - - let def = vst - .get_definition(3) - .expect("Failed to parse DEF") - .expect("Failed to find DEF"); - assert_eq!(def.hash, 0xC33237F); - assert_eq!(def.flags, 1); - assert!(!def.hidden); - let def_names: Vec<&str> = def.names.map(|res| res.expect("should parse")).collect(); - assert_eq!(def_names, &["hello.so"]); - - let def = vst - .get_definition(7) - .expect("Failed to parse DEF") - .expect("Failed to find DEF"); - assert_eq!(def.hash, 0x1570B62); - assert_eq!(def.flags, 0); - assert!(def.hidden); - let def_names: Vec<&str> = def.names.map(|res| res.expect("should parse")).collect(); - assert_eq!(def_names, &["HELLO_1.42"]); - } - - #[test] - fn sysv_hash_table() { - let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); - - // Look up the SysV hash section header - let common = file.find_common_data().expect("should parse"); - let hash_table = common.sysv_hash.expect("should have .hash section"); - - // Get the dynamic symbol table. - let (symtab, strtab) = file - .dynamic_symbol_table() - .expect("Failed to read symbol table") - .expect("Failed to find symbol table"); - - // Verify that these three symbols all collide in the hash table's buckets - assert_eq!(sysv_hash(b"use_memset_v2"), 0x8080542); - assert_eq!(sysv_hash(b"__gmon_start__"), 0xF4D007F); - assert_eq!(sysv_hash(b"memset"), 0x73C49C4); - assert_eq!(sysv_hash(b"use_memset_v2") % 3, 0); - assert_eq!(sysv_hash(b"__gmon_start__") % 3, 0); - assert_eq!(sysv_hash(b"memset") % 3, 0); - - // Use the hash table to find a given symbol in it. - let (sym_idx, sym) = hash_table - .find(b"memset", &symtab, &strtab) - .expect("Failed to parse hash") - .expect("Failed to find hash"); - - // Verify that we got the same symbol from the hash table we expected - assert_eq!(sym_idx, 2); - assert_eq!(strtab.get(sym.st_name as usize).unwrap(), "memset"); - assert_eq!( - sym, - symtab.get(sym_idx).expect("Failed to get expected sym") - ); - } - - #[test] - fn gnu_hash_table() { - let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so"); - let file_data = std::fs::read(path).expect("Could not read file."); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).unwrap(); - - // Look up the SysV hash section header - let common = file.find_common_data().unwrap(); - let hash_table = common.gnu_hash.expect("should have .gnu.hash section"); - - // Get the dynamic symbol table. - let (symtab, strtab) = (common.dynsyms.unwrap(), common.dynsyms_strs.unwrap()); - - // manually look one up by explicit name to make sure the above loop is doing something - let (sym_idx, sym) = hash_table - .find(b"use_memset", &symtab, &strtab) - .expect("Failed to parse hash") - .expect("Failed to find hash"); - - // Verify that we got the same symbol from the hash table we expected - assert_eq!(sym_idx, 9); - assert_eq!(strtab.get(sym.st_name as usize).unwrap(), "use_memset"); - assert_eq!( - sym, - symtab.get(sym_idx).expect("Failed to get expected sym") - ); - } -} - -#[cfg(test)] -mod arch_tests { - use super::*; - use crate::endian::AnyEndian; - - // Basic smoke test which parses out symbols and headers for a given sample object of a given architecture - macro_rules! arch_test { - ( $arch:expr, $e_machine:expr, $endian:expr) => {{ - let path_str = format!("sample-objects/symver.{}.so", $arch); - let path = std::path::PathBuf::from(path_str); - let file_data = std::fs::read(path).expect("file should exist"); - let slice = file_data.as_slice(); - let file = ElfBytes::::minimal_parse(slice).expect("should parse"); - - assert_eq!(file.ehdr.e_machine, $e_machine); - assert_eq!(file.ehdr.endianness, $endian); - - let (shdrs, strtab) = file.section_headers_with_strtab().expect("should parse"); - let (shdrs, strtab) = (shdrs.unwrap(), strtab.unwrap()); - let _: Vec<_> = shdrs - .iter() - .map(|shdr| { - ( - strtab.get(shdr.sh_name as usize).expect("should parse"), - shdr, - ) - }) - .collect(); - - let common = file.find_common_data().expect("should parse"); - - // parse out all the normal symbol table symbols with their names - { - let symtab = common.symtab.unwrap(); - let strtab = common.symtab_strs.unwrap(); - let _: Vec<_> = symtab - .iter() - .map(|sym| (strtab.get(sym.st_name as usize).expect("should parse"), sym)) - .collect(); - } - - // parse out all the dynamic symbols and look them up in the gnu hash table - { - let symtab = common.dynsyms.unwrap(); - let strtab = common.dynsyms_strs.unwrap(); - let symbols_with_names: Vec<_> = symtab - .iter() - .map(|sym| (strtab.get_raw(sym.st_name as usize).expect("should parse"), sym)) - .collect(); - - let hash_table = common.gnu_hash.unwrap(); - - // look up each entry that should be in the hash table and make sure its there - let start_idx = hash_table.hdr.table_start_idx as usize; - for sym_idx in 0..symtab.len() { - let (symbol_name, symbol) = symbols_with_names.get(sym_idx).unwrap(); - - let result = hash_table - .find(symbol_name, &symtab, &strtab) - .expect("Failed to parse hash"); - - if sym_idx < start_idx { - assert_eq!(result, None); - } else { - let (hash_sym_idx, hash_symbol) = result.unwrap(); - - // Verify that we got the same symbol from the hash table we expected - assert_eq!(sym_idx, hash_sym_idx); - assert_eq!( - strtab.get_raw(hash_symbol.st_name as usize).unwrap(), - *symbol_name - ); - assert_eq!(*symbol, hash_symbol); - } - } - } - - let phdrs = file.segments().unwrap(); - let note_phdrs: Vec<_> = phdrs - .iter() - .filter(|phdr| phdr.p_type == abi::PT_NOTE) - .collect(); - for phdr in note_phdrs { - let _: Vec<_> = file - .segment_data_as_notes(&phdr) - .expect("should parse") - .collect(); - } - }}; - } - - #[test] - fn x86_64() { - arch_test!("x86_64", abi::EM_X86_64, AnyEndian::Little); - } - - #[test] - fn m68k() { - arch_test!("m68k", abi::EM_68K, AnyEndian::Big); - } - - #[test] - fn aarch64() { - arch_test!("aarch64", abi::EM_AARCH64, AnyEndian::Little); - } - - #[test] - fn armhf() { - arch_test!("armhf", abi::EM_ARM, AnyEndian::Little); - } - - #[test] - fn powerpc64() { - arch_test!("powerpc64", abi::EM_PPC64, AnyEndian::Big); - } - - #[test] - fn powerpc64le() { - arch_test!("powerpc64le", abi::EM_PPC64, AnyEndian::Little); - } - - #[test] - fn riscv64() { - arch_test!("riscv64", abi::EM_RISCV, AnyEndian::Little); - } -} diff --git a/arceos/modules/elf/src/elf_stream.rs b/arceos/modules/elf/src/elf_stream.rs deleted file mode 100644 index 9b9b661ab..000000000 --- a/arceos/modules/elf/src/elf_stream.rs +++ /dev/null @@ -1,1280 +0,0 @@ -use core::ops::Range; -use std::collections::HashMap; -use std::io::{Read, Seek, SeekFrom}; - -use crate::abi; -use crate::compression::CompressionHeader; -use crate::dynamic::DynamicTable; -use crate::endian::EndianParse; -use crate::file::{parse_ident, Class}; -use crate::gnu_symver::{ - SymbolVersionTable, VerDefIterator, VerNeedIterator, VersionIndex, VersionIndexTable, -}; -use crate::note::NoteIterator; -use crate::parse::{ParseAt, ParseError}; -use crate::relocation::{RelIterator, RelaIterator}; -use crate::section::{SectionHeader, SectionHeaderTable}; -use crate::segment::ProgramHeader; -use crate::segment::SegmentTable; -use crate::string_table::StringTable; -use crate::symbol::{Symbol, SymbolTable}; - -use crate::file::FileHeader; - -/// This type encapsulates the stream-oriented interface for parsing ELF objects from -/// a `Read + Seek`. -#[derive(Debug)] -pub struct ElfStream { - pub ehdr: FileHeader, - shdrs: Vec, - phdrs: Vec, - reader: CachingReader, -} - -/// Read the stream bytes backing the section headers table and parse them all into their Rust native type. -/// -/// Returns a [ParseError] if the data bytes for the section table cannot be read. -/// i.e. if the ELF [FileHeader]'s e_shnum, e_shoff, e_shentsize are invalid and point -/// to a range in the file data that does not actually exist, or if any of the headers failed to parse. -fn parse_section_headers( - ehdr: &FileHeader, - reader: &mut CachingReader, -) -> Result, ParseError> { - // It's Ok to have no section headers - if ehdr.e_shoff == 0 { - return Ok(Vec::default()); - } - - // Validate shentsize before trying to read the table so that we can error early for corrupted files - let entsize = SectionHeader::validate_entsize(ehdr.class, ehdr.e_shentsize as usize)?; - - // If the number of sections is greater than or equal to SHN_LORESERVE (0xff00), - // e_shnum is zero and the actual number of section header table entries - // is contained in the sh_size field of the section header at index 0. - let shoff: usize = ehdr.e_shoff.try_into()?; - let mut shnum = ehdr.e_shnum as usize; - if shnum == 0 { - let end = shoff - .checked_add(entsize) - .ok_or(ParseError::IntegerOverflow)?; - let mut offset = 0; - let data = reader.read_bytes(shoff, end)?; - let shdr0 = SectionHeader::parse_at(ehdr.endianness, ehdr.class, &mut offset, data)?; - shnum = shdr0.sh_size.try_into()?; - } - - let size = entsize - .checked_mul(shnum) - .ok_or(ParseError::IntegerOverflow)?; - let end = shoff.checked_add(size).ok_or(ParseError::IntegerOverflow)?; - let buf = reader.read_bytes(shoff, end)?; - let shdr_vec = SectionHeaderTable::new(ehdr.endianness, ehdr.class, buf) - .iter() - .collect(); - Ok(shdr_vec) -} - -fn parse_program_headers( - ehdr: &FileHeader, - reader: &mut CachingReader, -) -> Result, ParseError> { - // It's Ok to have no program headers - if ehdr.e_phoff == 0 { - return Ok(Vec::default()); - } - - // If the number of segments is greater than or equal to PN_XNUM (0xffff), - // e_phnum is set to PN_XNUM, and the actual number of program header table - // entries is contained in the sh_info field of the section header at index 0. - let mut phnum = ehdr.e_phnum as usize; - if phnum == abi::PN_XNUM as usize { - let shoff: usize = ehdr.e_shoff.try_into()?; - let end = shoff - .checked_add(SectionHeader::size_for(ehdr.class)) - .ok_or(ParseError::IntegerOverflow)?; - let data = reader.read_bytes(shoff, end)?; - let mut offset = 0; - let shdr0 = SectionHeader::parse_at(ehdr.endianness, ehdr.class, &mut offset, data)?; - phnum = shdr0.sh_info.try_into()?; - } - - // Validate phentsize before trying to read the table so that we can error early for corrupted files - let entsize = ProgramHeader::validate_entsize(ehdr.class, ehdr.e_phentsize as usize)?; - - let phoff: usize = ehdr.e_phoff.try_into()?; - let size = entsize - .checked_mul(phnum) - .ok_or(ParseError::IntegerOverflow)?; - let end = phoff.checked_add(size).ok_or(ParseError::IntegerOverflow)?; - let buf = reader.read_bytes(phoff, end)?; - let phdrs_vec = SegmentTable::new(ehdr.endianness, ehdr.class, buf) - .iter() - .collect(); - Ok(phdrs_vec) -} - -impl ElfStream { - /// Do a minimal amount of parsing work to open an [ElfStream] handle from a Read+Seek containing an ELF object. - /// - /// This parses the ELF [FileHeader], [SectionHeader] table, and [ProgramHeader] (segments) table. - /// All other file data (section data, segment data) is left unread and unparsed. - pub fn open_stream(reader: S) -> Result, ParseError> { - let mut cr = CachingReader::new(reader)?; - let ident_buf = cr.read_bytes(0, abi::EI_NIDENT)?; - let ident = parse_ident(ident_buf)?; - - let tail_start = abi::EI_NIDENT; - let tail_end = match ident.1 { - Class::ELF32 => tail_start + crate::file::ELF32_EHDR_TAILSIZE, - Class::ELF64 => tail_start + crate::file::ELF64_EHDR_TAILSIZE, - }; - let tail_buf = cr.read_bytes(tail_start, tail_end)?; - - let ehdr = FileHeader::parse_tail(ident, tail_buf)?; - - let shdrs = parse_section_headers(&ehdr, &mut cr)?; - let phdrs = parse_program_headers(&ehdr, &mut cr)?; - - // We parsed out the ehdr and shdrs into their own allocated containers, so there's no need to keep - // around their backing data anymore. - cr.clear_cache(); - - Ok(ElfStream { - ehdr, - shdrs, - phdrs, - reader: cr, - }) - } - - /// Get the parsed section headers table - pub fn segments(&self) -> &Vec { - &self.phdrs - } - - /// Get the parsed section headers table - pub fn section_headers(&self) -> &Vec { - &self.shdrs - } - - /// Get an lazy-parsing table for the Section Headers in the file and its associated StringTable. - /// - /// The underlying ELF bytes backing the section headers table and string - /// table are read all at once when the table is requested, but parsing is - /// deferred to be lazily parsed on demand on each table.get(), strtab.get(), or - /// table.iter().next() call. - /// - /// Returns a [ParseError] if the data bytes for these tables cannot be - /// read i.e. if the ELF [FileHeader]'s - /// [e_shnum](FileHeader#structfield.e_shnum), - /// [e_shoff](FileHeader#structfield.e_shoff), - /// [e_shentsize](FileHeader#structfield.e_shentsize), - /// [e_shstrndx](FileHeader#structfield.e_shstrndx) are invalid and point - /// to a ranges in the file data that does not actually exist. - pub fn section_headers_with_strtab( - &mut self, - ) -> Result<(&Vec, Option>), ParseError> { - // It's Ok to have no section headers - if self.shdrs.is_empty() { - return Ok((&self.shdrs, None)); - } - - // It's Ok to not have a string table - if self.ehdr.e_shstrndx == abi::SHN_UNDEF { - return Ok((&self.shdrs, None)); - } - - // If the section name string table section index is greater than or - // equal to SHN_LORESERVE (0xff00), e_shstrndx has the value SHN_XINDEX - // (0xffff) and the actual index of the section name string table section - // is contained in the sh_link field of the section header at index 0. - let mut shstrndx = self.ehdr.e_shstrndx as usize; - if self.ehdr.e_shstrndx == abi::SHN_XINDEX { - shstrndx = self.shdrs[0].sh_link as usize; - } - - // We have a strtab, so wrap it in a zero-copy StringTable - let strtab = self - .shdrs - .get(shstrndx) - .ok_or(ParseError::BadOffset(shstrndx as u64))?; - let (strtab_start, strtab_end) = strtab.get_data_range()?; - let strtab_buf = self.reader.read_bytes(strtab_start, strtab_end)?; - let strtab = StringTable::new(strtab_buf); - Ok((&self.shdrs, Some(strtab))) - } - - /// Find the parsed section header with the given name (if any). - /// - /// Returns a ParseError if the section headers string table can't be read - /// - /// Example to get the ELF file's ABI-tag note - /// ``` - /// use elf::ElfStream; - /// use elf::endian::AnyEndian; - /// use elf::section::SectionHeader; - /// use elf::note::Note; - /// use elf::note::NoteGnuAbiTag; - /// - /// let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - /// let io = std::fs::File::open(path).expect("Could not open file."); - /// let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - /// let shdr: SectionHeader = *file - /// .section_header_by_name(".note.ABI-tag") - /// .expect("section table should be parseable") - /// .expect("file should have a .note.ABI-tag section"); - /// - /// let notes: Vec<_> = file - /// .section_data_as_notes(&shdr) - /// .expect("Should be able to get note section data") - /// .collect(); - /// assert_eq!( - /// notes[0], - /// Note::GnuAbiTag(NoteGnuAbiTag { - /// os: 0, - /// major: 2, - /// minor: 6, - /// subminor: 32 - /// })); - /// ``` - pub fn section_header_by_name( - &mut self, - name: &str, - ) -> Result, ParseError> { - let (shdrs, strtab) = match self.section_headers_with_strtab()? { - (shdr, Some(strtab)) => (shdr, strtab), - // We can't look up shdrs by name if there's no strtab. - // (hint: try looking it up by its sh_type). - _ => { - return Ok(None); - } - }; - - Ok(shdrs.iter().find(|shdr| { - let sh_name = match strtab.get(shdr.sh_name as usize) { - Ok(name) => name, - _ => { - return false; - } - }; - name == sh_name - })) - } - - /// Read the section data for the given [SectionHeader](SectionHeader). - /// Returns both the secion data and an optional CompressionHeader. - /// - /// No compression header signals that the section contents are uncompressed and can be used as-is. - /// - /// Some(chdr) signals that the section contents are compressed and need to be uncompressed via the - /// compression algorithm described in [ch_type](CompressionHeader#structfield.ch_type). - /// The returned buffer represents the compressed section bytes as found in the file, without the - /// CompressionHeader. - /// - /// It is up to the user to perform the decompression themselves with the compression library of - /// their choosing. - /// - /// SHT_NOBITS sections yield an empty slice. - pub fn section_data( - &mut self, - shdr: &SectionHeader, - ) -> Result<(&[u8], Option), ParseError> { - if shdr.sh_type == abi::SHT_NOBITS { - return Ok((&[], None)); - } - - let (start, end) = shdr.get_data_range()?; - let buf = self.reader.read_bytes(start, end)?; - - if shdr.sh_flags & abi::SHF_COMPRESSED as u64 == 0 { - Ok((buf, None)) - } else { - let mut offset = 0; - let chdr = CompressionHeader::parse_at( - self.ehdr.endianness, - self.ehdr.class, - &mut offset, - buf, - )?; - let compressed_buf = buf.get(offset..).ok_or(ParseError::SliceReadError(( - offset, - shdr.sh_size.try_into()?, - )))?; - Ok((compressed_buf, Some(chdr))) - } - } - - /// Read the section data for the given - /// [SectionHeader](SectionHeader) and interpret it in-place as a - /// [StringTable](StringTable). - /// - /// Returns a [ParseError] if the - /// [sh_type](SectionHeader#structfield.sh_type) is not - /// [SHT_STRTAB](abi::SHT_STRTAB). - pub fn section_data_as_strtab( - &mut self, - shdr: &SectionHeader, - ) -> Result, ParseError> { - if shdr.sh_type != abi::SHT_STRTAB { - return Err(ParseError::UnexpectedSectionType(( - shdr.sh_type, - abi::SHT_STRTAB, - ))); - } - - let (start, end) = shdr.get_data_range()?; - let buf = self.reader.read_bytes(start, end)?; - Ok(StringTable::new(buf)) - } - - fn get_symbol_table_of_type( - &mut self, - symtab_type: u32, - ) -> Result, StringTable<'_>)>, ParseError> { - if self.shdrs.is_empty() { - return Ok(None); - } - - // Get the symtab header for the symtab. The gABI states there can be zero or one per ELF file. - match self.shdrs.iter().find(|shdr| shdr.sh_type == symtab_type) { - Some(shdr) => { - // Load the section bytes for the symtab - // (we want immutable references to both the symtab and its strtab concurrently) - let (symtab_start, symtab_end) = shdr.get_data_range()?; - self.reader.load_bytes(symtab_start..symtab_end)?; - - // Load the section bytes for the strtab - // (we want immutable references to both the symtab and its strtab concurrently) - let strtab = self - .shdrs - .get(shdr.sh_link as usize) - .ok_or(ParseError::BadOffset(shdr.sh_link as u64))?; - let (strtab_start, strtab_end) = strtab.get_data_range()?; - self.reader.load_bytes(strtab_start..strtab_end)?; - - // Validate entsize before trying to read the table so that we can error early for corrupted files - Symbol::validate_entsize(self.ehdr.class, shdr.sh_entsize.try_into()?)?; - let symtab = SymbolTable::new( - self.ehdr.endianness, - self.ehdr.class, - self.reader.get_bytes(symtab_start..symtab_end), - ); - let strtab = StringTable::new(self.reader.get_bytes(strtab_start..strtab_end)); - Ok(Some((symtab, strtab))) - } - None => Ok(None), - } - } - - /// Get the symbol table (section of type SHT_SYMTAB) and its associated string table. - /// - /// The gABI specifies that ELF object files may have zero or one sections of type SHT_SYMTAB. - pub fn symbol_table( - &mut self, - ) -> Result, StringTable<'_>)>, ParseError> { - self.get_symbol_table_of_type(abi::SHT_SYMTAB) - } - - /// Get the dynamic symbol table (section of type SHT_DYNSYM) and its associated string table. - /// - /// The gABI specifies that ELF object files may have zero or one sections of type SHT_DYNSYM. - pub fn dynamic_symbol_table( - &mut self, - ) -> Result, StringTable<'_>)>, ParseError> { - self.get_symbol_table_of_type(abi::SHT_DYNSYM) - } - - /// Get the .dynamic section/segment contents. - pub fn dynamic(&mut self) -> Result>, ParseError> { - // If we have section headers, then look it up there - if !self.shdrs.is_empty() { - if let Some(shdr) = self - .shdrs - .iter() - .find(|shdr| shdr.sh_type == abi::SHT_DYNAMIC) - { - let (start, end) = shdr.get_data_range()?; - let buf = self.reader.read_bytes(start, end)?; - return Ok(Some(DynamicTable::new( - self.ehdr.endianness, - self.ehdr.class, - buf, - ))); - } - // Otherwise, look up the PT_DYNAMIC segment (if any) - } else if !self.phdrs.is_empty() { - if let Some(phdr) = self - .phdrs - .iter() - .find(|phdr| phdr.p_type == abi::PT_DYNAMIC) - { - let (start, end) = phdr.get_file_data_range()?; - let buf = self.reader.read_bytes(start, end)?; - return Ok(Some(DynamicTable::new( - self.ehdr.endianness, - self.ehdr.class, - buf, - ))); - } - } - Ok(None) - } - - /// Read the section data for the various GNU Symbol Versioning sections (if any) - /// and return them in a [SymbolVersionTable] that which can interpret them in-place to - /// yield [SymbolRequirement](crate::gnu_symver::SymbolRequirement)s - /// and [SymbolDefinition](crate::gnu_symver::SymbolDefinition)s - /// - /// This is a GNU extension and not all objects use symbol versioning. - /// Returns an empty Option if the object does not use symbol versioning. - pub fn symbol_version_table( - &mut self, - ) -> Result>, ParseError> { - // No sections means no GNU symbol versioning sections, which is ok - if self.shdrs.is_empty() { - return Ok(None); - } - - let mut versym_opt: Option = None; - let mut needs_opt: Option = None; - let mut defs_opt: Option = None; - // Find the GNU Symbol versioning sections (if any) - for shdr in self.shdrs.iter() { - if shdr.sh_type == abi::SHT_GNU_VERSYM { - versym_opt = Some(*shdr); - } else if shdr.sh_type == abi::SHT_GNU_VERNEED { - needs_opt = Some(*shdr); - } else if shdr.sh_type == abi::SHT_GNU_VERDEF { - defs_opt = Some(*shdr); - } - - // If we've found all three sections, then we're done - if versym_opt.is_some() && needs_opt.is_some() && defs_opt.is_some() { - break; - } - } - - // No VERSYM section means the object doesn't use symbol versioning, which is ok. - if versym_opt.is_none() { - return Ok(None); - } - - // Load the versym table - let versym_shdr = versym_opt.unwrap(); - // Validate VERSYM entsize before trying to read the table so that we can error early for corrupted files - VersionIndex::validate_entsize(self.ehdr.class, versym_shdr.sh_entsize.try_into()?)?; - let (versym_start, versym_end) = versym_shdr.get_data_range()?; - self.reader.load_bytes(versym_start..versym_end)?; - - // Get the VERNEED string shdr and load the VERNEED section data (if any) - let needs_shdrs = match needs_opt { - Some(shdr) => { - let (start, end) = shdr.get_data_range()?; - self.reader.load_bytes(start..end)?; - - let strs_shdr = self - .shdrs - .get(shdr.sh_link as usize) - .ok_or(ParseError::BadOffset(shdr.sh_link as u64))?; - let (strs_start, strs_end) = strs_shdr.get_data_range()?; - self.reader.load_bytes(strs_start..strs_end)?; - - Some((shdr, strs_shdr)) - } - // It's possible to have symbol versioning with no NEEDs if we're an object that only - // exports defined symbols. - None => None, - }; - - // Get the VERDEF string shdr and load the VERDEF section data (if any) - let defs_shdrs = match defs_opt { - Some(shdr) => { - let (start, end) = shdr.get_data_range()?; - self.reader.load_bytes(start..end)?; - - let strs_shdr = self - .shdrs - .get(shdr.sh_link as usize) - .ok_or(ParseError::BadOffset(shdr.sh_link as u64))?; - let (strs_start, strs_end) = strs_shdr.get_data_range()?; - self.reader.load_bytes(strs_start..strs_end)?; - - Some((shdr, strs_shdr)) - } - // It's possible to have symbol versioning with no DEFs if we're an object that doesn't - // export any symbols but does use dynamic symbols from other objects. - None => None, - }; - - // Wrap the VERNEED section and strings data in an iterator and string table - let verneeds = match needs_shdrs { - Some((shdr, strs_shdr)) => { - let (strs_start, strs_end) = strs_shdr.get_data_range()?; - let strs_buf = self.reader.get_bytes(strs_start..strs_end); - - let (start, end) = shdr.get_data_range()?; - let buf = self.reader.get_bytes(start..end); - Some(( - VerNeedIterator::new( - self.ehdr.endianness, - self.ehdr.class, - shdr.sh_info as u64, - 0, - buf, - ), - StringTable::new(strs_buf), - )) - } - // If there's no NEEDs, then construct empty wrappers for them - None => None, - }; - - // Wrap the VERDEF section and strings data in an iterator and string table - let verdefs = match defs_shdrs { - Some((shdr, strs_shdr)) => { - let (strs_start, strs_end) = strs_shdr.get_data_range()?; - let strs_buf = self.reader.get_bytes(strs_start..strs_end); - - let (start, end) = shdr.get_data_range()?; - let buf = self.reader.get_bytes(start..end); - Some(( - VerDefIterator::new( - self.ehdr.endianness, - self.ehdr.class, - shdr.sh_info as u64, - 0, - buf, - ), - StringTable::new(strs_buf), - )) - } - // If there's no DEFs, then construct empty wrappers for them - None => None, - }; - - // Wrap the versym section data in a parsing table - let version_ids = VersionIndexTable::new( - self.ehdr.endianness, - self.ehdr.class, - self.reader.get_bytes(versym_start..versym_end), - ); - - // whew, we're done here! - Ok(Some(SymbolVersionTable::new( - version_ids, - verneeds, - verdefs, - ))) - } - - /// Read the section data for the given - /// [SectionHeader](SectionHeader) and interpret it in-place as a - /// [RelIterator](RelIterator). - /// - /// Returns a [ParseError] if the - /// [sh_type](SectionHeader#structfield.sh_type) is not - /// [SHT_REL](abi::SHT_REL). - pub fn section_data_as_rels( - &mut self, - shdr: &SectionHeader, - ) -> Result, ParseError> { - if shdr.sh_type != abi::SHT_REL { - return Err(ParseError::UnexpectedSectionType(( - shdr.sh_type, - abi::SHT_REL, - ))); - } - - let (start, end) = shdr.get_data_range()?; - let buf = self.reader.read_bytes(start, end)?; - Ok(RelIterator::new(self.ehdr.endianness, self.ehdr.class, buf)) - } - - /// Read the section data for the given - /// [SectionHeader](SectionHeader) and interpret it in-place as a - /// [RelaIterator](RelaIterator). - /// - /// Returns a [ParseError] if the - /// [sh_type](SectionHeader#structfield.sh_type) is not - /// [SHT_RELA](abi::SHT_RELA). - pub fn section_data_as_relas( - &mut self, - shdr: &SectionHeader, - ) -> Result, ParseError> { - if shdr.sh_type != abi::SHT_RELA { - return Err(ParseError::UnexpectedSectionType(( - shdr.sh_type, - abi::SHT_RELA, - ))); - } - - let (start, end) = shdr.get_data_range()?; - let buf = self.reader.read_bytes(start, end)?; - Ok(RelaIterator::new( - self.ehdr.endianness, - self.ehdr.class, - buf, - )) - } - - /// Read the section data for the given - /// [SectionHeader](SectionHeader) and interpret it in-place as a - /// [NoteIterator](NoteIterator). - /// - /// Returns a [ParseError] if the - /// [sh_type](SectionHeader#structfield.sh_type) is not - /// [SHT_RELA](abi::SHT_NOTE). - pub fn section_data_as_notes( - &mut self, - shdr: &SectionHeader, - ) -> Result, ParseError> { - if shdr.sh_type != abi::SHT_NOTE { - return Err(ParseError::UnexpectedSectionType(( - shdr.sh_type, - abi::SHT_NOTE, - ))); - } - - let (start, end) = shdr.get_data_range()?; - let buf = self.reader.read_bytes(start, end)?; - Ok(NoteIterator::new( - self.ehdr.endianness, - self.ehdr.class, - shdr.sh_addralign as usize, - buf, - )) - } - - /// Read the segment data for the given - /// [Segment](ProgramHeader) and interpret it in-place as a - /// [NoteIterator](NoteIterator). - /// - /// Returns a [ParseError] if the - /// [p_type](ProgramHeader#structfield.p_type) is not - /// [PT_RELA](abi::PT_NOTE). - pub fn segment_data_as_notes( - &mut self, - phdr: &ProgramHeader, - ) -> Result, ParseError> { - if phdr.p_type != abi::PT_NOTE { - return Err(ParseError::UnexpectedSegmentType(( - phdr.p_type, - abi::PT_NOTE, - ))); - } - - let (start, end) = phdr.get_file_data_range()?; - let buf = self.reader.read_bytes(start, end)?; - Ok(NoteIterator::new( - self.ehdr.endianness, - self.ehdr.class, - phdr.p_align as usize, - buf, - )) - } -} - -#[derive(Debug)] -struct CachingReader { - reader: R, - stream_len: u64, - bufs: HashMap<(usize, usize), Box<[u8]>>, -} - -impl CachingReader { - fn new(mut reader: R) -> Result { - // Cache the size of the stream so that we can err (rather than OOM) on invalid - // huge read requests. - let stream_len = reader.seek(SeekFrom::End(0))?; - Ok(CachingReader { - reader, - stream_len, - bufs: HashMap::<(usize, usize), Box<[u8]>>::default(), - }) - } - - fn read_bytes(&mut self, start: usize, end: usize) -> Result<&[u8], ParseError> { - self.load_bytes(start..end)?; - Ok(self.get_bytes(start..end)) - } - - fn get_bytes(&self, range: Range) -> &[u8] { - // It's a programmer error to call get_bytes without first calling load_bytes, so - // we want to panic here. - self.bufs - .get(&(range.start, range.end)) - .expect("load_bytes must be called before get_bytes for every range") - } - - fn load_bytes(&mut self, range: Range) -> Result<(), ParseError> { - if self.bufs.contains_key(&(range.start, range.end)) { - return Ok(()); - } - - // Verify that the read range doesn't go past the end of the stream (corrupted files) - let end = range.end as u64; - if end > self.stream_len { - return Err(ParseError::BadOffset(end)); - } - - self.reader.seek(SeekFrom::Start(range.start as u64))?; - let mut bytes = vec![0; range.len()].into_boxed_slice(); - self.reader.read_exact(&mut bytes)?; - self.bufs.insert((range.start, range.end), bytes); - Ok(()) - } - - fn clear_cache(&mut self) { - self.bufs.clear() - } -} - -#[cfg(test)] -mod interface_tests { - use super::*; - use crate::dynamic::Dyn; - use crate::endian::AnyEndian; - use crate::hash::SysVHashTable; - use crate::note::{Note, NoteGnuAbiTag, NoteGnuBuildId}; - use crate::relocation::Rela; - use crate::symbol::Symbol; - - #[test] - fn test_open_stream() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let file = ElfStream::::open_stream(io).expect("Open test1"); - assert_eq!(file.ehdr.e_type, abi::ET_EXEC); - } - - #[test] - fn section_headers_with_strtab() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let (shdrs, strtab) = file - .section_headers_with_strtab() - .expect("Failed to get shdrs"); - let (shdrs, strtab) = (shdrs, strtab.unwrap()); - - let shdr_4 = &shdrs[4]; - let name = strtab - .get(shdr_4.sh_name as usize) - .expect("Failed to get section name"); - - assert_eq!(name, ".gnu.hash"); - assert_eq!(shdr_4.sh_type, abi::SHT_GNU_HASH); - } - - #[test] - fn shnum_and_shstrndx_in_shdr0() { - let path = std::path::PathBuf::from("sample-objects/shnum.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let (shdrs, strtab) = file - .section_headers_with_strtab() - .expect("shdrs should be parsable"); - let (shdrs, strtab) = (shdrs, strtab.unwrap()); - - let shdrs_len = shdrs.len(); - assert_eq!(shdrs_len, 0xFF15); - - let shdr = shdrs.get(shdrs_len - 1).unwrap(); - let name = strtab - .get(shdr.sh_name as usize) - .expect("Failed to get section name"); - - assert_eq!(name, ".shstrtab"); - assert_eq!(shdr.sh_type, abi::SHT_STRTAB); - } - - #[test] - fn section_header_by_name() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let shdr: SectionHeader = *file - .section_header_by_name(".gnu.hash") - .expect("section table should be parseable") - .expect("file should have .gnu.hash section"); - - assert_eq!(shdr.sh_type, abi::SHT_GNU_HASH); - - let shdr = file - .section_header_by_name(".not.found") - .expect("section table should be parseable"); - - assert_eq!(shdr, None); - } - - #[test] - fn section_data_for_nobits() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let shdr = file.section_headers()[26]; - assert_eq!(shdr.sh_type, abi::SHT_NOBITS); - let (data, chdr) = file - .section_data(&shdr) - .expect("Failed to get section data"); - assert_eq!(chdr, None); - assert_eq!(data, &[]); - } - - #[test] - fn section_data() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let shdr = file.section_headers()[7]; - assert_eq!(shdr.sh_type, abi::SHT_GNU_VERSYM); - let (data, chdr) = file - .section_data(&shdr) - .expect("Failed to get section data"); - assert_eq!(chdr, None); - assert_eq!(data, [0, 0, 2, 0, 2, 0, 0, 0]); - } - - #[test] - fn section_data_as_strtab() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let shdr = file.section_headers()[file.ehdr.e_shstrndx as usize]; - let strtab = file - .section_data_as_strtab(&shdr) - .expect("Failed to read strtab"); - assert_eq!( - strtab.get(1).expect("Failed to get strtab entry"), - ".symtab" - ); - } - - #[test] - fn segments() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let file = ElfStream::::open_stream(io).expect("Open test1"); - - let segments = file.segments(); - assert_eq!( - segments[0], - ProgramHeader { - p_type: abi::PT_PHDR, - p_offset: 64, - p_vaddr: 4194368, - p_paddr: 4194368, - p_filesz: 448, - p_memsz: 448, - p_flags: 5, - p_align: 8, - } - ) - } - - #[test] - fn segments_phnum_in_shdr0() { - let path = std::path::PathBuf::from("sample-objects/phnum.m68k.so"); - let io = std::fs::File::open(path).expect("Could not open file."); - let file = ElfStream::::open_stream(io).expect("Open test1"); - - assert_eq!( - file.segments()[0], - ProgramHeader { - p_type: abi::PT_PHDR, - p_offset: 92, - p_vaddr: 0, - p_paddr: 0, - p_filesz: 32, - p_memsz: 32, - p_flags: 0x20003, - p_align: 0x40000, - } - ); - } - - #[test] - fn symbol_table() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let (symtab, strtab) = file - .symbol_table() - .expect("Failed to read symbol table") - .expect("Failed to find symbol table"); - let symbol = symtab.get(30).expect("Failed to get symbol"); - assert_eq!( - symbol, - Symbol { - st_name: 19, - st_value: 6293200, - st_size: 0, - st_shndx: 21, - st_info: 1, - st_other: 0, - } - ); - assert_eq!( - strtab - .get(symbol.st_name as usize) - .expect("Failed to get name from strtab"), - "__JCR_LIST__" - ); - } - - #[test] - fn dynamic_symbol_table() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let (symtab, strtab) = file - .dynamic_symbol_table() - .expect("Failed to read symbol table") - .expect("Failed to find symbol table"); - let symbol = symtab.get(1).expect("Failed to get symbol"); - assert_eq!( - symbol, - Symbol { - st_name: 11, - st_value: 0, - st_size: 0, - st_shndx: 0, - st_info: 18, - st_other: 0, - } - ); - assert_eq!( - strtab - .get(symbol.st_name as usize) - .expect("Failed to get name from strtab"), - "memset" - ); - } - - #[test] - fn dynamic() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let mut dynamic = file - .dynamic() - .expect("Failed to parse .dynamic") - .expect("Failed to find .dynamic") - .iter(); - assert_eq!( - dynamic.next().expect("Failed to get dyn entry"), - Dyn { - d_tag: abi::DT_NEEDED, - d_un: 1 - } - ); - assert_eq!( - dynamic.next().expect("Failed to get dyn entry"), - Dyn { - d_tag: abi::DT_INIT, - d_un: 4195216 - } - ); - } - - #[test] - fn section_data_as_rels() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let shdr = file.section_headers()[10]; - file.section_data_as_rels(&shdr) - .expect_err("Expected error parsing non-REL scn as RELs"); - } - - #[test] - fn section_data_as_relas() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let shdr = file.section_headers()[10]; - let mut relas = file - .section_data_as_relas(&shdr) - .expect("Failed to read relas section"); - assert_eq!( - relas.next().expect("Failed to get rela entry"), - Rela { - r_offset: 6293704, - r_sym: 1, - r_type: 7, - r_addend: 0, - } - ); - assert_eq!( - relas.next().expect("Failed to get rela entry"), - Rela { - r_offset: 6293712, - r_sym: 2, - r_type: 7, - r_addend: 0, - } - ); - assert!(relas.next().is_none()); - } - - #[test] - fn section_data_as_notes() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let shdr = file.section_headers()[2]; - let mut notes = file - .section_data_as_notes(&shdr) - .expect("Failed to read relas section"); - assert_eq!( - notes.next().expect("Failed to get first note"), - Note::GnuAbiTag(NoteGnuAbiTag { - os: 0, - major: 2, - minor: 6, - subminor: 32 - }) - ); - assert!(notes.next().is_none()); - } - - #[test] - fn segment_data_as_notes() { - let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let phdrs = file.segments(); - let note_phdr = phdrs[5]; - let mut notes = file - .segment_data_as_notes(¬e_phdr) - .expect("Failed to read relas section"); - assert_eq!( - notes.next().expect("Failed to get first note"), - Note::GnuAbiTag(NoteGnuAbiTag { - os: 0, - major: 2, - minor: 6, - subminor: 32 - }) - ); - assert_eq!( - notes.next().expect("Failed to get second note"), - Note::GnuBuildId(NoteGnuBuildId(&[ - 119, 65, 159, 13, 165, 16, 131, 12, 87, 167, 200, 204, 176, 238, 133, 95, 238, 211, - 118, 163 - ])) - ); - assert!(notes.next().is_none()); - } - - #[test] - fn symbol_version_table() { - let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - let vst = file - .symbol_version_table() - .expect("Failed to parse GNU symbol versions") - .expect("Failed to find GNU symbol versions"); - - let req = vst - .get_requirement(2) - .expect("Failed to parse NEED") - .expect("Failed to find NEED"); - assert_eq!(req.file, "libc.so.6"); - assert_eq!(req.name, "GLIBC_2.2.5"); - assert_eq!(req.hash, 0x9691A75); - - let req = vst.get_requirement(3).expect("Failed to parse NEED"); - assert!(req.is_none()); - - let req = vst.get_requirement(4).expect("Failed to parse NEED"); - assert!(req.is_none()); - - let req = vst - .get_requirement(5) - .expect("Failed to parse NEED") - .expect("Failed to find NEED"); - assert_eq!(req.file, "libc.so.6"); - assert_eq!(req.name, "GLIBC_2.2.5"); - assert_eq!(req.hash, 0x9691A75); - - let def = vst - .get_definition(3) - .expect("Failed to parse DEF") - .expect("Failed to find DEF"); - assert_eq!(def.hash, 0xC33237F); - assert_eq!(def.flags, 1); - assert!(!def.hidden); - let def_names: Vec<&str> = def.names.map(|res| res.expect("should parse")).collect(); - assert_eq!(def_names, &["hello.so"]); - - let def = vst - .get_definition(7) - .expect("Failed to parse DEF") - .expect("Failed to find DEF"); - assert_eq!(def.hash, 0x1570B62); - assert_eq!(def.flags, 0); - assert!(def.hidden); - let def_names: Vec<&str> = def.names.map(|res| res.expect("should parse")).collect(); - assert_eq!(def_names, &["HELLO_1.42"]); - } - - #[test] - fn sysv_hash_table() { - let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so"); - let io = std::fs::File::open(path).expect("Could not open file."); - let mut file = ElfStream::::open_stream(io).expect("Open test1"); - - // Look up the SysV hash section header - let hash_shdr = *file - .section_header_by_name(".hash") - .expect("Failed to find sysv hash section") - .expect("Failed to find sysv hash section"); - - // We don't have a file interface for getting the SysV hash section yet, so clone the section bytes - // So we can use them to back a SysVHashTable - let (data, _) = file - .section_data(&hash_shdr) - .expect("Failed to get hash section data"); - let data_copy: Vec = data.into(); - let hash_table = - SysVHashTable::new(file.ehdr.endianness, file.ehdr.class, data_copy.as_ref()) - .expect("Failed to parse hash table"); - - // Get the dynamic symbol table. - let (symtab, strtab) = file - .dynamic_symbol_table() - .expect("Failed to read symbol table") - .expect("Failed to find symbol table"); - - // Verify that these three symbols all collide in the hash table's buckets - assert_eq!(crate::hash::sysv_hash(b"use_memset_v2"), 0x8080542); - assert_eq!(crate::hash::sysv_hash(b"__gmon_start__"), 0xF4D007F); - assert_eq!(crate::hash::sysv_hash(b"memset"), 0x73C49C4); - assert_eq!(crate::hash::sysv_hash(b"use_memset_v2") % 3, 0); - assert_eq!(crate::hash::sysv_hash(b"__gmon_start__") % 3, 0); - assert_eq!(crate::hash::sysv_hash(b"memset") % 3, 0); - - // Use the hash table to find a given symbol in it. - let (sym_idx, sym) = hash_table - .find(b"memset", &symtab, &strtab) - .expect("Failed to parse hash") - .expect("Failed to find hash"); - - // Verify that we got the same symbol from the hash table we expected - assert_eq!(sym_idx, 2); - assert_eq!(strtab.get(sym.st_name as usize).unwrap(), "memset"); - assert_eq!( - sym, - symtab.get(sym_idx).expect("Failed to get expected sym") - ); - } -} - -#[cfg(test)] -mod arch_tests { - use super::*; - use crate::endian::AnyEndian; - - // Basic smoke test which parses out symbols and headers for a given sample object of a given architecture - macro_rules! arch_test { - ( $arch:expr, $e_machine:expr, $endian:expr) => {{ - let path_str = format!("sample-objects/symver.{}.so", $arch); - let path = std::path::PathBuf::from(path_str); - let io = std::fs::File::open(path).expect("file should exist"); - let mut file = ElfStream::::open_stream(io).expect("should parse"); - - assert_eq!(file.ehdr.e_machine, $e_machine); - assert_eq!(file.ehdr.endianness, $endian); - - let (shdrs, strtab) = file.section_headers_with_strtab().expect("should parse"); - let (shdrs, strtab) = (shdrs, strtab.unwrap()); - let _: Vec<_> = shdrs - .iter() - .map(|shdr| { - ( - strtab.get(shdr.sh_name as usize).expect("should parse"), - shdr, - ) - }) - .collect(); - - if let Some((symtab, strtab)) = file.symbol_table().expect("should parse") { - let _: Vec<_> = symtab - .iter() - .map(|sym| (strtab.get(sym.st_name as usize).expect("should parse"), sym)) - .collect(); - } - - if let Some((symtab, strtab)) = file.dynamic_symbol_table().expect("should parse") { - let _: Vec<_> = symtab - .iter() - .map(|sym| (strtab.get(sym.st_name as usize).expect("should parse"), sym)) - .collect(); - } - - let note_phdrs: Vec<_> = file.segments() - .iter() - .filter(|phdr| phdr.p_type == abi::PT_NOTE) - .map(|phdr| *phdr) - .collect(); - for phdr in note_phdrs { - let _: Vec<_> = file - .segment_data_as_notes(&phdr) - .expect("should parse") - .collect(); - } - }}; - } - - #[test] - fn x86_64() { - arch_test!("x86_64", abi::EM_X86_64, AnyEndian::Little); - } - - #[test] - fn m68k() { - arch_test!("m68k", abi::EM_68K, AnyEndian::Big); - } - - #[test] - fn aarch64() { - arch_test!("aarch64", abi::EM_AARCH64, AnyEndian::Little); - } - - #[test] - fn armhf() { - arch_test!("armhf", abi::EM_ARM, AnyEndian::Little); - } - - #[test] - fn powerpc64() { - arch_test!("powerpc64", abi::EM_PPC64, AnyEndian::Big); - } - - #[test] - fn powerpc64le() { - arch_test!("powerpc64le", abi::EM_PPC64, AnyEndian::Little); - } - - #[test] - fn riscv64() { - arch_test!("riscv64", abi::EM_RISCV, AnyEndian::Little); - } -} diff --git a/arceos/modules/elf/src/endian.rs b/arceos/modules/elf/src/endian.rs deleted file mode 100644 index d07812d74..000000000 --- a/arceos/modules/elf/src/endian.rs +++ /dev/null @@ -1,327 +0,0 @@ -//! An all-safe-code endian-aware integer parsing implementation via the -//! [EndianParse] trait. -//! -//! This module provides four endian parsing implementations optimized to support the different -//! common use-cases for an ELF parsing library. Each trait impl represents a -//! specification that encapsulates an interface for parsing integers from some -//! set of allowed byte orderings. -//! -//! * [AnyEndian]: Dynamically parsing either byte order at runtime based on the type of ELF object being parsed. -//! * [BigEndian]/[LittleEndian]: For tools that know they only want to parse a single given byte order known at compile time. -//! * [type@NativeEndian]: For tools that know they want to parse the same byte order as the target's byte order. -// -// Note: -// I'd love to see this get replaced with safe transmutes, if that RFC ever gets formalized. -// Until then, this crate serves as an example implementation for what's possible with purely safe rust. -use crate::abi; -use crate::parse::ParseError; - -/// This macro writes out safe code to get a subslice from the the byte slice $data -/// at the given $off as a [u8; size_of<$typ>], then calls the corresponding safe -/// endian-aware conversion on it. -/// -/// This uses safe integer math and returns a ParseError on overflow or if $data did -/// not contain enough bytes at $off to perform the conversion. -macro_rules! safe_from { - ( $self:ident, $typ:ty, $off:ident, $data:ident) => {{ - const SIZE: usize = core::mem::size_of::<$typ>(); - - let end = (*$off) - .checked_add(SIZE) - .ok_or(ParseError::IntegerOverflow)?; - - let buf: [u8; SIZE] = $data - .get(*$off..end) - .ok_or(ParseError::SliceReadError((*$off, end)))? - .try_into()?; - - *$off = end; - - // Note: This check evaluates to a constant true/false for the "fixed" types - // so the compiler should optimize out the check (LittleEndian, BigEndian, NativeEndian) - if $self.is_little() { - Ok(<$typ>::from_le_bytes(buf)) - } else { - Ok(<$typ>::from_be_bytes(buf)) - } - }}; -} - -/// An all-safe-code endian-aware integer parsing trait. -/// -/// These methods use safe code to get a subslice from the the byte slice $data -/// at the given $off as a [u8; size_of<$typ>], then calls the corresponding safe -/// endian-aware conversion on it. -/// -/// These use checked integer math and returns a ParseError on overflow or if $data did -/// not contain enough bytes at $off to perform the conversion. -pub trait EndianParse: Clone + Copy + Default + PartialEq + Eq { - fn parse_u8_at(self, offset: &mut usize, data: &[u8]) -> Result { - safe_from!(self, u8, offset, data) - } - - fn parse_u16_at(self, offset: &mut usize, data: &[u8]) -> Result { - safe_from!(self, u16, offset, data) - } - - fn parse_u32_at(self, offset: &mut usize, data: &[u8]) -> Result { - safe_from!(self, u32, offset, data) - } - - fn parse_u64_at(self, offset: &mut usize, data: &[u8]) -> Result { - safe_from!(self, u64, offset, data) - } - - fn parse_i32_at(self, offset: &mut usize, data: &[u8]) -> Result { - safe_from!(self, i32, offset, data) - } - - fn parse_i64_at(self, offset: &mut usize, data: &[u8]) -> Result { - safe_from!(self, i64, offset, data) - } - - /// Get an endian-aware integer parsing spec for an ELF [FileHeader](crate::file::FileHeader)'s - /// `ident[EI_DATA]` byte. - /// - /// Returns an [UnsupportedElfEndianness](ParseError::UnsupportedElfEndianness) if this spec - /// doesn't support parsing the byte-order represented by ei_data. If you're - /// seeing this error, are you trying to read files of any endianness? i.e. - /// did you want to use AnyEndian? - fn from_ei_data(ei_data: u8) -> Result; - - fn is_little(self) -> bool; - - #[inline(always)] - fn is_big(self) -> bool { - !self.is_little() - } -} - -/// An endian parsing type that can choose at runtime which byte order to parse integers as. -/// This is useful for scenarios where a single compiled binary wants to dynamically -/// interpret ELF files of any byte order. -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] -pub enum AnyEndian { - /// Used for a little-endian ELF structures that have been parsed with AnyEndian - #[default] - Little, - /// Used for a big-endian ELF structures that have been parsed with AnyEndian - Big, -} - -/// A zero-sized type that always parses integers as if they're in little-endian order. -/// This is useful for scenarios where a combiled binary knows it only wants to interpret -/// little-endian ELF files and doesn't want the performance penalty of evaluating a match -/// each time it parses an integer. -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] -pub struct LittleEndian; - -/// A zero-sized type that always parses integers as if they're in big-endian order. -/// This is useful for scenarios where a combiled binary knows it only wants to interpret -/// big-endian ELF files and doesn't want the performance penalty of evaluating a match -/// each time it parses an integer. -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] -pub struct BigEndian; - -/// A zero-sized type that always parses integers as if they're in the compilation target's native-endian order. -/// This is useful for toolchain scenarios where a combiled binary knows it only wants to interpret -/// ELF files compiled for the same target and doesn't want the performance penalty of evaluating a match -/// each time it parses an integer. -#[cfg(target_endian = "little")] -pub type NativeEndian = LittleEndian; - -#[cfg(target_endian = "little")] -#[allow(non_upper_case_globals)] -#[doc(hidden)] -pub const NativeEndian: LittleEndian = LittleEndian; - -/// A zero-sized type that always parses integers as if they're in the compilation target's native-endian order. -/// This is useful for toolchain scenarios where a combiled binary knows it only wants to interpret -/// ELF files compiled for the same target and doesn't want the performance penalty of evaluating a match -/// each time it parses an integer. -#[cfg(target_endian = "big")] -pub type NativeEndian = BigEndian; - -#[cfg(target_endian = "big")] -#[allow(non_upper_case_globals)] -#[doc(hidden)] -pub const NativeEndian: BigEndian = BigEndian; - -impl EndianParse for LittleEndian { - fn from_ei_data(ei_data: u8) -> Result { - match ei_data { - abi::ELFDATA2LSB => Ok(LittleEndian), - _ => Err(ParseError::UnsupportedElfEndianness(ei_data)), - } - } - - #[inline(always)] - fn is_little(self) -> bool { - true - } -} - -impl EndianParse for BigEndian { - fn from_ei_data(ei_data: u8) -> Result { - match ei_data { - abi::ELFDATA2MSB => Ok(BigEndian), - _ => Err(ParseError::UnsupportedElfEndianness(ei_data)), - } - } - - #[inline(always)] - fn is_little(self) -> bool { - false - } -} - -impl EndianParse for AnyEndian { - fn from_ei_data(ei_data: u8) -> Result { - match ei_data { - abi::ELFDATA2LSB => Ok(AnyEndian::Little), - abi::ELFDATA2MSB => Ok(AnyEndian::Big), - _ => Err(ParseError::UnsupportedElfEndianness(ei_data)), - } - } - - #[inline(always)] - fn is_little(self) -> bool { - match self { - AnyEndian::Little => true, - AnyEndian::Big => false, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - macro_rules! parse_test { - ( $endian:expr, $res_typ:ty, $method:ident, $expect:expr) => {{ - let bytes = [ - 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8, - ]; - let mut offset = 0; - let result = $endian.$method(&mut offset, &bytes).unwrap(); - assert_eq!(result, $expect); - assert_eq!(offset, core::mem::size_of::<$res_typ>()); - }}; - } - - macro_rules! fuzz_too_short_test { - ( $endian:expr, $res_typ:ty, $method:ident) => {{ - let bytes = [ - 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8, - ]; - let size = core::mem::size_of::<$res_typ>(); - for n in 0..size { - let buf = bytes.split_at(n).0.as_ref(); - let mut offset: usize = 0; - let error = $endian - .$method(&mut offset, buf) - .expect_err("Expected an error, but parsed: "); - assert!( - matches!(error, ParseError::SliceReadError(_)), - "Unexpected Error type found: {error}" - ); - } - }}; - } - - #[test] - fn parse_u8_at() { - parse_test!(LittleEndian, u8, parse_u8_at, 0x01u8); - parse_test!(BigEndian, u8, parse_u8_at, 0x01u8); - parse_test!(AnyEndian::Little, u8, parse_u8_at, 0x01u8); - parse_test!(AnyEndian::Big, u8, parse_u8_at, 0x01u8); - } - - #[test] - fn parse_u16_at() { - parse_test!(LittleEndian, u16, parse_u16_at, 0x0201u16); - parse_test!(BigEndian, u16, parse_u16_at, 0x0102u16); - parse_test!(AnyEndian::Little, u16, parse_u16_at, 0x0201u16); - parse_test!(AnyEndian::Big, u16, parse_u16_at, 0x0102u16); - } - - #[test] - fn parse_u32_at() { - parse_test!(LittleEndian, u32, parse_u32_at, 0x04030201u32); - parse_test!(BigEndian, u32, parse_u32_at, 0x01020304u32); - parse_test!(AnyEndian::Little, u32, parse_u32_at, 0x04030201u32); - parse_test!(AnyEndian::Big, u32, parse_u32_at, 0x01020304u32); - } - - #[test] - fn parse_u64_at() { - parse_test!(LittleEndian, u64, parse_u64_at, 0x0807060504030201u64); - parse_test!(BigEndian, u64, parse_u64_at, 0x0102030405060708u64); - parse_test!(AnyEndian::Little, u64, parse_u64_at, 0x0807060504030201u64); - parse_test!(AnyEndian::Big, u64, parse_u64_at, 0x0102030405060708u64); - } - - #[test] - fn parse_i32_at() { - parse_test!(LittleEndian, i32, parse_i32_at, 0x04030201i32); - parse_test!(BigEndian, i32, parse_i32_at, 0x01020304i32); - parse_test!(AnyEndian::Little, i32, parse_i32_at, 0x04030201i32); - parse_test!(AnyEndian::Big, i32, parse_i32_at, 0x01020304i32); - } - - #[test] - fn parse_i64_at() { - parse_test!(LittleEndian, i64, parse_i64_at, 0x0807060504030201i64); - parse_test!(BigEndian, i64, parse_i64_at, 0x0102030405060708i64); - parse_test!(AnyEndian::Little, i64, parse_i64_at, 0x0807060504030201i64); - parse_test!(AnyEndian::Big, i64, parse_i64_at, 0x0102030405060708i64); - } - - #[test] - fn fuzz_u8_too_short() { - fuzz_too_short_test!(LittleEndian, u8, parse_u8_at); - fuzz_too_short_test!(BigEndian, u8, parse_u8_at); - fuzz_too_short_test!(AnyEndian::Little, u8, parse_u8_at); - fuzz_too_short_test!(AnyEndian::Big, u8, parse_u8_at); - } - - #[test] - fn fuzz_u16_too_short() { - fuzz_too_short_test!(LittleEndian, u16, parse_u16_at); - fuzz_too_short_test!(BigEndian, u16, parse_u16_at); - fuzz_too_short_test!(AnyEndian::Little, u16, parse_u16_at); - fuzz_too_short_test!(AnyEndian::Big, u16, parse_u16_at); - } - - #[test] - fn fuzz_u32_too_short() { - fuzz_too_short_test!(LittleEndian, u32, parse_u32_at); - fuzz_too_short_test!(BigEndian, u32, parse_u32_at); - fuzz_too_short_test!(AnyEndian::Little, u32, parse_u32_at); - fuzz_too_short_test!(AnyEndian::Big, u32, parse_u32_at); - } - - #[test] - fn fuzz_i32_too_short() { - fuzz_too_short_test!(LittleEndian, i32, parse_i32_at); - fuzz_too_short_test!(BigEndian, i32, parse_i32_at); - fuzz_too_short_test!(AnyEndian::Little, i32, parse_i32_at); - fuzz_too_short_test!(AnyEndian::Big, i32, parse_i32_at); - } - - #[test] - fn fuzz_u64_too_short() { - fuzz_too_short_test!(LittleEndian, u64, parse_u64_at); - fuzz_too_short_test!(BigEndian, u64, parse_u64_at); - fuzz_too_short_test!(AnyEndian::Little, u64, parse_u64_at); - fuzz_too_short_test!(AnyEndian::Big, u64, parse_u64_at); - } - - #[test] - fn fuzz_i64_too_short() { - fuzz_too_short_test!(LittleEndian, i64, parse_i64_at); - fuzz_too_short_test!(BigEndian, i64, parse_i64_at); - fuzz_too_short_test!(AnyEndian::Little, i64, parse_i64_at); - fuzz_too_short_test!(AnyEndian::Big, i64, parse_i64_at); - } -} diff --git a/arceos/modules/elf/src/file.rs b/arceos/modules/elf/src/file.rs deleted file mode 100644 index bf4137d11..000000000 --- a/arceos/modules/elf/src/file.rs +++ /dev/null @@ -1,478 +0,0 @@ -//! Parsing the ELF File Header -use crate::abi; -use crate::endian::EndianParse; -use crate::parse::ParseError; - -/// Represents the ELF file word size (32-bit vs 64-bit) -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum Class { - ELF32, - ELF64, -} - -/// C-style 32-bit ELF File Header definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf32_Ehdr { - pub e_ident: [u8; abi::EI_NIDENT], - pub e_type: u16, - pub e_machine: u16, - pub e_version: u32, - pub e_entry: u32, - pub e_phoff: u32, - pub e_shoff: u32, - pub e_flags: u32, - pub e_ehsize: u16, - pub e_phentsize: u16, - pub e_phnum: u16, - pub e_shentsize: u16, - pub e_shnum: u16, - pub e_shstrndx: u16, -} - -/// C-style 64-bit ELF File Header definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf64_Ehdr { - pub e_ident: [u8; abi::EI_NIDENT], - pub e_type: u16, - pub e_machine: u16, - pub e_version: u32, - pub e_entry: u64, - pub e_phoff: u64, - pub e_shoff: u64, - pub e_flags: u32, - pub e_ehsize: u16, - pub e_phentsize: u16, - pub e_phnum: u16, - pub e_shentsize: u16, - pub e_shnum: u16, - pub e_shstrndx: u16, -} - -/// Encapsulates the contents of the ELF File Header -/// -/// The ELF File Header starts off every ELF file and both identifies the -/// file contents and informs how to interpret said contents. This includes -/// the width of certain fields (32-bit vs 64-bit), the data endianness, the -/// file type, and more. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct FileHeader { - /// 32-bit vs 64-bit - pub class: Class, - // file byte order - pub endianness: E, - /// elf version - pub version: u32, - /// OS ABI - pub osabi: u8, - /// Version of the OS ABI - pub abiversion: u8, - /// ELF file type - pub e_type: u16, - /// Target machine architecture - pub e_machine: u16, - /// Virtual address of program entry point - /// This member gives the virtual address to which the system first transfers control, - /// thus starting the process. If the file has no associated entry point, this member holds zero. - /// - /// Note: Type is Elf32_Addr or Elf64_Addr which are either 4 or 8 bytes. We aren't trying to zero-copy - /// parse the FileHeader since there's only one per file and its only ~45 bytes anyway, so we use - /// u64 for the three Elf*_Addr and Elf*_Off fields here. - pub e_entry: u64, - /// This member holds the program header table's file offset in bytes. If the file has no program header - /// table, this member holds zero. - pub e_phoff: u64, - /// This member holds the section header table's file offset in bytes. If the file has no section header - /// table, this member holds zero. - pub e_shoff: u64, - /// This member holds processor-specific flags associated with the file. Flag names take the form EF_machine_flag. - pub e_flags: u32, - /// This member holds the ELF header's size in bytes. - pub e_ehsize: u16, - /// This member holds the size in bytes of one entry in the file's program header table; all entries are the same size. - pub e_phentsize: u16, - /// This member holds the number of entries in the program header table. Thus the product of e_phentsize and e_phnum - /// gives the table's size in bytes. If a file has no program header table, e_phnum holds the value zero. - pub e_phnum: u16, - /// This member holds a section header's size in bytes. A section header is one entry in the section header table; - /// all entries are the same size. - pub e_shentsize: u16, - /// This member holds the number of entries in the section header table. Thus the product of e_shentsize and e_shnum - /// gives the section header table's size in bytes. If a file has no section header table, e_shnum holds the value zero. - /// - /// If the number of sections is greater than or equal to SHN_LORESERVE (0xff00), this member has the value zero and - /// the actual number of section header table entries is contained in the sh_size field of the section header at index 0. - /// (Otherwise, the sh_size member of the initial entry contains 0.) - pub e_shnum: u16, - /// This member holds the section header table index of the entry associated with the section name string table. If the - /// file has no section name string table, this member holds the value SHN_UNDEF. - /// - /// If the section name string table section index is greater than or equal to SHN_LORESERVE (0xff00), this member has - /// the value SHN_XINDEX (0xffff) and the actual index of the section name string table section is contained in the - /// sh_link field of the section header at index 0. (Otherwise, the sh_link member of the initial entry contains 0.) - pub e_shstrndx: u16, -} - -pub const ELF32_EHDR_TAILSIZE: usize = 36; -pub const ELF64_EHDR_TAILSIZE: usize = 48; - -fn verify_ident(buf: &[u8]) -> Result<(), ParseError> { - // Verify the magic number - let magic = buf.split_at(abi::EI_CLASS).0; - if magic != abi::ELFMAGIC { - return Err(ParseError::BadMagic([ - magic[0], magic[1], magic[2], magic[3], - ])); - } - - // Verify ELF Version - let version = buf[abi::EI_VERSION]; - if version != abi::EV_CURRENT { - return Err(ParseError::UnsupportedVersion(( - version as u64, - abi::EV_CURRENT as u64, - ))); - } - - Ok(()) -} - -pub fn parse_ident(data: &[u8]) -> Result<(E, Class, u8, u8), ParseError> { - verify_ident(data)?; - - let e_class = data[abi::EI_CLASS]; - let class = match e_class { - abi::ELFCLASS32 => Class::ELF32, - abi::ELFCLASS64 => Class::ELF64, - _ => { - return Err(ParseError::UnsupportedElfClass(e_class)); - } - }; - - // Verify endianness is something we know how to parse - let file_endian = E::from_ei_data(data[abi::EI_DATA])?; - - Ok(( - file_endian, - class, - data[abi::EI_OSABI], - data[abi::EI_ABIVERSION], - )) -} - -impl FileHeader { - pub fn parse_tail(ident: (E, Class, u8, u8), data: &[u8]) -> Result, ParseError> { - let (file_endian, class, osabi, abiversion) = ident; - - let mut offset = 0; - let e_type = file_endian.parse_u16_at(&mut offset, data)?; - let e_machine = file_endian.parse_u16_at(&mut offset, data)?; - let version = file_endian.parse_u32_at(&mut offset, data)?; - - let e_entry: u64; - let e_phoff: u64; - let e_shoff: u64; - - if class == Class::ELF32 { - e_entry = file_endian.parse_u32_at(&mut offset, data)? as u64; - e_phoff = file_endian.parse_u32_at(&mut offset, data)? as u64; - e_shoff = file_endian.parse_u32_at(&mut offset, data)? as u64; - } else { - e_entry = file_endian.parse_u64_at(&mut offset, data)?; - e_phoff = file_endian.parse_u64_at(&mut offset, data)?; - e_shoff = file_endian.parse_u64_at(&mut offset, data)?; - } - - let e_flags = file_endian.parse_u32_at(&mut offset, data)?; - let e_ehsize = file_endian.parse_u16_at(&mut offset, data)?; - let e_phentsize = file_endian.parse_u16_at(&mut offset, data)?; - let e_phnum = file_endian.parse_u16_at(&mut offset, data)?; - let e_shentsize = file_endian.parse_u16_at(&mut offset, data)?; - let e_shnum = file_endian.parse_u16_at(&mut offset, data)?; - let e_shstrndx = file_endian.parse_u16_at(&mut offset, data)?; - - Ok(FileHeader { - class, - endianness: file_endian, - version, - e_type, - e_machine, - osabi, - abiversion, - e_entry, - e_phoff, - e_shoff, - e_flags, - e_ehsize, - e_phentsize, - e_phnum, - e_shentsize, - e_shnum, - e_shstrndx, - }) - } -} - -#[cfg(test)] -mod parse_tests { - use super::*; - use crate::endian::AnyEndian; - - #[test] - fn test_verify_ident_valid() { - let data: [u8; abi::EI_NIDENT] = [ - abi::ELFMAG0, - abi::ELFMAG1, - abi::ELFMAG2, - abi::ELFMAG3, - abi::ELFCLASS32, - abi::ELFDATA2LSB, - abi::EV_CURRENT, - abi::ELFOSABI_LINUX, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ]; - verify_ident(data.as_ref()).expect("Expected Ok result"); - } - - #[test] - fn test_verify_ident_invalid_mag0() { - let data: [u8; abi::EI_NIDENT] = [ - 0xFF, - abi::ELFMAG1, - abi::ELFMAG2, - abi::ELFMAG3, - abi::ELFCLASS32, - abi::ELFDATA2LSB, - abi::EV_CURRENT, - abi::ELFOSABI_LINUX, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ]; - let result = verify_ident(data.as_ref()).expect_err("Expected an error"); - assert!( - matches!(result, ParseError::BadMagic(_)), - "Unexpected Error type found: {result}" - ); - } - - #[test] - fn test_verify_ident_invalid_mag1() { - let data: [u8; abi::EI_NIDENT] = [ - abi::ELFMAG0, - 0xFF, - abi::ELFMAG2, - abi::ELFMAG3, - abi::ELFCLASS32, - abi::ELFDATA2LSB, - abi::EV_CURRENT, - abi::ELFOSABI_LINUX, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ]; - let result = verify_ident(data.as_ref()).expect_err("Expected an error"); - assert!( - matches!(result, ParseError::BadMagic(_)), - "Unexpected Error type found: {result}" - ); - } - - #[test] - fn test_verify_ident_invalid_mag2() { - let data: [u8; abi::EI_NIDENT] = [ - abi::ELFMAG0, - abi::ELFMAG1, - 0xFF, - abi::ELFMAG3, - abi::ELFCLASS32, - abi::ELFDATA2LSB, - abi::EV_CURRENT, - abi::ELFOSABI_LINUX, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ]; - let result = verify_ident(data.as_ref()).expect_err("Expected an error"); - assert!( - matches!(result, ParseError::BadMagic(_)), - "Unexpected Error type found: {result}" - ); - } - - #[test] - fn test_verify_ident_invalid_mag3() { - let data: [u8; abi::EI_NIDENT] = [ - abi::ELFMAG0, - abi::ELFMAG1, - abi::ELFMAG2, - 0xFF, - abi::ELFCLASS32, - abi::ELFDATA2LSB, - abi::EV_CURRENT, - abi::ELFOSABI_LINUX, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ]; - let result = verify_ident(data.as_ref()).expect_err("Expected an error"); - assert!( - matches!(result, ParseError::BadMagic(_)), - "Unexpected Error type found: {result}" - ); - } - - #[allow(deprecated)] - #[test] - fn test_verify_ident_invalid_version() { - let data: [u8; abi::EI_NIDENT] = [ - abi::ELFMAG0, - abi::ELFMAG1, - abi::ELFMAG2, - abi::ELFMAG3, - abi::ELFCLASS32, - abi::ELFDATA2LSB, - 42, - abi::ELFOSABI_LINUX, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ]; - let result = verify_ident(data.as_ref()).expect_err("Expected an error"); - assert!( - matches!(result, ParseError::UnsupportedVersion((42, 1))), - "Unexpected Error type found: {result}" - ); - } - - #[test] - fn test_parse_ehdr32_works() { - let ident = (AnyEndian::Little, Class::ELF32, abi::ELFOSABI_LINUX, 7u8); - let mut tail = [0u8; ELF64_EHDR_TAILSIZE]; - for (n, elem) in tail.iter_mut().enumerate().take(ELF64_EHDR_TAILSIZE) { - *elem = n as u8; - } - - assert_eq!( - FileHeader::parse_tail(ident, &tail).unwrap(), - FileHeader { - class: Class::ELF32, - endianness: AnyEndian::Little, - version: 0x7060504, - osabi: abi::ELFOSABI_LINUX, - abiversion: 7, - e_type: 0x100, - e_machine: 0x302, - e_entry: 0x0B0A0908, - e_phoff: 0x0F0E0D0C, - e_shoff: 0x13121110, - e_flags: 0x17161514, - e_ehsize: 0x1918, - e_phentsize: 0x1B1A, - e_phnum: 0x1D1C, - e_shentsize: 0x1F1E, - e_shnum: 0x2120, - e_shstrndx: 0x2322, - } - ); - } - - #[test] - fn test_parse_ehdr32_fuzz_too_short() { - let ident = (AnyEndian::Little, Class::ELF32, abi::ELFOSABI_LINUX, 7u8); - let tail = [0u8; ELF32_EHDR_TAILSIZE]; - - for n in 0..ELF32_EHDR_TAILSIZE { - let buf = tail.split_at(n).0; - let result = FileHeader::parse_tail(ident, buf).expect_err("Expected an error"); - assert!( - matches!(result, ParseError::SliceReadError(_)), - "Unexpected Error type found: {result:?}" - ); - } - } - - #[test] - fn test_parse_ehdr64_works() { - let ident = (AnyEndian::Big, Class::ELF64, abi::ELFOSABI_LINUX, 7u8); - let mut tail = [0u8; ELF64_EHDR_TAILSIZE]; - for (n, elem) in tail.iter_mut().enumerate().take(ELF64_EHDR_TAILSIZE) { - *elem = n as u8; - } - - assert_eq!( - FileHeader::parse_tail(ident, &tail).unwrap(), - FileHeader { - class: Class::ELF64, - endianness: AnyEndian::Big, - version: 0x04050607, - osabi: abi::ELFOSABI_LINUX, - abiversion: 7, - e_type: 0x0001, - e_machine: 0x0203, - e_entry: 0x08090A0B0C0D0E0F, - e_phoff: 0x1011121314151617, - e_shoff: 0x18191A1B1C1D1E1F, - e_flags: 0x20212223, - e_ehsize: 0x2425, - e_phentsize: 0x2627, - e_phnum: 0x2829, - e_shentsize: 0x2A2B, - e_shnum: 0x2C2D, - e_shstrndx: 0x2E2F, - } - ); - } - - #[test] - fn test_parse_ehdr64_fuzz_too_short() { - let ident = (AnyEndian::Little, Class::ELF64, abi::ELFOSABI_LINUX, 7u8); - let tail = [0u8; ELF64_EHDR_TAILSIZE]; - - for n in 0..ELF64_EHDR_TAILSIZE { - let buf = tail.split_at(n).0; - let result = FileHeader::parse_tail(ident, buf).expect_err("Expected an error"); - assert!( - matches!(result, ParseError::SliceReadError(_)), - "Unexpected Error type found: {result:?}" - ); - } - } -} diff --git a/arceos/modules/elf/src/gnu_symver.rs b/arceos/modules/elf/src/gnu_symver.rs deleted file mode 100644 index bd279c7d8..000000000 --- a/arceos/modules/elf/src/gnu_symver.rs +++ /dev/null @@ -1,1592 +0,0 @@ -//! Parsing GNU extension sections for dynamic symbol versioning `.gnu.version.*` -use crate::abi; -use crate::endian::EndianParse; -use crate::file::Class; -use crate::parse::{ParseAt, ParseError, ParsingTable}; -use crate::string_table::StringTable; - -#[derive(Debug, PartialEq, Eq)] -pub struct SymbolRequirement<'data> { - pub file: &'data str, - pub name: &'data str, - pub hash: u32, - pub flags: u16, - pub hidden: bool, -} - -#[derive(Debug)] -pub struct SymbolDefinition<'data, E: EndianParse> { - pub hash: u32, - pub flags: u16, - pub names: SymbolNamesIterator<'data, E>, - pub hidden: bool, -} - -#[derive(Debug)] -pub struct SymbolNamesIterator<'data, E: EndianParse> { - vda_iter: VerDefAuxIterator<'data, E>, - strtab: &'data StringTable<'data>, -} - -impl<'data, E: EndianParse> SymbolNamesIterator<'data, E> { - pub fn new(vda_iter: VerDefAuxIterator<'data, E>, strtab: &'data StringTable<'data>) -> Self { - SymbolNamesIterator { vda_iter, strtab } - } -} - -impl<'data, E: EndianParse> Iterator for SymbolNamesIterator<'data, E> { - type Item = Result<&'data str, ParseError>; - fn next(&mut self) -> Option { - let vda = self.vda_iter.next(); - match vda { - Some(vda) => Some(self.strtab.get(vda.vda_name as usize)), - None => None, - } - } -} - -#[derive(Debug)] -pub struct SymbolVersionTable<'data, E: EndianParse> { - version_ids: VersionIndexTable<'data, E>, - - verneeds: Option<(VerNeedIterator<'data, E>, StringTable<'data>)>, - verdefs: Option<(VerDefIterator<'data, E>, StringTable<'data>)>, -} - -impl<'data, E: EndianParse> SymbolVersionTable<'data, E> { - pub fn new( - version_ids: VersionIndexTable<'data, E>, - verneeds: Option<(VerNeedIterator<'data, E>, StringTable<'data>)>, - verdefs: Option<(VerDefIterator<'data, E>, StringTable<'data>)>, - ) -> Self { - SymbolVersionTable { - version_ids, - verneeds, - verdefs, - } - } - - pub fn get_requirement( - &self, - sym_idx: usize, - ) -> Result>, ParseError> { - let (verneeds, verneed_strs) = match self.verneeds { - Some(verneeds) => verneeds, - None => { - return Ok(None); - } - }; - - let ver_ndx = self.version_ids.get(sym_idx)?; - let iter = verneeds; - for (vn, vna_iter) in iter { - for vna in vna_iter { - if vna.vna_other != ver_ndx.index() { - continue; - } - - let file = verneed_strs.get(vn.vn_file as usize)?; - let name = verneed_strs.get(vna.vna_name as usize)?; - let hash = vna.vna_hash; - let hidden = ver_ndx.is_hidden(); - return Ok(Some(SymbolRequirement { - file, - name, - hash, - flags: vna.vna_flags, - hidden, - })); - } - } - - // Maybe we should treat this as a ParseError instead of returning an - // empty Option? This can only happen if .gnu.versions[N] contains an - // index that doesn't exist, which is likely a file corruption or - // programmer error (i.e asking for a requirement for a defined symbol) - Ok(None) - } - - pub fn get_definition( - &self, - sym_idx: usize, - ) -> Result>, ParseError> { - let (ref verdefs, ref verdef_strs) = match self.verdefs { - Some(ref verdefs) => verdefs, - None => { - return Ok(None); - } - }; - - let ver_ndx = self.version_ids.get(sym_idx)?; - let iter = *verdefs; - for (vd, vda_iter) in iter { - if vd.vd_ndx != ver_ndx.index() { - continue; - } - - let flags = vd.vd_flags; - let hash = vd.vd_hash; - let hidden = ver_ndx.is_hidden(); - return Ok(Some(SymbolDefinition { - hash, - flags, - names: SymbolNamesIterator { - vda_iter, - strtab: verdef_strs, - }, - hidden, - })); - } - - // Maybe we should treat this as a ParseError instead of returning an - // empty Option? This can only happen if .gnu.versions[N] contains an - // index that doesn't exist, which is likely a file corruption or - // programmer error (i.e asking for a definition for an undefined symbol) - Ok(None) - } -} - -//////////////////////////////////////////////////////////////////// -// _ // -// __ _ _ __ _ _ __ _____ _ __ ___(_) ___ _ __ // -// / _` | '_ \| | | | \ \ / / _ \ '__/ __| |/ _ \| '_ \ // -// _ | (_| | | | | |_| | _ \ V / __/ | \__ \ | (_) | | | | // -// (_) \__, |_| |_|\__,_| (_) \_/ \___|_| |___/_|\___/|_| |_| // -// |___/ // -//////////////////////////////////////////////////////////////////// - -pub type VersionIndexTable<'data, E> = ParsingTable<'data, E, VersionIndex>; - -/// The special GNU extension section .gnu.version has a section type of SHT_GNU_VERSYM. -/// This section shall have the same number of entries as the Dynamic Symbol Table in -/// the .dynsym section. The .gnu.version section shall contain an array of -/// elements of type Elfxx_Half (both of which are 16-bit unsigned integers). -/// -/// The .gnu.version section and VersionIndex values act as a lookup table for specifying -/// the version defined for or required by the corresponding symbol in the Dynamic Symbol Table. -/// -/// For example, the symbol at index N in the .dynsym Symbol Table will have a VersionIndex -/// value located in the versym table at .gnu.version\[N\] which identifies -/// structures in the .gnu.version_d and .gnu.version_r sections. These values -/// are located in identifiers provided by the the vna_other member of the VerNeedAux -/// structure or the vd_ndx member of the VerDef structure. -#[derive(Debug, PartialEq, Eq)] -pub struct VersionIndex(pub u16); - -impl VersionIndex { - pub fn index(&self) -> u16 { - self.0 & abi::VER_NDX_VERSION - } - - pub fn is_local(&self) -> bool { - self.index() == abi::VER_NDX_LOCAL - } - - pub fn is_global(&self) -> bool { - self.index() == abi::VER_NDX_GLOBAL - } - - pub fn is_hidden(&self) -> bool { - (self.0 & abi::VER_NDX_HIDDEN) != 0 - } -} - -impl ParseAt for VersionIndex { - fn parse_at( - endian: E, - _class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - Ok(VersionIndex(endian.parse_u16_at(offset, data)?)) - } - - #[inline] - fn size_for(_class: Class) -> usize { - core::mem::size_of::() - } -} - -/////////////////////////////////////////////////////////////////////////////// -// _ _ // -// __ _ _ __ _ _ __ _____ _ __ ___(_) ___ _ __ __| | // -// / _` | '_ \| | | | \ \ / / _ \ '__/ __| |/ _ \| '_ \ / _` | // -// _ | (_| | | | | |_| | _ \ V / __/ | \__ \ | (_) | | | | | (_| | // -// (_) \__, |_| |_|\__,_| (_) \_/ \___|_| |___/_|\___/|_| |_|_____\__,_| // -// |___/ |_____| // -/////////////////////////////////////////////////////////////////////////////// - -/// The special GNU extension section .gnu.version_d has a section type of SHT_GNU_VERDEF -/// This section shall contain symbol version definitions. The number of entries -/// in this section shall be contained in the DT_VERDEFNUM entry of the Dynamic -/// Section .dynamic, and also the sh_info member of the section header. -/// The sh_link member of the section header shall point to the section that -/// contains the strings referenced by this section. -/// -/// The .gnu.version_d section shall contain an array of VerDef structures -/// optionally followed by an array of VerDefAux structures. -#[derive(Debug, PartialEq, Eq)] -pub struct VerDef { - /// Version information flag bitmask. - pub vd_flags: u16, - /// VersionIndex value referencing the SHT_GNU_VERSYM section. - pub vd_ndx: u16, - /// Number of associated verdaux array entries. - pub vd_cnt: u16, - /// Version name hash value (ELF hash function). - pub vd_hash: u32, - /// Offset in bytes to a corresponding entry in an array of VerDefAux structures. - vd_aux: u32, - /// Offset to the next VerDef entry, in bytes. - vd_next: u32, -} - -impl ParseAt for VerDef { - fn parse_at( - endian: E, - _class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - let vd_version = endian.parse_u16_at(offset, data)?; - if vd_version != abi::VER_DEF_CURRENT { - return Err(ParseError::UnsupportedVersion(( - vd_version as u64, - abi::VER_DEF_CURRENT as u64, - ))); - } - - Ok(VerDef { - vd_flags: endian.parse_u16_at(offset, data)?, - vd_ndx: endian.parse_u16_at(offset, data)?, - vd_cnt: endian.parse_u16_at(offset, data)?, - vd_hash: endian.parse_u32_at(offset, data)?, - vd_aux: endian.parse_u32_at(offset, data)?, - vd_next: endian.parse_u32_at(offset, data)?, - }) - } - - #[inline] - fn size_for(_class: Class) -> usize { - ELFVERDEFSIZE - } -} - -const ELFVERDEFSIZE: usize = 20; - -#[derive(Debug, Clone, Copy)] -pub struct VerDefIterator<'data, E: EndianParse> { - endian: E, - class: Class, - /// The number of entries in this iterator is given by the .dynamic DT_VERDEFNUM entry - /// and also in the .gnu.version_d section header's sh_info field. - count: u64, - data: &'data [u8], - offset: usize, -} - -impl<'data, E: EndianParse> VerDefIterator<'data, E> { - pub fn new( - endian: E, - class: Class, - count: u64, - starting_offset: usize, - data: &'data [u8], - ) -> Self { - VerDefIterator { - endian, - class, - count, - data, - offset: starting_offset, - } - } -} - -impl<'data, E: EndianParse> Iterator for VerDefIterator<'data, E> { - type Item = (VerDef, VerDefAuxIterator<'data, E>); - fn next(&mut self) -> Option { - if self.data.is_empty() || self.count == 0 { - return None; - } - - let mut start = self.offset; - let vd = VerDef::parse_at(self.endian, self.class, &mut start, self.data).ok()?; - let vda_iter = VerDefAuxIterator::new( - self.endian, - self.class, - vd.vd_cnt, - self.offset + vd.vd_aux as usize, - self.data, - ); - - // If offset overflows, silently end iteration - match self.offset.checked_add(vd.vd_next as usize) { - Some(new_off) => self.offset = new_off, - None => self.count = 0, - } - self.count -= 1; - - // Silently end iteration early if the next link stops pointing somewhere new - // TODO: Make this an error condition by allowing the iterator to yield a ParseError - if self.count > 0 && vd.vd_next == 0 { - self.count = 0 - } - Some((vd, vda_iter)) - } -} - -/// Version Definition Auxiliary Entries from the .gnu.version_d section -#[derive(Debug, PartialEq, Eq)] -pub struct VerDefAux { - /// Offset to the version or dependency name string in the linked string table, in bytes. - pub vda_name: u32, - /// Offset to the next VerDefAux entry, in bytes. - vda_next: u32, -} - -impl ParseAt for VerDefAux { - fn parse_at( - endian: E, - _class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - Ok(VerDefAux { - vda_name: endian.parse_u32_at(offset, data)?, - vda_next: endian.parse_u32_at(offset, data)?, - }) - } - - #[inline] - fn size_for(_class: Class) -> usize { - 8 - } -} - -#[derive(Debug)] -pub struct VerDefAuxIterator<'data, E: EndianParse> { - endian: E, - class: Class, - count: u16, - data: &'data [u8], - offset: usize, -} - -impl<'data, E: EndianParse> VerDefAuxIterator<'data, E> { - pub fn new( - endian: E, - class: Class, - count: u16, - starting_offset: usize, - data: &'data [u8], - ) -> Self { - VerDefAuxIterator { - endian, - class, - count, - data, - offset: starting_offset, - } - } -} - -impl<'data, E: EndianParse> Iterator for VerDefAuxIterator<'data, E> { - type Item = VerDefAux; - fn next(&mut self) -> Option { - if self.data.is_empty() || self.count == 0 { - return None; - } - - // N.B. This offset handling is maybe unnecessary, but faithful to the - // spec. As far as I've observed, VerDefAux entries for a VerDef are all - // encoded sequentially after the VerDef, so we could likely just - // use the normal pattern here and pass in &mut self.offset here. - // - // The spec claims that "The section shall contain an array of - // Elfxx_Verdef structures, optionally followed by an array of - // Elfxx_Verdaux structures." This reads a bit ambiguously - // (is there one big array of Verdefs followed by one big array of - // Verdauxs?). If so, the vd_next and vda_next links seem unnecessary - // given the vd_cnt field. In practice, it appears that all the VerDefAux - // fields for a given VerDef are sequentially following the VerDef, meaning - // they're contiguous, but intersersed. The _next fields could theoretically - // give non-contiguous linked-list-like configurations, though (but only linking - // forward, not backward, since the link is a u32). - // - // The vd_next and vda_next fields are also not "pointers" i.e. offsets from - // the start of the section, but rather "increments" in telling how far to - // advance from where you just read the containing struct for where you should - // read the next. Given the sequentially-following nature described, these vd_next - // and vda_next fields end up being 0x14 and 0x8 (the size of the VerDef and - // VerDefAux structs). - // - // So observationally, we could likely get away with using self.offset and count here - // and ignoring the vda_next field, but that'd break things if they weren't contiguous. - let mut start = self.offset; - let vda = VerDefAux::parse_at(self.endian, self.class, &mut start, self.data).ok()?; - - // If offset overflows, silently end iteration - match self.offset.checked_add(vda.vda_next as usize) { - Some(new_off) => self.offset = new_off, - None => self.count = 0, - } - self.count -= 1; - - // Silently end iteration early if the next link stops pointing somewhere new - // TODO: Make this an error condition by allowing the iterator to yield a ParseError - if self.count > 0 && vda.vda_next == 0 { - self.count = 0 - } - Some(vda) - } -} - -/////////////////////////////////////////////////////////////////////////////// -// _ // -// __ _ _ __ _ _ __ _____ _ __ ___(_) ___ _ __ _ __ // -// / _` | '_ \| | | | \ \ / / _ \ '__/ __| |/ _ \| '_ \ | '__| // -// _ | (_| | | | | |_| | _ \ V / __/ | \__ \ | (_) | | | | | | // -// (_) \__, |_| |_|\__,_| (_) \_/ \___|_| |___/_|\___/|_| |_|_____|_| // -// |___/ |_____| // -/////////////////////////////////////////////////////////////////////////////// - -/// The GNU extension section .gnu.version_r has a section type of SHT_GNU_VERNEED. -/// This section contains required symbol version definitions. The number of -/// entries in this section shall be contained in the DT_VERNEEDNUM entry of the -/// Dynamic Section .dynamic and also the sh_info member of the section header. -/// The sh_link member of the section header shall point to the referenced -/// string table section. -/// -/// The section shall contain an array of VerNeed structures optionally -/// followed by an array of VerNeedAux structures. -#[derive(Debug, PartialEq, Eq)] -pub struct VerNeed { - /// Number of associated verneed array entries. - pub vn_cnt: u16, - /// Offset to the file name string in the linked string table, in bytes. - pub vn_file: u32, - /// Offset to a corresponding entry in the VerNeedAux array, in bytes. - vn_aux: u32, - /// Offset to the next VerNeed entry, in bytes. - vn_next: u32, -} - -impl ParseAt for VerNeed { - fn parse_at( - endian: E, - _class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - let vd_version = endian.parse_u16_at(offset, data)?; - if vd_version != abi::VER_NEED_CURRENT { - return Err(ParseError::UnsupportedVersion(( - vd_version as u64, - abi::VER_DEF_CURRENT as u64, - ))); - } - Ok(VerNeed { - vn_cnt: endian.parse_u16_at(offset, data)?, - vn_file: endian.parse_u32_at(offset, data)?, - vn_aux: endian.parse_u32_at(offset, data)?, - vn_next: endian.parse_u32_at(offset, data)?, - }) - } - - #[inline] - fn size_for(_class: Class) -> usize { - ELFVERNEEDSIZE - } -} - -const ELFVERNEEDSIZE: usize = 16; - -#[derive(Debug, Copy, Clone)] -pub struct VerNeedIterator<'data, E: EndianParse> { - endian: E, - class: Class, - /// The number of entries in this iterator is given by the .dynamic DT_VERNEEDNUM entry - /// and also in the .gnu.version_r section header's sh_info field. - count: u64, - data: &'data [u8], - offset: usize, -} - -impl<'data, E: EndianParse> VerNeedIterator<'data, E> { - pub fn new( - endian: E, - class: Class, - count: u64, - starting_offset: usize, - data: &'data [u8], - ) -> Self { - VerNeedIterator { - endian, - class, - count, - data, - offset: starting_offset, - } - } -} - -impl<'data, E: EndianParse> Iterator for VerNeedIterator<'data, E> { - type Item = (VerNeed, VerNeedAuxIterator<'data, E>); - fn next(&mut self) -> Option { - if self.data.is_empty() || self.count == 0 { - return None; - } - - let mut start = self.offset; - let vn = VerNeed::parse_at(self.endian, self.class, &mut start, self.data).ok()?; - let vna_iter = VerNeedAuxIterator::new( - self.endian, - self.class, - vn.vn_cnt, - self.offset + vn.vn_aux as usize, - self.data, - ); - - // If offset overflows, silently end iteration - match self.offset.checked_add(vn.vn_next as usize) { - Some(new_off) => self.offset = new_off, - None => self.count = 0, - } - self.count -= 1; - - // Silently end iteration early if the next link stops pointing somewhere new - // TODO: Make this an error condition by allowing the iterator to yield a ParseError - if self.count > 0 && vn.vn_next == 0 { - self.count = 0 - } - Some((vn, vna_iter)) - } -} - -/// Version Need Auxiliary Entries from the .gnu.version_r section -#[derive(Debug, PartialEq, Eq)] -pub struct VerNeedAux { - /// Dependency name hash value (ELF hash function). - pub vna_hash: u32, - /// Dependency information flag bitmask. - pub vna_flags: u16, - /// VersionIndex value used in the .gnu.version symbol version array. - pub vna_other: u16, - /// Offset to the dependency name string in the linked string table, in bytes. - pub vna_name: u32, - /// Offset to the next vernaux entry, in bytes. - vna_next: u32, -} - -impl ParseAt for VerNeedAux { - fn parse_at( - endian: E, - _class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - Ok(VerNeedAux { - vna_hash: endian.parse_u32_at(offset, data)?, - vna_flags: endian.parse_u16_at(offset, data)?, - vna_other: endian.parse_u16_at(offset, data)?, - vna_name: endian.parse_u32_at(offset, data)?, - vna_next: endian.parse_u32_at(offset, data)?, - }) - } - - #[inline] - fn size_for(_class: Class) -> usize { - 16 - } -} - -#[derive(Debug)] -pub struct VerNeedAuxIterator<'data, E: EndianParse> { - endian: E, - class: Class, - count: u16, - data: &'data [u8], - offset: usize, -} - -impl<'data, E: EndianParse> VerNeedAuxIterator<'data, E> { - pub fn new( - endian: E, - class: Class, - count: u16, - starting_offset: usize, - data: &'data [u8], - ) -> Self { - VerNeedAuxIterator { - endian, - class, - count, - data, - offset: starting_offset, - } - } -} - -impl<'data, E: EndianParse> Iterator for VerNeedAuxIterator<'data, E> { - type Item = VerNeedAux; - fn next(&mut self) -> Option { - if self.data.is_empty() || self.count == 0 { - return None; - } - - let mut start = self.offset; - let vna = VerNeedAux::parse_at(self.endian, self.class, &mut start, self.data).ok()?; - - // If offset overflows, silently end iteration - match self.offset.checked_add(vna.vna_next as usize) { - Some(new_off) => self.offset = new_off, - None => self.count = 0, - } - self.count -= 1; - - // Silently end iteration early if the next link stops pointing somewhere new - // TODO: Make this an error condition by allowing the iterator to yield a ParseError - if self.count > 0 && vna.vna_next == 0 { - self.count = 0 - } - Some(vna) - } -} - -////////////////////////////// -// _____ _ // -// |_ _|__ ___| |_ ___ // -// | |/ _ \/ __| __/ __| // -// | | __/\__ \ |_\__ \ // -// |_|\___||___/\__|___/ // -// // -////////////////////////////// - -#[cfg(test)] -mod iter_tests { - use super::*; - use crate::endian::LittleEndian; - - #[rustfmt::skip] - const GNU_VERNEED_STRINGS: [u8; 65] = [ - // ZLIB_1.2.0 (0x1) - 0x00, 0x5a, 0x4c, 0x49, 0x42, 0x5f, 0x31, 0x2e, 0x32, 0x2e, 0x30, 0x00, - // GLIBC_2.33 (0xC) - 0x47, 0x4c, 0x49, 0x42, 0x43, 0x5f, 0x32, 0x2e, 0x33, 0x33, 0x00, - // GLIBC_2.2.5 (0x17) - 0x47, 0x4c, 0x49, 0x42, 0x43, 0x5f, 0x32, 0x2e, 0x32, 0x2e, 0x35, 0x00, - // libz.so.1 (0x23) - 0x6c, 0x69, 0x62, 0x7a, 0x2e, 0x73, 0x6f, 0x2e, 0x31, 0x00, - // libc.so.6 (0x2D) - 0x6c, 0x69, 0x62, 0x63, 0x2e, 0x73, 0x6f, 0x2e, 0x36, 0x00, - // GLIBC_2.3 (0x37) - 0x47, 0x4c, 0x49, 0x42, 0x43, 0x5f, 0x32, 0x2e, 0x33, 0x00, - ]; - - #[rustfmt::skip] - const GNU_VERNEED_DATA: [u8; 96] = [ - // {vn_version, vn_cnt, vn_file, vn_aux, vn_next } - 0x01, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - // {vn_hash, vn_flags, vn_other, vn_name, vn_next } - 0xc0, 0xe5, 0x27, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // {vn_version, vn_cnt, vn_file, vn_aux, vn_next } - 0x01, 0x00, 0x03, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // {vn_hash, vn_flags, vn_other, vn_name, vn_next } - 0x13, 0x69, 0x69, 0x0d, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - // {vn_hash, vn_flags, vn_other, vn_name, vn_next } - 0xb3, 0x91, 0x96, 0x06, 0x00, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - // {vn_hash, vn_flags, vn_other, vn_name, vn_next } - 0x94, 0x91, 0x96, 0x06, 0x00, 0x00, 0x09, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - - #[test] - fn verneed_iter() { - let iter = VerNeedIterator::new(LittleEndian, Class::ELF64, 2, 0, &GNU_VERNEED_DATA); - let entries: Vec<(VerNeed, Vec)> = - iter.map(|(vn, iter)| (vn, iter.collect())).collect(); - - assert_eq!(entries.len(), 2); - } - - #[test] - fn verneed_iter_early_termination_on_broken_next_link() { - // set count = 3 even though there's only 2 entries - let iter = VerNeedIterator::new(LittleEndian, Class::ELF64, 3, 0, &GNU_VERNEED_DATA); - let entries: Vec<(VerNeed, Vec)> = - iter.map(|(vn, iter)| (vn, iter.collect())).collect(); - - // TODO: make this a ParseError condition instead of silently returning only the good data. - assert_eq!(entries.len(), 2); - } - - #[test] - fn verneedaux_iter_one_entry() { - let mut iter = - VerNeedAuxIterator::new(LittleEndian, Class::ELF64, 1, 0x10, &GNU_VERNEED_DATA); - let aux1 = iter.next().expect("Failed to parse"); - assert_eq!( - aux1, - VerNeedAux { - vna_hash: 0x0827e5c0, - vna_flags: 0, - vna_other: 0x0a, - vna_name: 0x01, - vna_next: 0 - } - ); - assert!(iter.next().is_none()); - } - - #[test] - fn verneedaux_iter_multiple_entries() { - let mut iter = - VerNeedAuxIterator::new(LittleEndian, Class::ELF64, 3, 0x30, &GNU_VERNEED_DATA); - let aux1 = iter.next().expect("Failed to parse"); - assert_eq!( - aux1, - VerNeedAux { - vna_hash: 0x0d696913, - vna_flags: 0, - vna_other: 0x0c, - vna_name: 0x0c, - vna_next: 0x10 - } - ); - let aux2 = iter.next().expect("Failed to parse"); - assert_eq!( - aux2, - VerNeedAux { - vna_hash: 0x069691b3, - vna_flags: 0, - vna_other: 0x0b, - vna_name: 0x17, - vna_next: 0x10 - } - ); - let aux3 = iter.next().expect("Failed to parse"); - assert_eq!( - aux3, - VerNeedAux { - vna_hash: 0x06969194, - vna_flags: 0, - vna_other: 0x09, - vna_name: 0x37, - vna_next: 0 - } - ); - assert!(iter.next().is_none()); - } - - // Hypothetical case where VerDefAux entries are non-contiguous - #[test] - fn verneedaux_iter_two_lists_interspersed() { - #[rustfmt::skip] - let data: [u8; 64] = [ - // {vn_hash, vn_flags, vn_other, vn_name, vn_next } - 0xc0, 0xe5, 0x27, 0x08, 0x00, 0x00, 0x0a, 0x00, 0xcc, 0x0c, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - // {vn_hash, vn_flags, vn_other, vn_name, vn_next } - 0x13, 0x69, 0x69, 0x0d, 0x00, 0x00, 0x0c, 0x00, 0xd7, 0x0c, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - // {vn_hash, vn_flags, vn_other, vn_name, vn_next } - 0xb3, 0x91, 0x96, 0x06, 0x00, 0x00, 0x0b, 0x00, 0xe1, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // {vn_hash, vn_flags, vn_other, vn_name, vn_next } - 0x94, 0x91, 0x96, 0x06, 0x00, 0x00, 0x09, 0x00, 0xec, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - - let mut iter1 = VerNeedAuxIterator::new(LittleEndian, Class::ELF64, 2, 0, &data); - let mut iter2 = VerNeedAuxIterator::new(LittleEndian, Class::ELF64, 2, 0x10, &data); - - let aux1_1 = iter1.next().expect("Failed to parse"); - assert_eq!( - aux1_1, - VerNeedAux { - vna_hash: 0x0827e5c0, - vna_flags: 0, - vna_other: 0x0a, - vna_name: 0x0ccc, - vna_next: 0x20, - } - ); - let aux2_1 = iter2.next().expect("Failed to parse"); - assert_eq!( - aux2_1, - VerNeedAux { - vna_hash: 0x0d696913, - vna_flags: 0, - vna_other: 0x0c, - vna_name: 0x0cd7, - vna_next: 0x20 - } - ); - let aux1_2 = iter1.next().expect("Failed to parse"); - assert_eq!( - aux1_2, - VerNeedAux { - vna_hash: 0x069691b3, - vna_flags: 0, - vna_other: 0x0b, - vna_name: 0x0ce1, - vna_next: 0 - } - ); - let aux2_2 = iter2.next().expect("Failed to parse"); - assert_eq!( - aux2_2, - VerNeedAux { - vna_hash: 0x06969194, - vna_flags: 0, - vna_other: 0x09, - vna_name: 0x0cec, - vna_next: 0 - } - ); - assert!(iter1.next().is_none()); - assert!(iter2.next().is_none()); - } - - #[test] - fn verneedaux_iter_early_termination_on_broken_next_link() { - // set count = 7 even though there's only 1 entry - let iter = VerNeedAuxIterator::new(LittleEndian, Class::ELF64, 7, 0x10, &GNU_VERNEED_DATA); - let entries: Vec = iter.collect(); - - // TODO: make this a ParseError condition instead of silently returning only the good data. - assert_eq!(entries.len(), 1); - } - - #[rustfmt::skip] - const GNU_VERDEF_STRINGS: [u8; 34] = [ - // LIBCTF_1.0 (0x1) - 0x00, 0x4c, 0x49, 0x42, 0x43, 0x54, 0x46, 0x5f, 0x31, 0x2e, 0x30, 0x00, - // LIBCTF_1.1 (0xC) - 0x4c, 0x49, 0x42, 0x43, 0x54, 0x46, 0x5f, 0x31, 0x2e, 0x31, 0x00, - // LIBCTF_1.2 (0x17) - 0x4c, 0x49, 0x42, 0x43, 0x54, 0x46, 0x5f, 0x31, 0x2e, 0x32, 0x00, - ]; - - // Sample .gnu.version_d section contents - #[rustfmt::skip] - const GNU_VERDEF_DATA: [u8; 128] = [ - // {vd_version, vd_flags, vd_ndx, vd_cnt - 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, - // vd_hash, vd_aux, - 0xb0, 0x7a, 0x07, 0x0b, 0x14, 0x00, 0x00, 0x00, - // vd_next}, {vda_name, - 0x1c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - // vda_next}, {vd_version, vd_flags, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - // vd_ndx, vd_cnt, vd_hash, - 0x02, 0x00, 0x01, 0x00, 0x70, 0x2f, 0x8f, 0x08, - // vd_aux, vd_next}, - 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - // {vda_name, vda_next}, - 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // {vd_version, vd_flags, vd_ndx, vd_cnt - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, - // vd_hash, vd_aux, - 0x71, 0x2f, 0x8f, 0x08, 0x14, 0x00, 0x00, 0x00, - // vd_next}, {vda_name, - 0x24, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - // vda_next}, {vda_name, - 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - // vda_next}, {vd_version, vd_flags, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - // vd_ndx, vd_cnt, vd_hash, - 0x04, 0x00, 0x02, 0x00, 0x72, 0x2f, 0x8f, 0x08, - // vd_aux, vd_next}, - 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // {vda_name, vda_next}, - 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - // {vda_name, vda_next}, - 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - - #[test] - fn verdef_iter() { - let iter = VerDefIterator::new(LittleEndian, Class::ELF64, 4, 0, &GNU_VERDEF_DATA); - let entries: Vec<(VerDef, Vec)> = - iter.map(|(vd, iter)| (vd, iter.collect())).collect(); - - assert_eq!(entries.len(), 4); - - assert_eq!( - entries, - vec![ - ( - VerDef { - vd_flags: 1, - vd_ndx: 1, - vd_cnt: 1, - vd_hash: 0x0B077AB0, - vd_aux: 20, - vd_next: 28, - }, - vec![VerDefAux { - vda_name: 0x1, - vda_next: 0 - }] - ), - ( - VerDef { - vd_flags: 0, - vd_ndx: 2, - vd_cnt: 1, - vd_hash: 0x088f2f70, - vd_aux: 20, - vd_next: 28, - }, - vec![VerDefAux { - vda_name: 0xC, - vda_next: 0 - }] - ), - ( - VerDef { - vd_flags: 0, - vd_ndx: 3, - vd_cnt: 2, - vd_hash: 0x088f2f71, - vd_aux: 20, - vd_next: 36, - }, - vec![ - VerDefAux { - vda_name: 0x17, - vda_next: 8 - }, - VerDefAux { - vda_name: 0xC, - vda_next: 0 - } - ] - ), - ( - VerDef { - vd_flags: 0, - vd_ndx: 4, - vd_cnt: 2, - vd_hash: 0x088f2f72, - vd_aux: 20, - vd_next: 0, - }, - vec![ - VerDefAux { - vda_name: 0xC, - vda_next: 8 - }, - VerDefAux { - vda_name: 0x17, - vda_next: 0 - } - ] - ), - ] - ); - } - - #[test] - fn verdef_iter_early_termination_on_broken_next_link() { - // set count = 7 even though there's only 4 entries - let iter = VerDefIterator::new(LittleEndian, Class::ELF64, 7, 0, &GNU_VERDEF_DATA); - let entries: Vec<(VerDef, Vec)> = - iter.map(|(vn, iter)| (vn, iter.collect())).collect(); - - // TODO: make this a ParseError condition instead of silently returning only the good data. - assert_eq!(entries.len(), 4); - } - - #[test] - fn verdefaux_iter_one_entry() { - let mut iter = - VerDefAuxIterator::new(LittleEndian, Class::ELF64, 1, 0x14, &GNU_VERDEF_DATA); - let aux1 = iter.next().expect("Failed to parse"); - assert_eq!( - aux1, - VerDefAux { - vda_name: 0x01, - vda_next: 0 - } - ); - assert!(iter.next().is_none()); - } - - #[test] - fn verdefaux_iter_multiple_entries() { - let mut iter = - VerDefAuxIterator::new(LittleEndian, Class::ELF64, 2, 0x4C, &GNU_VERDEF_DATA); - let aux1 = iter.next().expect("Failed to parse"); - assert_eq!( - aux1, - VerDefAux { - vda_name: 0x17, - vda_next: 8 - } - ); - let aux1 = iter.next().expect("Failed to parse"); - assert_eq!( - aux1, - VerDefAux { - vda_name: 0xC, - vda_next: 0 - } - ); - assert!(iter.next().is_none()); - } - - // Hypothetical case where VerDefAux entries are non-contiguous - #[test] - fn verdefaux_iter_two_lists_interspersed() { - #[rustfmt::skip] - let data: [u8; 32] = [ - 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // list 1 entry 1 - 0xA1, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // list 2 entry 1 - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // list 1 entry 2 - 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // list 2 entry 2 - ]; - - let mut iter1 = VerDefAuxIterator::new(LittleEndian, Class::ELF64, 2, 0, &data); - let mut iter2 = VerDefAuxIterator::new(LittleEndian, Class::ELF64, 2, 8, &data); - - let aux1_1 = iter1.next().expect("Failed to parse"); - assert_eq!( - aux1_1, - VerDefAux { - vda_name: 0x0001, - vda_next: 0x10, - } - ); - let aux2_1 = iter2.next().expect("Failed to parse"); - assert_eq!( - aux2_1, - VerDefAux { - vda_name: 0x00A1, - vda_next: 0x10, - } - ); - let aux1_2 = iter1.next().expect("Failed to parse"); - assert_eq!( - aux1_2, - VerDefAux { - vda_name: 0x0002, - vda_next: 0, - } - ); - let aux2_2 = iter2.next().expect("Failed to parse"); - assert_eq!( - aux2_2, - VerDefAux { - vda_name: 0x00A2, - vda_next: 0, - } - ); - assert!(iter1.next().is_none()); - assert!(iter2.next().is_none()); - } - - #[test] - fn verdefaux_iter_early_termination_on_broken_next_link() { - // set count = 7 even though there's only 1 entry - let iter = VerDefAuxIterator::new(LittleEndian, Class::ELF64, 7, 0x14, &GNU_VERDEF_DATA); - let entries: Vec = iter.collect(); - - // TODO: make this a ParseError condition instead of silently returning only the good data. - assert_eq!(entries.len(), 1); - } - - #[test] - fn version_table() { - let ver_idx_buf: [u8; 10] = [0x02, 0x00, 0x03, 0x00, 0x09, 0x00, 0x0A, 0x00, 0xff, 0xff]; - let version_ids = VersionIndexTable::new(LittleEndian, Class::ELF64, &ver_idx_buf); - let verdefs = VerDefIterator::new(LittleEndian, Class::ELF64, 4, 0, &GNU_VERDEF_DATA); - let verneed_strs = StringTable::new(&GNU_VERNEED_STRINGS); - let verneeds = VerNeedIterator::new(LittleEndian, Class::ELF64, 2, 0, &GNU_VERNEED_DATA); - let verdef_strs = StringTable::new(&GNU_VERDEF_STRINGS); - - let table = SymbolVersionTable::new( - version_ids, - Some((verneeds, verneed_strs)), - Some((verdefs, verdef_strs)), - ); - - let def1 = table - .get_definition(0) - .expect("Failed to parse definition") - .expect("Failed to find def"); - assert_eq!(def1.hash, 0x088f2f70); - assert_eq!(def1.flags, 0); - let def1_names: Vec<&str> = def1 - .names - .map(|res| res.expect("Failed to parse")) - .collect(); - assert_eq!(def1_names, ["LIBCTF_1.1"]); - assert!(!def1.hidden); - - let def2 = table - .get_definition(1) - .expect("Failed to parse definition") - .expect("Failed to find def"); - assert_eq!(def2.hash, 0x088f2f71); - assert_eq!(def2.flags, 0); - let def2_names: Vec<&str> = def2 - .names - .map(|res| res.expect("Failed to parse")) - .collect(); - assert_eq!(def2_names, ["LIBCTF_1.2", "LIBCTF_1.1"]); - assert!(!def2.hidden); - - let req1 = table - .get_requirement(2) - .expect("Failed to parse definition") - .expect("Failed to find req"); - assert_eq!( - req1, - SymbolRequirement { - file: "libc.so.6", - name: "GLIBC_2.3", - hash: 0x6969194, - flags: 0, - hidden: false - } - ); - - let req2 = table - .get_requirement(3) - .expect("Failed to parse definition") - .expect("Failed to find req"); - assert_eq!( - req2, - SymbolRequirement { - file: "libz.so.1", - name: "ZLIB_1.2.0", - hash: 0x827E5C0, - flags: 0, - hidden: false - } - ); - - // The last version_index points to non-existent definitions. Maybe we should treat - // this as a ParseError instead of returning an empty Option? This can only happen - // if .gnu.versions[N] contains an index that doesn't exist, which is likely a file corruption - // or programmer error (i.e asking for a definition for an undefined symbol) - assert!(table.get_definition(4).expect("Failed to parse").is_none()); - assert!(table.get_requirement(4).expect("Failed to parse").is_none()); - } -} - -#[cfg(test)] -mod parse_tests { - use super::*; - use crate::endian::{BigEndian, LittleEndian}; - use crate::parse::{test_parse_for, test_parse_fuzz_too_short}; - - #[test] - fn parse_verndx32_lsb() { - test_parse_for(LittleEndian, Class::ELF32, VersionIndex(0x0100)); - } - - #[test] - fn parse_verndx32_msb() { - test_parse_for(BigEndian, Class::ELF32, VersionIndex(0x0001)); - } - - #[test] - fn parse_verndx64_lsb() { - test_parse_for(LittleEndian, Class::ELF64, VersionIndex(0x0100)); - } - - #[test] - fn parse_verndx64_msb() { - test_parse_for(BigEndian, Class::ELF64, VersionIndex(0x0001)); - } - - #[test] - fn parse_verndx32_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, VersionIndex>(LittleEndian, Class::ELF32); - } - - #[test] - fn parse_verndx32_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, VersionIndex>(BigEndian, Class::ELF32); - } - - #[test] - fn parse_verndx64_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, VersionIndex>(LittleEndian, Class::ELF64); - } - - #[test] - fn parse_verndx64_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, VersionIndex>(BigEndian, Class::ELF64); - } - - // - // VerDef - // - #[test] - fn parse_verdef32_lsb() { - let mut data = [0u8; ELFVERDEFSIZE]; - for (n, elem) in data.iter_mut().enumerate().take(ELFVERDEFSIZE) { - *elem = n as u8; - } - data[0] = 1; - data[1] = 0; - - let mut offset = 0; - let entry = VerDef::parse_at(LittleEndian, Class::ELF32, &mut offset, data.as_ref()) - .expect("Failed to parse VerDef"); - - assert_eq!( - entry, - VerDef { - vd_flags: 0x0302, - vd_ndx: 0x0504, - vd_cnt: 0x0706, - vd_hash: 0x0B0A0908, - vd_aux: 0x0F0E0D0C, - vd_next: 0x13121110, - } - ); - assert_eq!(offset, ELFVERDEFSIZE); - } - - #[test] - fn parse_verdef32_fuzz_too_short() { - let mut data = [0u8; ELFVERDEFSIZE]; - data[1] = 1; - for n in 0..ELFVERDEFSIZE { - let buf = data.split_at(n).0; - let mut offset: usize = 0; - let error = VerDef::parse_at(BigEndian, Class::ELF32, &mut offset, buf) - .expect_err("Expected an error"); - assert!( - matches!(error, ParseError::SliceReadError(_)), - "Unexpected Error type found: {error}" - ); - } - } - - #[test] - fn parse_verdef64_msb() { - let mut data = [0u8; ELFVERDEFSIZE]; - for (n, elem) in data.iter_mut().enumerate().take(ELFVERDEFSIZE).skip(2) { - *elem = n as u8; - } - data[1] = 1; - - let mut offset = 0; - let entry = VerDef::parse_at(BigEndian, Class::ELF64, &mut offset, data.as_ref()) - .expect("Failed to parse VerDef"); - - assert_eq!( - entry, - VerDef { - vd_flags: 0x0203, - vd_ndx: 0x0405, - vd_cnt: 0x0607, - vd_hash: 0x08090A0B, - vd_aux: 0x0C0D0E0F, - vd_next: 0x10111213, - } - ); - assert_eq!(offset, ELFVERDEFSIZE); - } - - #[test] - fn parse_verdef64_fuzz_too_short() { - let mut data = [0u8; ELFVERDEFSIZE]; - data[1] = 1; - for n in 0..ELFVERDEFSIZE { - let buf = data.split_at(n).0; - let mut offset: usize = 0; - let error = VerDef::parse_at(BigEndian, Class::ELF64, &mut offset, buf) - .expect_err("Expected an error"); - assert!( - matches!(error, ParseError::SliceReadError(_)), - "Unexpected Error type found: {error}" - ); - } - } - - #[test] - fn parse_verdef_bad_version_errors() { - let data = [0u8; ELFVERDEFSIZE]; - // version is 0, which is not 1, which is bad :) - - let mut offset = 0; - let err = VerDef::parse_at(BigEndian, Class::ELF64, &mut offset, data.as_ref()) - .expect_err("Expected an error"); - assert!( - matches!(err, ParseError::UnsupportedVersion((0, 1))), - "Unexpected Error type found: {err}" - ); - } - - // - // VerDefAux - // - #[test] - fn parse_verdefaux32_lsb() { - test_parse_for( - LittleEndian, - Class::ELF32, - VerDefAux { - vda_name: 0x03020100, - vda_next: 0x07060504, - }, - ); - } - - #[test] - fn parse_verdefaux32_msb() { - test_parse_for( - BigEndian, - Class::ELF32, - VerDefAux { - vda_name: 0x00010203, - vda_next: 0x04050607, - }, - ); - } - - #[test] - fn parse_verdefaux64_lsb() { - test_parse_for( - LittleEndian, - Class::ELF64, - VerDefAux { - vda_name: 0x03020100, - vda_next: 0x07060504, - }, - ); - } - - #[test] - fn parse_verdefaux64_msb() { - test_parse_for( - BigEndian, - Class::ELF64, - VerDefAux { - vda_name: 0x00010203, - vda_next: 0x04050607, - }, - ); - } - - #[test] - fn parse_verdefaux32_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, VerDefAux>(LittleEndian, Class::ELF32); - } - - #[test] - fn parse_verdefaux32_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, VerDefAux>(BigEndian, Class::ELF32); - } - - #[test] - fn parse_verdefaux64_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, VerDefAux>(LittleEndian, Class::ELF64); - } - - #[test] - fn parse_verdefaux64_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, VerDefAux>(BigEndian, Class::ELF64); - } - - // - // VerNeed - // - #[test] - fn parse_verneed32_lsb() { - let mut data = [0u8; ELFVERNEEDSIZE]; - for (n, elem) in data.iter_mut().enumerate().take(ELFVERNEEDSIZE) { - *elem = n as u8; - } - data[0] = 1; - data[1] = 0; - - let mut offset = 0; - let entry = VerNeed::parse_at(LittleEndian, Class::ELF32, &mut offset, data.as_ref()) - .expect("Failed to parse VerNeed"); - - assert_eq!( - entry, - VerNeed { - vn_cnt: 0x0302, - vn_file: 0x07060504, - vn_aux: 0x0B0A0908, - vn_next: 0x0F0E0D0C, - } - ); - assert_eq!(offset, ELFVERNEEDSIZE); - } - - #[test] - fn parse_verneed32_fuzz_too_short() { - let mut data = [0u8; ELFVERNEEDSIZE]; - data[1] = 1; - for n in 0..ELFVERNEEDSIZE { - let buf = data.split_at(n).0; - let mut offset: usize = 0; - let error = VerNeed::parse_at(BigEndian, Class::ELF32, &mut offset, buf) - .expect_err("Expected an error"); - assert!( - matches!(error, ParseError::SliceReadError(_)), - "Unexpected Error type found: {error}" - ); - } - } - - #[test] - fn parse_verneed64_msb() { - let mut data = [0u8; ELFVERNEEDSIZE]; - for (n, elem) in data.iter_mut().enumerate().take(ELFVERNEEDSIZE) { - *elem = n as u8; - } - data[1] = 1; - - let mut offset = 0; - let entry = VerNeed::parse_at(BigEndian, Class::ELF64, &mut offset, data.as_ref()) - .expect("Failed to parse VerNeed"); - - assert_eq!( - entry, - VerNeed { - vn_cnt: 0x0203, - vn_file: 0x04050607, - vn_aux: 0x08090A0B, - vn_next: 0x0C0D0E0F, - } - ); - assert_eq!(offset, ELFVERNEEDSIZE); - } - - #[test] - fn parse_verneed64_fuzz_too_short() { - let mut data = [0u8; ELFVERNEEDSIZE]; - data[1] = 1; - for n in 0..ELFVERNEEDSIZE { - let buf = data.split_at(n).0; - let mut offset: usize = 0; - let error = VerNeed::parse_at(BigEndian, Class::ELF64, &mut offset, buf) - .expect_err("Expected an error"); - assert!( - matches!(error, ParseError::SliceReadError(_)), - "Unexpected Error type found: {error}" - ); - } - } - - // - // VerNeedAux - // - #[test] - fn parse_verneedaux32_lsb() { - test_parse_for( - LittleEndian, - Class::ELF32, - VerNeedAux { - vna_hash: 0x03020100, - vna_flags: 0x0504, - vna_other: 0x0706, - vna_name: 0x0B0A0908, - vna_next: 0x0F0E0D0C, - }, - ); - } - - #[test] - fn parse_verneedaux32_msb() { - test_parse_for( - BigEndian, - Class::ELF32, - VerNeedAux { - vna_hash: 0x00010203, - vna_flags: 0x0405, - vna_other: 0x0607, - vna_name: 0x08090A0B, - vna_next: 0x0C0D0E0F, - }, - ); - } - - #[test] - fn parse_verneedaux64_lsb() { - test_parse_for( - LittleEndian, - Class::ELF64, - VerNeedAux { - vna_hash: 0x03020100, - vna_flags: 0x0504, - vna_other: 0x0706, - vna_name: 0x0B0A0908, - vna_next: 0x0F0E0D0C, - }, - ); - } - - #[test] - fn parse_verneedaux64_msb() { - test_parse_for( - BigEndian, - Class::ELF64, - VerNeedAux { - vna_hash: 0x00010203, - vna_flags: 0x0405, - vna_other: 0x0607, - vna_name: 0x08090A0B, - vna_next: 0x0C0D0E0F, - }, - ); - } - - #[test] - fn parse_verneedaux32_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, VerNeedAux>(LittleEndian, Class::ELF32); - } - - #[test] - fn parse_verneedaux32_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, VerNeedAux>(BigEndian, Class::ELF32); - } - - #[test] - fn parse_verneedaux64_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, VerNeedAux>(LittleEndian, Class::ELF64); - } - - #[test] - fn parse_verneedaux64_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, VerNeedAux>(BigEndian, Class::ELF64); - } -} - -#[cfg(test)] -mod version_index_tests { - use super::*; - - #[test] - fn is_local() { - let idx = VersionIndex(0); - assert!(idx.is_local()); - } - - #[test] - fn is_global() { - let idx = VersionIndex(1); - assert!(idx.is_global()); - } - - #[test] - fn index_visible() { - let idx = VersionIndex(42); - assert_eq!(idx.index(), 42); - assert!(!idx.is_hidden()); - } - - #[test] - fn index_hidden() { - let idx = VersionIndex(42 | abi::VER_NDX_HIDDEN); - assert_eq!(idx.index(), 42); - assert!(idx.is_hidden()); - } -} diff --git a/arceos/modules/elf/src/hash.rs b/arceos/modules/elf/src/hash.rs deleted file mode 100644 index eb461f412..000000000 --- a/arceos/modules/elf/src/hash.rs +++ /dev/null @@ -1,495 +0,0 @@ -//! Parsing hash table sections for symbol tables: `.hash`, and `.gnu.hash` -use core::mem::size_of; - -use crate::endian::EndianParse; -use crate::file::Class; -use crate::parse::{ParseAt, ParseError, ParsingTable, ReadBytesExt}; -use crate::string_table::StringTable; -use crate::symbol::{Symbol, SymbolTable}; - -impl ParseAt for u32 { - fn parse_at( - endian: E, - _class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - endian.parse_u32_at(offset, data) - } - - #[inline] - fn size_for(_class: Class) -> usize { - core::mem::size_of::() - } -} - -type U32Table<'data, E> = ParsingTable<'data, E, u32>; - -/// Header at the start of SysV Hash Table sections of type [SHT_HASH](crate::abi::SHT_HASH). -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SysVHashHeader { - pub nbucket: u32, - pub nchain: u32, -} - -impl ParseAt for SysVHashHeader { - fn parse_at( - endian: E, - _class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - Ok(SysVHashHeader { - nbucket: endian.parse_u32_at(offset, data)?, - nchain: endian.parse_u32_at(offset, data)?, - }) - } - - #[inline] - fn size_for(_class: Class) -> usize { - size_of::() + size_of::() - } -} - -/// Calculate the SysV hash value for a given symbol name. -pub fn sysv_hash(name: &[u8]) -> u32 { - let mut hash = 0u32; - for byte in name { - hash = hash.wrapping_mul(16).wrapping_add(*byte as u32); - hash ^= (hash >> 24) & 0xf0; - } - hash & 0xfffffff -} - -#[derive(Debug)] -pub struct SysVHashTable<'data, E: EndianParse> { - buckets: U32Table<'data, E>, - chains: U32Table<'data, E>, -} - -/// This constructs a lazy-parsing type that keeps a reference to the provided data -/// bytes from which it lazily parses and interprets its contents. -impl<'data, E: EndianParse> SysVHashTable<'data, E> { - /// Construct a SysVHashTable from given bytes. Keeps a reference to the data for lazy parsing. - pub fn new(endian: E, class: Class, data: &'data [u8]) -> Result { - let mut offset = 0; - let hdr = SysVHashHeader::parse_at(endian, class, &mut offset, data)?; - - let buckets_size = size_of::() - .checked_mul(hdr.nbucket.try_into()?) - .ok_or(ParseError::IntegerOverflow)?; - let buckets_end = offset - .checked_add(buckets_size) - .ok_or(ParseError::IntegerOverflow)?; - let buckets_buf = data.get_bytes(offset..buckets_end)?; - let buckets = U32Table::new(endian, class, buckets_buf); - offset = buckets_end; - - let chains_size = size_of::() - .checked_mul(hdr.nchain.try_into()?) - .ok_or(ParseError::IntegerOverflow)?; - let chains_end = offset - .checked_add(chains_size) - .ok_or(ParseError::IntegerOverflow)?; - let chains_buf = data.get_bytes(offset..chains_end)?; - let chains = U32Table::new(endian, class, chains_buf); - - Ok(SysVHashTable { buckets, chains }) - } - - /// Use the hash table to find the symbol table entry with the given name and hash. - pub fn find( - &self, - name: &[u8], - symtab: &SymbolTable<'data, E>, - strtab: &StringTable<'data>, - ) -> Result, ParseError> { - // empty hash tables don't have any entries. This avoids a divde by zero in the modulus calculation - if self.buckets.is_empty() { - return Ok(None); - } - - let hash = sysv_hash(name); - - let start = (hash as usize) % self.buckets.len(); - let mut index = self.buckets.get(start)? as usize; - - // Bound the number of chain lookups by the chain size so we don't loop forever - let mut i = 0; - while index != 0 && i < self.chains.len() { - let symbol = symtab.get(index)?; - if strtab.get_raw(symbol.st_name as usize)? == name { - return Ok(Some((index, symbol))); - } - - index = self.chains.get(index)? as usize; - i += 1; - } - Ok(None) - } -} - -/// Calculate the GNU hash for a given symbol name. -pub fn gnu_hash(name: &[u8]) -> u32 { - let mut hash = 5381u32; - for byte in name { - hash = hash.wrapping_mul(33).wrapping_add(u32::from(*byte)); - } - hash -} - -/// Header at the start of a GNU extension Hash Table section of type [SHT_GNU_HASH](crate::abi::SHT_GNU_HASH). -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct GnuHashHeader { - pub nbucket: u32, - /// The symbol table index of the first symbol in the hash table. - /// (GNU hash sections omit symbols at the start of the table that wont be looked up) - pub table_start_idx: u32, - /// The number of words in the bloom filter. (must be a non-zero power of 2) - pub nbloom: u32, - /// The bit shift count for the bloom filter. - pub nshift: u32, -} - -impl ParseAt for GnuHashHeader { - fn parse_at( - endian: E, - _class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - Ok(GnuHashHeader { - nbucket: endian.parse_u32_at(offset, data)?, - table_start_idx: endian.parse_u32_at(offset, data)?, - nbloom: endian.parse_u32_at(offset, data)?, - nshift: endian.parse_u32_at(offset, data)?, - }) - } - - #[inline] - fn size_for(_class: Class) -> usize { - size_of::() + size_of::() + size_of::() + size_of::() - } -} - -type U64Table<'data, E> = ParsingTable<'data, E, u64>; - -impl ParseAt for u64 { - fn parse_at( - endian: E, - _class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - endian.parse_u64_at(offset, data) - } - - #[inline] - fn size_for(_class: Class) -> usize { - core::mem::size_of::() - } -} - -#[derive(Debug)] -pub struct GnuHashTable<'data, E: EndianParse> { - pub hdr: GnuHashHeader, - - endian: E, - class: Class, - bloom: &'data [u8], - buckets: U32Table<'data, E>, - chains: U32Table<'data, E>, -} - -impl<'data, E: EndianParse> GnuHashTable<'data, E> { - /// Construct a GnuHashTable from given bytes. Keeps a reference to the data for lazy parsing. - pub fn new(endian: E, class: Class, data: &'data [u8]) -> Result { - let mut offset = 0; - let hdr = GnuHashHeader::parse_at(endian, class, &mut offset, data)?; - - // length of the bloom filter in bytes. ELF32 is [u32; nbloom], ELF64 is [u64; nbloom]. - let nbloom: usize = hdr.nbloom as usize; - let bloom_size = match class { - Class::ELF32 => nbloom - .checked_mul(size_of::()) - .ok_or(ParseError::IntegerOverflow)?, - Class::ELF64 => nbloom - .checked_mul(size_of::()) - .ok_or(ParseError::IntegerOverflow)?, - }; - let bloom_end = offset - .checked_add(bloom_size) - .ok_or(ParseError::IntegerOverflow)?; - let bloom_buf = data.get_bytes(offset..bloom_end)?; - offset = bloom_end; - - let buckets_size = size_of::() - .checked_mul(hdr.nbucket.try_into()?) - .ok_or(ParseError::IntegerOverflow)?; - let buckets_end = offset - .checked_add(buckets_size) - .ok_or(ParseError::IntegerOverflow)?; - let buckets_buf = data.get_bytes(offset..buckets_end)?; - let buckets = U32Table::new(endian, class, buckets_buf); - offset = buckets_end; - - // the rest of the section is the chains - let chains_buf = data - .get(offset..) - .ok_or(ParseError::SliceReadError((offset, data.len())))?; - let chains = U32Table::new(endian, class, chains_buf); - - Ok(GnuHashTable { - hdr, - endian, - class, - bloom: bloom_buf, - buckets, - chains, - }) - } - - /// Use the hash table to find the symbol table entry with the given name. - pub fn find( - &self, - name: &[u8], - symtab: &SymbolTable<'data, E>, - strtab: &StringTable<'data>, - ) -> Result, ParseError> { - // empty hash tables don't have any entries. This avoids a divde by zero in the modulus calculation, - // and also avoids a potential division by zero panic in the bloom filter index calculation. - if self.buckets.is_empty() || self.hdr.nbloom == 0 { - return Ok(None); - } - - let hash = gnu_hash(name); - - // Test against bloom filter. - let (bloom_width, filter) = match self.class { - Class::ELF32 => { - let bloom_width: u32 = 8 * size_of::() as u32; // 32 - let bloom_idx = (hash / (bloom_width)) % self.hdr.nbloom; - let bloom_table = U32Table::new(self.endian, self.class, self.bloom); - (bloom_width, bloom_table.get(bloom_idx as usize)? as u64) - } - Class::ELF64 => { - let bloom_width: u32 = 8 * size_of::() as u32; // 64 - let bloom_idx = (hash / (bloom_width)) % self.hdr.nbloom; - let bloom_table = U64Table::new(self.endian, self.class, self.bloom); - (bloom_width, bloom_table.get(bloom_idx as usize)?) - } - }; - - // Check bloom filter for both hashes - symbol is present in the hash table IFF both bits are set. - if filter & (1 << (hash % bloom_width)) == 0 { - return Ok(None); - } - let hash2 = hash - .checked_shr(self.hdr.nshift) - .ok_or(ParseError::IntegerOverflow)?; - if filter & (1 << (hash2 % bloom_width)) == 0 { - return Ok(None); - } - - let table_start_idx = self.hdr.table_start_idx as usize; - let chain_start_idx = self.buckets.get((hash as usize) % self.buckets.len())? as usize; - if chain_start_idx < table_start_idx { - // All symbols before table_start_idx don't exist in the hash table - return Ok(None); - } - - let chain_len = self.chains.len(); - for chain_idx in (chain_start_idx - table_start_idx)..chain_len { - let chain_hash = self.chains.get(chain_idx)?; - - // compare the hashes by or'ing the 1's bit back on - if hash | 1 == chain_hash | 1 { - // we have a hash match! - // let's see if this symtab[sym_idx].name is what we're looking for - let sym_idx = chain_idx - .checked_add(table_start_idx) - .ok_or(ParseError::IntegerOverflow)?; - let symbol = symtab.get(sym_idx)?; - let r_sym_name = strtab.get_raw(symbol.st_name as usize)?; - - if r_sym_name == name { - return Ok(Some((sym_idx, symbol))); - } - } - - // the chain uses the 1's bit to signal chain comparison stoppage - if chain_hash & 1 != 0 { - break; - } - } - - Ok(None) - } -} - -#[cfg(test)] -mod sysv_parse_tests { - use super::*; - use crate::endian::{BigEndian, LittleEndian}; - use crate::parse::{test_parse_for, test_parse_fuzz_too_short}; - - #[test] - fn parse_sysvhdr32_lsb() { - test_parse_for( - LittleEndian, - Class::ELF32, - SysVHashHeader { - nbucket: 0x03020100, - nchain: 0x07060504, - }, - ); - } - - #[test] - fn parse_sysvhdr32_msb() { - test_parse_for( - BigEndian, - Class::ELF32, - SysVHashHeader { - nbucket: 0x00010203, - nchain: 0x04050607, - }, - ); - } - - #[test] - fn parse_sysvhdr64_lsb() { - test_parse_for( - LittleEndian, - Class::ELF64, - SysVHashHeader { - nbucket: 0x03020100, - nchain: 0x07060504, - }, - ); - } - - #[test] - fn parse_sysvhdr64_msb() { - test_parse_for( - BigEndian, - Class::ELF64, - SysVHashHeader { - nbucket: 0x00010203, - nchain: 0x04050607, - }, - ); - } - - #[test] - fn parse_sysvhdr32_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, SysVHashHeader>(LittleEndian, Class::ELF32); - } - - #[test] - fn parse_sysvhdr32_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, SysVHashHeader>(BigEndian, Class::ELF32); - } - - #[test] - fn parse_sysvhdr64_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, SysVHashHeader>(LittleEndian, Class::ELF64); - } - - #[test] - fn parse_sysvhdr64_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, SysVHashHeader>(BigEndian, Class::ELF64); - } -} - -#[cfg(test)] -mod gnu_parse_tests { - use super::*; - use crate::endian::{BigEndian, LittleEndian}; - use crate::parse::{test_parse_for, test_parse_fuzz_too_short}; - - #[test] - fn gnu_hash_tests() { - // some known example hash values - assert_eq!(gnu_hash(b""), 0x00001505); - assert_eq!(gnu_hash(b"printf"), 0x156b2bb8); - assert_eq!(gnu_hash(b"exit"), 0x7c967e3f); - assert_eq!(gnu_hash(b"syscall"), 0xbac212a0); - } - - #[test] - fn parse_gnuhdr32_lsb() { - test_parse_for( - LittleEndian, - Class::ELF32, - GnuHashHeader { - nbucket: 0x03020100, - table_start_idx: 0x07060504, - nbloom: 0x0B0A0908, - nshift: 0x0F0E0D0C, - }, - ); - } - - #[test] - fn parse_gnuhdr32_msb() { - test_parse_for( - BigEndian, - Class::ELF32, - GnuHashHeader { - nbucket: 0x00010203, - table_start_idx: 0x04050607, - nbloom: 0x008090A0B, - nshift: 0x0C0D0E0F, - }, - ); - } - - #[test] - fn parse_gnuhdr64_lsb() { - test_parse_for( - LittleEndian, - Class::ELF64, - GnuHashHeader { - nbucket: 0x03020100, - table_start_idx: 0x07060504, - nbloom: 0x0B0A0908, - nshift: 0x0F0E0D0C, - }, - ); - } - - #[test] - fn parse_gnuhdr64_msb() { - test_parse_for( - BigEndian, - Class::ELF64, - GnuHashHeader { - nbucket: 0x00010203, - table_start_idx: 0x04050607, - nbloom: 0x008090A0B, - nshift: 0x0C0D0E0F, - }, - ); - } - - #[test] - fn parse_gnuhdr32_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, GnuHashHeader>(LittleEndian, Class::ELF32); - } - - #[test] - fn parse_gnuhdr32_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, GnuHashHeader>(BigEndian, Class::ELF32); - } - - #[test] - fn parse_gnuhdr64_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, GnuHashHeader>(LittleEndian, Class::ELF64); - } - - #[test] - fn parse_gnuhdr64_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, GnuHashHeader>(BigEndian, Class::ELF64); - } -} diff --git a/arceos/modules/elf/src/lib.rs b/arceos/modules/elf/src/lib.rs deleted file mode 100644 index 5ac480ba7..000000000 --- a/arceos/modules/elf/src/lib.rs +++ /dev/null @@ -1,163 +0,0 @@ -//! The `elf` crate provides a pure-safe-rust interface for reading ELF object files. -//! -//! # Capabilities -//! -//! ### ✨ Works in `no_std` environments ✨ -//! This crate provides an elf parsing interface which does not allocate or use any std -//! features, so it can be used in `no_std` environments such as kernels and bootloaders. -//! The no_std variant merely disables the additional stream-oriented `std:: Read + Seek` interface. -//! All core parsing functionality is the same! -//! -//! ### ✨ Endian-aware ✨ -//! This crate handles translating between file and host endianness when -//! parsing the ELF contents and provides four endian parsing implementations -//! optimized to support the different common use-cases for an ELF parsing library. -//! Parsing is generic across the specifications and each trait impl represents a -//! specification that encapsulates an interface for parsing integers from some -//! set of allowed byte orderings. -//! -//! * [AnyEndian](endian::AnyEndian): Dynamically parsing either byte order at runtime based on the type of ELF object being parsed. -//! * [BigEndian](endian::BigEndian)/[LittleEndian](endian::LittleEndian): For tools that know they only want to parse a single given byte order known at compile time. -//! * [NativeEndian](type@endian::NativeEndian): For tools that know they want to parse the same byte order as the compilation target's byte order. -//! -//! When the limited specifications are used, errors are properly returned when asked to parse an ELF file -//! with an unexpected byte ordering. -//! -//! ### ✨ Zero-alloc parser ✨ -//! This crate implements parsing in a way that avoids heap allocations. ELF structures -//! are parsed and stored on the stack and provided by patterns such as lazily parsed iterators -//! that yield stack allocated rust types, or lazily parsing tables that only parse out a particular -//! entry on table.get(index). The structures are copy-converted as needed from the underlying file -//! data into Rust's native struct representation. -//! -//! ### ✨ Fuzz Tested ✨ -//! Various parts of the library are fuzz tested for panics and crashes (see `fuzz/`). -//! -//! Memory safety is a core goal, as is providing a safe interface that errors on bad data -//! over crashing or panicking. Checked integer math is used where appropriate, and ParseErrors are -//! returned when bad or corrupted ELF structures are encountered. -//! -//! ### ✨ Uses only safe interfaces ✨ -//! With memory safety a core goal, this crate contains zero unsafe code blocks -//! of its own and only uses safe interface methods from core and std, so you can -//! trust in rust's memory safety guarantees without also having to trust this -//! library developer as having truly been "right" in why some unsafe block was -//! safe. 💃 -//! -//! Note: I'd love to see this crate be enhanced further once rust provides safe transmutes. -//! -//! See: -//! -//! ### ✨ Some zero-copy interfaces ✨ -//! The StringTable, for instance, yields `&[u8]` and `&str` backed by the raw string table bytes. -//! -//! The [ElfBytes] parser type also does not make raw copies of the underlying file data to back -//! the parser lazy parser interfaces `ParsingIterator` and `ParsingTable`. They merely wrap byte slices -//! internally, and yield rust repr values on demand, which does entail copying of the bytes into the -//! parsed rust-native format. -//! -//! Depending on the use-case, it can be more efficient to restructure the raw ELF into different layouts -//! for more efficient interpretation, say, by re-indexing a flat table into a HashMap. `ParsingIterator`s -//! make that easy and rustily-intuitive. -//! -//! The `ParsingIterator`s are also nice in that you can easily zip/enumerate/filter/collect them -//! how you wish. Do you know that you want to do multiple passes over pairs from different tables? Just -//! zip/collect them into another type so you only parse/endian-flip each entry once! -//! -//! ### ✨ Stream-based lazy i/o interface ✨ -//! The [ElfStream] parser type takes a `std:: Read + Seek` (such as `std::fs::File`) where ranges of -//! file contents are read lazily on-demand based on what the user wants to parse. -//! -//! This, alongside the bytes-oriented interface, allow you to decide which tradeoffs -//! you want to make. If you're going to be working with the whole file contents, -//! then the byte slice approach is probably worthwhile to minimize i/o overhead by -//! streaming the whole file into memory at once. If you're only going to be -//! inspecting part of the file, then the [ElfStream] approach would help avoid the -//! overhead of reading a bunch of unused file data just to parse out a few things, (like -//! grabbing the `.gnu.note.build-id`) -//! -//! ### ✨ Tiny library with no dependencies and fast compilation times ✨ -//! Release-target compilation times on this developer's 2021 m1 macbook are sub-second. -//! -//! Example using [ElfBytes]: -//! ``` -//! use elf::ElfBytes; -//! use elf::endian::AnyEndian; -//! use elf::note::Note; -//! use elf::note::NoteGnuBuildId; -//! use elf::section::SectionHeader; -//! -//! let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so"); -//! let file_data = std::fs::read(path).expect("Could not read file."); -//! let slice = file_data.as_slice(); -//! let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); -//! -//! // Get the ELF file's build-id -//! let abi_shdr: SectionHeader = file -//! .section_header_by_name(".note.gnu.build-id") -//! .expect("section table should be parseable") -//! .expect("file should have a .note.ABI-tag section"); -//! -//! let notes: Vec = file -//! .section_data_as_notes(&abi_shdr) -//! .expect("Should be able to get note section data") -//! .collect(); -//! assert_eq!( -//! notes[0], -//! Note::GnuBuildId(NoteGnuBuildId( -//! &[140, 51, 19, 23, 221, 90, 215, 131, 169, 13, -//! 210, 183, 215, 77, 216, 175, 167, 110, 3, 209])) -//! ); -//! -//! // Find lazy-parsing types for the common ELF sections (we want .dynsym, .dynstr, .hash) -//! let common = file.find_common_data().expect("shdrs should parse"); -//! let (dynsyms, strtab) = (common.dynsyms.unwrap(), common.dynsyms_strs.unwrap()); -//! let hash_table = common.sysv_hash.unwrap(); -//! -//! // Use the hash table to find a given symbol in it. -//! let name = b"memset"; -//! let (sym_idx, sym) = hash_table.find(name, &dynsyms, &strtab) -//! .expect("hash table and symbols should parse").unwrap(); -//! -//! // Verify that we got the same symbol from the hash table we expected -//! assert_eq!(sym_idx, 2); -//! assert_eq!(strtab.get(sym.st_name as usize).unwrap(), "memset"); -//! assert_eq!(sym, dynsyms.get(sym_idx).unwrap()); -//! ``` - -#![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(all(feature = "nightly", not(feature = "std")), feature(error_in_core))] -#![warn(rust_2018_idioms)] -#![deny(missing_debug_implementations)] -#![forbid(unsafe_code)] - -pub mod abi; - -pub mod compression; -pub mod dynamic; -pub mod file; -pub mod gnu_symver; -pub mod hash; -pub mod note; -pub mod relocation; -pub mod section; -pub mod segment; -pub mod string_table; -pub mod symbol; - -#[cfg(feature = "to_str")] -pub mod to_str; - -pub mod endian; -pub mod parse; - -mod elf_bytes; -pub use elf_bytes::CommonElfData; -pub use elf_bytes::ElfBytes; - -#[cfg(feature = "std")] -mod elf_stream; -#[cfg(feature = "std")] -pub use elf_stream::ElfStream; - -pub use parse::ParseError; diff --git a/arceos/modules/elf/src/note.rs b/arceos/modules/elf/src/note.rs deleted file mode 100644 index c196083c2..000000000 --- a/arceos/modules/elf/src/note.rs +++ /dev/null @@ -1,599 +0,0 @@ -//! Parsing ELF notes: `.note.*`, [SHT_NOTE](crate::abi::SHT_NOTE), [PT_NOTE](crate::abi::PT_NOTE) -//! -//! Example for getting the GNU ABI-tag note: -//! ``` -//! use elf::ElfBytes; -//! use elf::endian::AnyEndian; -//! use elf::note::Note; -//! use elf::note::NoteGnuAbiTag; -//! -//! let path = std::path::PathBuf::from("sample-objects/basic.x86_64"); -//! let file_data = std::fs::read(path).expect("Could not read file."); -//! let slice = file_data.as_slice(); -//! let file = ElfBytes::::minimal_parse(slice).expect("Open test1"); -//! -//! let shdr = file -//! .section_header_by_name(".note.ABI-tag") -//! .expect("section table should be parseable") -//! .expect("file should have a .note.ABI-tag section"); -//! -//! let notes: Vec<_> = file -//! .section_data_as_notes(&shdr) -//! .expect("Should be able to get note section data") -//! .collect(); -//! assert_eq!( -//! notes[0], -//! Note::GnuAbiTag(NoteGnuAbiTag { -//! os: 0, -//! major: 2, -//! minor: 6, -//! subminor: 32 -//! }) -//! ); -//! ``` -use crate::abi; -use crate::endian::EndianParse; -use crate::file::Class; -use crate::parse::{ParseAt, ParseError, ReadBytesExt}; -use core::mem::size_of; -use core::str::from_utf8; - -/// This enum contains parsed Note variants which can be matched on -#[derive(Debug, PartialEq, Eq)] -pub enum Note<'data> { - /// (name: [abi::ELF_NOTE_GNU], n_type: [abi::NT_GNU_ABI_TAG]) - GnuAbiTag(NoteGnuAbiTag), - /// (name: [abi::ELF_NOTE_GNU], n_type: [abi::NT_GNU_BUILD_ID]) - GnuBuildId(NoteGnuBuildId<'data>), - /// All other notes that we don't know how to parse - Unknown(NoteAny<'data>), -} - -impl<'data> Note<'data> { - fn parse_at( - endian: E, - _class: Class, - align: usize, - offset: &mut usize, - data: &'data [u8], - ) -> Result { - // We don't know what to do if the section or segment header specified a zero alignment, so error - // (this is likely a file corruption) - if align == 0 { - return Err(ParseError::UnexpectedAlignment(align)); - } - - // It looks like clang and gcc emit 32-bit notes for 64-bit files, so we - // currently always parse all note headers as 32-bit. - let nhdr = NoteHeader::parse_at(endian, Class::ELF32, offset, data)?; - - let name_start = *offset; - let name_buf_size: usize = nhdr.n_namesz.saturating_sub(1).try_into()?; - let name_buf_end = name_start - .checked_add(name_buf_size) - .ok_or(ParseError::IntegerOverflow)?; - let name_buf = data.get_bytes(name_start..name_buf_end)?; - let name = from_utf8(name_buf)?; - - // move forward for entire namesz, including the NUL byte we left out of our str - *offset = (*offset) - .checked_add(nhdr.n_namesz.try_into()?) - .ok_or(ParseError::IntegerOverflow)?; - - // skip over padding if needed to get back to 4-byte alignment - if *offset % align > 0 { - *offset = (*offset) - .checked_add(align - *offset % align) - .ok_or(ParseError::IntegerOverflow)?; - } - - let desc_start = *offset; - let desc_size: usize = nhdr.n_descsz.try_into()?; - let desc_end = desc_start - .checked_add(desc_size) - .ok_or(ParseError::IntegerOverflow)?; - let raw_desc = data.get_bytes(desc_start..desc_end)?; - *offset = desc_end; - - // skip over padding if needed to get back to 4-byte alignment - if *offset % align > 0 { - *offset = (*offset) - .checked_add(align - *offset % align) - .ok_or(ParseError::IntegerOverflow)?; - } - - // Interpret the note contents to try to return a known note variant - match name { - abi::ELF_NOTE_GNU => match nhdr.n_type { - abi::NT_GNU_ABI_TAG => { - let mut offset = 0; - Ok(Note::GnuAbiTag(NoteGnuAbiTag::parse_at( - endian, - _class, - &mut offset, - raw_desc, - )?)) - } - abi::NT_GNU_BUILD_ID => Ok(Note::GnuBuildId(NoteGnuBuildId(raw_desc))), - _ => Ok(Note::Unknown(NoteAny { - n_type: nhdr.n_type, - name, - desc: raw_desc, - })), - }, - _ => Ok(Note::Unknown(NoteAny { - n_type: nhdr.n_type, - name, - desc: raw_desc, - })), - } - } -} - -/// Contains four 4-byte integers. -/// The first 4-byte integer specifies the os. The second, third, and fourth -/// 4-byte integers contain the earliest compatible kernel version. -/// For example, if the 3 integers are 6, 0, and 7, this signifies a 6.0.7 kernel. -/// -/// (see: ) -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct NoteGnuAbiTag { - pub os: u32, - pub major: u32, - pub minor: u32, - pub subminor: u32, -} - -impl ParseAt for NoteGnuAbiTag { - fn parse_at( - endian: E, - _class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - Ok(NoteGnuAbiTag { - os: endian.parse_u32_at(offset, data)?, - major: endian.parse_u32_at(offset, data)?, - minor: endian.parse_u32_at(offset, data)?, - subminor: endian.parse_u32_at(offset, data)?, - }) - } - - fn size_for(_class: Class) -> usize { - size_of::() * 4 - } -} - -/// Contains a build ID note which is unique among the set of meaningful contents -/// for ELF files and identical when the output file would otherwise have been identical. -/// This is a zero-copy type which merely contains a slice of the note data from which it was parsed. -/// -/// (see: ) -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct NoteGnuBuildId<'data>(pub &'data [u8]); - -/// Contains the raw fields found in any ELF note. Used for notes that we don't know -/// how to parse into more specific types. -#[derive(Debug, PartialEq, Eq)] -pub struct NoteAny<'data> { - pub n_type: u64, - pub name: &'data str, - pub desc: &'data [u8], -} - -#[derive(Debug)] -pub struct NoteIterator<'data, E: EndianParse> { - endian: E, - class: Class, - align: usize, - data: &'data [u8], - offset: usize, -} - -impl<'data, E: EndianParse> NoteIterator<'data, E> { - pub fn new(endian: E, class: Class, align: usize, data: &'data [u8]) -> Self { - NoteIterator { - endian, - class, - align, - data, - offset: 0, - } - } -} - -impl<'data, E: EndianParse> Iterator for NoteIterator<'data, E> { - type Item = Note<'data>; - fn next(&mut self) -> Option { - if self.data.is_empty() { - return None; - } - - Note::parse_at( - self.endian, - self.class, - self.align, - &mut self.offset, - self.data, - ) - .ok() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct NoteHeader { - pub n_namesz: u64, - pub n_descsz: u64, - pub n_type: u64, -} - -impl ParseAt for NoteHeader { - fn parse_at( - endian: E, - class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - match class { - Class::ELF32 => Ok(NoteHeader { - n_namesz: endian.parse_u32_at(offset, data)? as u64, - n_descsz: endian.parse_u32_at(offset, data)? as u64, - n_type: endian.parse_u32_at(offset, data)? as u64, - }), - Class::ELF64 => Ok(NoteHeader { - n_namesz: endian.parse_u64_at(offset, data)?, - n_descsz: endian.parse_u64_at(offset, data)?, - n_type: endian.parse_u64_at(offset, data)?, - }), - } - } - - #[inline] - fn size_for(class: Class) -> usize { - match class { - Class::ELF32 => 12, - Class::ELF64 => 24, - } - } -} - -#[cfg(test)] -mod parse_tests { - use super::*; - use crate::abi; - use crate::endian::{BigEndian, LittleEndian}; - - #[test] - fn parse_nt_gnu_abi_tag() { - #[rustfmt::skip] - let data = [ - 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - ]; - - let mut offset = 0; - let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data) - .expect("Failed to parse"); - - assert_eq!( - note, - Note::GnuAbiTag(NoteGnuAbiTag { - os: abi::ELF_NOTE_GNU_ABI_TAG_OS_LINUX, - major: 2, - minor: 6, - subminor: 32 - }) - ); - } - - #[test] - fn parse_desc_gnu_build_id() { - let data = [ - 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x4e, - 0x55, 0x00, 0x77, 0x41, 0x9f, 0x0d, 0xa5, 0x10, 0x83, 0x0c, 0x57, 0xa7, 0xc8, 0xcc, - 0xb0, 0xee, 0x85, 0x5f, 0xee, 0xd3, 0x76, 0xa3, - ]; - - let mut offset = 0; - let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data) - .expect("Failed to parse"); - - assert_eq!( - note, - Note::GnuBuildId(NoteGnuBuildId(&[ - 0x77, 0x41, 0x9f, 0x0d, 0xa5, 0x10, 0x83, 0x0c, 0x57, 0xa7, 0xc8, 0xcc, 0xb0, 0xee, - 0x85, 0x5f, 0xee, 0xd3, 0x76, 0xa3, - ])) - ); - } - - #[test] - fn parse_note_errors_with_zero_alignment() { - // This is a .note.gnu.property section - #[rustfmt::skip] - let data = [ - 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, - 0x02, 0x00, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - - let mut offset = 0; - Note::parse_at(LittleEndian, Class::ELF64, 0, &mut offset, &data) - .expect_err("Should have gotten an alignment error"); - } - #[test] - fn parse_note_with_8_byte_alignment() { - // This is a .note.gnu.property section, which has been seen generated with 8-byte alignment - #[rustfmt::skip] - let data = [ - 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, - 0x02, 0x00, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - - // Even though the file class is ELF64, we parse it as a 32-bit struct. gcc/clang seem to output 32-bit notes - // even though the gABI states that ELF64 files should contain 64-bit notes. Sometimes those notes are generated - // in sections with 4-byte alignment, and other times with 8-byte alignment, as specified by shdr.sh_addralign. - // - // See https://raw.githubusercontent.com/wiki/hjl-tools/linux-abi/linux-abi-draft.pdf - // Excerpt: - // All entries in a PT_NOTE segment have the same alignment which equals to the - // p_align field in program header. - // According to gABI, each note entry should be aligned to 4 bytes in 32-bit - // objects or 8 bytes in 64-bit objects. But .note.ABI-tag section (see Sec- - // tion 2.1.6) and .note.gnu.build-id section (see Section 2.1.4) are aligned - // to 4 bytes in both 32-bit and 64-bit objects. Note parser should use p_align for - // note alignment, instead of assuming alignment based on ELF file class. - let mut offset = 0; - let note = Note::parse_at(LittleEndian, Class::ELF64, 8, &mut offset, &data) - .expect("Failed to parse"); - assert_eq!( - note, - Note::Unknown(NoteAny { - n_type: 5, - name: abi::ELF_NOTE_GNU, - desc: &[ - 0x2, 0x0, 0x0, 0xc0, 0x4, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 - ] - }) - ); - } - - #[test] - fn parse_note_with_8_byte_alignment_unaligned_namesz() { - let data = [ - 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // namesz 5, descsz 2 - 0x42, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x55, // type 42 (unknown), name GNUU - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // NUL + 7 pad for 8 alignment - 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // desc 0102 + 6 pad for alignment - ]; - - let mut offset = 0; - let note = Note::parse_at(LittleEndian, Class::ELF32, 8, &mut offset, &data) - .expect("Failed to parse"); - assert_eq!( - note, - Note::Unknown(NoteAny { - n_type: 0x42, - name: &"GNUU", - desc: &[0x01, 0x02], - }) - ); - assert_eq!(offset, 32); - } - - #[test] - fn parse_note_for_elf64_expects_nhdr32() { - let data = [ - 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x4e, - 0x55, 0x00, 0x77, 0x41, 0x9f, 0x0d, 0xa5, 0x10, 0x83, 0x0c, 0x57, 0xa7, 0xc8, 0xcc, - 0xb0, 0xee, 0x85, 0x5f, 0xee, 0xd3, 0x76, 0xa3, - ]; - - let mut offset = 0; - // Even though the file class is ELF64, we parse it as a 32-bit struct. gcc/clang seem to output 32-bit notes - // even though the gABI states that ELF64 files should contain 64-bit notes. - let note = Note::parse_at(LittleEndian, Class::ELF64, 4, &mut offset, &data) - .expect("Failed to parse"); - assert_eq!( - note, - Note::GnuBuildId(NoteGnuBuildId(&[ - 0x77, 0x41, 0x9f, 0x0d, 0xa5, 0x10, 0x83, 0x0c, 0x57, 0xa7, 0xc8, 0xcc, 0xb0, 0xee, - 0x85, 0x5f, 0xee, 0xd3, 0x76, 0xa3, - ])) - ); - } - - #[test] - fn parse_note_32_lsb() { - let data = [ - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, - 0x00, 0x00, - ]; - - let mut offset = 0; - let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data) - .expect("Failed to parse"); - assert_eq!( - note, - Note::Unknown(NoteAny { - n_type: 6, - name: "", - desc: &[0x20, 0x0], - }) - ); - assert_eq!(offset, 16); - } - - #[test] - fn parse_note_32_lsb_with_name_padding() { - let data = [ - 0x03, 0x00, 0x00, 0x00, // namesz 3 - 0x04, 0x00, 0x00, 0x00, // descsz 4 - 0x01, 0x00, 0x00, 0x00, // type 1 - 0x47, 0x4e, 0x00, 0x00, // name GN\0 + 1 pad byte - 0x01, 0x02, 0x03, 0x04, - ]; // desc 01020304 - - let mut offset = 0; - let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data) - .expect("Failed to parse"); - assert_eq!( - note, - Note::Unknown(NoteAny { - n_type: 1, - name: "GN", - desc: &[0x01, 0x02, 0x03, 0x04], - }) - ); - assert_eq!(offset, 20); - } - - #[test] - fn parse_note_32_lsb_with_desc_padding() { - let data = [ - 0x04, 0x00, 0x00, 0x00, // namesz 4 - 0x02, 0x00, 0x00, 0x00, // descsz 2 - 0x42, 0x00, 0x00, 0x00, // type 42 (unknown) - 0x47, 0x4e, 0x55, 0x00, // name GNU\0 - 0x01, 0x02, 0x00, 0x00, // desc 0102 + 2 pad bytes - ]; - - let mut offset = 0; - let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data) - .expect("Failed to parse"); - assert_eq!( - note, - Note::Unknown(NoteAny { - n_type: 0x42, - name: abi::ELF_NOTE_GNU, - desc: &[0x01, 0x02], - }) - ); - assert_eq!(offset, 20); - } - - #[test] - fn parse_note_32_lsb_with_no_name() { - let data = [ - 0x00, 0x00, 0x00, 0x00, // namesz 0 - 0x02, 0x00, 0x00, 0x00, // descsz 2 - 0x42, 0x00, 0x00, 0x00, // type 42 (unknown) - 0x20, 0x00, 0x00, 0x00, // desc 20, 00 + 2 pad bytes - ]; - - let mut offset = 0; - let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data) - .expect("Failed to parse"); - assert_eq!( - note, - Note::Unknown(NoteAny { - n_type: 0x42, - name: "", - desc: &[0x20, 0x0], - }) - ); - assert_eq!(offset, 16); - } - - #[test] - fn parse_note_32_lsb_with_no_desc() { - let data = [ - 0x04, 0x00, 0x00, 0x00, // namesz 4 - 0x00, 0x00, 0x00, 0x00, // descsz 0 - 0x42, 0x00, 0x00, 0x00, // type 42 (unknown) - 0x47, 0x4e, 0x55, 0x00, // name GNU\0 - ]; - - let mut offset = 0; - let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data) - .expect("Failed to parse"); - assert_eq!( - note, - Note::Unknown(NoteAny { - n_type: 0x42, - name: abi::ELF_NOTE_GNU, - desc: &[], - }) - ); - assert_eq!(offset, 16); - } - - use crate::parse::{test_parse_for, test_parse_fuzz_too_short}; - - #[test] - fn parse_nhdr32_lsb() { - test_parse_for( - LittleEndian, - Class::ELF32, - NoteHeader { - n_namesz: 0x03020100, - n_descsz: 0x07060504, - n_type: 0x0B0A0908, - }, - ); - } - - #[test] - fn parse_nhdr32_msb() { - test_parse_for( - BigEndian, - Class::ELF32, - NoteHeader { - n_namesz: 0x00010203, - n_descsz: 0x04050607, - n_type: 0x08090A0B, - }, - ); - } - - #[test] - fn parse_nhdr64_lsb() { - test_parse_for( - LittleEndian, - Class::ELF64, - NoteHeader { - n_namesz: 0x0706050403020100, - n_descsz: 0x0F0E0D0C0B0A0908, - n_type: 0x1716151413121110, - }, - ); - } - - #[test] - fn parse_nhdr64_msb() { - test_parse_for( - BigEndian, - Class::ELF64, - NoteHeader { - n_namesz: 0x0001020304050607, - n_descsz: 0x08090A0B0C0D0E0F, - n_type: 0x1011121314151617, - }, - ); - } - - #[test] - fn parse_nhdr32_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, NoteHeader>(LittleEndian, Class::ELF32); - } - - #[test] - fn parse_nhdr32_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, NoteHeader>(BigEndian, Class::ELF32); - } - - #[test] - fn parse_nhdr64_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, NoteHeader>(LittleEndian, Class::ELF64); - } - - #[test] - fn parse_nhdr64_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, NoteHeader>(BigEndian, Class::ELF64); - } -} diff --git a/arceos/modules/elf/src/parse.rs b/arceos/modules/elf/src/parse.rs deleted file mode 100644 index a47e90559..000000000 --- a/arceos/modules/elf/src/parse.rs +++ /dev/null @@ -1,502 +0,0 @@ -//! Utilities to drive safe and lazy parsing of ELF structures. -use core::{marker::PhantomData, ops::Range}; - -use crate::endian::EndianParse; -use crate::file::Class; - -#[derive(Debug)] -pub enum ParseError { - /// Returned when the ELF File Header's magic bytes weren't ELF's defined - /// magic bytes - BadMagic([u8; 4]), - /// Returned when the ELF File Header's `e_ident[EI_CLASS]` wasn't one of the - /// defined `ELFCLASS*` constants - UnsupportedElfClass(u8), - /// Returned when the ELF File Header's `e_ident[EI_DATA]` wasn't one of the - /// defined `ELFDATA*` constants - UnsupportedElfEndianness(u8), - /// Returned when parsing an ELF struct with a version field whose value wasn't - /// something we support and know how to parse. - UnsupportedVersion((u64, u64)), - /// Returned when parsing an ELF structure resulted in an offset which fell - /// out of bounds of the requested structure - BadOffset(u64), - /// Returned when parsing a string out of a StringTable failed to find the - /// terminating NUL byte - StringTableMissingNul(u64), - /// Returned when parsing a table of ELF structures and the file specified - /// an entry size for that table that was different than what we had - /// expected - BadEntsize((u64, u64)), - /// Returned when trying to interpret a section's data as the wrong type. - /// For example, trying to treat an SHT_PROGBIGS section as a SHT_STRTAB. - UnexpectedSectionType((u32, u32)), - /// Returned when trying to interpret a segment's data as the wrong type. - /// For example, trying to treat an PT_LOAD section as a PT_NOTE. - UnexpectedSegmentType((u32, u32)), - /// Returned when a section has a sh_addralign value that was different - /// than we expected. - UnexpectedAlignment(usize), - /// Returned when parsing an ELF structure out of an in-memory `&[u8]` - /// resulted in a request for a section of file bytes outside the range of - /// the slice. Commonly caused by truncated file contents. - SliceReadError((usize, usize)), - /// Returned when doing math with parsed elf fields that resulted in integer overflow. - IntegerOverflow, - /// Returned when parsing a string out of a StringTable that contained - /// invalid Utf8 - Utf8Error(core::str::Utf8Error), - /// Returned when parsing an ELF structure and the underlying structure data - /// was truncated and thus the full structure contents could not be parsed. - TryFromSliceError(core::array::TryFromSliceError), - /// Returned when parsing an ELF structure whose on-disk fields were too big - /// to represent in the native machine's usize type for in-memory processing. - /// This could be the case when processessing large 64-bit files on a 32-bit machine. - TryFromIntError(core::num::TryFromIntError), - #[cfg(feature = "std")] - /// Returned when parsing an ELF structure out of an io stream encountered - /// an io error. - IOError(std::io::Error), -} - -#[cfg(feature = "std")] -impl std::error::Error for ParseError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match *self { - ParseError::BadMagic(_) => None, - ParseError::UnsupportedElfClass(_) => None, - ParseError::UnsupportedElfEndianness(_) => None, - ParseError::UnsupportedVersion(_) => None, - ParseError::BadOffset(_) => None, - ParseError::StringTableMissingNul(_) => None, - ParseError::BadEntsize(_) => None, - ParseError::UnexpectedSectionType(_) => None, - ParseError::UnexpectedSegmentType(_) => None, - ParseError::UnexpectedAlignment(_) => None, - ParseError::SliceReadError(_) => None, - ParseError::IntegerOverflow => None, - ParseError::Utf8Error(ref err) => Some(err), - ParseError::TryFromSliceError(ref err) => Some(err), - ParseError::TryFromIntError(ref err) => Some(err), - ParseError::IOError(ref err) => Some(err), - } - } -} - -#[cfg(all(feature = "nightly", not(feature = "std")))] -impl core::error::Error for ParseError { - fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { - match *self { - ParseError::BadMagic(_) => None, - ParseError::UnsupportedElfClass(_) => None, - ParseError::UnsupportedElfEndianness(_) => None, - ParseError::UnsupportedVersion(_) => None, - ParseError::BadOffset(_) => None, - ParseError::StringTableMissingNul(_) => None, - ParseError::BadEntsize(_) => None, - ParseError::UnexpectedSectionType(_) => None, - ParseError::UnexpectedSegmentType(_) => None, - ParseError::UnexpectedAlignment(_) => None, - ParseError::SliceReadError(_) => None, - ParseError::IntegerOverflow => None, - ParseError::Utf8Error(ref err) => Some(err), - ParseError::TryFromSliceError(ref err) => Some(err), - ParseError::TryFromIntError(ref err) => Some(err), - } - } -} - -impl core::fmt::Display for ParseError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match *self { - ParseError::BadMagic(ref magic) => { - write!(f, "Invalid Magic Bytes: {magic:X?}") - } - ParseError::UnsupportedElfClass(class) => { - write!(f, "Unsupported ELF Class: {class}") - } - ParseError::UnsupportedElfEndianness(endianness) => { - write!(f, "Unsupported ELF Endianness: {endianness}") - } - ParseError::UnsupportedVersion((found, expected)) => { - write!( - f, - "Unsupported ELF Version field found: {found} expected: {expected}" - ) - } - ParseError::BadOffset(offset) => { - write!(f, "Bad offset: {offset:#X}") - } - ParseError::StringTableMissingNul(offset) => { - write!( - f, - "Could not find terminating NUL byte starting at offset: {offset:#X}" - ) - } - ParseError::BadEntsize((found, expected)) => { - write!( - f, - "Invalid entsize. Expected: {expected:#X}, Found: {found:#X}" - ) - } - ParseError::UnexpectedSectionType((found, expected)) => { - write!( - f, - "Could not interpret section of type {found} as type {expected}" - ) - } - ParseError::UnexpectedSegmentType((found, expected)) => { - write!( - f, - "Could not interpret section of type {found} as type {expected}" - ) - } - ParseError::UnexpectedAlignment(align) => { - write!( - f, - "Could not interpret section with unexpected alignment of {align}" - ) - } - ParseError::SliceReadError((start, end)) => { - write!(f, "Could not read bytes in range [{start:#X}, {end:#X})") - } - ParseError::IntegerOverflow => { - write!(f, "Integer overflow detected") - } - ParseError::Utf8Error(ref err) => err.fmt(f), - ParseError::TryFromSliceError(ref err) => err.fmt(f), - ParseError::TryFromIntError(ref err) => err.fmt(f), - #[cfg(feature = "std")] - ParseError::IOError(ref err) => err.fmt(f), - } - } -} - -impl From for ParseError { - fn from(err: core::str::Utf8Error) -> Self { - ParseError::Utf8Error(err) - } -} - -impl From for ParseError { - fn from(err: core::array::TryFromSliceError) -> Self { - ParseError::TryFromSliceError(err) - } -} - -impl From for ParseError { - fn from(err: core::num::TryFromIntError) -> Self { - ParseError::TryFromIntError(err) - } -} - -#[cfg(feature = "std")] -impl From for ParseError { - fn from(err: std::io::Error) -> ParseError { - ParseError::IOError(err) - } -} - -/// Trait for safely parsing an ELF structure of a given class (32/64 bit) with -/// an given endian-awareness at the given offset into the data buffer. -/// -/// This is the trait that drives our elf parser, where the various ELF -/// structures implement ParseAt in order to parse their Rust-native representation -/// from a buffer, all using safe code. -pub trait ParseAt: Sized { - /// Parse this type by using the given endian-awareness and ELF class layout. - /// This is generic on EndianParse in order to allow users to optimize for - /// their expectations of data layout. See EndianParse for more details. - fn parse_at( - endian: E, - class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result; - - /// Returns the expected size of the type being parsed for the given ELF class - fn size_for(class: Class) -> usize; - - /// Checks whether the given entsize matches what we need to parse this type - /// - /// Returns a ParseError for bad/unexpected entsizes that don't match what this type parses. - fn validate_entsize(class: Class, entsize: usize) -> Result { - let expected = Self::size_for(class); - match entsize == expected { - true => Ok(entsize), - false => Err(ParseError::BadEntsize((entsize as u64, expected as u64))), - } - } -} - -/// Lazy-parsing iterator which wraps bytes and parses out a `P: ParseAt` on each `next()` -#[derive(Debug)] -pub struct ParsingIterator<'data, E: EndianParse, P: ParseAt> { - endian: E, - class: Class, - data: &'data [u8], - offset: usize, - // This struct doesn't technically own a P, but it yields them - // as it iterates - pd: PhantomData<&'data P>, -} - -impl<'data, E: EndianParse, P: ParseAt> ParsingIterator<'data, E, P> { - pub fn new(endian: E, class: Class, data: &'data [u8]) -> Self { - ParsingIterator { - endian, - class, - data, - offset: 0, - pd: PhantomData, - } - } -} - -impl<'data, E: EndianParse, P: ParseAt> Iterator for ParsingIterator<'data, E, P> { - type Item = P; - fn next(&mut self) -> Option { - if self.data.is_empty() { - return None; - } - - Self::Item::parse_at(self.endian, self.class, &mut self.offset, self.data).ok() - } -} - -/// Lazy-parsing table which wraps bytes and parses out a `P: ParseAt` at a given index into -/// the table on each `get()`. -#[derive(Debug, Clone, Copy)] -pub struct ParsingTable<'data, E: EndianParse, P: ParseAt> { - endian: E, - class: Class, - data: &'data [u8], - // This struct doesn't technically own a P, but it yields them - pd: PhantomData<&'data P>, -} - -impl<'data, E: EndianParse, P: ParseAt> ParsingTable<'data, E, P> { - pub fn new(endian: E, class: Class, data: &'data [u8]) -> Self { - ParsingTable { - endian, - class, - data, - pd: PhantomData, - } - } - - /// Get a lazy-parsing iterator for the table's bytes - pub fn iter(&self) -> ParsingIterator<'data, E, P> { - ParsingIterator::new(self.endian, self.class, self.data) - } - - /// Returns the number of elements of type P in the table. - pub fn len(&self) -> usize { - self.data.len() / P::size_for(self.class) - } - - /// Returns whether the table is empty (contains zero elements). - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Parse the element at `index` in the table. - pub fn get(&self, index: usize) -> Result { - if self.data.is_empty() { - return Err(ParseError::BadOffset(index as u64)); - } - - let entsize = P::size_for(self.class); - let mut start = index - .checked_mul(entsize) - .ok_or(ParseError::IntegerOverflow)?; - if start > self.data.len() { - return Err(ParseError::BadOffset(index as u64)); - } - - P::parse_at(self.endian, self.class, &mut start, self.data) - } -} - -impl<'data, E: EndianParse, P: ParseAt> IntoIterator for ParsingTable<'data, E, P> { - type IntoIter = ParsingIterator<'data, E, P>; - type Item = P; - - fn into_iter(self) -> Self::IntoIter { - ParsingIterator::new(self.endian, self.class, self.data) - } -} - -// Simple convenience extension trait to wrap get() with .ok_or(SliceReadError) -pub(crate) trait ReadBytesExt<'data> { - fn get_bytes(self, range: Range) -> Result<&'data [u8], ParseError>; -} - -impl<'data> ReadBytesExt<'data> for &'data [u8] { - fn get_bytes(self, range: Range) -> Result<&'data [u8], ParseError> { - let start = range.start; - let end = range.end; - self.get(range) - .ok_or(ParseError::SliceReadError((start, end))) - } -} - -#[cfg(test)] -pub(crate) fn test_parse_for( - endian: E, - class: Class, - expected: P, -) { - let size = P::size_for(class); - let mut data = vec![0u8; size]; - for (n, elem) in data.iter_mut().enumerate().take(size) { - *elem = n as u8; - } - - let mut offset = 0; - let entry = P::parse_at(endian, class, &mut offset, data.as_ref()).expect("Failed to parse"); - - assert_eq!(entry, expected); - assert_eq!(offset, size); -} - -#[cfg(test)] -pub(crate) fn test_parse_fuzz_too_short( - endian: E, - class: Class, -) { - let size = P::size_for(class); - let data = vec![0u8; size]; - for n in 0..size { - let buf = data.split_at(n).0; - let mut offset: usize = 0; - let error = P::parse_at(endian, class, &mut offset, buf).expect_err("Expected an error"); - assert!( - matches!(error, ParseError::SliceReadError(_)), - "Unexpected Error type found: {error}" - ); - } -} - -#[cfg(test)] -mod read_bytes_tests { - use super::ParseError; - use super::ReadBytesExt; - - #[test] - fn get_bytes_works() { - let data = &[0u8, 1, 2, 3]; - let subslice = data.get_bytes(1..3).expect("should be within range"); - assert_eq!(subslice, [1, 2]); - } - - #[test] - fn get_bytes_out_of_range_errors() { - let data = &[0u8, 1, 2, 3]; - let err = data.get_bytes(3..9).expect_err("should be out of range"); - assert!( - matches!(err, ParseError::SliceReadError((3, 9))), - "Unexpected Error type found: {err}" - ); - } -} - -#[cfg(test)] -mod parsing_table_tests { - use crate::endian::{AnyEndian, BigEndian, LittleEndian}; - - use super::*; - - type U32Table<'data, E> = ParsingTable<'data, E, u32>; - - #[test] - fn test_u32_validate_entsize() { - assert!(matches!(u32::validate_entsize(Class::ELF32, 4), Ok(4))); - assert!(matches!( - u32::validate_entsize(Class::ELF32, 8), - Err(ParseError::BadEntsize((8, 4))) - )); - } - - #[test] - fn test_u32_parse_at() { - let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7]; - let mut offset = 2; - let result = u32::parse_at(LittleEndian, Class::ELF32, &mut offset, data.as_ref()) - .expect("Expected to parse but:"); - assert_eq!(result, 0x05040302); - } - - #[test] - fn test_u32_table_len() { - let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7]; - let table = U32Table::new(LittleEndian, Class::ELF32, data.as_ref()); - assert_eq!(table.len(), 2); - } - - #[test] - fn test_u32_table_is_empty() { - let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7]; - let table = U32Table::new(LittleEndian, Class::ELF32, data.as_ref()); - assert!(!table.is_empty()); - - let table = U32Table::new(LittleEndian, Class::ELF32, &[]); - assert!(table.is_empty()); - - let table = U32Table::new(LittleEndian, Class::ELF32, data.get(0..1).unwrap()); - assert!(table.is_empty()); - } - - #[test] - fn test_u32_table_get_parse_failure() { - let data = vec![0u8, 1]; - let table = U32Table::new(LittleEndian, Class::ELF32, data.as_ref()); - assert!(matches!( - table.get(0), - Err(ParseError::SliceReadError((0, 4))) - )); - } - - #[test] - fn test_lsb_u32_table_get() { - let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7]; - let table = U32Table::new(LittleEndian, Class::ELF32, data.as_ref()); - assert!(matches!(table.get(0), Ok(0x03020100))); - assert!(matches!(table.get(1), Ok(0x07060504))); - assert!(matches!(table.get(7), Err(ParseError::BadOffset(7)))); - } - - #[test] - fn test_any_lsb_u32_table_get() { - let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7]; - let table = U32Table::new(AnyEndian::Little, Class::ELF32, data.as_ref()); - assert!(matches!(table.get(0), Ok(0x03020100))); - assert!(matches!(table.get(1), Ok(0x07060504))); - assert!(matches!(table.get(7), Err(ParseError::BadOffset(7)))); - } - - #[test] - fn test_msb_u32_table_get() { - let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7]; - let table = U32Table::new(BigEndian, Class::ELF32, data.as_ref()); - assert!(matches!(table.get(0), Ok(0x00010203))); - assert!(matches!(table.get(1), Ok(0x04050607))); - assert!(matches!(table.get(7), Err(ParseError::BadOffset(7)))); - } - - #[test] - fn test_any_msb_u32_table_get() { - let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7]; - let table = U32Table::new(AnyEndian::Big, Class::ELF32, data.as_ref()); - assert!(matches!(table.get(0), Ok(0x00010203))); - assert!(matches!(table.get(1), Ok(0x04050607))); - assert!(matches!(table.get(7), Err(ParseError::BadOffset(7)))); - } - - #[test] - fn test_u32_table_get_unaligned() { - let data = [0u8, 1, 2, 3, 4, 5, 6, 7]; - let table = U32Table::new(LittleEndian, Class::ELF32, data.get(1..).unwrap()); - assert!(matches!(table.get(0), Ok(0x04030201))); - } -} diff --git a/arceos/modules/elf/src/relocation.rs b/arceos/modules/elf/src/relocation.rs deleted file mode 100644 index bbec4a0f3..000000000 --- a/arceos/modules/elf/src/relocation.rs +++ /dev/null @@ -1,299 +0,0 @@ -//! Parsing relocation sections: `.rel.*`, `.rela.*`, [SHT_REL](crate::abi::SHT_REL), [SHT_RELA](crate::abi::SHT_RELA) -use crate::endian::EndianParse; -use crate::file::Class; -use crate::parse::{ParseAt, ParseError, ParsingIterator}; - -pub type RelIterator<'data, E> = ParsingIterator<'data, E, Rel>; -pub type RelaIterator<'data, E> = ParsingIterator<'data, E, Rela>; - -/// C-style 32-bit ELF Relocation definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf32_Rel { - pub r_offset: u32, - pub r_info: u32, -} - -/// C-style 64-bit ELF Relocation definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf64_Rel { - pub r_offset: u64, - pub r_info: u64, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Rel { - pub r_offset: u64, - pub r_sym: u32, - pub r_type: u32, -} - -impl ParseAt for Rel { - fn parse_at( - endian: E, - class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - match class { - Class::ELF32 => { - let r_offset = endian.parse_u32_at(offset, data)? as u64; - let r_info = endian.parse_u32_at(offset, data)?; - Ok(Rel { - r_offset, - r_sym: r_info >> 8, - r_type: r_info & 0xFF, - }) - } - Class::ELF64 => { - let r_offset = endian.parse_u64_at(offset, data)?; - let r_info = endian.parse_u64_at(offset, data)?; - Ok(Rel { - r_offset, - r_sym: (r_info >> 32) as u32, - r_type: (r_info & 0xFFFFFFFF) as u32, - }) - } - } - } - - #[inline] - fn size_for(class: Class) -> usize { - match class { - Class::ELF32 => 8, - Class::ELF64 => 16, - } - } -} - -/// C-style 32-bit ELF Relocation (with addend) definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf32_Rela { - pub r_offset: u32, - pub r_info: u32, - pub r_addend: i32, -} - -/// C-style 64-bit ELF Relocation (with addend) definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf64_Rela { - pub r_offset: u64, - pub r_info: u64, - pub r_addend: i64, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Rela { - pub r_offset: u64, - pub r_sym: u32, - pub r_type: u32, - pub r_addend: i64, -} - -impl ParseAt for Rela { - fn parse_at( - endian: E, - class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - match class { - Class::ELF32 => { - let r_offset = endian.parse_u32_at(offset, data)? as u64; - let r_info = endian.parse_u32_at(offset, data)?; - let r_addend = endian.parse_i32_at(offset, data)? as i64; - Ok(Rela { - r_offset, - r_sym: r_info >> 8, - r_type: r_info & 0xFF, - r_addend, - }) - } - Class::ELF64 => { - let r_offset = endian.parse_u64_at(offset, data)?; - let r_info = endian.parse_u64_at(offset, data)?; - let r_addend = endian.parse_i64_at(offset, data)?; - Ok(Rela { - r_offset, - r_sym: (r_info >> 32) as u32, - r_type: (r_info & 0xFFFFFFFF) as u32, - r_addend, - }) - } - } - } - - #[inline] - fn size_for(class: Class) -> usize { - match class { - Class::ELF32 => 12, - Class::ELF64 => 24, - } - } -} - -#[cfg(test)] -mod parse_tests { - use super::*; - use crate::endian::{BigEndian, LittleEndian}; - use crate::parse::{test_parse_for, test_parse_fuzz_too_short}; - - #[test] - fn parse_rel32_lsb() { - test_parse_for( - LittleEndian, - Class::ELF32, - Rel { - r_offset: 0x03020100, - r_sym: 0x00070605, - r_type: 0x00000004, - }, - ); - } - - #[test] - fn parse_rel32_msb() { - test_parse_for( - BigEndian, - Class::ELF32, - Rel { - r_offset: 0x00010203, - r_sym: 0x00040506, - r_type: 0x00000007, - }, - ); - } - - #[test] - fn parse_rel64_lsb() { - test_parse_for( - LittleEndian, - Class::ELF64, - Rel { - r_offset: 0x0706050403020100, - r_sym: 0x0F0E0D0C, - r_type: 0x0B0A0908, - }, - ); - } - - #[test] - fn parse_rel64_msb() { - test_parse_for( - BigEndian, - Class::ELF64, - Rel { - r_offset: 0x0001020304050607, - r_sym: 0x08090A0B, - r_type: 0x0C0D0E0F, - }, - ); - } - - #[test] - fn parse_rel32_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Rel>(LittleEndian, Class::ELF32); - } - - #[test] - fn parse_rel32_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Rel>(BigEndian, Class::ELF32); - } - - #[test] - fn parse_rel64_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Rel>(LittleEndian, Class::ELF64); - } - - #[test] - fn parse_rel64_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Rel>(BigEndian, Class::ELF64); - } - - #[test] - fn parse_rela32_lsb() { - test_parse_for( - LittleEndian, - Class::ELF32, - Rela { - r_offset: 0x03020100, - r_sym: 0x00070605, - r_type: 0x00000004, - r_addend: 0x0B0A0908, - }, - ); - } - - #[test] - fn parse_rela32_msb() { - test_parse_for( - BigEndian, - Class::ELF32, - Rela { - r_offset: 0x00010203, - r_sym: 0x00040506, - r_type: 0x00000007, - r_addend: 0x08090A0B, - }, - ); - } - - #[test] - fn parse_rela64_lsb() { - test_parse_for( - LittleEndian, - Class::ELF64, - Rela { - r_offset: 0x0706050403020100, - r_sym: 0x0F0E0D0C, - r_type: 0x0B0A0908, - r_addend: 0x1716151413121110, - }, - ); - } - - #[test] - fn parse_rela64_msb() { - test_parse_for( - BigEndian, - Class::ELF64, - Rela { - r_offset: 0x0001020304050607, - r_sym: 0x08090A0B, - r_type: 0x0C0D0E0F, - r_addend: 0x1011121314151617, - }, - ); - } - - #[test] - fn parse_rela32_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Rela>(LittleEndian, Class::ELF32); - } - - #[test] - fn parse_rela32_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Rela>(BigEndian, Class::ELF32); - } - - #[test] - fn parse_rela64_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Rela>(LittleEndian, Class::ELF64); - } - - #[test] - fn parse_rela64_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Rela>(BigEndian, Class::ELF64); - } -} diff --git a/arceos/modules/elf/src/section.rs b/arceos/modules/elf/src/section.rs deleted file mode 100644 index a9730516d..000000000 --- a/arceos/modules/elf/src/section.rs +++ /dev/null @@ -1,231 +0,0 @@ -//! Parsing the Section Header table -use crate::endian::EndianParse; -use crate::file::Class; -use crate::parse::{ParseAt, ParseError, ParsingTable}; - -pub type SectionHeaderTable<'data, E> = ParsingTable<'data, E, SectionHeader>; - -/// C-style 32-bit ELF Section Header definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf32_Shdr { - pub sh_name: u32, - pub sh_type: u32, - pub sh_flags: u32, - pub sh_addr: u32, - pub sh_offset: u32, - pub sh_size: u32, - pub sh_link: u32, - pub sh_info: u32, - pub sh_addralign: u32, - pub sh_entsize: u32, -} - -/// C-style 64-bit ELF Section Header definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf64_Shdr { - pub sh_name: u32, - pub sh_type: u32, - pub sh_flags: u64, - pub sh_addr: u64, - pub sh_offset: u64, - pub sh_size: u64, - pub sh_link: u32, - pub sh_info: u32, - pub sh_addralign: u64, - pub sh_entsize: u64, -} - -/// Encapsulates the contents of an ELF Section Header -/// -/// This is a Rust-native type that represents a Section Header that is bit-width-agnostic. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct SectionHeader { - /// Section Name - pub sh_name: u32, - /// Section Type - pub sh_type: u32, - /// Section Flags - pub sh_flags: u64, - /// in-memory address where this section is loaded - pub sh_addr: u64, - /// Byte-offset into the file where this section starts - pub sh_offset: u64, - /// Section size in bytes - pub sh_size: u64, - /// Defined by section type - pub sh_link: u32, - /// Defined by section type - pub sh_info: u32, - /// address alignment - pub sh_addralign: u64, - /// size of an entry if section data is an array of entries - pub sh_entsize: u64, -} - -impl ParseAt for SectionHeader { - fn parse_at( - endian: E, - class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - match class { - Class::ELF32 => Ok(SectionHeader { - sh_name: endian.parse_u32_at(offset, data)?, - sh_type: endian.parse_u32_at(offset, data)?, - sh_flags: endian.parse_u32_at(offset, data)? as u64, - sh_addr: endian.parse_u32_at(offset, data)? as u64, - sh_offset: endian.parse_u32_at(offset, data)? as u64, - sh_size: endian.parse_u32_at(offset, data)? as u64, - sh_link: endian.parse_u32_at(offset, data)?, - sh_info: endian.parse_u32_at(offset, data)?, - sh_addralign: endian.parse_u32_at(offset, data)? as u64, - sh_entsize: endian.parse_u32_at(offset, data)? as u64, - }), - Class::ELF64 => Ok(SectionHeader { - sh_name: endian.parse_u32_at(offset, data)?, - sh_type: endian.parse_u32_at(offset, data)?, - sh_flags: endian.parse_u64_at(offset, data)?, - sh_addr: endian.parse_u64_at(offset, data)?, - sh_offset: endian.parse_u64_at(offset, data)?, - sh_size: endian.parse_u64_at(offset, data)?, - sh_link: endian.parse_u32_at(offset, data)?, - sh_info: endian.parse_u32_at(offset, data)?, - sh_addralign: endian.parse_u64_at(offset, data)?, - sh_entsize: endian.parse_u64_at(offset, data)?, - }), - } - } - - #[inline] - fn size_for(class: Class) -> usize { - match class { - Class::ELF32 => 40, - Class::ELF64 => 64, - } - } -} - -impl SectionHeader { - /// Helper method which uses checked integer math to get a tuple of (start,end) for - /// this SectionHeader's (sh_offset, sh_offset + sh_size) - pub(crate) fn get_data_range(&self) -> Result<(usize, usize), ParseError> { - let start: usize = self.sh_offset.try_into()?; - let size: usize = self.sh_size.try_into()?; - let end = start.checked_add(size).ok_or(ParseError::IntegerOverflow)?; - Ok((start, end)) - } -} - -#[cfg(test)] -mod parse_tests { - use super::*; - use crate::endian::{BigEndian, LittleEndian}; - use crate::parse::{test_parse_for, test_parse_fuzz_too_short}; - - #[test] - fn parse_shdr32_lsb() { - test_parse_for( - LittleEndian, - Class::ELF32, - SectionHeader { - sh_name: 0x03020100, - sh_type: 0x07060504, - sh_flags: 0xB0A0908, - sh_addr: 0x0F0E0D0C, - sh_offset: 0x13121110, - sh_size: 0x17161514, - sh_link: 0x1B1A1918, - sh_info: 0x1F1E1D1C, - sh_addralign: 0x23222120, - sh_entsize: 0x27262524, - }, - ); - } - - #[test] - fn parse_shdr32_msb() { - test_parse_for( - BigEndian, - Class::ELF32, - SectionHeader { - sh_name: 0x00010203, - sh_type: 0x04050607, - sh_flags: 0x08090A0B, - sh_addr: 0x0C0D0E0F, - sh_offset: 0x10111213, - sh_size: 0x14151617, - sh_link: 0x18191A1B, - sh_info: 0x1C1D1E1F, - sh_addralign: 0x20212223, - sh_entsize: 0x24252627, - }, - ); - } - - #[test] - fn parse_shdr64_lsb() { - test_parse_for( - LittleEndian, - Class::ELF64, - SectionHeader { - sh_name: 0x03020100, - sh_type: 0x07060504, - sh_flags: 0x0F0E0D0C0B0A0908, - sh_addr: 0x1716151413121110, - sh_offset: 0x1F1E1D1C1B1A1918, - sh_size: 0x2726252423222120, - sh_link: 0x2B2A2928, - sh_info: 0x2F2E2D2C, - sh_addralign: 0x3736353433323130, - sh_entsize: 0x3F3E3D3C3B3A3938, - }, - ); - } - - #[test] - fn parse_shdr64_msb() { - test_parse_for( - BigEndian, - Class::ELF64, - SectionHeader { - sh_name: 0x00010203, - sh_type: 0x04050607, - sh_flags: 0x08090A0B0C0D0E0F, - sh_addr: 0x1011121314151617, - sh_offset: 0x18191A1B1C1D1E1F, - sh_size: 0x2021222324252627, - sh_link: 0x28292A2B, - sh_info: 0x2C2D2E2F, - sh_addralign: 0x3031323334353637, - sh_entsize: 0x38393A3B3C3D3E3F, - }, - ); - } - - #[test] - fn parse_shdr32_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, SectionHeader>(LittleEndian, Class::ELF32); - } - - #[test] - fn parse_shdr32_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, SectionHeader>(BigEndian, Class::ELF32); - } - - #[test] - fn parse_shdr64_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, SectionHeader>(LittleEndian, Class::ELF64); - } - - #[test] - fn parse_shdr64_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, SectionHeader>(BigEndian, Class::ELF64); - } -} diff --git a/arceos/modules/elf/src/segment.rs b/arceos/modules/elf/src/segment.rs deleted file mode 100644 index 737fc9fbe..000000000 --- a/arceos/modules/elf/src/segment.rs +++ /dev/null @@ -1,223 +0,0 @@ -//! Parsing the Program Header table aka Segment table aka `Elf_Phdr` -use crate::endian::EndianParse; -use crate::file::Class; -use crate::parse::{ParseAt, ParseError, ParsingTable}; - -pub type SegmentTable<'data, E> = ParsingTable<'data, E, ProgramHeader>; - -/// C-style 32-bit ELF Program Segment Header definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf32_Phdr { - pub p_type: u32, - pub p_offset: u32, - pub p_vaddr: u32, - pub p_paddr: u32, - pub p_filesz: u32, - pub p_memsz: u32, - pub p_flags: u32, - pub p_align: u32, -} - -/// C-style 64-bit ELF Program Segment Header definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf64_Phdr { - pub p_type: u32, - pub p_flags: u32, - pub p_offset: u64, - pub p_vaddr: u64, - pub p_paddr: u64, - pub p_filesz: u64, - pub p_memsz: u64, - pub p_align: u64, -} - -/// Encapsulates the contents of an ELF Program Header -/// -/// The program header table is an array of program header structures describing -/// the various segments for program execution. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct ProgramHeader { - /// Program segment type - pub p_type: u32, - /// Offset into the ELF file where this segment begins - pub p_offset: u64, - /// Virtual adress where this segment should be loaded - pub p_vaddr: u64, - /// Physical address where this segment should be loaded - pub p_paddr: u64, - /// Size of this segment in the file - pub p_filesz: u64, - /// Size of this segment in memory - pub p_memsz: u64, - /// Flags for this segment - pub p_flags: u32, - /// file and memory alignment - pub p_align: u64, -} - -impl ParseAt for ProgramHeader { - fn parse_at( - endian: E, - class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - if class == Class::ELF32 { - return Ok(ProgramHeader { - p_type: endian.parse_u32_at(offset, data)?, - p_offset: endian.parse_u32_at(offset, data)? as u64, - p_vaddr: endian.parse_u32_at(offset, data)? as u64, - p_paddr: endian.parse_u32_at(offset, data)? as u64, - p_filesz: endian.parse_u32_at(offset, data)? as u64, - p_memsz: endian.parse_u32_at(offset, data)? as u64, - p_flags: endian.parse_u32_at(offset, data)?, - p_align: endian.parse_u32_at(offset, data)? as u64, - }); - } - - // Note: 64-bit fields are in a different order - let p_type = endian.parse_u32_at(offset, data)?; - let p_flags = endian.parse_u32_at(offset, data)?; - let p_offset = endian.parse_u64_at(offset, data)?; - let p_vaddr = endian.parse_u64_at(offset, data)?; - let p_paddr = endian.parse_u64_at(offset, data)?; - let p_filesz = endian.parse_u64_at(offset, data)?; - let p_memsz = endian.parse_u64_at(offset, data)?; - let p_align = endian.parse_u64_at(offset, data)?; - Ok(ProgramHeader { - p_type, - p_offset, - p_vaddr, - p_paddr, - p_filesz, - p_memsz, - p_flags, - p_align, - }) - } - - #[inline] - fn size_for(class: Class) -> usize { - match class { - Class::ELF32 => 32, - Class::ELF64 => 56, - } - } -} - -impl ProgramHeader { - /// Helper method which uses checked integer math to get a tuple of (start, end) for - /// the location in bytes for this ProgramHeader's data in the file. - /// i.e. (p_offset, p_offset + p_filesz) - pub fn get_file_data_range(&self) -> Result<(usize, usize), ParseError> { - let start: usize = self.p_offset.try_into()?; - let size: usize = self.p_filesz.try_into()?; - let end = start.checked_add(size).ok_or(ParseError::IntegerOverflow)?; - Ok((start, end)) - } -} - -#[cfg(test)] -mod parse_tests { - use super::*; - use crate::endian::{BigEndian, LittleEndian}; - use crate::parse::{test_parse_for, test_parse_fuzz_too_short}; - - #[test] - fn parse_phdr32_lsb() { - test_parse_for( - LittleEndian, - Class::ELF32, - ProgramHeader { - p_type: 0x03020100, - p_offset: 0x07060504, - p_vaddr: 0xB0A0908, - p_paddr: 0x0F0E0D0C, - p_filesz: 0x13121110, - p_memsz: 0x17161514, - p_flags: 0x1B1A1918, - p_align: 0x1F1E1D1C, - }, - ); - } - - #[test] - fn parse_phdr32_msb() { - test_parse_for( - BigEndian, - Class::ELF32, - ProgramHeader { - p_type: 0x00010203, - p_offset: 0x04050607, - p_vaddr: 0x08090A0B, - p_paddr: 0x0C0D0E0F, - p_filesz: 0x10111213, - p_memsz: 0x14151617, - p_flags: 0x18191A1B, - p_align: 0x1C1D1E1F, - }, - ); - } - - #[test] - fn parse_phdr64_lsb() { - test_parse_for( - LittleEndian, - Class::ELF64, - ProgramHeader { - p_type: 0x03020100, - p_offset: 0x0F0E0D0C0B0A0908, - p_vaddr: 0x1716151413121110, - p_paddr: 0x1F1E1D1C1B1A1918, - p_filesz: 0x2726252423222120, - p_memsz: 0x2F2E2D2C2B2A2928, - p_flags: 0x07060504, - p_align: 0x3736353433323130, - }, - ); - } - - #[test] - fn parse_phdr64_msb() { - test_parse_for( - BigEndian, - Class::ELF64, - ProgramHeader { - p_type: 0x00010203, - p_offset: 0x08090A0B0C0D0E0F, - p_vaddr: 0x1011121314151617, - p_paddr: 0x18191A1B1C1D1E1F, - p_filesz: 0x2021222324252627, - p_memsz: 0x28292A2B2C2D2E2F, - p_flags: 0x04050607, - p_align: 0x3031323334353637, - }, - ); - } - - #[test] - fn parse_phdr32_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, ProgramHeader>(LittleEndian, Class::ELF32); - } - - #[test] - fn parse_phdr32_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, ProgramHeader>(BigEndian, Class::ELF32); - } - - #[test] - fn parse_phdr64_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, ProgramHeader>(LittleEndian, Class::ELF64); - } - - #[test] - fn parse_phdr64_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, ProgramHeader>(BigEndian, Class::ELF64); - } -} diff --git a/arceos/modules/elf/src/string_table.rs b/arceos/modules/elf/src/string_table.rs deleted file mode 100644 index 0311cb0a2..000000000 --- a/arceos/modules/elf/src/string_table.rs +++ /dev/null @@ -1,116 +0,0 @@ -//! Interpreting string table sections: `.strtab`, [SHT_STRTAB][crate::abi::SHT_STRTAB] -use crate::parse::ParseError; -use core::str::from_utf8; - -#[derive(Debug, Default, Clone, Copy)] -pub struct StringTable<'data> { - data: &'data [u8], -} - -impl<'data> StringTable<'data> { - pub fn new(data: &'data [u8]) -> Self { - StringTable { data } - } - - pub fn get_raw(&self, offset: usize) -> Result<&'data [u8], ParseError> { - if self.data.is_empty() { - return Err(ParseError::BadOffset(offset as u64)); - }; - - let start = self - .data - .get(offset..) - .ok_or(ParseError::BadOffset(offset as u64))?; - let end = start - .iter() - .position(|&b| b == 0u8) - .ok_or(ParseError::StringTableMissingNul(offset as u64))?; - - Ok(start.split_at(end).0) - } - - pub fn get(&self, offset: usize) -> Result<&'data str, ParseError> { - let raw_data = self.get_raw(offset)?; - Ok(from_utf8(raw_data)?) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_empty_table_errors() { - let st = StringTable::default(); - assert!(matches!(st.get(0), Err(ParseError::BadOffset(0)))); - assert!(matches!(st.get(1), Err(ParseError::BadOffset(1)))); - } - - /// Note: ELF string tables are defined to always start with a NUL and use - /// index 0 to give an empty string, so getting a string starting at a NUL - /// should properly give an empty string. - #[test] - fn test_get_index_0_gives_empty_string() { - let data = [0u8, 42u8, 0u8]; - let st = StringTable::new(&data); - assert_eq!(st.get(0).unwrap(), ""); - } - - #[test] - fn test_get_raw_works() { - let data = [0u8, 0x45, 0x4C, 0x46, 0u8]; - let st = StringTable::new(&data); - assert_eq!(st.get_raw(1).unwrap(), [0x45, 0x4c, 0x46]); - } - - #[test] - fn test_get_string_works() { - let data = [0u8, 0x45, 0x4C, 0x46, 0u8]; - let st = StringTable::new(&data); - assert_eq!(st.get(1).unwrap(), "ELF"); - } - - #[test] - fn test_get_raw_index_out_of_bounds_errors() { - let data = [0u8, 0x45, 0x4C, 0x46, 0u8]; - let st = StringTable::new(&data); - let result = st.get_raw(7); - assert!( - matches!(result, Err(ParseError::BadOffset(7))), - "Unexpected Error type found: {result:?}" - ); - } - - #[test] - fn test_get_index_out_of_bounds_errors() { - let data = [0u8, 0x45, 0x4C, 0x46, 0u8]; - let st = StringTable::new(&data); - let result = st.get(7); - assert!( - matches!(result, Err(ParseError::BadOffset(7))), - "Unexpected Error type found: {result:?}" - ); - } - - #[test] - fn test_get_raw_with_malformed_table_no_trailing_nul() { - let data = [0u8, 0x45, 0x4C, 0x46]; - let st = StringTable::new(&data); - let result = st.get_raw(1); - assert!( - matches!(result, Err(ParseError::StringTableMissingNul(1))), - "Unexpected Error type found: {result:?}" - ); - } - - #[test] - fn test_get_with_malformed_table_no_trailing_nul() { - let data = [0u8, 0x45, 0x4C, 0x46]; - let st = StringTable::new(&data); - let result = st.get(1); - assert!( - matches!(result, Err(ParseError::StringTableMissingNul(1))), - "Unexpected Error type found: {result:?}" - ); - } -} diff --git a/arceos/modules/elf/src/symbol.rs b/arceos/modules/elf/src/symbol.rs deleted file mode 100644 index 90a12b4a3..000000000 --- a/arceos/modules/elf/src/symbol.rs +++ /dev/null @@ -1,271 +0,0 @@ -//! Parsing symbol table sections: `.symtab`, `.dynsym` -use crate::abi; -use crate::endian::EndianParse; -use crate::file::Class; -use crate::parse::{ParseAt, ParseError, ParsingTable}; - -pub type SymbolTable<'data, E> = ParsingTable<'data, E, Symbol>; - -/// C-style 32-bit ELF Symbol definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf32_Sym { - pub st_name: u32, - pub st_value: u32, - pub st_size: u32, - pub st_info: u8, - pub st_other: u8, - pub st_shndx: u32, -} - -/// C-style 64-bit ELF Symbol definition -/// -/// These C-style definitions are for users who want to implement their own ELF manipulation logic. -#[derive(Debug)] -#[repr(C)] -pub struct Elf64_Sym { - pub st_name: u32, - pub st_info: u8, - pub st_other: u8, - pub st_shndx: u16, - pub st_value: u64, - pub st_size: u64, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Symbol { - /// This member holds an index into the symbol table's string table, - /// which holds the character representations of the symbol names. If the - /// value is non-zero, it represents a string table index that gives the - /// symbol name. Otherwise, the symbol table entry has no name. - pub st_name: u32, - - /// Every symbol table entry is defined in relation to some section. This - /// member holds the relevant section header table index. As the sh_link and - /// sh_info interpretation table and the related text describe, some section - /// indexes indicate special meanings. - /// - /// If this member contains SHN_XINDEX, then the actual section header index - /// is too large to fit in this field. The actual value is contained in the - /// associated section of type SHT_SYMTAB_SHNDX. - pub st_shndx: u16, - - /// This member specifies the symbol's type and binding attributes. - pub(super) st_info: u8, - - /// This member currently specifies a symbol's visibility. - pub(super) st_other: u8, - - /// This member gives the value of the associated symbol. Depending on the - /// context, this may be an absolute value, an address, and so on. - /// - /// * In relocatable files, st_value holds alignment constraints for a - /// symbol whose section index is SHN_COMMON. - /// * In relocatable files, st_value holds a section offset for a defined - /// symbol. st_value is an offset from the beginning of the section that - /// st_shndx identifies. - /// * In executable and shared object files, st_value holds a virtual - /// address. To make these files' symbols more useful for the dynamic - /// linker, the section offset (file interpretation) gives way to a - /// virtual address (memory interpretation) for which the section number - /// is irrelevant. - pub st_value: u64, - - /// This member gives the symbol's size. - /// For example, a data object's size is the number of bytes contained in - /// the object. This member holds 0 if the symbol has no size or an unknown - /// size. - pub st_size: u64, -} - -impl Symbol { - /// Returns true if a symbol is undefined in this ELF object. - /// - /// When linking and loading, undefined symbols in this object get linked to - /// a defined symbol in another object. - pub fn is_undefined(&self) -> bool { - self.st_shndx == abi::SHN_UNDEF - } - - pub fn st_symtype(&self) -> u8 { - self.st_info & 0xf - } - - pub fn st_bind(&self) -> u8 { - self.st_info >> 4 - } - - pub fn st_vis(&self) -> u8 { - self.st_other & 0x3 - } -} - -impl ParseAt for Symbol { - fn parse_at( - endian: E, - class: Class, - offset: &mut usize, - data: &[u8], - ) -> Result { - let st_name: u32; - let st_value: u64; - let st_size: u64; - let st_shndx: u16; - let st_info: u8; - let st_other: u8; - - if class == Class::ELF32 { - st_name = endian.parse_u32_at(offset, data)?; - st_value = endian.parse_u32_at(offset, data)? as u64; - st_size = endian.parse_u32_at(offset, data)? as u64; - st_info = endian.parse_u8_at(offset, data)?; - st_other = endian.parse_u8_at(offset, data)?; - st_shndx = endian.parse_u16_at(offset, data)?; - } else { - st_name = endian.parse_u32_at(offset, data)?; - st_info = endian.parse_u8_at(offset, data)?; - st_other = endian.parse_u8_at(offset, data)?; - st_shndx = endian.parse_u16_at(offset, data)?; - st_value = endian.parse_u64_at(offset, data)?; - st_size = endian.parse_u64_at(offset, data)?; - } - - Ok(Symbol { - st_name, - st_value, - st_size, - st_shndx, - st_info, - st_other, - }) - } - - #[inline] - fn size_for(class: Class) -> usize { - match class { - Class::ELF32 => 16, - Class::ELF64 => 24, - } - } -} - -#[cfg(test)] -mod symbol_tests { - use super::*; - - #[test] - fn symbol_undefined() { - let undef_sym = Symbol { - st_name: 0, - st_value: 0, - st_size: 0, - st_shndx: 0, - st_info: 0, - st_other: 0, - }; - assert!(undef_sym.is_undefined()); - - let def_sym = Symbol { - st_name: 0, - st_value: 0, - st_size: 0, - st_shndx: 42, - st_info: 0, - st_other: 0, - }; - assert!(!def_sym.is_undefined()); - } -} - -#[cfg(test)] -mod parse_tests { - use super::*; - use crate::endian::{BigEndian, LittleEndian}; - use crate::parse::{test_parse_for, test_parse_fuzz_too_short}; - - #[test] - fn parse_sym32_lsb() { - test_parse_for( - LittleEndian, - Class::ELF32, - Symbol { - st_name: 0x03020100, - st_value: 0x07060504, - st_size: 0x0B0A0908, - st_shndx: 0x0F0E, - st_info: 0x0C, - st_other: 0x0D, - }, - ); - } - - #[test] - fn parse_sym32_msb() { - test_parse_for( - BigEndian, - Class::ELF32, - Symbol { - st_name: 0x00010203, - st_value: 0x04050607, - st_size: 0x08090A0B, - st_shndx: 0x0E0F, - st_info: 0x0C, - st_other: 0x0D, - }, - ); - } - - #[test] - fn parse_sym64_lsb() { - test_parse_for( - LittleEndian, - Class::ELF64, - Symbol { - st_name: 0x03020100, - st_value: 0x0F0E0D0C0B0A0908, - st_size: 0x1716151413121110, - st_shndx: 0x0706, - st_info: 0x04, - st_other: 0x05, - }, - ); - } - - #[test] - fn parse_sym64_msb() { - test_parse_for( - BigEndian, - Class::ELF64, - Symbol { - st_name: 0x00010203, - st_value: 0x08090A0B0C0D0E0F, - st_size: 0x1011121314151617, - st_shndx: 0x0607, - st_info: 0x04, - st_other: 0x05, - }, - ); - } - - #[test] - fn parse_sym32_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Symbol>(LittleEndian, Class::ELF32); - } - - #[test] - fn parse_sym32_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Symbol>(BigEndian, Class::ELF32); - } - - #[test] - fn parse_sym64_lsb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Symbol>(LittleEndian, Class::ELF64); - } - - #[test] - fn parse_sym64_msb_fuzz_too_short() { - test_parse_fuzz_too_short::<_, Symbol>(BigEndian, Class::ELF64); - } -} diff --git a/arceos/modules/elf/src/to_str.rs b/arceos/modules/elf/src/to_str.rs deleted file mode 100644 index 0f1e2e24a..000000000 --- a/arceos/modules/elf/src/to_str.rs +++ /dev/null @@ -1,677 +0,0 @@ -//! Optional module for getting string representations of ELF constants -use crate::abi; - -pub fn e_osabi_to_str(e_osabi: u8) -> Option<&'static str> { - match e_osabi { - abi::ELFOSABI_SYSV => Some("ELFOSABI_SYSV"), - abi::ELFOSABI_HPUX => Some("ELFOSABI_HPUX"), - abi::ELFOSABI_NETBSD => Some("ELFOSABI_NETBSD"), - abi::ELFOSABI_LINUX => Some("ELFOSABI_LINUX"), - abi::ELFOSABI_SOLARIS => Some("ELFOSABI_SOLARIS"), - abi::ELFOSABI_AIX => Some("ELFOSABI_AIX"), - abi::ELFOSABI_IRIX => Some("ELFOSABI_IRIX"), - abi::ELFOSABI_FREEBSD => Some("ELFOSABI_FREEBSD"), - abi::ELFOSABI_TRU64 => Some("ELFOSABI_TRU64"), - abi::ELFOSABI_MODESTO => Some("ELFOSABI_MODESTO"), - abi::ELFOSABI_OPENBSD => Some("ELFOSABI_OPENBSD"), - abi::ELFOSABI_OPENVMS => Some("ELFOSABI_OPENVMS"), - abi::ELFOSABI_NSK => Some("ELFOSABI_NSK"), - abi::ELFOSABI_AROS => Some("ELFOSABI_AROS"), - abi::ELFOSABI_FENIXOS => Some("ELFOSABI_FENIXOS"), - abi::ELFOSABI_CLOUDABI => Some("ELFOSABI_CLOUDABI"), - abi::ELFOSABI_OPENVOS => Some("ELFOSABI_OPENVOS"), - _ => None, - } -} - -pub fn e_osabi_to_string(e_osabi: u8) -> String { - match e_osabi_to_str(e_osabi) { - Some(s) => s.to_string(), - None => format!("e_osabi({e_osabi:#x})"), - } -} - -pub fn e_type_to_human_str(e_type: u16) -> Option<&'static str> { - match e_type { - abi::ET_NONE => Some("No file type"), - abi::ET_REL => Some("Relocatable file"), - abi::ET_EXEC => Some("Executable file"), - abi::ET_DYN => Some("Shared object file"), - abi::ET_CORE => Some("Core file"), - _ => None, - } -} - -pub fn e_type_to_str(e_type: u16) -> Option<&'static str> { - match e_type { - abi::ET_NONE => Some("ET_NONE"), - abi::ET_REL => Some("ET_REL"), - abi::ET_EXEC => Some("ET_EXEC"), - abi::ET_DYN => Some("ET_DYN"), - abi::ET_CORE => Some("ET_CORE"), - _ => None, - } -} - -pub fn e_type_to_string(e_type: u16) -> String { - match e_type_to_str(e_type) { - Some(s) => s.to_string(), - None => format!("e_type({e_type:#x})"), - } -} - -pub fn e_machine_to_human_str(e_machine: u16) -> Option<&'static str> { - match e_machine { - abi::EM_NONE => Some("No machine"), - abi::EM_M32 => Some("AT&T WE 32100"), - abi::EM_SPARC => Some("SPARC"), - abi::EM_386 => Some("Intel 80386"), - abi::EM_68K => Some("Motorola 68000"), - abi::EM_88K => Some("Motorola 88000"), - abi::EM_IAMCU => Some("Intel MCU"), - abi::EM_860 => Some("Intel 80860"), - abi::EM_MIPS => Some("MIPS I Architecture"), - abi::EM_S370 => Some("IBM System/370 Processor"), - abi::EM_MIPS_RS3_LE => Some("MIPS RS3000 Little-endian"), - abi::EM_PARISC => Some("Hewlett-Packard PA-RISC"), - abi::EM_VPP500 => Some("Fujitsu VPP500"), - abi::EM_SPARC32PLUS => Some("Enhanced instruction set SPARC"), - abi::EM_960 => Some("Intel 80960"), - abi::EM_PPC => Some("PowerPC"), - abi::EM_PPC64 => Some("64-bit PowerPC"), - abi::EM_S390 => Some("IBM System/390 Processor"), - abi::EM_SPU => Some("IBM SPU/SPC"), - abi::EM_V800 => Some("NEC V800"), - abi::EM_FR20 => Some("Fujitsu FR20"), - abi::EM_RH32 => Some("TRW RH-32"), - abi::EM_RCE => Some("Motorola RCE"), - abi::EM_ARM => Some("ARM 32-bit architecture (AARCH32)"), - abi::EM_ALPHA => Some("Digital Alpha"), - abi::EM_SH => Some("Hitachi SH"), - abi::EM_SPARCV9 => Some("SPARC Version 9"), - abi::EM_TRICORE => Some("Siemens TriCore embedded processor"), - abi::EM_ARC => Some("Argonaut RISC Core, Argonaut Technologies Inc."), - abi::EM_H8_300 => Some("Hitachi H8/300"), - abi::EM_H8_300H => Some("Hitachi H8/300H"), - abi::EM_H8S => Some("Hitachi H8S"), - abi::EM_H8_500 => Some("Hitachi H8/500"), - abi::EM_IA_64 => Some("Intel IA-64 processor architecture"), - abi::EM_MIPS_X => Some("Stanford MIPS-X"), - abi::EM_COLDFIRE => Some("Motorola ColdFire"), - abi::EM_68HC12 => Some("Motorola M68HC12"), - abi::EM_MMA => Some("Fujitsu MMA Multimedia Accelerator"), - abi::EM_PCP => Some("Siemens PCP"), - abi::EM_NCPU => Some("Sony nCPU embedded RISC processor"), - abi::EM_NDR1 => Some("Denso NDR1 microprocessor"), - abi::EM_STARCORE => Some("Motorola Star*Core processor"), - abi::EM_ME16 => Some("Toyota ME16 processor"), - abi::EM_ST100 => Some("STMicroelectronics ST100 processor"), - abi::EM_TINYJ => Some("Advanced Logic Corp. TinyJ embedded processor family"), - abi::EM_X86_64 => Some("AMD x86-64 architecture"), - abi::EM_PDSP => Some("Sony DSP Processor"), - abi::EM_PDP10 => Some("Digital Equipment Corp. PDP-10"), - abi::EM_PDP11 => Some("Digital Equipment Corp. PDP-11"), - abi::EM_FX66 => Some("Siemens FX66 microcontroller"), - abi::EM_ST9PLUS => Some("STMicroelectronics ST9+ 8/16 bit microcontroller"), - abi::EM_ST7 => Some("STMicroelectronics ST7 8-bit microcontroller"), - abi::EM_68HC16 => Some("Motorola MC68HC16 Microcontroller"), - abi::EM_68HC11 => Some("Motorola MC68HC11 Microcontroller"), - abi::EM_68HC08 => Some("Motorola MC68HC08 Microcontroller"), - abi::EM_68HC05 => Some("Motorola MC68HC05 Microcontroller"), - abi::EM_SVX => Some("Silicon Graphics SVx"), - abi::EM_ST19 => Some("STMicroelectronics ST19 8-bit microcontroller"), - abi::EM_VAX => Some("Digital VAX"), - abi::EM_CRIS => Some("Axis Communications 32-bit embedded processor"), - abi::EM_JAVELIN => Some("Infineon Technologies 32-bit embedded processor"), - abi::EM_FIREPATH => Some("Element 14 64-bit DSP Processor"), - abi::EM_ZSP => Some("LSI Logic 16-bit DSP Processor"), - abi::EM_MMIX => Some("Donald Knuth's educational 64-bit processor"), - abi::EM_HUANY => Some("Harvard University machine-independent object files"), - abi::EM_PRISM => Some("SiTera Prism"), - abi::EM_AVR => Some("Atmel AVR 8-bit microcontroller"), - abi::EM_FR30 => Some("Fujitsu FR30"), - abi::EM_D10V => Some("Mitsubishi D10V"), - abi::EM_D30V => Some("Mitsubishi D30V"), - abi::EM_V850 => Some("NEC v850"), - abi::EM_M32R => Some("Mitsubishi M32R"), - abi::EM_MN10300 => Some("Matsushita MN10300"), - abi::EM_MN10200 => Some("Matsushita MN10200"), - abi::EM_PJ => Some("picoJava"), - abi::EM_OPENRISC => Some("OpenRISC 32-bit embedded processor"), - abi::EM_ARC_COMPACT => Some("ARC International ARCompact processor"), - abi::EM_XTENSA => Some("Tensilica Xtensa Architecture"), - abi::EM_VIDEOCORE => Some("Alphamosaic VideoCore processor"), - abi::EM_TMM_GPP => Some("Thompson Multimedia General Purpose Processor"), - abi::EM_NS32K => Some("National Semiconductor 32000 series"), - abi::EM_TPC => Some("Tenor Network TPC processor"), - abi::EM_SNP1K => Some("Trebia SNP 1000 processor"), - abi::EM_ST200 => Some("STMicroelectronics (www.st.com) ST200 microcontroller"), - abi::EM_IP2K => Some("Ubicom IP2xxx microcontroller family"), - abi::EM_MAX => Some("MAX Processor"), - abi::EM_CR => Some("National Semiconductor CompactRISC microprocessor"), - abi::EM_F2MC16 => Some("Fujitsu F2MC16"), - abi::EM_MSP430 => Some("Texas Instruments embedded microcontroller msp430"), - abi::EM_BLACKFIN => Some("Analog Devices Blackfin (DSP) processor"), - abi::EM_SE_C33 => Some("S1C33 Family of Seiko Epson processors"), - abi::EM_SEP => Some("Sharp embedded microprocessor"), - abi::EM_ARCA => Some("Arca RISC Microprocessor"), - abi::EM_UNICORE => { - Some("Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University") - } - abi::EM_EXCESS => Some("eXcess: 16/32/64-bit configurable embedded CPU"), - abi::EM_DXP => Some("Icera Semiconductor Inc. Deep Execution Processor"), - abi::EM_ALTERA_NIOS2 => Some("Altera Nios II soft-core processor"), - abi::EM_CRX => Some("National Semiconductor CompactRISC CRX microprocessor"), - abi::EM_XGATE => Some("Motorola XGATE embedded processor"), - abi::EM_C166 => Some("Infineon C16x/XC16x processor"), - abi::EM_M16C => Some("Renesas M16C series microprocessors"), - abi::EM_DSPIC30F => Some("Microchip Technology dsPIC30F Digital Signal Controller"), - abi::EM_CE => Some("Freescale Communication Engine RISC core"), - abi::EM_M32C => Some("Renesas M32C series microprocessors"), - abi::EM_TSK3000 => Some("Altium TSK3000 core"), - abi::EM_RS08 => Some("Freescale RS08 embedded processor"), - abi::EM_SHARC => Some("Analog Devices SHARC family of 32-bit DSP processors"), - abi::EM_ECOG2 => Some("Cyan Technology eCOG2 microprocessor"), - abi::EM_SCORE7 => Some("Sunplus S+core7 RISC processor"), - abi::EM_DSP24 => Some("New Japan Radio (NJR) 24-bit DSP Processor"), - abi::EM_VIDEOCORE3 => Some("Broadcom VideoCore III processor"), - abi::EM_LATTICEMICO32 => Some("RISC processor for Lattice FPGA architecture"), - abi::EM_SE_C17 => Some("Seiko Epson C17 family"), - abi::EM_TI_C6000 => Some("The Texas Instruments TMS320C6000 DSP family"), - abi::EM_TI_C2000 => Some("The Texas Instruments TMS320C2000 DSP family"), - abi::EM_TI_C5500 => Some("The Texas Instruments TMS320C55x DSP family"), - abi::EM_TI_ARP32 => { - Some("Texas Instruments Application Specific RISC Processor, 32bit fetch") - } - abi::EM_TI_PRU => Some("Texas Instruments Programmable Realtime Unit"), - abi::EM_MMDSP_PLUS => Some("STMicroelectronics 64bit VLIW Data Signal Processor"), - abi::EM_CYPRESS_M8C => Some("Cypress M8C microprocessor"), - abi::EM_R32C => Some("Renesas R32C series microprocessors"), - abi::EM_TRIMEDIA => Some("NXP Semiconductors TriMedia architecture family"), - abi::EM_QDSP6 => Some("QUALCOMM DSP6 Processor"), - abi::EM_8051 => Some("Intel 8051 and variants"), - abi::EM_STXP7X => { - Some("STMicroelectronics STxP7x family of configurable and extensible RISC processors") - } - abi::EM_NDS32 => Some("Andes Technology compact code size embedded RISC processor family"), - abi::EM_ECOG1X => Some("Cyan Technology eCOG1X family"), - abi::EM_MAXQ30 => Some("Dallas Semiconductor MAXQ30 Core Micro-controllers"), - abi::EM_XIMO16 => Some("New Japan Radio (NJR) 16-bit DSP Processor"), - abi::EM_MANIK => Some("M2000 Reconfigurable RISC Microprocessor"), - abi::EM_CRAYNV2 => Some("Cray Inc. NV2 vector architecture"), - abi::EM_RX => Some("Renesas RX family"), - abi::EM_METAG => Some("Imagination Technologies META processor architecture"), - abi::EM_MCST_ELBRUS => Some("MCST Elbrus general purpose hardware architecture"), - abi::EM_ECOG16 => Some("Cyan Technology eCOG16 family"), - abi::EM_CR16 => Some("National Semiconductor CompactRISC CR16 16-bit microprocessor"), - abi::EM_ETPU => Some("Freescale Extended Time Processing Unit"), - abi::EM_SLE9X => Some("Infineon Technologies SLE9X core"), - abi::EM_L10M => Some("Intel L10M"), - abi::EM_K10M => Some("Intel K10M"), - abi::EM_AARCH64 => Some("ARM 64-bit architecture (AARCH64)"), - abi::EM_AVR32 => Some("Atmel Corporation 32-bit microprocessor family"), - abi::EM_STM8 => Some("STMicroeletronics STM8 8-bit microcontroller"), - abi::EM_TILE64 => Some("Tilera TILE64 multicore architecture family"), - abi::EM_TILEPRO => Some("Tilera TILEPro multicore architecture family"), - abi::EM_MICROBLAZE => Some("Xilinx MicroBlaze 32-bit RISC soft processor core"), - abi::EM_CUDA => Some("NVIDIA CUDA architecture"), - abi::EM_TILEGX => Some("Tilera TILE-Gx multicore architecture family"), - abi::EM_CLOUDSHIELD => Some("CloudShield architecture family"), - abi::EM_COREA_1ST => Some("KIPO-KAIST Core-A 1st generation processor family"), - abi::EM_COREA_2ND => Some("KIPO-KAIST Core-A 2nd generation processor family"), - abi::EM_ARC_COMPACT2 => Some("Synopsys ARCompact V2"), - abi::EM_OPEN8 => Some("Open8 8-bit RISC soft processor core"), - abi::EM_RL78 => Some("Renesas RL78 family"), - abi::EM_VIDEOCORE5 => Some("Broadcom VideoCore V processor"), - abi::EM_78KOR => Some("Renesas 78KOR family"), - abi::EM_56800EX => Some("Freescale 56800EX Digital Signal Controller (DSC)"), - abi::EM_BA1 => Some("Beyond BA1 CPU architecture"), - abi::EM_BA2 => Some("Beyond BA2 CPU architecture"), - abi::EM_XCORE => Some("XMOS xCORE processor family"), - abi::EM_MCHP_PIC => Some("Microchip 8-bit PIC(r) family"), - abi::EM_INTEL205 => Some("Reserved by Intel"), - abi::EM_INTEL206 => Some("Reserved by Intel"), - abi::EM_INTEL207 => Some("Reserved by Intel"), - abi::EM_INTEL208 => Some("Reserved by Intel"), - abi::EM_INTEL209 => Some("Reserved by Intel"), - abi::EM_KM32 => Some("KM211 KM32 32-bit processor"), - abi::EM_KMX32 => Some("KM211 KMX32 32-bit processor"), - abi::EM_KMX16 => Some("KM211 KMX16 16-bit processor"), - abi::EM_KMX8 => Some("KM211 KMX8 8-bit processor"), - abi::EM_KVARC => Some("KM211 KVARC processor"), - abi::EM_CDP => Some("Paneve CDP architecture family"), - abi::EM_COGE => Some("Cognitive Smart Memory Processor"), - abi::EM_COOL => Some("Bluechip Systems CoolEngine"), - abi::EM_NORC => Some("Nanoradio Optimized RISC"), - abi::EM_CSR_KALIMBA => Some("CSR Kalimba architecture family"), - abi::EM_Z80 => Some("Zilog Z80"), - abi::EM_VISIUM => Some("Controls and Data Services VISIUMcore processor"), - abi::EM_FT32 => Some("FTDI Chip FT32 high performance 32-bit RISC architecture"), - abi::EM_MOXIE => Some("Moxie processor family"), - abi::EM_AMDGPU => Some("AMD GPU architecture"), - abi::EM_RISCV => Some("RISC-V"), - abi::EM_BPF => Some("Linux BPF"), - _ => None, - } -} - -pub fn e_machine_to_str(e_machine: u16) -> Option<&'static str> { - match e_machine { - abi::EM_NONE => Some("EM_NONE"), - abi::EM_M32 => Some("EM_M32"), - abi::EM_SPARC => Some("EM_SPARC"), - abi::EM_386 => Some("EM_386"), - abi::EM_68K => Some("EM_68K"), - abi::EM_88K => Some("EM_88K"), - abi::EM_IAMCU => Some("EM_IAMCU"), - abi::EM_860 => Some("EM_860"), - abi::EM_MIPS => Some("EM_MIPS"), - abi::EM_S370 => Some("EM_S370"), - abi::EM_MIPS_RS3_LE => Some("EM_MIPS_RS3_LE"), - abi::EM_PARISC => Some("EM_PARISC"), - abi::EM_VPP500 => Some("EM_VPP500"), - abi::EM_SPARC32PLUS => Some("EM_SPARC32PLUS"), - abi::EM_960 => Some("EM_960"), - abi::EM_PPC => Some("EM_PPC"), - abi::EM_PPC64 => Some("EM_PPC64"), - abi::EM_S390 => Some("EM_S390"), - abi::EM_SPU => Some("EM_SPU"), - abi::EM_V800 => Some("EM_V800"), - abi::EM_FR20 => Some("EM_FR20"), - abi::EM_RH32 => Some("EM_RH32"), - abi::EM_RCE => Some("EM_RCE"), - abi::EM_ARM => Some("EM_ARM"), - abi::EM_ALPHA => Some("EM_ALPHA"), - abi::EM_SH => Some("EM_SH"), - abi::EM_SPARCV9 => Some("EM_SPARCV9"), - abi::EM_TRICORE => Some("EM_TRICORE"), - abi::EM_ARC => Some("EM_ARC"), - abi::EM_H8_300 => Some("EM_H8_300"), - abi::EM_H8_300H => Some("EM_H8_300H"), - abi::EM_H8S => Some("EM_H8S"), - abi::EM_H8_500 => Some("EM_H8_500"), - abi::EM_IA_64 => Some("EM_IA_64"), - abi::EM_MIPS_X => Some("EM_MIPS_X"), - abi::EM_COLDFIRE => Some("EM_COLDFIRE"), - abi::EM_68HC12 => Some("EM_68HC12"), - abi::EM_MMA => Some("EM_MMA"), - abi::EM_PCP => Some("EM_PCP"), - abi::EM_NCPU => Some("EM_NCPU"), - abi::EM_NDR1 => Some("EM_NDR1"), - abi::EM_STARCORE => Some("EM_STARCORE"), - abi::EM_ME16 => Some("EM_ME16"), - abi::EM_ST100 => Some("EM_ST100"), - abi::EM_TINYJ => Some("EM_TINYJ"), - abi::EM_X86_64 => Some("EM_X86_64"), - abi::EM_PDSP => Some("EM_PDSP"), - abi::EM_PDP10 => Some("EM_PDP10"), - abi::EM_PDP11 => Some("EM_PDP11"), - abi::EM_FX66 => Some("EM_FX66"), - abi::EM_ST9PLUS => Some("EM_ST9PLUS"), - abi::EM_ST7 => Some("EM_ST7"), - abi::EM_68HC16 => Some("EM_68HC16"), - abi::EM_68HC11 => Some("EM_68HC11"), - abi::EM_68HC08 => Some("EM_68HC08"), - abi::EM_68HC05 => Some("EM_68HC05"), - abi::EM_SVX => Some("EM_SVX"), - abi::EM_ST19 => Some("EM_ST19"), - abi::EM_VAX => Some("EM_VAX"), - abi::EM_CRIS => Some("EM_CRIS"), - abi::EM_JAVELIN => Some("EM_JAVELIN"), - abi::EM_FIREPATH => Some("EM_FIREPATH"), - abi::EM_ZSP => Some("EM_ZSP"), - abi::EM_MMIX => Some("EM_MMIX"), - abi::EM_HUANY => Some("EM_HUANY"), - abi::EM_PRISM => Some("EM_PRISM"), - abi::EM_AVR => Some("EM_AVR"), - abi::EM_FR30 => Some("EM_FR30"), - abi::EM_D10V => Some("EM_D10V"), - abi::EM_D30V => Some("EM_D30V"), - abi::EM_V850 => Some("EM_V850"), - abi::EM_M32R => Some("EM_M32R"), - abi::EM_MN10300 => Some("EM_MN10300"), - abi::EM_MN10200 => Some("EM_MN10200"), - abi::EM_PJ => Some("EM_PJ"), - abi::EM_OPENRISC => Some("EM_OPENRISC"), - abi::EM_ARC_COMPACT => Some("EM_ARC_COMPACT"), - abi::EM_XTENSA => Some("EM_XTENSA"), - abi::EM_VIDEOCORE => Some("EM_VIDEOCORE"), - abi::EM_TMM_GPP => Some("EM_TMM_GPP"), - abi::EM_NS32K => Some("EM_NS32K"), - abi::EM_TPC => Some("EM_TPC"), - abi::EM_SNP1K => Some("EM_SNP1K"), - abi::EM_ST200 => Some("EM_ST200"), - abi::EM_IP2K => Some("EM_IP2K"), - abi::EM_MAX => Some("EM_MAX"), - abi::EM_CR => Some("EM_CR"), - abi::EM_F2MC16 => Some("EM_F2MC16"), - abi::EM_MSP430 => Some("EM_MSP430"), - abi::EM_BLACKFIN => Some("EM_BLACKFIN"), - abi::EM_SE_C33 => Some("EM_SE_C33"), - abi::EM_SEP => Some("EM_SEP"), - abi::EM_ARCA => Some("EM_ARCA"), - abi::EM_UNICORE => Some("EM_UNICORE"), - abi::EM_EXCESS => Some("EM_EXCESS"), - abi::EM_DXP => Some("EM_DXP"), - abi::EM_ALTERA_NIOS2 => Some("EM_ALTERA_NIOS2"), - abi::EM_CRX => Some("EM_CRX"), - abi::EM_XGATE => Some("EM_XGATE"), - abi::EM_C166 => Some("EM_C166"), - abi::EM_M16C => Some("EM_M16C"), - abi::EM_DSPIC30F => Some("EM_DSPIC30F"), - abi::EM_CE => Some("EM_CE"), - abi::EM_M32C => Some("EM_M32C"), - abi::EM_TSK3000 => Some("EM_TSK3000"), - abi::EM_RS08 => Some("EM_RS08"), - abi::EM_SHARC => Some("EM_SHARC"), - abi::EM_ECOG2 => Some("EM_ECOG2"), - abi::EM_SCORE7 => Some("EM_SCORE7"), - abi::EM_DSP24 => Some("EM_DSP24"), - abi::EM_VIDEOCORE3 => Some("EM_VIDEOCORE3"), - abi::EM_LATTICEMICO32 => Some("EM_LATTICEMICO32"), - abi::EM_SE_C17 => Some("EM_SE_C17"), - abi::EM_TI_C6000 => Some("EM_TI_C6000"), - abi::EM_TI_C2000 => Some("EM_TI_C2000"), - abi::EM_TI_C5500 => Some("EM_TI_C5500"), - abi::EM_TI_ARP32 => Some("EM_TI_ARP32"), - abi::EM_TI_PRU => Some("EM_TI_PRU"), - abi::EM_MMDSP_PLUS => Some("EM_MMDSP_PLUS"), - abi::EM_CYPRESS_M8C => Some("EM_CYPRESS_M8C"), - abi::EM_R32C => Some("EM_R32C"), - abi::EM_TRIMEDIA => Some("EM_TRIMEDIA"), - abi::EM_QDSP6 => Some("EM_QDSP6"), - abi::EM_8051 => Some("EM_8051"), - abi::EM_STXP7X => Some("EM_STXP7X"), - abi::EM_NDS32 => Some("EM_NDS32"), - abi::EM_ECOG1X => Some("EM_ECOG1X"), - abi::EM_MAXQ30 => Some("EM_MAXQ30"), - abi::EM_XIMO16 => Some("EM_XIMO16"), - abi::EM_MANIK => Some("EM_MANIK"), - abi::EM_CRAYNV2 => Some("EM_CRAYNV2"), - abi::EM_RX => Some("EM_RX"), - abi::EM_METAG => Some("EM_METAG"), - abi::EM_MCST_ELBRUS => Some("EM_MCST_ELBRUS"), - abi::EM_ECOG16 => Some("EM_ECOG16"), - abi::EM_CR16 => Some("EM_CR16"), - abi::EM_ETPU => Some("EM_ETPU"), - abi::EM_SLE9X => Some("EM_SLE9X"), - abi::EM_L10M => Some("EM_L10M"), - abi::EM_K10M => Some("EM_K10M"), - abi::EM_AARCH64 => Some("EM_AARCH64"), - abi::EM_AVR32 => Some("EM_AVR32"), - abi::EM_STM8 => Some("EM_STM8"), - abi::EM_TILE64 => Some("EM_TILE64"), - abi::EM_TILEPRO => Some("EM_TILEPRO"), - abi::EM_MICROBLAZE => Some("EM_MICROBLAZE"), - abi::EM_CUDA => Some("EM_CUDA"), - abi::EM_TILEGX => Some("EM_TILEGX"), - abi::EM_CLOUDSHIELD => Some("EM_CLOUDSHIELD"), - abi::EM_COREA_1ST => Some("EM_COREA_1ST"), - abi::EM_COREA_2ND => Some("EM_COREA_2ND"), - abi::EM_ARC_COMPACT2 => Some("EM_ARC_COMPACT2"), - abi::EM_OPEN8 => Some("EM_OPEN8"), - abi::EM_RL78 => Some("EM_RL78"), - abi::EM_VIDEOCORE5 => Some("EM_VIDEOCORE5"), - abi::EM_78KOR => Some("EM_78KOR"), - abi::EM_56800EX => Some("EM_56800EX"), - abi::EM_BA1 => Some("EM_BA1"), - abi::EM_BA2 => Some("EM_BA2"), - abi::EM_XCORE => Some("EM_XCORE"), - abi::EM_MCHP_PIC => Some("EM_MCHP_PIC"), - abi::EM_INTEL205 => Some("EM_INTEL205"), - abi::EM_INTEL206 => Some("EM_INTEL206"), - abi::EM_INTEL207 => Some("EM_INTEL207"), - abi::EM_INTEL208 => Some("EM_INTEL208"), - abi::EM_INTEL209 => Some("EM_INTEL209"), - abi::EM_KM32 => Some("EM_KM32"), - abi::EM_KMX32 => Some("EM_KMX32"), - abi::EM_KMX16 => Some("EM_KMX16"), - abi::EM_KMX8 => Some("EM_KMX8"), - abi::EM_KVARC => Some("EM_KVARC"), - abi::EM_CDP => Some("EM_CDP"), - abi::EM_COGE => Some("EM_COGE"), - abi::EM_COOL => Some("EM_COOL"), - abi::EM_NORC => Some("EM_NORC"), - abi::EM_CSR_KALIMBA => Some("EM_CSR_KALIMBA"), - abi::EM_Z80 => Some("EM_Z80"), - abi::EM_VISIUM => Some("EM_VISIUM"), - abi::EM_FT32 => Some("EM_FT32"), - abi::EM_MOXIE => Some("EM_MOXIE"), - abi::EM_AMDGPU => Some("EM_AMDGPU"), - abi::EM_RISCV => Some("RISC-V"), - abi::EM_BPF => Some("EM_BPF"), - _ => None, - } -} - -pub fn e_machine_to_string(e_machine: u16) -> String { - match e_machine_to_str(e_machine) { - Some(s) => s.to_string(), - None => format!("e_machine({e_machine:#x})"), - } -} - -pub fn sh_type_to_str(sh_type: u32) -> Option<&'static str> { - match sh_type { - abi::SHT_NULL => Some("SHT_NULL"), - abi::SHT_PROGBITS => Some("SHT_PROGBITS"), - abi::SHT_SYMTAB => Some("SHT_SYMTAB"), - abi::SHT_STRTAB => Some("SHT_STRTAB"), - abi::SHT_RELA => Some("SHT_RELA"), - abi::SHT_HASH => Some("SHT_HASH"), - abi::SHT_DYNAMIC => Some("SHT_DYNAMIC"), - abi::SHT_NOTE => Some("SHT_NOTE"), - abi::SHT_NOBITS => Some("SHT_NOBITS"), - abi::SHT_REL => Some("SHT_REL"), - abi::SHT_SHLIB => Some("SHT_SHLIB"), - abi::SHT_DYNSYM => Some("SHT_DYNSYM"), - abi::SHT_INIT_ARRAY => Some("SHT_INIT_ARRAY"), - abi::SHT_FINI_ARRAY => Some("SHT_FINI_ARRAY"), - abi::SHT_PREINIT_ARRAY => Some("SHT_PREINIT_ARRAY"), - abi::SHT_GROUP => Some("SHT_GROUP"), - abi::SHT_SYMTAB_SHNDX => Some("SHT_SYMTAB_SHNDX"), - abi::SHT_GNU_ATTRIBUTES => Some("SHT_GNU_ATTRIBUTES"), - abi::SHT_GNU_HASH => Some("SHT_GNU_HASH"), - abi::SHT_GNU_LIBLIST => Some("SHT_GNU_LIBLIST"), - abi::SHT_GNU_VERDEF => Some("SHT_GNU_VERDEF"), - abi::SHT_GNU_VERNEED => Some("SHT_GNU_VERNEED"), - abi::SHT_GNU_VERSYM => Some("SHT_GNU_VERSYM"), - _ => None, - } -} - -pub fn sh_type_to_string(sh_type: u32) -> String { - match sh_type_to_str(sh_type) { - Some(s) => s.to_string(), - None => format!("sh_type({sh_type:#x})"), - } -} - -pub fn p_flags_to_string(p_flags: u32) -> String { - match p_flags < 8 { - true => { - let r = if p_flags & abi::PF_R != 0 { "R" } else { " " }; - let w = if p_flags & abi::PF_W != 0 { "W" } else { " " }; - let x = if p_flags & abi::PF_X != 0 { "E" } else { " " }; - format!("{r}{w}{x}") - } - false => format!("p_flags({p_flags:#x})"), - } -} - -pub fn p_type_to_str(p_type: u32) -> Option<&'static str> { - match p_type { - abi::PT_NULL => Some("PT_NULL"), - abi::PT_LOAD => Some("PT_LOAD"), - abi::PT_DYNAMIC => Some("PT_DYNAMIC"), - abi::PT_INTERP => Some("PT_INTERP"), - abi::PT_NOTE => Some("PT_NOTE"), - abi::PT_SHLIB => Some("PT_SHLIB"), - abi::PT_PHDR => Some("PT_PHDR"), - abi::PT_TLS => Some("PT_TLS"), - abi::PT_GNU_EH_FRAME => Some("PT_GNU_EH_FRAME"), - abi::PT_GNU_STACK => Some("PT_GNU_STACK"), - abi::PT_GNU_RELRO => Some("PT_GNU_RELRO"), - abi::PT_GNU_PROPERTY => Some("PT_GNU_PROPERTY"), - _ => None, - } -} - -pub fn p_type_to_string(p_type: u32) -> String { - match p_type_to_str(p_type) { - Some(s) => s.to_string(), - None => format!("p_type({p_type:#x})"), - } -} - -pub fn st_symtype_to_str(st_symtype: u8) -> Option<&'static str> { - match st_symtype { - abi::STT_NOTYPE => Some("STT_NOTYPE"), - abi::STT_OBJECT => Some("STT_OBJECT"), - abi::STT_FUNC => Some("STT_FUNC"), - abi::STT_SECTION => Some("STT_SECTION"), - abi::STT_FILE => Some("STT_FILE"), - abi::STT_COMMON => Some("STT_COMMON"), - abi::STT_TLS => Some("STT_TLS"), - abi::STT_GNU_IFUNC => Some("STT_GNU_IFUNC"), - _ => None, - } -} - -pub fn st_symtype_to_string(st_symtype: u8) -> String { - match st_symtype_to_str(st_symtype) { - Some(s) => s.to_string(), - None => format!("st_symtype({st_symtype:#x})"), - } -} - -pub fn st_bind_to_str(st_bind: u8) -> Option<&'static str> { - match st_bind { - abi::STB_LOCAL => Some("STB_LOCAL"), - abi::STB_GLOBAL => Some("STB_GLOBAL"), - abi::STB_WEAK => Some("STB_WEAK"), - abi::STB_GNU_UNIQUE => Some("STB_GNU_UNIQUE"), - _ => None, - } -} - -pub fn st_bind_to_string(st_bind: u8) -> String { - match st_bind_to_str(st_bind) { - Some(s) => s.to_string(), - None => format!("st_bind({st_bind:#x})"), - } -} - -pub fn st_vis_to_str(st_vis: u8) -> Option<&'static str> { - match st_vis { - abi::STV_DEFAULT => Some("STV_DEFAULT"), - abi::STV_INTERNAL => Some("STV_INTERNAL"), - abi::STV_HIDDEN => Some("STV_HIDDEN"), - abi::STV_PROTECTED => Some("STV_PROTECTED"), - _ => None, - } -} - -pub fn st_vis_to_string(st_vis: u8) -> String { - match st_vis_to_str(st_vis) { - Some(s) => s.to_string(), - None => format!("st_vis({st_vis:#x})"), - } -} - -pub fn ch_type_to_str(ch_type: u32) -> Option<&'static str> { - match ch_type { - abi::ELFCOMPRESS_ZLIB => Some("ELFCOMPRESS_ZLIB"), - abi::ELFCOMPRESS_ZSTD => Some("ELFCOMPRESS_ZSTD "), - _ => None, - } -} - -pub fn note_abi_tag_os_to_str(os: u32) -> Option<&'static str> { - match os { - abi::ELF_NOTE_GNU_ABI_TAG_OS_LINUX => Some("Linux"), - abi::ELF_NOTE_GNU_ABI_TAG_OS_GNU => Some("GNU"), - abi::ELF_NOTE_GNU_ABI_TAG_OS_SOLARIS2 => Some("Solaris"), - abi::ELF_NOTE_GNU_ABI_TAG_OS_FREEBSD => Some("FreeBSD"), - _ => None, - } -} - -pub fn d_tag_to_str(d_tag: i64) -> Option<&'static str> { - match d_tag { - abi::DT_NULL => Some("DT_NULL"), - abi::DT_NEEDED => Some("DT_NEEDED"), - abi::DT_PLTRELSZ => Some("DT_PLTRELSZ"), - abi::DT_PLTGOT => Some("DT_PLTGOT"), - abi::DT_HASH => Some("DT_HASH"), - abi::DT_STRTAB => Some("DT_STRTAB"), - abi::DT_SYMTAB => Some("DT_SYMTAB"), - abi::DT_RELA => Some("DT_RELA"), - abi::DT_RELASZ => Some("DT_RELASZ"), - abi::DT_RELAENT => Some("DT_RELAENT"), - abi::DT_STRSZ => Some("DT_STRSZ"), - abi::DT_SYMENT => Some("DT_SYMENT"), - abi::DT_INIT => Some("DT_INIT"), - abi::DT_FINI => Some("DT_FINI"), - abi::DT_SONAME => Some("DT_SONAME"), - abi::DT_RPATH => Some("DT_RPATH"), - abi::DT_SYMBOLIC => Some("DT_SYMBOLIC"), - abi::DT_REL => Some("DT_REL"), - abi::DT_RELSZ => Some("DT_RELSZ"), - abi::DT_RELENT => Some("DT_RELENT"), - abi::DT_PLTREL => Some("DT_PLTREL"), - abi::DT_DEBUG => Some("DT_DEBUG"), - abi::DT_TEXTREL => Some("DT_TEXTREL"), - abi::DT_JMPREL => Some("DT_JMPREL"), - abi::DT_BIND_NOW => Some("DT_BIND_NOW"), - abi::DT_INIT_ARRAY => Some("DT_INIT_ARRAY"), - abi::DT_FINI_ARRAY => Some("DT_FINI_ARRAY"), - abi::DT_INIT_ARRAYSZ => Some("DT_INIT_ARRAYSZ"), - abi::DT_FINI_ARRAYSZ => Some("DT_FINI_ARRAYSZ"), - abi::DT_RUNPATH => Some("DT_RUNPATH"), - abi::DT_FLAGS => Some("DT_FLAGS"), - abi::DT_PREINIT_ARRAY => Some("DT_PREINIT_ARRAY"), - abi::DT_PREINIT_ARRAYSZ => Some("DT_PREINIT_ARRAYSZ"), - abi::DT_SYMTAB_SHNDX => Some("DT_SYMTAB_SHNDX"), - abi::DT_GUILE_GC_ROOT => Some("DT_GUILE_GC_ROOT"), - abi::DT_GUILE_GC_ROOT_SZ => Some("DT_GUILE_GC_ROOT_SZ"), - abi::DT_GUILE_ENTRY => Some("DT_GUILE_ENTRY"), - abi::DT_GUILE_VM_VERSION => Some("DT_GUILE_VM_VERSION"), - abi::DT_GUILE_FRAME_MAPS => Some("DT_GUILE_FRAME_MAPS"), - abi::DT_LOOS => Some("DT_LOOS"), - abi::DT_GNU_PRELINKED => Some("DT_GNU_PRELINKED"), - abi::DT_GNU_CONFLICTSZ => Some("DT_GNU_CONFLICTSZ"), - abi::DT_GNU_LIBLISTSZ => Some("DT_GNU_LIBLISTSZ"), - abi::DT_CHECKSUM => Some("DT_CHECKSUM"), - abi::DT_PLTPADSZ => Some("DT_PLTPADSZ"), - abi::DT_MOVEENT => Some("DT_MOVEENT"), - abi::DT_MOVESZ => Some("DT_MOVESZ"), - abi::DT_FEATURE_1 => Some("DT_FEATURE_1"), - abi::DT_POSFLAG_1 => Some("DT_POSFLAG_1"), - abi::DT_SYMINSZ => Some("DT_SYMINSZ"), - abi::DT_SYMINENT => Some("DT_SYMINENT"), - abi::DT_GNU_HASH => Some("DT_GNU_HASH"), - abi::DT_TLSDESC_PLT => Some("DT_TLSDESC_PLT"), - abi::DT_TLSDESC_GOT => Some("DT_TLSDESC_GOT"), - abi::DT_GNU_CONFLICT => Some("DT_GNU_CONFLICT"), - abi::DT_GNU_LIBLIST => Some("DT_GNU_LIBLIST"), - abi::DT_CONFIG => Some("DT_CONFIG"), - abi::DT_DEPAUDIT => Some("DT_DEPAUDIT"), - abi::DT_AUDIT => Some("DT_AUDIT"), - abi::DT_PLTPAD => Some("DT_PLTPAD"), - abi::DT_MOVETAB => Some("DT_MOVETAB"), - abi::DT_SYMINFO => Some("DT_SYMINFO"), - abi::DT_VERSYM => Some("DT_VERSYM"), - abi::DT_RELACOUNT => Some("DT_RELACOUNT"), - abi::DT_RELCOUNT => Some("DT_RELCOUNT"), - abi::DT_FLAGS_1 => Some("DT_FLAGS_1"), - abi::DT_VERDEF => Some("DT_VERDEF"), - abi::DT_VERDEFNUM => Some("DT_VERDEFNUM"), - abi::DT_VERNEED => Some("DT_VERNEED"), - abi::DT_VERNEEDNUM => Some("DT_VERNEEDNUM"), - abi::DT_HIOS => Some("DT_HIOS"), - abi::DT_LOPROC => Some("DT_LOPROC"), - abi::DT_HIPROC => Some("DT_HIPROC"), - _ => None, - } -} diff --git a/arceos/modules/riscv_vcpu/.gitignore b/arceos/modules/riscv_vcpu/.gitignore deleted file mode 100644 index 55c0d4550..000000000 --- a/arceos/modules/riscv_vcpu/.gitignore +++ /dev/null @@ -1,18 +0,0 @@ -# Build output and other log files from arceos -/target -*.asm -*.img -*.bin -*.elf -actual.out -qemu.log -rusty-tags.vi - -# Visual Studio Code settings -/.vscode - -# macOS system files -.DS_Store - -# We ignore Cargo.lock because `axvcpu` is just a library -Cargo.lock diff --git a/arceos/modules/riscv_vcpu/Cargo.toml b/arceos/modules/riscv_vcpu/Cargo.toml deleted file mode 100644 index 3fe9948d7..000000000 --- a/arceos/modules/riscv_vcpu/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "riscv_vcpu" -version = "0.1.0" -edition = "2021" - -[dependencies] -log = "0.4.19" -cfg-if = "1.0" -bitflags = "2.2" -bit_field = "0.10" - -riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } -riscv-decode = { git = "https://github.com/KuangjuX/riscv-decode.git" } -sbi-spec = { version = "0.0.6", features = ["legacy"] } -sbi-rt = { version = "0.0.2", features = ["integer-impls", "legacy"] } -tock-registers = "0.8.1" -memoffset = { version = ">=0.6.5", features = ["unstable_const"] } - -axerrno = "0.1.0" -#page_table_entry = "0.3.3" -memory_addr = "0.3" -axhal = { workspace = true } diff --git a/arceos/modules/riscv_vcpu/README.md b/arceos/modules/riscv_vcpu/README.md deleted file mode 100644 index 0cec46459..000000000 --- a/arceos/modules/riscv_vcpu/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# riscv_vcpu - -[![CI](https://github.com/arceos-hypervisor/riscv_vcpu/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/arceos-hypervisor/riscv_vcpu/actions/workflows/ci.yml) - -Definition of the vCPU structure and virtualization-related interface support for the AArch64 architecture. \ No newline at end of file diff --git a/arceos/modules/riscv_vcpu/src/csrs.rs b/arceos/modules/riscv_vcpu/src/csrs.rs deleted file mode 100644 index d42b5790a..000000000 --- a/arceos/modules/riscv_vcpu/src/csrs.rs +++ /dev/null @@ -1,310 +0,0 @@ -use defs::*; -use tock_registers::interfaces::{Readable, Writeable}; -use tock_registers::RegisterLongName; - -/// Define each registers of hypervisor using. -pub struct CSR { - pub sie: ReadWriteCsr, - pub hstatus: ReadWriteCsr, - pub hedeleg: ReadWriteCsr, - pub hideleg: ReadWriteCsr, - pub hcounteren: ReadWriteCsr, - pub hvip: ReadWriteCsr, -} - -#[allow(clippy::identity_op, clippy::erasing_op)] -pub const CSR: &CSR = &CSR { - sie: ReadWriteCsr::new(), - hstatus: ReadWriteCsr::new(), - hedeleg: ReadWriteCsr::new(), - hideleg: ReadWriteCsr::new(), - hcounteren: ReadWriteCsr::new(), - hvip: ReadWriteCsr::new(), -}; - -/// Trait defining the possible operations on a RISC-V CSR. -pub trait RiscvCsrTrait { - type R: RegisterLongName; - /// Reads the value of the CSR. - fn get_value(&self) -> usize; - - /// Writes the value of the CSR. - fn write_value(&self, value: usize); - - /// Atomicllt swaps the value of CSRs. - fn atomic_replace(&self, value: usize) -> usize; - - /// Atomically read a CSR and set bits specified in a bitmask - fn read_and_set_bits(&self, bitmasks: usize) -> usize; - - /// Atomically read a CSR and set bits specified in a bitmask - fn read_and_clear_bits(&self, bitmasks: usize) -> usize; -} - -/// Read/Write register. -pub struct ReadWriteCsr { - associated_register: core::marker::PhantomData, -} - -impl ReadWriteCsr { - pub const fn new() -> Self { - Self { - associated_register: core::marker::PhantomData, - } - } -} - -impl RiscvCsrTrait for ReadWriteCsr { - type R = R; - - fn get_value(&self) -> usize { - let r: usize; - unsafe { - core::arch::asm!("csrr {rd}, {csr}", rd = out(reg) r, csr = const V); - } - r - } - - fn write_value(&self, value: usize) { - unsafe { - core::arch::asm!("csrw {csr}, {rs}", csr = const V, rs = in(reg) value); - } - } - - fn atomic_replace(&self, value: usize) -> usize { - let r: usize; - unsafe { - core::arch::asm!("csrrw {rd}, {csr}, {rs}", rd = out(reg) r, csr = const V, rs = in(reg) value); - } - r - } - - fn read_and_set_bits(&self, bitmask: usize) -> usize { - let r: usize; - unsafe { - core::arch::asm!("csrrs {rd}, {csr}, {rs}", rd = out(reg) r, csr = const V, rs = in(reg) bitmask); - } - r - } - - fn read_and_clear_bits(&self, bitmask: usize) -> usize { - let r: usize; - unsafe { - core::arch::asm!("csrrc {rd}, {csr}, {rs}", rd = out(reg) r, csr = const V, rs = in(reg) bitmask); - } - r - } -} - -// The Readable and Writeable traits aren't object-safe so unfortunately we can't implement them -// for RiscvCsrInterface. -impl Readable for ReadWriteCsr { - type T = usize; - type R = R; - - fn get(&self) -> usize { - self.get_value() - } -} - -impl Writeable for ReadWriteCsr { - type T = usize; - type R = R; - - fn set(&self, val_to_set: usize) { - self.write_value(val_to_set); - } -} - -pub mod defs { - use tock_registers::register_bitfields; - pub const CSR_SSTATUS: u16 = 0x100; - pub const CSR_SEDELEG: u16 = 0x102; - pub const CSR_SIDELEG: u16 = 0x103; - pub const CSR_SIE: u16 = 0x104; - pub const CSR_STVEC: u16 = 0x105; - pub const CSR_SCOUNTEREN: u16 = 0x106; - pub const CSR_SENVCFG: u16 = 0x10a; - pub const CSR_SSCRATCH: u16 = 0x140; - pub const CSR_SEPC: u16 = 0x141; - pub const CSR_SCAUSE: u16 = 0x142; - pub const CSR_STVAL: u16 = 0x143; - pub const CSR_SIP: u16 = 0x144; - pub const CSR_STIMECMP: u16 = 0x14d; - pub const CSR_SISELECT: u16 = 0x150; - pub const CSR_SIREG: u16 = 0x151; - pub const CSR_STOPEI: u16 = 0x15c; - pub const CSR_SATP: u16 = 0x180; - pub const CSR_STOPI: u16 = 0xdb0; - pub const CSR_SCONTEXT: u16 = 0x5a8; - pub const CSR_VSSTATUS: u16 = 0x200; - pub const CSR_VSIE: u16 = 0x204; - pub const CSR_VSTVEC: u16 = 0x205; - pub const CSR_VSSCRATCH: u16 = 0x240; - pub const CSR_VSEPC: u16 = 0x241; - pub const CSR_VSCAUSE: u16 = 0x242; - pub const CSR_VSTVAL: u16 = 0x243; - pub const CSR_VSIP: u16 = 0x244; - pub const CSR_VSTIMECMP: u16 = 0x24d; - pub const CSR_VSISELECT: u16 = 0x250; - pub const CSR_VSIREG: u16 = 0x251; - pub const CSR_VSTOPEI: u16 = 0x25c; - pub const CSR_VSATP: u16 = 0x280; - pub const CSR_VSTOPI: u16 = 0xeb0; - pub const CSR_HSTATUS: u16 = 0x600; - pub const CSR_HEDELEG: u16 = 0x602; - pub const CSR_HIDELEG: u16 = 0x603; - pub const CSR_HIE: u16 = 0x604; - pub const CSR_HTIMEDELTA: u16 = 0x605; - pub const CSR_HCOUNTEREN: u16 = 0x606; - pub const CSR_HGEIE: u16 = 0x607; - pub const CSR_HVICTL: u16 = 0x609; - pub const CSR_HENVCFG: u16 = 0x60a; - pub const CSR_HTVAL: u16 = 0x643; - pub const CSR_HIP: u16 = 0x644; - pub const CSR_HVIP: u16 = 0x645; - pub const CSR_HTINST: u16 = 0x64a; - pub const CSR_HGATP: u16 = 0x680; - pub const CSR_HCONTEXT: u16 = 0x6a8; - pub const CSR_HGEIP: u16 = 0xe12; - - // Hypervisor exception delegation register. - register_bitfields![usize, - pub hedeleg [ - instr_misaligned OFFSET(0) NUMBITS(1) [], - instr_fault OFFSET(1) NUMBITS(1) [], - illegal_instr OFFSET(2) NUMBITS(1) [], - breakpoint OFFSET(3) NUMBITS(1) [], - load_misaligned OFFSET(4) NUMBITS(1) [], - load_fault OFFSET(5) NUMBITS(1) [], - store_misaligned OFFSET(6) NUMBITS(1) [], - store_fault OFFSET(7) NUMBITS(1) [], - u_ecall OFFSET(8) NUMBITS(1) [], - instr_page_fault OFFSET(12) NUMBITS(1) [], - load_page_fault OFFSET(13) NUMBITS(1) [], - store_page_fault OFFSET(15) NUMBITS(1) [], - ] - ]; - - // Supervisor interrupt enable register. - register_bitfields![usize, - pub sie [ - ssoft OFFSET(1) NUMBITS(1) [], - stimer OFFSET(5) NUMBITS(1) [], - sext OFFSET(9) NUMBITS(1) [], - ] - ]; - - // Hypervisor status register. - register_bitfields![usize, - pub hstatus [ - // VS mode endianness control. - vsbe OFFSET(6) NUMBITS(1) [], - // A guest virtual address was written to stval as a result of the trap. - gva OFFSET(6) NUMBITS(1) [], - // Virtualization mode at time of trap. - spv OFFSET(7) NUMBITS(1) [ - User = 0, - Supervisor = 1, - ], - // Privilege level the virtual hart was executing before entering HS-mode. - spvp OFFSET(8) NUMBITS(1) [ - User = 0, - Supervisor = 1, - ], - // Allow hypervisor instructions in U-mode. - hu OFFSET(9) NUMBITS(1) [], - // Selects the guest external interrupt source for VS external interrupts. - vgein OFFSET(12) NUMBITS(6) [], - // Trap on SFENCE, SINVAL, or changes to vsatp. - vtvm OFFSET(20) NUMBITS(1) [], - // Trap on WFI timeout. - vtw OFFSET(21) NUMBITS(1) [], - // Trap SRET instruction. - vtsr OFFSET(22) NUMBITS(1) [], - // Native base integer ISA width for VS-mode. - vsxl OFFSET(32) NUMBITS(2) [ - Xlen32 = 1, - Xlen64 = 2, - ], - ] - ]; - - // Hypervisor interrupt delegation register. - register_bitfields![usize, - pub hideleg [ - vssoft OFFSET(2) NUMBITS(1) [], - vstimer OFFSET(6) NUMBITS(1) [], - vsext OFFSET(10) NUMBITS(1) [], - ] - ]; - - // Hypervisor interrupt enable register. - register_bitfields![usize, - pub hie [ - vssoft OFFSET(2) NUMBITS(1) [], - vstimer OFFSET(6) NUMBITS(1) [], - vsext OFFSET(10) NUMBITS(1) [], - sgext OFFSET(12) NUMBITS(1) [], - ] - ]; - - // VS-mode counter availability control. - register_bitfields![usize, - pub hcounteren [ - cycle OFFSET(0) NUMBITS(1) [], - time OFFSET(1) NUMBITS(1) [], - instret OFFSET(2) NUMBITS(1) [], - hpm OFFSET(3) NUMBITS(29) [], - ] - ]; - - // Hypervisor virtual interrupt pending. - register_bitfields![usize, - pub hvip [ - vssoft OFFSET(2) NUMBITS(1) [], - vstimer OFFSET(6) NUMBITS(1) [], - vsext OFFSET(10) NUMBITS(1) [], - ] - ]; -} - -pub mod traps { - pub mod interrupt { - pub const USER_SOFT: usize = 1 << 0; - pub const SUPERVISOR_SOFT: usize = 1 << 1; - pub const VIRTUAL_SUPERVISOR_SOFT: usize = 1 << 2; - pub const MACHINE_SOFT: usize = 1 << 3; - pub const USER_TIMER: usize = 1 << 4; - pub const SUPERVISOR_TIMER: usize = 1 << 5; - pub const VIRTUAL_SUPERVISOR_TIMER: usize = 1 << 6; - pub const MACHINE_TIMER: usize = 1 << 7; - pub const USER_EXTERNAL: usize = 1 << 8; - pub const SUPERVISOR_EXTERNAL: usize = 1 << 9; - pub const VIRTUAL_SUPERVISOR_EXTERNAL: usize = 1 << 10; - pub const MACHINEL_EXTERNAL: usize = 1 << 11; - pub const SUPERVISOR_GUEST_EXTERNEL: usize = 1 << 12; - } - - pub mod exception { - pub const INST_ADDR_MISALIGN: usize = 1 << 0; - pub const INST_ACCESSS_FAULT: usize = 1 << 1; - pub const ILLEGAL_INST: usize = 1 << 2; - pub const BREAKPOINT: usize = 1 << 3; - pub const LOAD_ADDR_MISALIGNED: usize = 1 << 4; - pub const LOAD_ACCESS_FAULT: usize = 1 << 5; - pub const STORE_ADDR_MISALIGNED: usize = 1 << 6; - pub const STORE_ACCESS_FAULT: usize = 1 << 7; - pub const ENV_CALL_FROM_U_OR_VU: usize = 1 << 8; - pub const ENV_CALL_FROM_HS: usize = 1 << 9; - pub const ENV_CALL_FROM_VS: usize = 1 << 10; - pub const ENV_CALL_FROM_M: usize = 1 << 11; - pub const INST_PAGE_FAULT: usize = 1 << 12; - pub const LOAD_PAGE_FAULT: usize = 1 << 13; - pub const STORE_PAGE_FAULT: usize = 1 << 15; - pub const INST_GUEST_PAGE_FAULT: usize = 1 << 20; - pub const LOAD_GUEST_PAGE_FAULT: usize = 1 << 21; - pub const VIRTUAL_INST: usize = 1 << 22; - pub const STORE_GUEST_PAGE_FAULT: usize = 1 << 23; - } -} diff --git a/arceos/modules/riscv_vcpu/src/detect.rs b/arceos/modules/riscv_vcpu/src/detect.rs deleted file mode 100644 index 8322f6a57..000000000 --- a/arceos/modules/riscv_vcpu/src/detect.rs +++ /dev/null @@ -1,210 +0,0 @@ -//! Detect instruction sets (ISA extensions) by trap-and-return procedure -//! -//! First, it disables all S-level interrupts. Remaining traps in RISC-V core -//! are all exceptions. -//! Then, it filters out illegal instruction from exceptions. -//! ref: https://github.com/luojia65/zihai/blob/main/zihai/src/detect.rs - -use core::arch::asm; -use riscv::register::{ - scause::{Exception, Scause, Trap}, - sstatus, - stvec::{self, Stvec, TrapMode}, -}; - -// Detect if hypervisor extension exists on current hart environment -// -// This function tries to read hgatp and returns false if the read operation failed. -pub fn detect_h_extension() -> bool { - // run detection by trap on csrr instruction. - let ans = with_detect_trap(0, || unsafe { - asm!("csrr {}, 0x680", out(reg) _, options(nomem, nostack)); // 0x680 => hgatp - }); - // return the answer from output flag. 0 => success, 2 => failed, illegal instruction - ans != 2 -} - -// Tries to execute all instructions defined in clojure `f`. -// If resulted in an exception, this function returns its exception id. -// -// This function is useful to detect if an instruction exists on current environment. -#[inline] -fn with_detect_trap(param: usize, f: impl FnOnce()) -> usize { - // disable interrupts and handle exceptions only - let (sie, stvec, tp) = unsafe { init_detect_trap(param) }; - // run detection inner - f(); - // restore trap handler and enable interrupts - unsafe { restore_detect_trap(sie, stvec, tp) } -} - -// rust trap handler for detect exceptions -extern "C" fn rust_detect_trap(trap_frame: &mut TrapFrame) { - // store returned exception id value into tp register - // specially: illegal instruction => 2 - trap_frame.tp = trap_frame.scause.bits(); - // if illegal instruction, skip current instruction - match trap_frame.scause.cause() { - Trap::Exception(Exception::IllegalInstruction) => { - let mut insn_bits = riscv_illegal_insn_bits((trap_frame.stval & 0xFFFF) as u16); - if insn_bits == 0 { - let insn_half = unsafe { *(trap_frame.sepc as *const u16) }; - insn_bits = riscv_illegal_insn_bits(insn_half); - } - // skip current instruction - trap_frame.sepc = trap_frame.sepc.wrapping_add(insn_bits); - } - Trap::Exception(_) => unreachable!(), // FIXME: unexpected instruction errors - Trap::Interrupt(_) => unreachable!(), // filtered out for sie == false - } -} - -// Gets risc-v instruction bits from illegal instruction stval value, or 0 if unknown -#[inline] -fn riscv_illegal_insn_bits(insn: u16) -> usize { - if insn == 0 { - return 0; // stval[0..16] == 0, unknown - } - if insn & 0b11 != 0b11 { - return 2; // 16-bit - } - if insn & 0b11100 != 0b11100 { - return 4; // 32-bit - } - // FIXME: add >= 48-bit instructions in the future if we need to detect such instrucions - // >= 48-bit, unknown from this function by now - 0 -} - -// Initialize environment for trap detection and filter in exception only -#[inline] -unsafe fn init_detect_trap(param: usize) -> (bool, Stvec, usize) { - // clear SIE to handle exception only - let stored_sie = sstatus::read().sie(); - sstatus::clear_sie(); - // use detect trap handler to handle exceptions - let stored_stvec = stvec::read(); - let mut trap_addr = on_detect_trap as usize; - if trap_addr & 0b1 != 0 { - trap_addr += 0b1; - } - stvec::write(trap_addr, TrapMode::Direct); - // store tp register. tp will be used to load parameter and store return value - let stored_tp: usize; - asm!("mv {}, tp", "mv tp, {}", out(reg) stored_tp, in(reg) param, options(nomem, nostack)); - // returns preserved previous hardware states - (stored_sie, stored_stvec, stored_tp) -} - -// Restore previous hardware states before trap detection -#[inline] -unsafe fn restore_detect_trap(sie: bool, stvec: Stvec, tp: usize) -> usize { - // read the return value from tp register, and restore tp value - let ans: usize; - asm!("mv {}, tp", "mv tp, {}", out(reg) ans, in(reg) tp, options(nomem, nostack)); - // restore trap vector settings - asm!("csrw stvec, {}", in(reg) stvec.bits(), options(nomem, nostack)); - // enable interrupts - if sie { - sstatus::set_sie(); - }; - ans -} - -// Trap frame for instruction exception detection -#[repr(C)] -struct TrapFrame { - ra: usize, - tp: usize, - a0: usize, - a1: usize, - a2: usize, - a3: usize, - a4: usize, - a5: usize, - a6: usize, - a7: usize, - t0: usize, - t1: usize, - t2: usize, - t3: usize, - t4: usize, - t5: usize, - t6: usize, - sstatus: usize, - sepc: usize, - scause: Scause, - stval: usize, -} - -// Assembly trap handler for instruction detection. -// -// This trap handler shares the same stack from its prospective caller, -// the caller must ensure it has abundant stack size for a trap handler. -// -// This function should not be used in conventional trap handling, -// as it does not preserve a special trap stack, and it's designed to -// handle exceptions only rather than interrupts. -#[naked] -unsafe extern "C" fn on_detect_trap() -> ! { - asm!( - ".p2align 2", - "addi sp, sp, -8*21", - "sd ra, 0*8(sp)", - "sd tp, 1*8(sp)", - "sd a0, 2*8(sp)", - "sd a1, 3*8(sp)", - "sd a2, 4*8(sp)", - "sd a3, 5*8(sp)", - "sd a4, 6*8(sp)", - "sd a5, 7*8(sp)", - "sd a6, 8*8(sp)", - "sd a7, 9*8(sp)", - "sd t0, 10*8(sp)", - "sd t1, 11*8(sp)", - "sd t2, 12*8(sp)", - "sd t3, 13*8(sp)", - "sd t4, 14*8(sp)", - "sd t5, 15*8(sp)", - "sd t6, 16*8(sp)", - "csrr t0, sstatus", - "sd t0, 17*8(sp)", - "csrr t1, sepc", - "sd t1, 18*8(sp)", - "csrr t2, scause", - "sd t2, 19*8(sp)", - "csrr t3, stval", - "sd t3, 20*8(sp)", - "mv a0, sp", - "call {rust_detect_trap}", - "ld t0, 17*8(sp)", - "csrw sstatus, t0", - "ld t1, 18*8(sp)", - "csrw sepc, t1", - "ld t2, 19*8(sp)", - "csrw scause, t2", - "ld t3, 20*8(sp)", - "csrw stval, t3", - "ld ra, 0*8(sp)", - "ld tp, 1*8(sp)", - "ld a0, 2*8(sp)", - "ld a1, 3*8(sp)", - "ld a2, 4*8(sp)", - "ld a3, 5*8(sp)", - "ld a4, 6*8(sp)", - "ld a5, 7*8(sp)", - "ld a6, 8*8(sp)", - "ld a7, 9*8(sp)", - "ld t0, 10*8(sp)", - "ld t1, 11*8(sp)", - "ld t2, 12*8(sp)", - "ld t3, 13*8(sp)", - "ld t4, 14*8(sp)", - "ld t5, 15*8(sp)", - "ld t6, 16*8(sp)", - "addi sp, sp, 8*21", - "sret", - rust_detect_trap = sym rust_detect_trap, - options(noreturn), - ) -} diff --git a/arceos/modules/riscv_vcpu/src/guest.S b/arceos/modules/riscv_vcpu/src/guest.S deleted file mode 100644 index 60ab203fa..000000000 --- a/arceos/modules/riscv_vcpu/src/guest.S +++ /dev/null @@ -1,181 +0,0 @@ - -/// Enter the guest given in `VmCpuRegisters` from `a0` -.global _run_guest -_run_guest: - /* Save hypervisor state */ - - /* Save hypervisor GPRs (except T0-T6 and a0, which is GuestInfo and stashed in sscratch) */ - sd ra, ({hyp_ra})(a0) - sd gp, ({hyp_gp})(a0) - sd tp, ({hyp_tp})(a0) - sd s0, ({hyp_s0})(a0) - sd s1, ({hyp_s1})(a0) - sd a1, ({hyp_a1})(a0) - sd a2, ({hyp_a2})(a0) - sd a3, ({hyp_a3})(a0) - sd a4, ({hyp_a4})(a0) - sd a5, ({hyp_a5})(a0) - sd a6, ({hyp_a6})(a0) - sd a7, ({hyp_a7})(a0) - sd s2, ({hyp_s2})(a0) - sd s3, ({hyp_s3})(a0) - sd s4, ({hyp_s4})(a0) - sd s5, ({hyp_s5})(a0) - sd s6, ({hyp_s6})(a0) - sd s7, ({hyp_s7})(a0) - sd s8, ({hyp_s8})(a0) - sd s9, ({hyp_s9})(a0) - sd s10, ({hyp_s10})(a0) - sd s11, ({hyp_s11})(a0) - sd sp, ({hyp_sp})(a0) - - /* Swap in guest CSRs. */ - ld t1, ({guest_sstatus})(a0) - csrrw t1, sstatus, t1 - sd t1, ({hyp_sstatus})(a0) - - ld t1, ({guest_hstatus})(a0) - csrrw t1, hstatus, t1 - - ld t1, ({guest_scounteren})(a0) - csrrw t1, scounteren, t1 - sd t1, ({hyp_scounteren})(a0) - - ld t1, ({guest_sepc})(a0) - csrw sepc, t1 - - /* Set stvec so that hypervisor resumes after the sret when the guest exits. */ - la t1, _guest_exit - csrrw t1, stvec, t1 - sd t1, ({hyp_stvec})(a0) - - /* Save sscratch and replace with pointer to GuestInfo. */ - csrrw t1, sscratch, a0 - sd t1, ({hyp_sscratch})(a0) - - /* Restore the gprs from this GuestInfo */ - ld ra, ({guest_ra})(a0) - ld gp, ({guest_gp})(a0) - ld tp, ({guest_tp})(a0) - ld s0, ({guest_s0})(a0) - ld s1, ({guest_s1})(a0) - ld a1, ({guest_a1})(a0) - ld a2, ({guest_a2})(a0) - ld a3, ({guest_a3})(a0) - ld a4, ({guest_a4})(a0) - ld a5, ({guest_a5})(a0) - ld a6, ({guest_a6})(a0) - ld a7, ({guest_a7})(a0) - ld s2, ({guest_s2})(a0) - ld s3, ({guest_s3})(a0) - ld s4, ({guest_s4})(a0) - ld s5, ({guest_s5})(a0) - ld s6, ({guest_s6})(a0) - ld s7, ({guest_s7})(a0) - ld s8, ({guest_s8})(a0) - ld s9, ({guest_s9})(a0) - ld s10, ({guest_s10})(a0) - ld s11, ({guest_s11})(a0) - ld t0, ({guest_t0})(a0) - ld t1, ({guest_t1})(a0) - ld t2, ({guest_t2})(a0) - ld t3, ({guest_t3})(a0) - ld t4, ({guest_t4})(a0) - ld t5, ({guest_t5})(a0) - ld t6, ({guest_t6})(a0) - ld sp, ({guest_sp})(a0) - ld a0, ({guest_a0})(a0) - - sret - -.align 2 -_guest_exit: - /* Pull GuestInfo out of sscratch, swapping with guest's a0 */ - csrrw a0, sscratch, a0 - - /* Save guest GPRs. */ - sd ra, ({guest_ra})(a0) - sd gp, ({guest_gp})(a0) - sd tp, ({guest_tp})(a0) - sd s0, ({guest_s0})(a0) - sd s1, ({guest_s1})(a0) - sd a1, ({guest_a1})(a0) - sd a2, ({guest_a2})(a0) - sd a3, ({guest_a3})(a0) - sd a4, ({guest_a4})(a0) - sd a5, ({guest_a5})(a0) - sd a6, ({guest_a6})(a0) - sd a7, ({guest_a7})(a0) - sd s2, ({guest_s2})(a0) - sd s3, ({guest_s3})(a0) - sd s4, ({guest_s4})(a0) - sd s5, ({guest_s5})(a0) - sd s6, ({guest_s6})(a0) - sd s7, ({guest_s7})(a0) - sd s8, ({guest_s8})(a0) - sd s9, ({guest_s9})(a0) - sd s10, ({guest_s10})(a0) - sd s11, ({guest_s11})(a0) - sd t0, ({guest_t0})(a0) - sd t1, ({guest_t1})(a0) - sd t2, ({guest_t2})(a0) - sd t3, ({guest_t3})(a0) - sd t4, ({guest_t4})(a0) - sd t5, ({guest_t5})(a0) - sd t6, ({guest_t6})(a0) - sd sp, ({guest_sp})(a0) - - /* Save Guest a0 after recovering from sscratch. */ - csrr t0, sscratch - sd t0, ({guest_a0})(a0) - -_restore_csrs: - /* Swap in hypervisor CSRs. */ - ld t1, ({hyp_sstatus})(a0) - csrrw t1, sstatus, t1 - sd t1, ({guest_sstatus})(a0) - - csrr t1, hstatus - sd t1, ({guest_hstatus})(a0) - - ld t1, ({hyp_scounteren})(a0) - csrrw t1, scounteren, t1 - sd t1, ({guest_scounteren})(a0) - - ld t1, ({hyp_stvec})(a0) - csrw stvec, t1 - - ld t1, ({hyp_sscratch})(a0) - csrw sscratch, t1 - - /* Save guest EPC. */ - csrr t1, sepc - sd t1, ({guest_sepc})(a0) - - - /* Restore hypervisor GPRs. */ - ld ra, ({hyp_ra})(a0) - ld gp, ({hyp_gp})(a0) - ld tp, ({hyp_tp})(a0) - ld s0, ({hyp_s0})(a0) - ld s1, ({hyp_s1})(a0) - ld a1, ({hyp_a1})(a0) - ld a2, ({hyp_a2})(a0) - ld a3, ({hyp_a3})(a0) - ld a4, ({hyp_a4})(a0) - ld a5, ({hyp_a5})(a0) - ld a6, ({hyp_a6})(a0) - ld a7, ({hyp_a7})(a0) - ld s2, ({hyp_s2})(a0) - ld s3, ({hyp_s3})(a0) - ld s4, ({hyp_s4})(a0) - ld s5, ({hyp_s5})(a0) - ld s6, ({hyp_s6})(a0) - ld s7, ({hyp_s7})(a0) - ld s8, ({hyp_s8})(a0) - ld s9, ({hyp_s9})(a0) - ld s10, ({hyp_s10})(a0) - ld s11, ({hyp_s11})(a0) - ld sp, ({hyp_sp})(a0) - - ret diff --git a/arceos/modules/riscv_vcpu/src/lib.rs b/arceos/modules/riscv_vcpu/src/lib.rs deleted file mode 100644 index 00f21ee9b..000000000 --- a/arceos/modules/riscv_vcpu/src/lib.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![no_std] -#![feature(doc_cfg)] -#![feature(naked_functions)] -#![feature(riscv_ext_intrinsics)] -#![feature(asm_const)] -#![doc = include_str!("../README.md")] - -#[macro_use] -extern crate log; - -pub mod csrs; -mod detect; -mod regs; -pub mod sbi; -mod vcpu; - -pub use self::vcpu::RISCVVCpu; -pub use detect::detect_h_extension as has_hardware_support; -pub use vcpu::AxVCpuExitReason; -use csrs::{traps, CSR, RiscvCsrTrait}; - -pub struct RISCVPerCpu {} - -/// Initialize (H)S-level CSRs to a reasonable state. -pub unsafe fn setup_csrs() { - // Delegate some synchronous exceptions. - CSR.hedeleg.write_value( - traps::exception::INST_ADDR_MISALIGN - | traps::exception::BREAKPOINT - | traps::exception::ENV_CALL_FROM_U_OR_VU - | traps::exception::INST_PAGE_FAULT - | traps::exception::LOAD_PAGE_FAULT - | traps::exception::STORE_PAGE_FAULT - | traps::exception::ILLEGAL_INST, - ); - - // Delegate all interupts. - CSR.hideleg.write_value( - traps::interrupt::VIRTUAL_SUPERVISOR_TIMER - | traps::interrupt::VIRTUAL_SUPERVISOR_EXTERNAL - | traps::interrupt::VIRTUAL_SUPERVISOR_SOFT, - ); - - // Clear all interrupts. - CSR.hvip.read_and_clear_bits( - traps::interrupt::VIRTUAL_SUPERVISOR_TIMER - | traps::interrupt::VIRTUAL_SUPERVISOR_EXTERNAL - | traps::interrupt::VIRTUAL_SUPERVISOR_SOFT, - ); - - // clear all interrupts. - CSR.hcounteren.write_value(0xffff_ffff); - - // enable interrupt - CSR.sie.write_value( - traps::interrupt::SUPERVISOR_EXTERNAL - | traps::interrupt::SUPERVISOR_SOFT - | traps::interrupt::SUPERVISOR_TIMER, - ); - debug!("sie: {:#x}", CSR.sie.get_value()); -} diff --git a/arceos/modules/riscv_vcpu/src/mem_extable.S b/arceos/modules/riscv_vcpu/src/mem_extable.S deleted file mode 100644 index ea19738e8..000000000 --- a/arceos/modules/riscv_vcpu/src/mem_extable.S +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2022 by Rivos Inc. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Very unoptimized memcpy() to/from guest memory functions, using the HLV/HSV instructions. - -// Adds the instruction at 'lbl' to the exception table. -.macro add_extable lbl -.pushsection .extable, "a" -.balign 8 -.quad \lbl -.popsection -.endm -.option push -.option arch, +h -.section .text - -// memcpy() to a guest physical address using HSV. -.global _copy_to_guest -_copy_to_guest: - // handle_trap assumes t0 holds the address of where we want to jump to when we encounter - // a fault and will stick SCAUSE in t1. - la t0, _ret_from_copy - // _ret_from_copy assumes the return value is in t2. - mv t2, zero -1: - beq t2, a2, _ret_from_copy - lb t3, (a1) -2: - hsv.b t3, (a0) - add_extable 2b - addi a0, a0, 1 - addi a1, a1, 1 - addi t2, t2, 1 - j 1b - -// memcpy() from a guest physical address using HLV. -.global _copy_from_guest -_copy_from_guest: - // handle_trap assumes t0 holds the address of where we want to jump to when we encounter - // a fault and will stick SCAUSE in t1. - la t0, _ret_from_copy - // _ret_from_copy assumes the return value is in t2. - mv t2, zero -1: - beq t2, a2, _ret_from_copy -2: - hlv.b t3, (a1) - add_extable 2b - sb t3, (a0) - addi a0, a0, 1 - addi a1, a1, 1 - addi t2, t2, 1 - j 1b - -// Fetch an instruction from guest memory using HLVX. Only supports 2 or 4 byte instructions. -// -// Arguments: -// A0: Guest address of the instruction to fetch, using the translation modes/tables currently -// programmed in HGATP and VSATP. -// A1: Pointer to a u32 where the instruction will be written. -// -// Returns -1 on error. -.global _fetch_guest_instruction -_fetch_guest_instruction: - // handle_trap assumes t0 holds the address of where we want to jump to when we encounter - // a fault and will stick SCAUSE in t1. - la t0, 4f -1: - hlvx.hu t2, (a0) - add_extable 1b - sh t2, (a1) - addi a0, a0, 2 - addi a1, a1, 2 - // If it's a compressed instrution (bits [1:0] != 'b11) then we're done. - li t3, 3 - and t2, t2, t3 - bne t2, t3, 3f - // Load the next half-word. -2: - hlvx.hu t2, (a0) - add_extable 2b - sh t2, (a1) -3: - mv a0, zero - ret -4: - // Took a fault, return -1. - not a0, zero - ret - -// memcpy() to a user address. -.global _copy_to_user -_copy_to_user: - // handle_trap assumes t0 holds the address of where we want to jump to when we encounter - // a fault and will stick SCAUSE in t1. - la t0, _ret_from_copy - // _ret_from_copy assumes the return value is in t2. - mv t2, zero -1: - beq t2, a2, _ret_from_copy - lb t3, (a1) -2: - sb t3, (a0) - add_extable 2b - addi a0, a0, 1 - addi a1, a1, 1 - addi t2, t2, 1 - j 1b - -// memcpy() from a user address. -.global _copy_from_user -_copy_from_user: - // handle_trap assumes t0 holds the address of where we want to jump to when we encounter - // a fault and will stick SCAUSE in t1. - la t0, _ret_from_copy - // _ret_from_copy assumes the return value is in t2. - mv t2, zero -1: - beq t2, a2, _ret_from_copy -2: - lb t3, (a1) - add_extable 2b - sb t3, (a0) - addi a0, a0, 1 - addi a1, a1, 1 - addi t2, t2, 1 - j 1b - -.align 2 -_ret_from_copy: - mv a0, t2 - ret -.option pop \ No newline at end of file diff --git a/arceos/modules/riscv_vcpu/src/regs.rs b/arceos/modules/riscv_vcpu/src/regs.rs deleted file mode 100644 index 5d7aadccc..000000000 --- a/arceos/modules/riscv_vcpu/src/regs.rs +++ /dev/null @@ -1,114 +0,0 @@ -#[derive(Default)] -#[repr(C)] -pub struct GeneralPurposeRegisters([usize; 32]); - -/// Index of risc-v general purpose registers in `GeneralPurposeRegisters`. -#[allow(missing_docs)] -#[repr(u32)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum GprIndex { - Zero = 0, - RA, - SP, - GP, - TP, - T0, - T1, - T2, - S0, - S1, - A0, - A1, - A2, - A3, - A4, - A5, - A6, - A7, - S2, - S3, - S4, - S5, - S6, - S7, - S8, - S9, - S10, - S11, - T3, - T4, - T5, - T6, -} - -impl GprIndex { - /// Get register index from raw value. - pub fn from_raw(raw: u32) -> Option { - use GprIndex::*; - let index = match raw { - 0 => Zero, - 1 => RA, - 2 => SP, - 3 => GP, - 4 => TP, - 5 => T0, - 6 => T1, - 7 => T2, - 8 => S0, - 9 => S1, - 10 => A0, - 11 => A1, - 12 => A2, - 13 => A3, - 14 => A4, - 15 => A5, - 16 => A6, - 17 => A7, - 18 => S2, - 19 => S3, - 20 => S4, - 21 => S5, - 22 => S6, - 23 => S7, - 24 => S8, - 25 => S9, - 26 => S10, - 27 => S11, - 28 => T3, - 29 => T4, - 30 => T5, - 31 => T6, - _ => { - return None; - } - }; - Some(index) - } -} - -impl GeneralPurposeRegisters { - /// Returns the value of the given register. - pub fn reg(&self, reg_index: GprIndex) -> usize { - self.0[reg_index as usize] - } - - /// Sets the value of the given register. - pub fn set_reg(&mut self, reg_index: GprIndex, val: usize) { - if reg_index == GprIndex::Zero { - return; - } - - self.0[reg_index as usize] = val; - } - - /// Returns the argument registers. - /// This is avoids many calls when an SBI handler needs all of the argmuent regs. - pub fn a_regs(&self) -> &[usize] { - &self.0[GprIndex::A0 as usize..=GprIndex::A7 as usize] - } - - /// Returns the arguments register as a mutable. - pub fn a_regs_mut(&mut self) -> &mut [usize] { - &mut self.0[GprIndex::A0 as usize..=GprIndex::A7 as usize] - } -} diff --git a/arceos/modules/riscv_vcpu/src/sbi/base.rs b/arceos/modules/riscv_vcpu/src/sbi/base.rs deleted file mode 100644 index 4fe4ba931..000000000 --- a/arceos/modules/riscv_vcpu/src/sbi/base.rs +++ /dev/null @@ -1,35 +0,0 @@ -use axerrno::{AxError, AxResult}; - -/// Functions defined for the Base extension -#[derive(Clone, Copy, Debug)] -pub enum BaseFunction { - /// Returns the implemented version of the SBI standard. - GetSepcificationVersion, - /// Returns the ID of the SBI implementation. - GetImplementationID, - /// Returns the version of the SBI implementation. - GetImplementationVersion, - /// Checks if the given SBI extension is supported. - ProbeSbiExtension(u64), - /// Returns the vendor that produced this machine(`mvendorid`). - GetMachineVendorID, - /// Returns the architecture implementation ID of this machine(`marchid`). - GetMachineArchitectureID, - /// Returns the ID of this machine(`mimpid`). - GetMachineImplementationID, -} - -impl BaseFunction { - pub(crate) fn from_regs(args: &[usize]) -> AxResult { - match args[6] { - 0 => Ok(BaseFunction::GetSepcificationVersion), - 1 => Ok(BaseFunction::GetImplementationID), - 2 => Ok(BaseFunction::GetImplementationVersion), - 3 => Ok(BaseFunction::ProbeSbiExtension(args[0] as u64)), - 4 => Ok(BaseFunction::GetMachineVendorID), - 5 => Ok(BaseFunction::GetMachineArchitectureID), - 6 => Ok(BaseFunction::GetMachineImplementationID), - _ => Err(AxError::NotFound), - } - } -} diff --git a/arceos/modules/riscv_vcpu/src/sbi/dbcn.rs b/arceos/modules/riscv_vcpu/src/sbi/dbcn.rs deleted file mode 100644 index cde124639..000000000 --- a/arceos/modules/riscv_vcpu/src/sbi/dbcn.rs +++ /dev/null @@ -1,11 +0,0 @@ -/// Functions for the Debug Console extension -#[derive(Copy, Clone, Debug)] -pub enum DebugConsoleFunction { - /// Prints the given string to the system console. - PutString { - /// The length of the string to print. - len: u64, - /// The address of the string. - addr: u64, - }, -} diff --git a/arceos/modules/riscv_vcpu/src/sbi/mod.rs b/arceos/modules/riscv_vcpu/src/sbi/mod.rs deleted file mode 100644 index 7c13c7833..000000000 --- a/arceos/modules/riscv_vcpu/src/sbi/mod.rs +++ /dev/null @@ -1,88 +0,0 @@ -mod base; -mod dbcn; -mod pmu; -mod rfnc; -mod srst; - -use axerrno::{AxError, AxResult}; -pub use base::BaseFunction; -use dbcn::DebugConsoleFunction; -pub use pmu::PmuFunction; -pub use rfnc::RemoteFenceFunction; -use sbi_spec; -pub use srst::ResetFunction; - -pub const SBI_SUCCESS: usize = 0; -pub const SBI_ERR_FAILUER: isize = -1; -pub const SBI_ERR_NOT_SUPPORTED: isize = -2; -pub const SBI_ERR_INAVLID_PARAM: isize = -3; -pub const SBI_ERR_DENIED: isize = -4; -pub const SBI_ERR_INVALID_ADDRESS: isize = -5; -pub const SBI_ERR_ALREADY_AVAILABLE: isize = -6; - -/// The values returned from an SBI function call. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct SbiReturn { - /// The error code(0 for success) - pub error_code: i64, - /// The return value if the operation is successful - pub return_value: i64, -} - -/// SBI return value conventions -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum SbiReturnTyoe { - /// Legacy(v0.1) extensions return a single value in A0, usually with the convention that 0 - /// is success and < 0 is an implementation defined error code. - Legacy(u64), - /// Modern extensions use the standard error code values enumerated above. - Standard(SbiReturn), -} - -/// SBI Message used to invoke the specfified SBI extension in the firmware. -#[derive(Clone, Copy, Debug)] -pub enum SbiMessage { - /// The base SBI extension functions. - Base(BaseFunction), - /// The legacy GetChar extension. - GetChar, - /// The legacy PutChar extension. - PutChar(usize), - /// The SetTimer Extension - SetTimer(usize), - /// Handles output to the console for debug - DebugConsole(DebugConsoleFunction), - /// Handles system reset - Reset(ResetFunction), - /// The RemoteFence Extension. - RemoteFence(RemoteFenceFunction), - /// The PMU Extension - PMU(PmuFunction), -} - -impl SbiMessage { - /// Creates an SbiMessage struct from the given GPRs. Intended for use from the ECALL handler - /// and passed the saved register state from the calling OS. A7 must contain a valid SBI - /// extension and the other A* registers will be interpreted based on the extension A7 selects. - pub fn from_regs(args: &[usize]) -> AxResult { - match args[7] { - sbi_spec::base::EID_BASE => BaseFunction::from_regs(args).map(SbiMessage::Base), - sbi_spec::legacy::LEGACY_CONSOLE_PUTCHAR => Ok(SbiMessage::PutChar(args[0])), - sbi_spec::legacy::LEGACY_CONSOLE_GETCHAR => Ok(SbiMessage::GetChar), - sbi_spec::legacy::LEGACY_SET_TIMER => Ok(SbiMessage::SetTimer(args[0])), - sbi_spec::legacy::LEGACY_SHUTDOWN => Ok(SbiMessage::Reset(ResetFunction::shutdown())), - sbi_spec::time::EID_TIME => Ok(SbiMessage::SetTimer(args[0])), - sbi_spec::srst::EID_SRST => ResetFunction::from_regs(args).map(SbiMessage::Reset), - sbi_spec::rfnc::EID_RFNC => { - RemoteFenceFunction::from_args(args).map(SbiMessage::RemoteFence) - } - sbi_spec::pmu::EID_PMU => PmuFunction::from_regs(args).map(SbiMessage::PMU), - _ => { - error!("args: {:?}", args); - error!("args[7]: {:#x}", args[7]); - error!("EID_RFENCE: {:#x}", sbi_spec::rfnc::EID_RFNC); - Err(AxError::NotFound) - } - } - } -} diff --git a/arceos/modules/riscv_vcpu/src/sbi/pmu.rs b/arceos/modules/riscv_vcpu/src/sbi/pmu.rs deleted file mode 100644 index 990d2780e..000000000 --- a/arceos/modules/riscv_vcpu/src/sbi/pmu.rs +++ /dev/null @@ -1,34 +0,0 @@ -use axerrno::AxResult; - -#[derive(Clone, Copy, Debug)] -pub enum PmuFunction { - /// Returns the total of performance counters (hardware and fireware). - GetNumCounters, - /// Returns information about hardware counter specified by the inner value. - GetCounterInfo(u64), - /// Stops the couters selected by counter_index and counter_mask. - /// See the sbi_pmu_counter_stop documentation for details. - StopCounter { - /// Countert index base. - counter_index: u64, - /// Counter index mask. - counter_mask: u64, - /// Counter stop flags. - stop_flags: u64, - }, -} - -impl PmuFunction { - pub(crate) fn from_regs(args: &[usize]) -> AxResult { - match args[6] { - 0 => Ok(Self::GetNumCounters), - 1 => Ok(Self::GetCounterInfo(args[0] as u64)), - 4 => Ok(Self::StopCounter { - counter_index: args[0] as u64, - counter_mask: args[1] as u64, - stop_flags: args[2] as u64, - }), - _ => panic!("Unsupported yet!"), - } - } -} diff --git a/arceos/modules/riscv_vcpu/src/sbi/rfnc.rs b/arceos/modules/riscv_vcpu/src/sbi/rfnc.rs deleted file mode 100644 index 249803462..000000000 --- a/arceos/modules/riscv_vcpu/src/sbi/rfnc.rs +++ /dev/null @@ -1,35 +0,0 @@ -use sbi_spec::rfnc::{REMOTE_FENCE_I, REMOTE_SFENCE_VMA}; - -use axerrno::AxResult; - -#[derive(Clone, Copy, Debug)] -pub enum RemoteFenceFunction { - FenceI { - hart_mask: u64, - hart_mask_base: u64, - }, - RemoteSFenceVMA { - hart_mask: u64, - hart_mask_base: u64, - start_addr: u64, - size: u64, - }, -} - -impl RemoteFenceFunction { - pub fn from_args(args: &[usize]) -> AxResult { - match args[6] { - REMOTE_FENCE_I => Ok(Self::FenceI { - hart_mask: args[0] as u64, - hart_mask_base: args[1] as u64, - }), - REMOTE_SFENCE_VMA => Ok(Self::RemoteSFenceVMA { - hart_mask: args[0] as u64, - hart_mask_base: args[1] as u64, - start_addr: args[2] as u64, - size: args[3] as u64, - }), - _ => panic!("Unsupported yet!"), - } - } -} diff --git a/arceos/modules/riscv_vcpu/src/sbi/srst.rs b/arceos/modules/riscv_vcpu/src/sbi/srst.rs deleted file mode 100644 index d6512ae93..000000000 --- a/arceos/modules/riscv_vcpu/src/sbi/srst.rs +++ /dev/null @@ -1,84 +0,0 @@ -use axerrno::{AxError, AxResult}; - -/// Functions for the Reset extension -#[derive(Copy, Clone, Debug)] -pub enum ResetFunction { - /// Performs a system reset. - Reset { - /// Determines the type of reset to perform. - reset_type: ResetType, - /// Represents the reason for system reset. - reason: ResetReason, - }, -} - -/// The types of reset a supervisor can request. -#[repr(usize)] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum ResetType { - /// Powers down the system. - Shutdown = 0, - /// Powers down, then reboots. - ColdReset = 1, - /// Reboots, doesn't power down. - WarmReset = 2, -} - -impl ResetType { - // Creates a reset type from the a0 register value or returns an error if no mapping is - // known for the given value. - fn from_reg(a0: usize) -> AxResult { - use ResetType::*; - Ok(match a0 { - 0 => Shutdown, - 1 => ColdReset, - 2 => WarmReset, - _ => return Err(AxError::InvalidInput), - }) - } -} - -/// Reasons why a supervisor requests a reset. -#[repr(u64)] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum ResetReason { - /// Used for normal resets. - NoReason = 0, - /// Used when the system has failed. - SystemFailure = 1, -} - -impl ResetReason { - // Creates a reset reason from the a1 register value or returns an error if no mapping is - // known for the given value. - fn from_reg(a1: usize) -> AxResult { - use ResetReason::*; - Ok(match a1 { - 0 => NoReason, - 1 => SystemFailure, - _ => return Err(AxError::InvalidInput), - }) - } -} -impl ResetFunction { - /// Attempts to parse `Self` from the passed in `a0-a7`. - pub(crate) fn from_regs(args: &[usize]) -> AxResult { - use ResetFunction::*; - - Ok(match args[6] { - 0 => Reset { - reset_type: ResetType::from_reg(args[0])?, - reason: ResetReason::from_reg(args[1])?, - }, - _ => return Err(AxError::InvalidInput), - }) - } - - /// Creates an operation to shutdown the machine. - pub fn shutdown() -> Self { - ResetFunction::Reset { - reset_type: ResetType::Shutdown, - reason: ResetReason::NoReason, - } - } -} diff --git a/arceos/modules/riscv_vcpu/src/vcpu.rs b/arceos/modules/riscv_vcpu/src/vcpu.rs deleted file mode 100644 index 674a162e6..000000000 --- a/arceos/modules/riscv_vcpu/src/vcpu.rs +++ /dev/null @@ -1,581 +0,0 @@ -use core::arch::global_asm; -use core::mem::size_of; - -use memoffset::offset_of; -use riscv::register::{htinst, htval, scause, sstatus, stval}; -use sbi_rt::{pmu_counter_get_info, pmu_counter_stop}; -use tock_registers::LocalRegisterCopy; - -use axerrno::AxResult; - -use super::csrs::defs::hstatus; -use super::csrs::{traps, RiscvCsrTrait, CSR}; -use super::sbi::{BaseFunction, PmuFunction, RemoteFenceFunction, SbiMessage}; - -use super::regs::{GeneralPurposeRegisters, GprIndex}; -use memory_addr::{VirtAddr, PhysAddr}; -use axhal::paging::MappingFlags; - -/// Guest physical address. -pub type GuestPhysAddr = VirtAddr; -/// Host physical address. -pub type HostPhysAddr = PhysAddr; - -/// Hypervisor GPR and CSR state which must be saved/restored when entering/exiting virtualization. -#[derive(Default)] -#[repr(C)] -struct HypervisorCpuState { - gprs: GeneralPurposeRegisters, - sstatus: usize, - //hstatus: usize, - scounteren: usize, - stvec: usize, - sscratch: usize, -} - -/// Guest GPR and CSR state which must be saved/restored when exiting/entering virtualization. -#[derive(Default)] -#[repr(C)] -pub struct GuestCpuState { - pub gprs: GeneralPurposeRegisters, - pub sstatus: usize, - pub hstatus: usize, - pub scounteren: usize, - pub sepc: usize, -} - -/// The CSRs that are only in effect when virtualization is enabled (V=1) and must be saved and -/// restored whenever we switch between VMs. -#[derive(Default)] -#[repr(C)] -pub struct GuestVsCsrs { - htimedelta: usize, - vsstatus: usize, - vsie: usize, - vstvec: usize, - vsscratch: usize, - vsepc: usize, - vscause: usize, - vstval: usize, - vsatp: usize, - vstimecmp: usize, -} - -/// Virtualized HS-level CSRs that are used to emulate (part of) the hypervisor extension for the -/// guest. -#[derive(Default)] -#[repr(C)] -pub struct GuestVirtualHsCsrs { - hie: usize, - hgeie: usize, - hgatp: usize, -} - -/// CSRs written on an exit from virtualization that are used by the hypervisor to determine the cause -/// of the trap. -#[derive(Default, Clone)] -#[repr(C)] -pub struct VmCpuTrapState { - pub scause: usize, - pub stval: usize, - pub htval: usize, - pub htinst: usize, -} - -/// (v)CPU register state that must be saved or restored when entering/exiting a VM or switching -/// between VMs. -#[derive(Default)] -#[repr(C)] -pub struct VmCpuRegisters { - // CPU state that's shared between our's and the guest's execution environment. Saved/restored - // when entering/exiting a VM. - hyp_regs: HypervisorCpuState, - pub guest_regs: GuestCpuState, - - // CPU state that only applies when V=1, e.g. the VS-level CSRs. Saved/restored on activation of - // the vCPU. - vs_csrs: GuestVsCsrs, - - // Virtualized HS-level CPU state. - virtual_hs_csrs: GuestVirtualHsCsrs, - - // Read on VM exit. - pub trap_csrs: VmCpuTrapState, -} - -#[allow(dead_code)] -const fn hyp_gpr_offset(index: GprIndex) -> usize { - offset_of!(VmCpuRegisters, hyp_regs) - + offset_of!(HypervisorCpuState, gprs) - + (index as usize) * size_of::() -} - -#[allow(dead_code)] -const fn guest_gpr_offset(index: GprIndex) -> usize { - offset_of!(VmCpuRegisters, guest_regs) - + offset_of!(GuestCpuState, gprs) - + (index as usize) * size_of::() -} - -#[allow(unused_macros)] -macro_rules! hyp_csr_offset { - ($reg:tt) => { - offset_of!(VmCpuRegisters, hyp_regs) + offset_of!(HypervisorCpuState, $reg) - }; -} - -#[allow(unused_macros)] -macro_rules! guest_csr_offset { - ($reg:tt) => { - offset_of!(VmCpuRegisters, guest_regs) + offset_of!(GuestCpuState, $reg) - }; -} - -global_asm!( - include_str!("guest.S"), - hyp_ra = const hyp_gpr_offset(GprIndex::RA), - hyp_gp = const hyp_gpr_offset(GprIndex::GP), - hyp_tp = const hyp_gpr_offset(GprIndex::TP), - hyp_s0 = const hyp_gpr_offset(GprIndex::S0), - hyp_s1 = const hyp_gpr_offset(GprIndex::S1), - hyp_a1 = const hyp_gpr_offset(GprIndex::A1), - hyp_a2 = const hyp_gpr_offset(GprIndex::A2), - hyp_a3 = const hyp_gpr_offset(GprIndex::A3), - hyp_a4 = const hyp_gpr_offset(GprIndex::A4), - hyp_a5 = const hyp_gpr_offset(GprIndex::A5), - hyp_a6 = const hyp_gpr_offset(GprIndex::A6), - hyp_a7 = const hyp_gpr_offset(GprIndex::A7), - hyp_s2 = const hyp_gpr_offset(GprIndex::S2), - hyp_s3 = const hyp_gpr_offset(GprIndex::S3), - hyp_s4 = const hyp_gpr_offset(GprIndex::S4), - hyp_s5 = const hyp_gpr_offset(GprIndex::S5), - hyp_s6 = const hyp_gpr_offset(GprIndex::S6), - hyp_s7 = const hyp_gpr_offset(GprIndex::S7), - hyp_s8 = const hyp_gpr_offset(GprIndex::S8), - hyp_s9 = const hyp_gpr_offset(GprIndex::S9), - hyp_s10 = const hyp_gpr_offset(GprIndex::S10), - hyp_s11 = const hyp_gpr_offset(GprIndex::S11), - hyp_sp = const hyp_gpr_offset(GprIndex::SP), - hyp_sstatus = const hyp_csr_offset!(sstatus), - hyp_scounteren = const hyp_csr_offset!(scounteren), - hyp_stvec = const hyp_csr_offset!(stvec), - hyp_sscratch = const hyp_csr_offset!(sscratch), - guest_ra = const guest_gpr_offset(GprIndex::RA), - guest_gp = const guest_gpr_offset(GprIndex::GP), - guest_tp = const guest_gpr_offset(GprIndex::TP), - guest_s0 = const guest_gpr_offset(GprIndex::S0), - guest_s1 = const guest_gpr_offset(GprIndex::S1), - guest_a0 = const guest_gpr_offset(GprIndex::A0), - guest_a1 = const guest_gpr_offset(GprIndex::A1), - guest_a2 = const guest_gpr_offset(GprIndex::A2), - guest_a3 = const guest_gpr_offset(GprIndex::A3), - guest_a4 = const guest_gpr_offset(GprIndex::A4), - guest_a5 = const guest_gpr_offset(GprIndex::A5), - guest_a6 = const guest_gpr_offset(GprIndex::A6), - guest_a7 = const guest_gpr_offset(GprIndex::A7), - guest_s2 = const guest_gpr_offset(GprIndex::S2), - guest_s3 = const guest_gpr_offset(GprIndex::S3), - guest_s4 = const guest_gpr_offset(GprIndex::S4), - guest_s5 = const guest_gpr_offset(GprIndex::S5), - guest_s6 = const guest_gpr_offset(GprIndex::S6), - guest_s7 = const guest_gpr_offset(GprIndex::S7), - guest_s8 = const guest_gpr_offset(GprIndex::S8), - guest_s9 = const guest_gpr_offset(GprIndex::S9), - guest_s10 = const guest_gpr_offset(GprIndex::S10), - guest_s11 = const guest_gpr_offset(GprIndex::S11), - guest_t0 = const guest_gpr_offset(GprIndex::T0), - guest_t1 = const guest_gpr_offset(GprIndex::T1), - guest_t2 = const guest_gpr_offset(GprIndex::T2), - guest_t3 = const guest_gpr_offset(GprIndex::T3), - guest_t4 = const guest_gpr_offset(GprIndex::T4), - guest_t5 = const guest_gpr_offset(GprIndex::T5), - guest_t6 = const guest_gpr_offset(GprIndex::T6), - guest_sp = const guest_gpr_offset(GprIndex::SP), - - guest_sstatus = const guest_csr_offset!(sstatus), - guest_hstatus = const guest_csr_offset!(hstatus), - guest_scounteren = const guest_csr_offset!(scounteren), - guest_sepc = const guest_csr_offset!(sepc), - -); - -extern "C" { - fn _run_guest(state: *mut VmCpuRegisters); -} - -/// The architecture dependent configuration of a `AxArchVCpu`. -#[derive(Clone, Copy, Debug, Default)] -pub struct VCpuConfig {} - -#[derive(Default)] -/// A virtual CPU within a guest -pub struct RISCVVCpu { - regs: VmCpuRegisters, -} - -impl RISCVVCpu { - pub fn set_entry(&mut self, entry: GuestPhysAddr) -> AxResult { - let regs = &mut self.regs; - regs.guest_regs.sepc = entry.as_usize(); - Ok(()) - } - - pub fn set_ept_root(&mut self, ept_root: HostPhysAddr) -> AxResult { - self.regs.virtual_hs_csrs.hgatp = 8usize << 60 | usize::from(ept_root) >> 12; - unsafe { - core::arch::asm!( - "csrw hgatp, {hgatp}", - hgatp = in(reg) self.regs.virtual_hs_csrs.hgatp, - ); - core::arch::riscv64::hfence_gvma_all(); - } - Ok(()) - } - - pub fn run(&mut self) -> AxResult { - let regs = &mut self.regs; - unsafe { - // Safe to run the guest as it only touches memory assigned to it by being owned - // by its page table - _run_guest(regs); - } - self.vmexit_handler() - } -} - -impl RISCVVCpu { - pub fn init() -> Self { - let mut regs = VmCpuRegisters::default(); - // Set hstatus - let mut hstatus = LocalRegisterCopy::::new( - riscv::register::hstatus::read().bits(), - ); - hstatus.modify(hstatus::spv::Supervisor); - // Set SPVP bit in order to accessing VS-mode memory from HS-mode. - hstatus.modify(hstatus::spvp::Supervisor); - CSR.hstatus.write_value(hstatus.get()); - regs.guest_regs.hstatus = hstatus.get(); - - // Set sstatus - let mut sstatus = sstatus::read(); - sstatus.set_spp(sstatus::SPP::Supervisor); - regs.guest_regs.sstatus = sstatus.bits(); - - CSR.sie - .read_and_clear_bits(traps::interrupt::SUPERVISOR_TIMER); - Self { regs } - } - - /// Gets one of the vCPU's general purpose registers. - pub fn get_gpr(&self, index: GprIndex) -> usize { - self.regs.guest_regs.gprs.reg(index) - } - - /// Set one of the vCPU's general purpose register. - pub fn set_gpr_from_gpr_index(&mut self, index: GprIndex, val: usize) { - self.regs.guest_regs.gprs.set_reg(index, val); - } - - /// Advance guest pc by `instr_len` bytes - pub fn advance_pc(&mut self, instr_len: usize) { - self.regs.guest_regs.sepc += instr_len - } - - /// Gets the vCPU's registers. - pub fn regs(&mut self) -> &mut VmCpuRegisters { - &mut self.regs - } -} - -impl RISCVVCpu { - fn vmexit_handler(&mut self) -> AxResult { - self.regs.trap_csrs.scause = scause::read().bits(); - self.regs.trap_csrs.stval = stval::read(); - self.regs.trap_csrs.htval = htval::read(); - self.regs.trap_csrs.htinst = htinst::read(); - - let scause = scause::read(); - use scause::{Exception, Interrupt, Trap}; - match scause.cause() { - Trap::Exception(Exception::VirtualSupervisorEnvCall) => { - let sbi_msg = SbiMessage::from_regs(self.regs.guest_regs.gprs.a_regs()).ok(); - debug!("VSuperEcall: {:?}", sbi_msg); - if let Some(sbi_msg) = sbi_msg { - match sbi_msg { - SbiMessage::Base(base) => { - self.handle_base_function(base).unwrap(); - } - SbiMessage::GetChar => { - #[allow(deprecated)] - let c = sbi_rt::legacy::console_getchar(); - self.set_gpr_from_gpr_index(GprIndex::A0, c); - } - SbiMessage::PutChar(c) => { - #[allow(deprecated)] - sbi_rt::legacy::console_putchar(c); - } - SbiMessage::SetTimer(timer) => { - info!("Set timer... "); - sbi_rt::set_timer(timer as u64); - // Clear guest timer interrupt - CSR.hvip - .read_and_clear_bits(traps::interrupt::VIRTUAL_SUPERVISOR_TIMER); - // Enable host timer interrupt - CSR.sie - .read_and_set_bits(traps::interrupt::SUPERVISOR_TIMER); - } - SbiMessage::Reset(_) => { - sbi_rt::system_reset(sbi_rt::Shutdown, sbi_rt::SystemFailure); - } - SbiMessage::RemoteFence(rfnc) => { - self.handle_rfnc_function(rfnc).unwrap(); - } - SbiMessage::PMU(pmu) => { - self.handle_pmu_function(pmu).unwrap(); - } - _ => todo!(), - } - self.advance_pc(4); - Ok(AxVCpuExitReason::Nothing) - } else { - panic!() - } - } - Trap::Interrupt(Interrupt::SupervisorTimer) => { - info!("timer irq emulation"); - // Enable guest timer interrupt - CSR.hvip - .read_and_set_bits(traps::interrupt::VIRTUAL_SUPERVISOR_TIMER); - // Clear host timer interrupt - CSR.sie - .read_and_clear_bits(traps::interrupt::SUPERVISOR_TIMER); - Ok(AxVCpuExitReason::Nothing) - } - Trap::Interrupt(Interrupt::SupervisorExternal) => { - Ok(AxVCpuExitReason::ExternalInterrupt { vector: 0 }) - } - Trap::Exception(Exception::LoadGuestPageFault) - | Trap::Exception(Exception::StoreGuestPageFault) => { - let fault_addr = self.regs.trap_csrs.htval << 2 | self.regs.trap_csrs.stval & 0x3; - Ok(AxVCpuExitReason::NestedPageFault { - addr: GuestPhysAddr::from(fault_addr), - access_flags: MappingFlags::empty(), - }) - } - _ => { - panic!( - "Unhandled trap: {:?}, sepc: {:#x}, stval: {:#x}", - scause.cause(), - self.regs.guest_regs.sepc, - self.regs.trap_csrs.stval - ); - } - } - } - - fn handle_base_function(&mut self, base: BaseFunction) -> AxResult<()> { - match base { - BaseFunction::GetSepcificationVersion => { - let version = sbi_rt::get_spec_version(); - self.set_gpr_from_gpr_index(GprIndex::A1, version.major() << 24 | version.minor()); - debug!( - "GetSepcificationVersion: {}", - version.major() << 24 | version.minor() - ); - } - BaseFunction::GetImplementationID => { - let id = sbi_rt::get_sbi_impl_id(); - self.set_gpr_from_gpr_index(GprIndex::A1, id); - } - BaseFunction::GetImplementationVersion => { - let impl_version = sbi_rt::get_sbi_impl_version(); - self.set_gpr_from_gpr_index(GprIndex::A1, impl_version); - } - BaseFunction::ProbeSbiExtension(extension) => { - let extension = sbi_rt::probe_extension(extension as usize).raw; - self.set_gpr_from_gpr_index(GprIndex::A1, extension); - } - BaseFunction::GetMachineVendorID => { - let mvendorid = sbi_rt::get_mvendorid(); - self.set_gpr_from_gpr_index(GprIndex::A1, mvendorid); - } - BaseFunction::GetMachineArchitectureID => { - let marchid = sbi_rt::get_marchid(); - self.set_gpr_from_gpr_index(GprIndex::A1, marchid); - } - BaseFunction::GetMachineImplementationID => { - let mimpid = sbi_rt::get_mimpid(); - self.set_gpr_from_gpr_index(GprIndex::A1, mimpid); - } - } - self.set_gpr_from_gpr_index(GprIndex::A0, 0); - Ok(()) - } - - fn handle_rfnc_function(&mut self, rfnc: RemoteFenceFunction) -> AxResult<()> { - self.set_gpr_from_gpr_index(GprIndex::A0, 0); - match rfnc { - RemoteFenceFunction::FenceI { - hart_mask, - hart_mask_base, - } => { - let sbi_ret = sbi_rt::remote_fence_i(hart_mask as usize, hart_mask_base as usize); - self.set_gpr_from_gpr_index(GprIndex::A0, sbi_ret.error); - self.set_gpr_from_gpr_index(GprIndex::A1, sbi_ret.value); - } - RemoteFenceFunction::RemoteSFenceVMA { - hart_mask, - hart_mask_base, - start_addr, - size, - } => { - let sbi_ret = sbi_rt::remote_sfence_vma( - hart_mask as usize, - hart_mask_base as usize, - start_addr as usize, - size as usize, - ); - self.set_gpr_from_gpr_index(GprIndex::A0, sbi_ret.error); - self.set_gpr_from_gpr_index(GprIndex::A1, sbi_ret.value); - } - } - Ok(()) - } - - fn handle_pmu_function(&mut self, pmu: PmuFunction) -> AxResult<()> { - self.set_gpr_from_gpr_index(GprIndex::A0, 0); - match pmu { - PmuFunction::GetNumCounters => { - self.set_gpr_from_gpr_index(GprIndex::A1, sbi_rt::pmu_num_counters()) - } - PmuFunction::GetCounterInfo(counter_index) => { - let sbi_ret = pmu_counter_get_info(counter_index as usize); - self.set_gpr_from_gpr_index(GprIndex::A0, sbi_ret.error); - self.set_gpr_from_gpr_index(GprIndex::A1, sbi_ret.value); - } - PmuFunction::StopCounter { - counter_index, - counter_mask, - stop_flags, - } => { - let sbi_ret = pmu_counter_stop( - counter_index as usize, - counter_mask as usize, - stop_flags as usize, - ); - self.set_gpr_from_gpr_index(GprIndex::A0, sbi_ret.error); - self.set_gpr_from_gpr_index(GprIndex::A1, sbi_ret.value); - } - } - Ok(()) - } -} - -/// The width of an access. -/// -/// Note that the term "word" here refers to 16-bit data, as in the x86 architecture. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum AccessWidth { - /// 8-bit access. - Byte, - /// 16-bit access. - Word, - /// 32-bit access. - Dword, - /// 64-bit access. - Qword, -} - -/// The port number of an I/O operation. -type Port = u16; - -/// The result of [`AxArchVCpu::run`]. -/// Can we reference or directly reuse content from [kvm-ioctls](https://github.com/rust-vmm/kvm-ioctls/blob/main/src/ioctls/vcpu.rs) ? -#[non_exhaustive] -#[derive(Debug)] -pub enum AxVCpuExitReason { - /// The instruction executed by the vcpu performs a hypercall. - Hypercall { - /// The hypercall number. - nr: u64, - /// The arguments for the hypercall. - args: [u64; 6], - }, - /// The instruction executed by the vcpu performs a MMIO read operation. - MmioRead { - /// The physical address of the MMIO read. - addr: GuestPhysAddr, - /// The width of the MMIO read. - width: AccessWidth, - /// The index of reg to be read - reg: usize, - /// The width of the reg to be read - reg_width: AccessWidth, - }, - /// The instruction executed by the vcpu performs a MMIO write operation. - MmioWrite { - /// The physical address of the MMIO write. - addr: GuestPhysAddr, - /// The width of the MMIO write. - width: AccessWidth, - /// The data to be written. - data: u64, - }, - /// The instruction executed by the vcpu performs a I/O read operation. - /// - /// It's unnecessary to specify the destination register because it's always `al`, `ax`, or `eax` (as port-I/O exists only in x86). - IoRead { - /// The port number of the I/O read. - port: Port, - /// The width of the I/O read. - width: AccessWidth, - }, - /// The instruction executed by the vcpu performs a I/O write operation. - /// - /// It's unnecessary to specify the source register because it's always `al`, `ax`, or `eax` (as port-I/O exists only in x86). - IoWrite { - /// The port number of the I/O write. - port: Port, - /// The width of the I/O write. - width: AccessWidth, - /// The data to be written. - data: u64, - }, - /// An external interrupt happened. - /// - /// Note that fields may be added in the future, use `..` to handle them. - ExternalInterrupt { - /// The interrupt vector. - vector: u64, - }, - /// A nested page fault happened. (EPT violation in x86) - /// - /// Note that fields may be added in the future, use `..` to handle them. - NestedPageFault { - /// The guest physical address of the fault. - addr: GuestPhysAddr, - /// The access flags of the fault. - access_flags: MappingFlags, - }, - /// The vcpu is halted. - Halt, - /// The vcpu is powered off. - /// - /// This vcpu may be resumed later. - CpuDown, - /// The system should be powered off. - /// - /// This is used to notify the hypervisor that the whole system should be powered off. - SystemDown, - /// Nothing special happened, the vcpu has handled the exit itself. - /// - /// This exists to allow the caller to have a chance to check virtual devices/physical devices/virtual interrupts. - Nothing, - /// Something bad happened during VM entry, the vcpu could not be run due to unknown reasons. - /// Further architecture-specific information is available in hardware_entry_failure_reason. - /// Corresponds to `KVM_EXIT_FAIL_ENTRY`. - FailEntry { - /// Architecture related VM entry failure reasons. - hardware_entry_failure_reason: u64, - }, -} diff --git a/arceos/modules/riscv_vcpu/src/vmexit.rs b/arceos/modules/riscv_vcpu/src/vmexit.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/arceos/payload/Makefile b/arceos/payload/Makefile deleted file mode 100644 index 42ddac8ae..000000000 --- a/arceos/payload/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -SUB_DIRS=origin hello_c fileops_c mapfile_c skernel skernel2 - -all: $(SUB_DIRS) - -$(SUB_DIRS): FORCE - make -C $@ - -FORCE: - -.PHONY: all SUB_DIRS FORCE diff --git a/arceos/payload/fileops_c/.gitignore b/arceos/payload/fileops_c/.gitignore deleted file mode 100644 index b91e12299..000000000 --- a/arceos/payload/fileops_c/.gitignore +++ /dev/null @@ -1 +0,0 @@ -fileops diff --git a/arceos/payload/fileops_c/Makefile b/arceos/payload/fileops_c/Makefile deleted file mode 100644 index 4364f919e..000000000 --- a/arceos/payload/fileops_c/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -TARGET := fileops - -CC := riscv64-linux-musl-gcc -STRIP := riscv64-linux-musl-strip - -all: $(TARGET) - -%: %.c - $(CC) -static $< -o $@ - $(STRIP) $@ - -clean: - @rm -rf ./$(TARGET) diff --git a/arceos/payload/fileops_c/fileops.c b/arceos/payload/fileops_c/fileops.c deleted file mode 100644 index 85f6e6bbc..000000000 --- a/arceos/payload/fileops_c/fileops.c +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include -#include - -void create_file(const char *fname) -{ - int fd; - int ret; - char content[] = "hello, arceos!"; - - fd = creat(fname, 0600); - if (fd < 0) { - printf("Create file error!\n"); - exit(-1); - } - ret = write(fd, content, strlen(content)+1); - if (ret < 0) { - printf("Write file error!\n"); - exit(-1); - } - close(fd); -} - -void verify_file(const char *fname) -{ - int fd; - int ret; - char buf[64]; - - fd = open(fname, O_RDONLY); - if (fd < 0) { - printf("Open file error!\n"); - exit(-1); - } - ret = read(fd, buf, sizeof(buf)); - if (ret <= 0) { - printf("Read file error!\n"); - exit(-1); - } - buf[ret] = 0; - printf("Read back content: [%d] %s\n", ret, buf); - close(fd); -} - -int main() -{ - int fd; - int ret; - char fname[] = "test_file"; - - printf("FileOps ...\n"); - - create_file(fname); - verify_file(fname); - - printf("FileOps ok!\n"); - return 0; -} diff --git a/arceos/payload/hello_c/.gitignore b/arceos/payload/hello_c/.gitignore deleted file mode 100644 index ce0136250..000000000 --- a/arceos/payload/hello_c/.gitignore +++ /dev/null @@ -1 +0,0 @@ -hello diff --git a/arceos/payload/hello_c/Makefile b/arceos/payload/hello_c/Makefile deleted file mode 100644 index 9525dd3f1..000000000 --- a/arceos/payload/hello_c/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -TARGET := hello - -CC := riscv64-linux-musl-gcc -STRIP := riscv64-linux-musl-strip - -all: $(TARGET) - -%: %.c - $(CC) -static $< -o $@ - $(STRIP) $@ - -clean: - @rm -rf ./$(TARGET) diff --git a/arceos/payload/hello_c/hello.c b/arceos/payload/hello_c/hello.c deleted file mode 100644 index 9a5cd153b..000000000 --- a/arceos/payload/hello_c/hello.c +++ /dev/null @@ -1,7 +0,0 @@ -#include - -int main() -{ - puts("Hello, UserApp!\n"); - return 0; -} diff --git a/arceos/payload/mapfile_c/.gitignore b/arceos/payload/mapfile_c/.gitignore deleted file mode 100644 index 43934792d..000000000 --- a/arceos/payload/mapfile_c/.gitignore +++ /dev/null @@ -1 +0,0 @@ -mapfile diff --git a/arceos/payload/mapfile_c/Makefile b/arceos/payload/mapfile_c/Makefile deleted file mode 100644 index 7cebfb3d0..000000000 --- a/arceos/payload/mapfile_c/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -TARGET := mapfile - -CC := riscv64-linux-musl-gcc -STRIP := riscv64-linux-musl-strip - -all: $(TARGET) - -%: %.c - $(CC) -static $< -o $@ - $(STRIP) $@ - -clean: - @rm -rf ./$(TARGET) diff --git a/arceos/payload/mapfile_c/mapfile.c b/arceos/payload/mapfile_c/mapfile.c deleted file mode 100644 index 79c394550..000000000 --- a/arceos/payload/mapfile_c/mapfile.c +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include -#include -#include - -void create_file(const char *fname) -{ - int fd; - int ret; - char content[] = "hello, arceos!"; - - fd = creat(fname, 0600); - if (fd < 0) { - printf("Create file error!\n"); - exit(-1); - } - ret = write(fd, content, strlen(content)+1); - if (ret < 0) { - printf("Write file error!\n"); - exit(-1); - } - close(fd); -} - -void verify_file(const char *fname) -{ - int fd; - int ret; - char *addr = NULL; - - fd = open(fname, O_RDONLY); - if (fd < 0) { - printf("Open file error!\n"); - exit(-1); - } - addr = mmap(NULL, 32, PROT_READ, MAP_PRIVATE, fd, 0); - if (addr == NULL) { - printf("Map file error!\n"); - exit(-1); - } - printf("Read back content: %s\n", addr); - close(fd); -} - -int main() -{ - int fd; - int ret; - char fname[] = "test_file"; - - printf("MapFile ...\n"); - - create_file(fname); - verify_file(fname); - - printf("MapFile ok!\n"); - return 0; -} diff --git a/arceos/payload/origin/.gitignore b/arceos/payload/origin/.gitignore deleted file mode 100644 index 60924258b..000000000 --- a/arceos/payload/origin/.gitignore +++ /dev/null @@ -1 +0,0 @@ -origin diff --git a/arceos/payload/origin/Cargo.toml b/arceos/payload/origin/Cargo.toml deleted file mode 100644 index 96f4245a4..000000000 --- a/arceos/payload/origin/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "origin" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/arceos/payload/origin/Makefile b/arceos/payload/origin/Makefile deleted file mode 100644 index 2c6c83504..000000000 --- a/arceos/payload/origin/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -TARGET := origin -TARGET_ELF := ../../target/riscv64gc-unknown-none-elf/release/$(TARGET) - -all: $(TARGET) FORCE - -$(TARGET): $(TARGET_ELF) - @rust-objcopy --binary-architecture=riscv64 --strip-all -O binary $< $@ - -$(TARGET_ELF): - @cargo build -p $(TARGET) --target riscv64gc-unknown-none-elf --release - -clean: - @rm -rf ./$(TARGET) - @cargo clean -p $(TARGET) --target riscv64gc-unknown-none-elf --release - -FORCE: - -.PHONY: FORCE diff --git a/arceos/payload/origin/src/main.rs b/arceos/payload/origin/src/main.rs deleted file mode 100644 index 8fb6403f2..000000000 --- a/arceos/payload/origin/src/main.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![no_std] -#![no_main] - -use core::panic::PanicInfo; - -#[no_mangle] -unsafe extern "C" fn _start() -> ! { - core::arch::asm!( - "addi sp, sp, -4", - "sw a0, (sp)", - "li a7, 93", - "ecall", - options(noreturn) - ) -} - -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - loop {} -} diff --git a/arceos/payload/skernel/.gitignore b/arceos/payload/skernel/.gitignore deleted file mode 100644 index 03c4346f5..000000000 --- a/arceos/payload/skernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -skernel diff --git a/arceos/payload/skernel/Cargo.toml b/arceos/payload/skernel/Cargo.toml deleted file mode 100644 index 1e83ca85d..000000000 --- a/arceos/payload/skernel/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "skernel" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/arceos/payload/skernel/Makefile b/arceos/payload/skernel/Makefile deleted file mode 100644 index aa98ac2fa..000000000 --- a/arceos/payload/skernel/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -TARGET := skernel -TARGET_ELF := ../../target/riscv64gc-unknown-none-elf/release/$(TARGET) - -all: $(TARGET) FORCE - -$(TARGET): $(TARGET_ELF) - @rust-objcopy --binary-architecture=riscv64 --strip-all -O binary $< $@ - -$(TARGET_ELF): - @cargo build -p $(TARGET) --target riscv64gc-unknown-none-elf --release - -clean: - @rm -rf ./$(TARGET) - @cargo clean -p $(TARGET) --target riscv64gc-unknown-none-elf --release - -FORCE: - -.PHONY: FORCE diff --git a/arceos/payload/skernel/src/main.rs b/arceos/payload/skernel/src/main.rs deleted file mode 100644 index b0e170b2b..000000000 --- a/arceos/payload/skernel/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![no_std] -#![no_main] - -use core::panic::PanicInfo; - -#[no_mangle] -unsafe extern "C" fn _start() -> ! { - core::arch::asm!( - "li a7, 8", - "ecall", - options(noreturn) - ) -} - -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - loop {} -} diff --git a/arceos/payload/skernel2/.gitignore b/arceos/payload/skernel2/.gitignore deleted file mode 100644 index 8792f8d21..000000000 --- a/arceos/payload/skernel2/.gitignore +++ /dev/null @@ -1 +0,0 @@ -skernel2 diff --git a/arceos/payload/skernel2/Cargo.toml b/arceos/payload/skernel2/Cargo.toml deleted file mode 100644 index fd67c9c77..000000000 --- a/arceos/payload/skernel2/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "skernel2" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/arceos/payload/skernel2/Makefile b/arceos/payload/skernel2/Makefile deleted file mode 100644 index 4541a9196..000000000 --- a/arceos/payload/skernel2/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -TARGET := skernel2 -TARGET_ELF := ../../target/riscv64gc-unknown-none-elf/release/$(TARGET) - -all: clean $(TARGET) FORCE - -$(TARGET): $(TARGET_ELF) - @rust-objcopy --binary-architecture=riscv64 --strip-all -O binary $< $@ - -$(TARGET_ELF): - @cargo build -p $(TARGET) --target riscv64gc-unknown-none-elf --release - -clean: - @rm -rf ./$(TARGET) - @cargo clean -p $(TARGET) --target riscv64gc-unknown-none-elf --release - -FORCE: - -.PHONY: FORCE diff --git a/arceos/payload/skernel2/src/main.rs b/arceos/payload/skernel2/src/main.rs deleted file mode 100644 index 638915a92..000000000 --- a/arceos/payload/skernel2/src/main.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![no_std] -#![no_main] - -use core::panic::PanicInfo; - -#[no_mangle] -unsafe extern "C" fn _start() -> ! { - core::arch::asm!( - "csrr a1, mhartid", - "ld a0, 64(zero)", - "li a7, 8", - "ecall", - options(noreturn) - ) -} - -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - loop {} -} diff --git a/arceos/platforms/aarch64-bsta1000b.toml b/arceos/platforms/aarch64-bsta1000b.toml deleted file mode 100644 index 48f66efa3..000000000 --- a/arceos/platforms/aarch64-bsta1000b.toml +++ /dev/null @@ -1,64 +0,0 @@ -# Architecture identifier. -arch = "aarch64" -# Platform identifier. -platform = "aarch64-bsta1000b" -# Platform family. -family = "aarch64-bsta1000b" - -# Base address of the whole physical memory. -phys-memory-base = "0x80000000" -# Size of the whole physical memory. -phys-memory-size = "0x70000000" -# Offset of bus address and phys address. some boards, the bus address is -# different from the physical address. -phys-bus-offset = "0" -# Base physical address of the kernel image. -kernel-base-paddr = "0x81000000" -# Base virtual address of the kernel image. -kernel-base-vaddr = "0xffff_0000_8100_0000" -# Linear mapping offset, for quick conversions between physical and virtual -# addresses. -phys-virt-offset = "0xffff_0000_0000_0000" -# Kernel address space base. -kernel-aspace-base = "0xffff_0000_0000_0000" -# Kernel address space size. -kernel-aspace-size = "0x0000_ffff_ffff_f000" -# MMIO regions with format (`base_paddr`, `size`). -mmio-regions = [ - ["0x20008000", "0x1000"], # uart8250 UART0 - ["0x32000000", "0x8000"], # arm,gic-400 - ["0x32011000", "0x1000"], # CPU CSR - ["0x33002000", "0x1000"], # Top CRM - ["0x70035000", "0x1000"], # CRM reg - ["0x70038000", "0x1000"], # aon pinmux -] - -virtio-mmio-regions = [] - -# Base physical address of the PCIe ECAM space. -# pci-ecam-base = "0x40_1000_0000" -# End PCI bus number (`bus-range` property in device tree). -# pci-bus-end = "0xff" -# PCI device memory ranges (`ranges` property in device tree). -# pci-ranges = [] - -# UART Address -uart-paddr = "0x20008000" -# UART irq from device tree -uart-irq = "0xd5" -# GICD Address -gicd-paddr = "0x32001000" -# GICC Address -gicc-paddr = "0x32002000" - -# BST A1000B board registers -CPU_CSR_BASE = "0x32011000" -A1000BASE_TOPCRM = "0x33002000" -A1000BASE_SAFETYCRM = "0x70035000" -A1000BASE_AONCFG = "0x70038000" - -# PSCI -psci-method = "smc" - -# RTC (PL031) Address (Need to read from DTB). -rtc-paddr = "0x0" \ No newline at end of file diff --git a/arceos/platforms/aarch64-qemu-virt.toml b/arceos/platforms/aarch64-qemu-virt.toml deleted file mode 100644 index 8f8867375..000000000 --- a/arceos/platforms/aarch64-qemu-virt.toml +++ /dev/null @@ -1,99 +0,0 @@ -# Architecture identifier. -arch = "aarch64" -# Platform identifier. -platform = "aarch64-qemu-virt" -# Platform family. -family = "aarch64-qemu-virt" - -# Base address of the whole physical memory. -phys-memory-base = "0x4000_0000" -# Size of the whole physical memory. -phys-memory-size = "0x800_0000" # 128M -# Base physical address of the kernel image. -kernel-base-paddr = "0x4008_0000" -# Base virtual address of the kernel image. -kernel-base-vaddr = "0xffff_0000_4008_0000" -# Linear mapping offset, for quick conversions between physical and virtual -# addresses. -phys-virt-offset = "0xffff_0000_0000_0000" -# Offset of bus address and phys address. some boards, the bus address is -# different from the physical address. -phys-bus-offset = "0" -# Kernel address space base. -kernel-aspace-base = "0xffff_0000_0000_0000" -# Kernel address space size. -kernel-aspace-size = "0x0000_ffff_ffff_f000" -# MMIO regions with format (`base_paddr`, `size`). -mmio-regions = [ - ["0x0900_0000", "0x1000"], # PL011 UART - ["0x0910_0000", "0x1000"], # PL031 RTC - ["0x0800_0000", "0x2_0000"], # GICv2 - ["0x0a00_0000", "0x4000"], # VirtIO - ["0x1000_0000", "0x2eff_0000"], # PCI memory ranges (ranges 1: 32-bit MMIO space) - ["0x40_1000_0000", "0x1000_0000"], # PCI config space -] -# VirtIO MMIO regions with format (`base_paddr`, `size`). -virtio-mmio-regions = [ - ["0x0a00_0000", "0x200"], - ["0x0a00_0200", "0x200"], - ["0x0a00_0400", "0x200"], - ["0x0a00_0600", "0x200"], - ["0x0a00_0800", "0x200"], - ["0x0a00_0a00", "0x200"], - ["0x0a00_0c00", "0x200"], - ["0x0a00_0e00", "0x200"], - ["0x0a00_1000", "0x200"], - ["0x0a00_1200", "0x200"], - ["0x0a00_1400", "0x200"], - ["0x0a00_1600", "0x200"], - ["0x0a00_1800", "0x200"], - ["0x0a00_1a00", "0x200"], - ["0x0a00_1c00", "0x200"], - ["0x0a00_1e00", "0x200"], - ["0x0a00_3000", "0x200"], - ["0x0a00_2200", "0x200"], - ["0x0a00_2400", "0x200"], - ["0x0a00_2600", "0x200"], - ["0x0a00_2800", "0x200"], - ["0x0a00_2a00", "0x200"], - ["0x0a00_2c00", "0x200"], - ["0x0a00_2e00", "0x200"], - ["0x0a00_3000", "0x200"], - ["0x0a00_3200", "0x200"], - ["0x0a00_3400", "0x200"], - ["0x0a00_3600", "0x200"], - ["0x0a00_3800", "0x200"], - ["0x0a00_3a00", "0x200"], - ["0x0a00_3c00", "0x200"], - ["0x0a00_3e00", "0x200"], -] -# Base physical address of the PCIe ECAM space. -pci-ecam-base = "0x40_1000_0000" -# End PCI bus number (`bus-range` property in device tree). -pci-bus-end = "0xff" -# PCI device memory ranges (`ranges` property in device tree). -pci-ranges = [ - ["0x3ef_f0000", "0x1_0000"], # PIO space - ["0x1000_0000", "0x2eff_0000"], # 32-bit MMIO space - ["0x80_0000_0000", "0x80_0000_0000"], # 64-but MMIO space -] -# UART Address -uart-paddr = "0x0900_0000" -uart-irq = "1" - -# GICC Address -gicc-paddr = "0x0801_0000" -gicd-paddr = "0x0800_0000" - -# PSCI -psci-method = "hvc" - -# pl031@9010000 { -# clock-names = "apb_pclk"; -# clocks = <0x8000>; -# interrupts = <0x00 0x02 0x04>; -# reg = <0x00 0x9010000 0x00 0x1000>; -# compatible = "arm,pl031\0arm,primecell"; -# }; -# RTC (PL031) Address -rtc-paddr = "0x901_0000" \ No newline at end of file diff --git a/arceos/platforms/aarch64-raspi4.toml b/arceos/platforms/aarch64-raspi4.toml deleted file mode 100644 index 5edae2850..000000000 --- a/arceos/platforms/aarch64-raspi4.toml +++ /dev/null @@ -1,40 +0,0 @@ -# Architecture identifier. -arch = "aarch64" -# Platform identifier. -platform = "aarch64-raspi4" -# Platform family. -family = "aarch64-raspi" - -# Base address of the whole physical memory. -phys-memory-base = "0x0" -# Size of the whole physical memory. -phys-memory-size = "0xFC00_0000" # 3G 960M -# Base physical address of the kernel image. -kernel-base-paddr = "0x8_0000" -# Base virtual address of the kernel image. -kernel-base-vaddr = "0xffff_0000_0008_0000" -# Linear mapping offset, for quick conversions between physical and virtual -# addresses. -phys-virt-offset = "0xffff_0000_0000_0000" -# Offset of bus address and phys address. -phys-bus-offset = "0xC0000000" -# Kernel address space base. -kernel-aspace-base = "0xffff_0000_0000_0000" -# Kernel address space size. -kernel-aspace-size = "0x0000_ffff_ffff_f000" -# MMIO regions with format (`base_paddr`, `size`). -mmio-regions = [ - ["0xFE20_1000", "0x1000"], # PL011 UART - ["0xFF84_1000", "0x8000"], # GICv2 -] -virtio-mmio-regions = [] -# UART Address -uart-paddr = "0xFE20_1000" -uart-irq = "0x79" - -# GIC Address -gicc-paddr = "0xFF84_2000" -gicd-paddr = "0xFF84_1000" - -# RTC (PL031) Address (Need to read from DTB). -rtc-paddr = "0x0" diff --git a/arceos/platforms/riscv64-qemu-virt.toml b/arceos/platforms/riscv64-qemu-virt.toml deleted file mode 100644 index 283be75bd..000000000 --- a/arceos/platforms/riscv64-qemu-virt.toml +++ /dev/null @@ -1,68 +0,0 @@ -# Architecture identifier. -arch = "riscv64" -# Platform identifier. -platform = "riscv64-qemu-virt" -# Platform family. -family = "riscv64-qemu-virt" - -# Base address of the whole physical memory. -phys-memory-base = "0x8000_0000" -# Size of the whole physical memory. -phys-memory-size = "0x800_0000" # 128M -# Base physical address of the kernel image. -kernel-base-paddr = "0x8020_0000" -# Base virtual address of the kernel image. -kernel-base-vaddr = "0xffff_ffc0_8020_0000" -# Linear mapping offset, for quick conversions between physical and virtual -# addresses. -phys-virt-offset = "0xffff_ffc0_0000_0000" -# Offset of bus address and phys address. some boards, the bus address is -# different from the physical address. -phys-bus-offset = "0" -# Kernel address space base. -kernel-aspace-base = "0xffff_ffc0_0000_0000" -# Kernel address space size. -kernel-aspace-size = "0x0000_003f_ffff_f000" -# MMIO regions with format (`base_paddr`, `size`). -mmio-regions = [ - ["0x0010_1000", "0x1000"], # RTC - ["0x0c00_0000", "0x21_0000"], # PLIC - ["0x1000_0000", "0x1000"], # UART - ["0x1000_1000", "0x8000"], # VirtIO - ["0x2200_0000", "0x0200_0000"], # PFlash - ["0x3000_0000", "0x1000_0000"], # PCI config space - ["0x4000_0000", "0x4000_0000"], # PCI memory ranges (ranges 1: 32-bit MMIO space) -] -# VirtIO MMIO regions with format (`base_paddr`, `size`). -virtio-mmio-regions = [ - ["0x1000_1000", "0x1000"], - ["0x1000_2000", "0x1000"], - ["0x1000_3000", "0x1000"], - ["0x1000_4000", "0x1000"], - ["0x1000_5000", "0x1000"], - ["0x1000_6000", "0x1000"], - ["0x1000_7000", "0x1000"], - ["0x1000_8000", "0x1000"], -] -# Base physical address of the PCIe ECAM space. -pci-ecam-base = "0x3000_0000" -# End PCI bus number (`bus-range` property in device tree). -pci-bus-end = "0xff" -# PCI device memory ranges (`ranges` property in device tree). -pci-ranges = [ - ["0x0300_0000", "0x1_0000"], # PIO space - ["0x4000_0000", "0x4000_0000"], # 32-bit MMIO space - ["0x4_0000_0000", "0x4_0000_0000"], # 64-but MMIO space -] - -# Timer interrupt frequency in Hz. -timer-frequency = "10_000_000" # 10MHz - -# rtc@101000 { -# interrupts = <0x0b>; -# interrupt-parent = <0x03>; -# reg = <0x00 0x101000 0x00 0x1000>; -# compatible = "google,goldfish-rtc"; -# }; -# RTC (goldfish) Address -rtc-paddr = "0x10_1000" diff --git a/arceos/platforms/x86_64-pc-oslab.toml b/arceos/platforms/x86_64-pc-oslab.toml deleted file mode 100644 index 8c4d1238a..000000000 --- a/arceos/platforms/x86_64-pc-oslab.toml +++ /dev/null @@ -1,44 +0,0 @@ -# Architecture identifier. -arch = "x86_64" -# Platform identifier. -platform = "x86_64-pc-oslab" -# Platform family. -family = "x86-pc" - -# Base address of the whole physical memory. -phys-memory-base = "0" -# Size of the whole physical memory. -phys-memory-size = "0x8000_0000" # 2G -# Base physical address of the kernel image. -kernel-base-paddr = "0x20_0000" -# Base virtual address of the kernel image. -kernel-base-vaddr = "0xffff_ff80_0020_0000" -# Linear mapping offset, for quick conversions between physical and virtual -# addresses. -phys-virt-offset = "0xffff_ff80_0000_0000" -# Offset of bus address and phys address. some boards, the bus address is -# different from the physical address. -phys-bus-offset = "0" -# Kernel address space base. -kernel-aspace-base = "0xffff_ff80_0000_0000" -# Kernel address space size. -kernel-aspace-size = "0x0000_007f_ffff_f000" -# MMIO regions with format (`base_paddr`, `size`). -mmio-regions = [ - ["0xfec0_0000", "0x1000"], # IO APIC - ["0xfed0_0000", "0x1000"], # HPET - ["0xfee0_0000", "0x1000"], # Local APIC - ["0xf000_0000", "0x0800_0000"], # PCI config space - ["0xfcd8_0000", "0x0008_0000"], # Ixgbe BAR0 -] -# VirtIO MMIO regions with format (`base_paddr`, `size`). -virtio-mmio-regions = [] -# Base physical address of the PCIe ECAM space (should read from ACPI 'MCFG' table). -pci-ecam-base = "0xf000_0000" -# End PCI bus number. -pci-bus-end = "0x7f" -# PCI device memory ranges (not used on x86). -pci-ranges = [] - -# Timer interrupt frequencyin Hz. -timer-frequency = "4_000_000_000" # 4.0GHz diff --git a/arceos/platforms/x86_64-qemu-q35.toml b/arceos/platforms/x86_64-qemu-q35.toml deleted file mode 100644 index 9b9b9e0fb..000000000 --- a/arceos/platforms/x86_64-qemu-q35.toml +++ /dev/null @@ -1,44 +0,0 @@ -# Architecture identifier. -arch = "x86_64" -# Platform identifier. -platform = "x86_64-qemu-q35" -# Platform family. -family = "x86-pc" - -# Base address of the whole physical memory. -phys-memory-base = "0" -# Size of the whole physical memory. -phys-memory-size = "0x800_0000" # 128M -# Base physical address of the kernel image. -kernel-base-paddr = "0x20_0000" -# Base virtual address of the kernel image. -kernel-base-vaddr = "0xffff_ff80_0020_0000" -# Linear mapping offset, for quick conversions between physical and virtual -# addresses. -phys-virt-offset = "0xffff_ff80_0000_0000" -# Offset of bus address and phys address. some boards, the bus address is -# different from the physical address. -phys-bus-offset = "0" -# Kernel address space base. -kernel-aspace-base = "0xffff_ff80_0000_0000" -# Kernel address space size. -kernel-aspace-size = "0x0000_007f_ffff_f000" -# MMIO regions with format (`base_paddr`, `size`). -mmio-regions = [ - ["0xb000_0000", "0x1000_0000"], # PCI config space - ["0xfe00_0000", "0xc0_0000"], # PCI devices - ["0xfec0_0000", "0x1000"], # IO APIC - ["0xfed0_0000", "0x1000"], # HPET - ["0xfee0_0000", "0x1000"], # Local APIC -] -# VirtIO MMIO regions with format (`base_paddr`, `size`). -virtio-mmio-regions = [] -# Base physical address of the PCIe ECAM space (should read from ACPI 'MCFG' table). -pci-ecam-base = "0xb000_0000" -# End PCI bus number. -pci-bus-end = "0xff" -# PCI device memory ranges (not used on x86). -pci-ranges = [] - -# Timer interrupt frequencyin Hz. -timer-frequency = "4_000_000_000" # 4.0GHz diff --git a/arceos/rust-toolchain.toml b/arceos/rust-toolchain.toml deleted file mode 100644 index 6d76fb10c..000000000 --- a/arceos/rust-toolchain.toml +++ /dev/null @@ -1,6 +0,0 @@ -[toolchain] -profile = "minimal" -# channel = "nightly-2024-05-02" -channel = "nightly-2024-09-04" -components = ["rust-src", "llvm-tools", "rustfmt", "clippy"] -targets = ["x86_64-unknown-none", "riscv64gc-unknown-none-elf", "aarch64-unknown-none", "aarch64-unknown-none-softfloat"] diff --git a/arceos/scripts/make/bsta1000b-fada.mk b/arceos/scripts/make/bsta1000b-fada.mk deleted file mode 100644 index 7a9efe400..000000000 --- a/arceos/scripts/make/bsta1000b-fada.mk +++ /dev/null @@ -1,4 +0,0 @@ -fada: build - gzip -9 -cvf $(OUT_BIN) > arceos-fada.bin.gz - mkimage -f tools/bsta1000b/bsta1000b-fada-arceos.its arceos-fada.itb - @echo 'Built the FIT-uImage arceos-fada.itb' diff --git a/arceos/scripts/make/build.mk b/arceos/scripts/make/build.mk deleted file mode 100644 index a8790ec71..000000000 --- a/arceos/scripts/make/build.mk +++ /dev/null @@ -1,47 +0,0 @@ -# Main building script - -include scripts/make/cargo.mk - -ifeq ($(APP_TYPE), c) - include scripts/make/build_c.mk -else - rust_package := $(shell cat $(APP)/Cargo.toml | sed -n 's/^name = "\([a-z0-9A-Z_\-]*\)"/\1/p') - rust_elf := $(TARGET_DIR)/$(TARGET)/$(MODE)/$(rust_package) -endif - -ifneq ($(filter $(MAKECMDGOALS),doc doc_check_missing),) # run `cargo doc` - $(if $(V), $(info RUSTDOCFLAGS: "$(RUSTDOCFLAGS)")) - export RUSTDOCFLAGS -else ifeq ($(filter $(MAKECMDGOALS),clippy unittest unittest_no_fail_fast),) # not run `cargo test` or `cargo clippy` - ifneq ($(V),) - $(info APP: "$(APP)") - $(info APP_TYPE: "$(APP_TYPE)") - $(info FEATURES: "$(FEATURES)") - $(info arceos features: "$(AX_FEAT)") - $(info lib features: "$(LIB_FEAT)") - $(info app features: "$(APP_FEAT)") - endif - ifeq ($(APP_TYPE), c) - $(if $(V), $(info CFLAGS: "$(CFLAGS)") $(info LDFLAGS: "$(LDFLAGS)")) - else - $(if $(V), $(info RUSTFLAGS: "$(RUSTFLAGS)")) - export RUSTFLAGS - endif -endif - -_cargo_build: - @printf " $(GREEN_C)Building$(END_C) App: $(APP_NAME), Arch: $(ARCH), Platform: $(PLATFORM_NAME), App type: $(APP_TYPE)\n" -ifeq ($(APP_TYPE), rust) - $(call cargo_build,$(APP),$(AX_FEAT) $(LIB_FEAT) $(APP_FEAT)) - @cp $(rust_elf) $(OUT_ELF) -else ifeq ($(APP_TYPE), c) - $(call cargo_build,ulib/axlibc,$(AX_FEAT) $(LIB_FEAT)) -endif - -$(OUT_DIR): - $(call run_cmd,mkdir,-p $@) - -$(OUT_BIN): _cargo_build $(OUT_ELF) - $(call run_cmd,$(OBJCOPY),$(OUT_ELF) --strip-all -O binary $@) - -.PHONY: _cargo_build diff --git a/arceos/scripts/make/build_c.mk b/arceos/scripts/make/build_c.mk deleted file mode 100644 index 76064b502..000000000 --- a/arceos/scripts/make/build_c.mk +++ /dev/null @@ -1,75 +0,0 @@ -rust_lib_name := axlibc -rust_lib := $(TARGET_DIR)/$(TARGET)/$(MODE)/lib$(rust_lib_name).a - -ulib_dir := ulib/axlibc -src_dir := $(ulib_dir)/c -obj_dir := $(ulib_dir)/build_$(ARCH) -inc_dir := $(ulib_dir)/include -c_lib := $(obj_dir)/libc.a -libgcc := - -last_cflags := $(obj_dir)/.cflags - -ulib_src := $(wildcard $(src_dir)/*.c) -ulib_hdr := $(wildcard $(inc_dir)/*.h) -ulib_obj := $(patsubst $(src_dir)/%.c,$(obj_dir)/%.o,$(ulib_src)) - -CFLAGS += $(addprefix -DAX_CONFIG_,$(shell echo $(lib_feat) | tr 'a-z' 'A-Z' | tr '-' '_')) -CFLAGS += -DAX_LOG_$(shell echo $(LOG) | tr 'a-z' 'A-Z') - -CFLAGS += -nostdinc -fno-builtin -ffreestanding -Wall -CFLAGS += -I$(CURDIR)/$(inc_dir) -LDFLAGS += -nostdlib -static -no-pie --gc-sections -znostart-stop-gc -T$(LD_SCRIPT) - -ifeq ($(MODE), release) - CFLAGS += -O3 -endif - -ifeq ($(ARCH), riscv64) - CFLAGS += -march=rv64gc -mabi=lp64d -mcmodel=medany -endif - -ifeq ($(findstring fp_simd,$(FEATURES)),) - ifeq ($(ARCH), x86_64) - CFLAGS += -mno-sse - else ifeq ($(ARCH), aarch64) - CFLAGS += -mgeneral-regs-only - endif -else - ifneq ($(filter $(ARCH),riscv64 aarch64),) - # for compiler-rt fallbacks like `__divtf3`, `__multf3`, ... - libgcc := $(shell $(CC) -print-libgcc-file-name) - endif -endif - -_check_need_rebuild: $(obj_dir) - @if [ "$(CFLAGS)" != "`cat $(last_cflags) 2>&1`" ]; then \ - echo "CFLAGS changed, rebuild"; \ - echo "$(CFLAGS)" > $(last_cflags); \ - fi - -$(obj_dir): - $(call run_cmd,mkdir,-p $@) - -$(obj_dir)/%.o: $(src_dir)/%.c $(last_cflags) - $(call run_cmd,$(CC),$(CFLAGS) -c -o $@ $<) - -$(c_lib): $(obj_dir) _check_need_rebuild $(ulib_obj) - $(call run_cmd,$(AR),rcs $@ $(ulib_obj)) - -app-objs := main.o - --include $(APP)/axbuild.mk # override `app-objs` - -app-objs := $(addprefix $(APP)/,$(app-objs)) - -$(APP)/%.o: $(APP)/%.c $(ulib_hdr) - $(call run_cmd,$(CC),$(CFLAGS) $(APP_CFLAGS) -c -o $@ $<) - -$(OUT_ELF): $(libgcc) $(app-objs) $(c_lib) $(rust_lib) - @printf " $(CYAN_C)Linking$(END_C) $(OUT_ELF)\n" - $(call run_cmd,$(LD),$(LDFLAGS) $^ -o $@) - -$(APP)/axbuild.mk: ; - -.PHONY: _check_need_rebuild diff --git a/arceos/scripts/make/cargo.mk b/arceos/scripts/make/cargo.mk deleted file mode 100644 index bda44e2de..000000000 --- a/arceos/scripts/make/cargo.mk +++ /dev/null @@ -1,48 +0,0 @@ -# Cargo features and build args - -ifeq ($(V),1) - verbose := -v -else ifeq ($(V),2) - verbose := -vv -else - verbose := -endif - -build_args-release := --release - -build_args := \ - -Z unstable-options \ - --target $(TARGET) \ - --target-dir $(TARGET_DIR) \ - $(build_args-$(MODE)) \ - $(verbose) - -RUSTFLAGS := -C link-arg=-T$(LD_SCRIPT) -C link-arg=-no-pie -C link-arg=-znostart-stop-gc -RUSTDOCFLAGS := -Z unstable-options --enable-index-page -D rustdoc::broken_intra_doc_links - -ifeq ($(MAKECMDGOALS), doc_check_missing) - RUSTDOCFLAGS += -D missing-docs -endif - -define cargo_build - $(call run_cmd,cargo -C $(1) build,$(build_args) --features "$(strip $(2))") -endef - -clippy_args := -A clippy::new_without_default - -define cargo_clippy - $(call run_cmd,cargo clippy,--all-features --workspace --exclude axlog $(1) $(verbose) -- $(clippy_args)) - $(call run_cmd,cargo clippy,-p axlog $(1) $(verbose) -- $(clippy_args)) -endef - -all_packages := \ - $(shell ls $(CURDIR)/modules) \ - axfeat arceos_api axstd axlibc - -define cargo_doc - $(call run_cmd,cargo doc,--no-deps --all-features --workspace --exclude "arceos-*" $(verbose)) - @# run twice to fix broken hyperlinks - $(foreach p,$(all_packages), \ - $(call run_cmd,cargo rustdoc,--all-features -p $(p) $(verbose)) - ) -endef diff --git a/arceos/scripts/make/features.mk b/arceos/scripts/make/features.mk deleted file mode 100644 index 48ae99cf9..000000000 --- a/arceos/scripts/make/features.mk +++ /dev/null @@ -1,60 +0,0 @@ -# Features resolving. -# -# Inputs: -# - `FEATURES`: a list of features to be enabled split by spaces or commas. -# The features can be selected from the crate `axfeat` or the user library -# (crate `axstd` or `axlibc`). -# - `APP_FEATURES`: a list of features to be enabled for the Rust app. -# -# Outputs: -# - `AX_FEAT`: features to be enabled for ArceOS modules (crate `axfeat`). -# - `LIB_FEAT`: features to be enabled for the user library (crate `axstd`, `axlibc`). -# - `APP_FEAT`: features to be enabled for the Rust app. - -ifeq ($(APP_TYPE),c) - ax_feat_prefix := axfeat/ - lib_feat_prefix := axlibc/ - lib_features := fp_simd irq alloc multitask fs net fd pipe select epoll -else - # TODO: it's better to use `axfeat/` as `ax_feat_prefix`, but all apps need to have `axfeat` as a dependency - ax_feat_prefix := axstd/ - lib_feat_prefix := axstd/ - lib_features := -endif - -override FEATURES := $(shell echo $(FEATURES) | tr ',' ' ') - -ifeq ($(APP_TYPE), c) - ifneq ($(wildcard $(APP)/features.txt),) # check features.txt exists - override FEATURES += $(shell cat $(APP)/features.txt) - endif - ifneq ($(filter fs net pipe select epoll,$(FEATURES)),) - override FEATURES += fd - endif -endif - -override FEATURES := $(strip $(FEATURES)) - -ax_feat := -lib_feat := - -ifneq ($(filter $(LOG),off error warn info debug trace),) - ax_feat += log-level-$(LOG) -else - $(error "LOG" must be one of "off", "error", "warn", "info", "debug", "trace") -endif - -ifeq ($(BUS),mmio) - ax_feat += bus-mmio -endif - -ifeq ($(shell test $(SMP) -gt 1; echo $$?),0) - lib_feat += smp -endif - -ax_feat += $(filter-out $(lib_features),$(FEATURES)) -lib_feat += $(filter $(lib_features),$(FEATURES)) - -AX_FEAT := $(strip $(addprefix $(ax_feat_prefix),$(ax_feat))) -LIB_FEAT := $(strip $(addprefix $(lib_feat_prefix),$(lib_feat))) -APP_FEAT := $(strip $(shell echo $(APP_FEATURES) | tr ',' ' ')) diff --git a/arceos/scripts/make/qemu.mk b/arceos/scripts/make/qemu.mk deleted file mode 100644 index c2a642d9a..000000000 --- a/arceos/scripts/make/qemu.mk +++ /dev/null @@ -1,91 +0,0 @@ -# QEMU arguments - -QEMU := qemu-system-$(ARCH) - -ifeq ($(BUS), mmio) - vdev-suffix := device -else ifeq ($(BUS), pci) - vdev-suffix := pci -else - $(error "BUS" must be one of "mmio" or "pci") -endif - -qemu_args-x86_64 := \ - -machine q35 \ - -kernel $(OUT_ELF) - -qemu_args-riscv64 := \ - -machine virt \ - -bios default \ - -kernel $(OUT_BIN) - -qemu_args-aarch64 := \ - -cpu cortex-a72 \ - -machine virt \ - -kernel $(OUT_BIN) - -qemu_args-y := -m 128M -smp $(SMP) $(qemu_args-$(ARCH)) - -qemu_args-$(PFLASH) += \ - -drive if=pflash,file=$(CURDIR)/$(PFLASH_IMG),format=raw,unit=1 - -qemu_args-$(BLK) += \ - -device virtio-blk-$(vdev-suffix),drive=disk0 \ - -drive id=disk0,if=none,format=raw,file=$(DISK_IMG) - -qemu_args-$(NET) += \ - -device virtio-net-$(vdev-suffix),netdev=net0 - -ifeq ($(NET_DEV), user) - qemu_args-$(NET) += -netdev user,id=net0,hostfwd=tcp::5555-:5555,hostfwd=udp::5555-:5555 -else ifeq ($(NET_DEV), tap) - qemu_args-$(NET) += -netdev tap,id=net0,script=scripts/net/qemu-ifup.sh,downscript=no,vhost=$(VHOST),vhostforce=$(VHOST) - QEMU := sudo $(QEMU) -else ifeq ($(NET_DEV), bridge) - qemu_args-$(NET) += -netdev bridge,id=net0,br=virbr0 - QEMU := sudo $(QEMU) -else - $(error "NET_DEV" must be one of "user", "tap", or "bridge") -endif - -ifneq ($(VFIO_PCI),) - qemu_args-y += --device vfio-pci,host=$(VFIO_PCI) - QEMU := sudo $(QEMU) -endif - -ifeq ($(NET_DUMP), y) - qemu_args-$(NET) += -object filter-dump,id=dump0,netdev=net0,file=netdump.pcap -endif - -qemu_args-$(GRAPHIC) += \ - -device virtio-gpu-$(vdev-suffix) -vga none \ - -serial mon:stdio - -ifeq ($(GRAPHIC), n) - qemu_args-y += -nographic -endif - -ifeq ($(QEMU_LOG), y) - qemu_args-y += -D qemu.log -d in_asm,int,mmu,pcall,cpu_reset,guest_errors -endif - -qemu_args-debug := $(qemu_args-y) -s -S - -# Do not use KVM for debugging -ifeq ($(shell uname), Darwin) - qemu_args-$(ACCEL) += -cpu host -accel hvf -else ifeq ($(wildcard /dev/kvm),) - qemu_args-$(ACCEL) += -accel tcg -else - qemu_args-$(ACCEL) += -cpu host -accel kvm -endif - -define run_qemu - @printf " $(CYAN_C)Running$(END_C) on qemu...\n" - $(call run_cmd,$(QEMU),$(qemu_args-y)) -endef - -define run_qemu_debug - @printf " $(CYAN_C)Debugging$(END_C) on qemu...\n" - $(call run_cmd,$(QEMU),$(qemu_args-debug)) -endef diff --git a/arceos/scripts/make/raspi4.mk b/arceos/scripts/make/raspi4.mk deleted file mode 100644 index dbc2fb565..000000000 --- a/arceos/scripts/make/raspi4.mk +++ /dev/null @@ -1,95 +0,0 @@ -include tools/raspi4/common/docker.mk -include tools/raspi4/common/format.mk -include tools/raspi4/common/operating_system.mk - -##-------------------------------------------------------------------------------------------------- -## Optional, user-provided configuration values -##-------------------------------------------------------------------------------------------------- - -# Default to the RPi4. -BSP ?= rpi4 - -# Default to a serial device name that is common in Linux. -DEV_SERIAL ?= /dev/ttyUSB0 - -##-------------------------------------------------------------------------------------------------- -## BSP-specific configuration values -##-------------------------------------------------------------------------------------------------- -QEMU_MISSING_STRING = "This board is not yet supported for QEMU." - -ifeq ($(BSP),rpi4) - TARGET = aarch64-unknown-none-softfloat - KERNEL_BIN := $(OUT_BIN) - OBJDUMP_BINARY = aarch64-none-elf-objdump - NM_BINARY = aarch64-none-elf-nm - READELF_BINARY = aarch64-none-elf-readelf - # OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi4.cfg - OPENOCD_ARG = -f /openocd/tcl/interface/jlink.cfg -f /openocd/rpi4.cfg - JTAG_BOOT_IMAGE := $(OUT_BIN) - RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 -endif - -EXEC_MINIPUSH = ruby tools/raspi4/common/serial/minipush.rb - -##------------------------------------------------------------------------------ -## Dockerization -##------------------------------------------------------------------------------ -DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial -DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i -DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/tools/raspi4/common:/work/common -DOCKER_ARG_DIR_JTAG = -v $(shell pwd)/tools/raspi4/X1_JTAG_boot:/work/X1_JTAG_boot -DOCKER_ARG_DEV = --privileged -v /dev:/dev -DOCKER_ARG_NET = --network host - -# DOCKER_IMAGE defined in include file (see top of this file). -DOCKER_GDB = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_NET) $(DOCKER_IMAGE) - -# Dockerize commands, which require USB device passthrough, only on Linux. -ifeq ($(shell uname -s),Linux) - DOCKER_CMD_DEV = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DEV) - DOCKER_CHAINBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) - DOCKER_JTAGBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_ARG_DIR_JTAG) $(DOCKER_IMAGE) - DOCKER_OPENOCD = $(DOCKER_CMD_DEV) $(DOCKER_ARG_NET) $(DOCKER_IMAGE) -else - DOCKER_OPENOCD = echo "Not yet supported on non-Linux systems."; \# -endif - -##-------------------------------------------------------------------------------------------------- -## Targets -##-------------------------------------------------------------------------------------------------- -.PHONY: all chainboot - -all: $(KERNEL_BIN) - -##------------------------------------------------------------------------------ -## Push the kernel to the real HW target -##------------------------------------------------------------------------------ -chainboot: $(KERNEL_BIN) - @$(DOCKER_CHAINBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(KERNEL_BIN) - - -##-------------------------------------------------------------------------------------------------- -## Debugging targets -##-------------------------------------------------------------------------------------------------- -.PHONY: jtagboot openocd gdb gdb-opt0 - -##------------------------------------------------------------------------------ -## Push the JTAG boot image to the real HW target -##------------------------------------------------------------------------------ -jtagboot: $(KERNEL_BIN) - @$(DOCKER_JTAGBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(JTAG_BOOT_IMAGE) - -##------------------------------------------------------------------------------ -## Start OpenOCD session -##------------------------------------------------------------------------------ -openocd: - $(call color_header, "Launching OpenOCD") - @$(DOCKER_OPENOCD) openocd $(OPENOCD_ARG) - -##------------------------------------------------------------------------------ -## Start GDB session -##------------------------------------------------------------------------------ -gdb: RUSTC_MISC_ARGS += -C debuginfo=2 -gdb: $(KERNEL_ELF) - $(call color_header, "Launching GDB") - @$(DOCKER_GDB) gdb-multiarch -q $(KERNEL_ELF) diff --git a/arceos/scripts/make/test.mk b/arceos/scripts/make/test.mk deleted file mode 100644 index 76e74920d..000000000 --- a/arceos/scripts/make/test.mk +++ /dev/null @@ -1,6 +0,0 @@ -# Test scripts - -define unit_test - $(call run_cmd,cargo test,-p axfs $(1) --features "myfs" -- --nocapture) - $(call run_cmd,cargo test,--workspace $(1) -- --nocapture) -endef diff --git a/arceos/scripts/make/utils.mk b/arceos/scripts/make/utils.mk deleted file mode 100644 index 42579be88..000000000 --- a/arceos/scripts/make/utils.mk +++ /dev/null @@ -1,49 +0,0 @@ -# Utility definitions and functions - -GREEN_C := \033[92;1m -CYAN_C := \033[96;1m -YELLOW_C := \033[93;1m -GRAY_C := \033[90m -WHITE_C := \033[37m -END_C := \033[0m - -define run_cmd - @printf '$(WHITE_C)$(1)$(END_C) $(GRAY_C)$(2)$(END_C)\n' - @$(1) $(2) -endef - -define make_disk_image_fat32 - @printf " $(GREEN_C)Creating$(END_C) FAT32 disk image \"$(1)\" ...\n" - @dd if=/dev/zero of=$(1) bs=1M count=64 - @mkfs.fat -F 32 $(1) -endef - -define make_disk_image - $(if $(filter $(1),fat32), $(call make_disk_image_fat32,$(2))) -endef - -define mk_pflash - @RUSTFLAGS="" cargo build -p origin --target riscv64gc-unknown-none-elf --release - @rust-objcopy --binary-architecture=riscv64 --strip-all -O binary ./target/riscv64gc-unknown-none-elf/release/origin /tmp/origin.bin - @printf "pfld\00\00\00\01" > /tmp/prefix.bin - @printf "%08x" `stat -c "%s" /tmp/origin.bin` | xxd -r -ps > /tmp/size.bin - @cat /tmp/prefix.bin /tmp/size.bin > /tmp/head.bin - @dd if=/dev/zero of=./$(1) bs=1M count=32 - @dd if=/tmp/head.bin of=./$(1) conv=notrunc - @dd if=/tmp/origin.bin of=./$(1) seek=16 obs=1 conv=notrunc -endef - -define setup_disk - $(call build_origin) - @mkdir -p ./mnt - @sudo mount $(1) ./mnt - @sudo mkdir -p ./mnt/sbin - @sudo cp /tmp/origin.bin ./mnt/sbin - @sudo umount ./mnt - @rm -rf mnt -endef - -define build_origin - @RUSTFLAGS="" cargo build -p origin --target riscv64gc-unknown-none-elf --release - @rust-objcopy --binary-architecture=riscv64 --strip-all -O binary ./target/riscv64gc-unknown-none-elf/release/origin /tmp/origin.bin -endef diff --git a/arceos/scripts/net/create-bridge.sh b/arceos/scripts/net/create-bridge.sh deleted file mode 100755 index 3ed9cb01c..000000000 --- a/arceos/scripts/net/create-bridge.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -# -# Create virtual bridge for QEMU. -# -# sudo ./create-bridge.sh [virbr0] - -BR=$1 -IP=10.0.2.2 - -if [ -z "$BR" ]; then - BR=virbr0 -fi - -echo "Deleting old virtual bridge $BR ..." - -ip link set dev $BR down 2> /dev/null -brctl delbr $BR 2> /dev/null - -echo "Setting up virtual bridge $BR ..." - -brctl addbr $BR -ip addr add $IP/24 dev $BR -ip link set dev $BR up -brctl show $BR - -ifconfig $BR diff --git a/arceos/scripts/net/del-iface.sh b/arceos/scripts/net/del-iface.sh deleted file mode 100755 index 7d679b0a2..000000000 --- a/arceos/scripts/net/del-iface.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# -# Delete virtual interface (e.g. virtual bridge). -# -# sudo ./del-iface.sh - -IFACE=$1 - -if [ -z "$IFACE" ]; then - echo "Usage: $0 " - exit 1 -fi - -ip link del $IFACE diff --git a/arceos/scripts/net/pci-bind.sh b/arceos/scripts/net/pci-bind.sh deleted file mode 100755 index d2479328b..000000000 --- a/arceos/scripts/net/pci-bind.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -# Bind a PCI device to the `vfio-pci` driver for PCI passthrough. -# -# Bind: sudo ./pci-bind.sh vfio-pci 02:00.0 -# Unbind: sudo ./pci-bind.sh ixgbe 02:00.0 - -new_drv=$1 -bdf=$2 - -if [ -z "$bdf" -o -z "$new_drv" ]; then - echo "Usage: $0 " - exit 1 -fi - -bdf=0000:$bdf -old_drv=$(readlink /sys/bus/pci/devices/$bdf/driver | awk -F/ '{print $NF}') - -echo "Bind $bdf from $old_drv to $new_drv" - -echo $bdf > /sys/bus/pci/drivers/$old_drv/unbind -echo $new_drv > /sys/bus/pci/devices/$bdf/driver_override -echo $bdf > /sys/bus/pci/drivers/$new_drv/bind diff --git a/arceos/scripts/net/qemu-ifup.sh b/arceos/scripts/net/qemu-ifup.sh deleted file mode 100755 index b3e2c21b2..000000000 --- a/arceos/scripts/net/qemu-ifup.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# -# Create a TAP interface and add it to the bridge. -# -# It's used for the startup script of QEMU netdev, DO NOT run it manually. - -br=virbr0 -if [ -n "$1" ]; then - #create a TAP interface; qemu will handle it automatically. - #tunctl -u $(whoami) -t $1 - #start up the TAP interface - ip link set "$1" up - brctl addif $br "$1" - exit -else - echo "Error: no interface specified" - exit 1 -fi diff --git a/arceos/scripts/net/set-ip-forward.sh b/arceos/scripts/net/set-ip-forward.sh deleted file mode 100755 index 3ccb8bf50..000000000 --- a/arceos/scripts/net/set-ip-forward.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# -# Setup IP forwarding to allow Internet access in the VM. - -WLAN_IF=$1 -BR=virbr0 -IP_RANGE=10.0.2.0/24 - -if [ -z "$WLAN_IF" ]; then - echo "Usage: $0 " - exit 1 -fi - -sysctl -w net.ipv4.ip_forward=1 - -iptables -t nat -A POSTROUTING -s $IP_RANGE -o $WLAN_IF -j MASQUERADE -iptables -A FORWARD -i $BR -j ACCEPT -iptables -A FORWARD -o $BR -m state --state RELATED,ESTABLISHED -j ACCEPT diff --git a/arceos/scripts/net/unset-ip-forward.sh b/arceos/scripts/net/unset-ip-forward.sh deleted file mode 100755 index c361b6443..000000000 --- a/arceos/scripts/net/unset-ip-forward.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# -# Disable IP forwarding and restore iptables rules. - -WLAN_IF=$1 -BR=virbr0 -IP_RANGE=10.0.2.0/24 - -if [ -z "$WLAN_IF" ]; then - echo "Usage: $0 " - exit 1 -fi - -sysctl -w net.ipv4.ip_forward=0 - -iptables -t nat -D POSTROUTING -s $IP_RANGE -o $WLAN_IF -j MASQUERADE -iptables -D FORWARD -i $BR -j ACCEPT -iptables -D FORWARD -o $BR -m state --state RELATED,ESTABLISHED -j ACCEPT diff --git a/arceos/test_tour.sh b/arceos/test_tour.sh deleted file mode 100755 index b6d6ce3f1..000000000 --- a/arceos/test_tour.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -rm pflash.img -rm disk.img - -make pflash_img -make disk_img - -make run A=tour/u_1_0 -make run A=tour/u_2_0 -make run A=tour/u_3_0 -make run A=tour/u_4_0 -make run A=tour/u_5_0 -make run A=tour/u_6_0 -make run A=tour/u_6_1 -make run A=tour/u_7_0 BLK=y -make run A=tour/u_8_0 BLK=y diff --git a/arceos/tools/.gitignore b/arceos/tools/.gitignore deleted file mode 100644 index 632baf2a0..000000000 --- a/arceos/tools/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -deptool/Cargo.lock -deptool/target -deptool/output.txt -bwbench_client/target -bwbench_client/Cargo.lock \ No newline at end of file diff --git a/arceos/tools/bsta1000b/bsta1000b-fada-arceos.its b/arceos/tools/bsta1000b/bsta1000b-fada-arceos.its deleted file mode 100755 index 8062b6354..000000000 --- a/arceos/tools/bsta1000b/bsta1000b-fada-arceos.its +++ /dev/null @@ -1,50 +0,0 @@ -/* - * U-Boot uImage source file with multiple kernels, ramdisks and FDT blobs - */ - -/dts-v1/; - -/ { - description = "Various kernels, ramdisks and FDT blobs"; - #address-cells = <1>; - - images { - kernel { - description = "ArceOS for BST A1000B"; - data = /incbin/("../../arceos-fada.bin.gz"); - type = "kernel"; - arch = "arm64"; - os = "linux"; - compression = "gzip"; - load = <0x81000000>; - entry = <0x81000000>; - hash-1 { - algo = "md5"; - }; - hash-2 { - algo = "sha1"; - }; - }; - - fdt-fada { - description = "bsta1000b-fada fdt"; - data = /incbin/("./bsta1000b-fada.dtb"); - type = "flat_dt"; - arch = "arm64"; - compression = "none"; - hash-1 { - algo = "crc32"; - }; - }; - }; - - configurations { - default = "config-fada"; - - config-fada { - description = "bsta1000b fada configuration"; - kernel = "kernel"; - fdt = "fdt-fada"; - }; - }; -}; diff --git a/arceos/tools/bsta1000b/bsta1000b-fada.dtb b/arceos/tools/bsta1000b/bsta1000b-fada.dtb deleted file mode 100644 index ff0ea9a42..000000000 Binary files a/arceos/tools/bsta1000b/bsta1000b-fada.dtb and /dev/null differ diff --git a/arceos/tools/bwbench_client/Cargo.toml b/arceos/tools/bwbench_client/Cargo.toml deleted file mode 100644 index 5f20be709..000000000 --- a/arceos/tools/bwbench_client/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "bwbench-client" -version = "0.1.0" -edition = "2021" -authors = ["ChengXiang Qi "] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -chrono = "0.4" -libc = "0.2.18" - -[workspace] \ No newline at end of file diff --git a/arceos/tools/bwbench_client/README.md b/arceos/tools/bwbench_client/README.md deleted file mode 100644 index 0d447ccc0..000000000 --- a/arceos/tools/bwbench_client/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# Benchmark BandWidth Client - -Benchmark BandWidth Client is a performance testing tool for measuring the network card's ability to send Ethernet packets. It can test both the transmission throughput and the reception throughput. - -## Usage -In client: -```shell -cargo build --release -sudo ./target/release/bwbench_client [sender|receiver] [interface] -``` - -By reading the source code, you can control the behavior of the benchmark by modifying constants such as `MAX_BYTES`. - -In arceos: - -```shell -make A=apps/net/bwbench LOG=info NET=y run -``` - -By default, arceos `bebench` uses `bench_transmit`. You can uncomment the line and add `bench_receive`, but please note that currently only one of either `bench_transmit` or `bench_receive` is allowed to be enabled. - - -## Example: benchmark bandwidth of QEMU tap netdev - -In client: - -```shell -cargo build --release -sudo ./scripts/net/qemu-tap-ifup.sh enp8s0 -sudo ./target/release/bwbench_client [sender|receiver] tap0 -``` - -In arceos: - -```shell -make A=apps/net/bwbench LOG=info NET=y NET_DEV=tap run -``` diff --git a/arceos/tools/bwbench_client/src/device.rs b/arceos/tools/bwbench_client/src/device.rs deleted file mode 100644 index 67097482a..000000000 --- a/arceos/tools/bwbench_client/src/device.rs +++ /dev/null @@ -1,217 +0,0 @@ -use std::os::unix::io::AsRawFd; - -const ETH_P_ALL: libc::c_short = 0x0003; -const SIOCGIFINDEX: libc::c_ulong = 0x8933; -const SIOCGIFMTU: libc::c_ulong = 0x8921; -const SIOCSIFMTU: libc::c_ulong = 0x8922; -const SIOCGIFHWADDR: libc::c_ulong = 0x8927; - -#[repr(C)] -#[derive(Clone, Copy)] -#[allow(non_camel_case_types)] -union ifreq_data { - ifr_mtu: libc::c_int, - mac_addr: libc::sockaddr, -} - -#[repr(C)] -#[allow(non_camel_case_types)] -struct ifreq { - ifr_name: [libc::c_char; libc::IF_NAMESIZE], - ifr_data: ifreq_data, -} - -impl ifreq { - #[cfg(target_os = "linux")] - fn ifreq_for(interface: &str) -> ifreq { - let mut ifreq = ifreq { - ifr_name: [0; libc::IF_NAMESIZE], - ifr_data: ifreq_data { ifr_mtu: 0 }, - }; - for (i, byte) in interface.as_bytes().iter().enumerate() { - ifreq.ifr_name[i] = *byte as libc::c_char - } - ifreq - } - - #[cfg(target_os = "linux")] - fn ioctl(&mut self, lower: libc::c_int, cmd: libc::c_ulong) -> std::io::Result { - unsafe { - if libc::ioctl(lower, cmd as _, self as *mut Self) < 0 { - return Err(std::io::Error::last_os_error()); - } - } - Ok(self.ifr_data) - } -} - -pub struct NetDevice { - fd: libc::c_int, - ifreq: ifreq, - mac_addr: [u8; 6], -} - -impl AsRawFd for NetDevice { - fn as_raw_fd(&self) -> std::os::unix::io::RawFd { - self.fd - } -} - -impl NetDevice { - pub fn new(interface: &str) -> std::io::Result { - #[cfg(target_os = "linux")] - { - let lower = unsafe { - let lower = libc::socket( - libc::AF_PACKET, - libc::SOCK_RAW | libc::SOCK_NONBLOCK, - ETH_P_ALL.to_be() as i32, - ); - if lower == -1 { - return Err(std::io::Error::last_os_error()); - } - lower - }; - - let mut ifreq = ifreq::ifreq_for(interface); - - let ifreq_mac_addr = unsafe { ifreq.ioctl(lower, SIOCGIFHWADDR)?.mac_addr }; - let mut mac_addr = [0u8; 6]; - for i in 0..6 { - mac_addr[i] = ifreq_mac_addr.sa_data[i] as u8; - } - - println!( - "Device MAC: {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", - mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5] - ); - - let mut dev = Self { - fd: lower, - ifreq, - mac_addr, - }; - - dev.bind_interface()?; - - let mtu = dev.interface_mtu()?; - println!("DEVICE MTU: {}", mtu); - - Ok(dev) - } - #[cfg(not(target_os = "linux"))] - { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "Not supported", - )) - } - } - - pub fn mac_addr(&self) -> [u8; 6] { - self.mac_addr - } - - pub fn bind_interface(&mut self) -> std::io::Result<()> { - #[cfg(target_os = "linux")] - { - let sockaddr = libc::sockaddr_ll { - sll_family: libc::AF_PACKET as u16, - sll_protocol: ETH_P_ALL.to_be() as u16, - sll_ifindex: unsafe { - self.ifreq.ioctl(self.fd, SIOCGIFINDEX)?.ifr_mtu as libc::c_int - }, - sll_hatype: 1, - sll_pkttype: 0, - sll_halen: 6, - sll_addr: [0; 8], - }; - - unsafe { - let res = libc::bind( - self.fd, - &sockaddr as *const libc::sockaddr_ll as *const libc::sockaddr, - std::mem::size_of::() as libc::socklen_t, - ); - if res == -1 { - return Err(std::io::Error::last_os_error()); - } - } - - Ok(()) - } - #[cfg(not(target_os = "linux"))] - { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "Not supported", - )) - } - } - - pub fn interface_mtu(&mut self) -> std::io::Result { - #[cfg(target_os = "linux")] - { - self.ifreq - .ioctl(self.fd, SIOCGIFMTU) - .map(|mtu| unsafe { mtu.ifr_mtu as usize }) - } - #[cfg(not(target_os = "linux"))] - { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "Not supported", - )) - } - } - - pub fn recv(&mut self, buffer: &mut [u8]) -> std::io::Result { - let len = unsafe { - libc::recv( - self.fd, - buffer.as_mut_ptr() as *mut libc::c_void, - buffer.len(), - 0, - ) - }; - - if len == -1 { - let err = std::io::Error::last_os_error(); - if err.kind() == std::io::ErrorKind::WouldBlock { - return Err(err); - } else { - panic!("err: {:?}", err); - } - } - Ok(len as usize) - } - - pub fn send(&mut self, buffer: &[u8]) -> std::io::Result { - let len = unsafe { - libc::send( - self.fd, - buffer.as_ptr() as *const libc::c_void, - buffer.len(), - 0, - ) - }; - - if len == -1 { - let err = std::io::Error::last_os_error(); - if err.kind() == std::io::ErrorKind::WouldBlock { - return Err(err); - } else { - panic!("err: {:?}", err); - } - } - Ok(len as usize) - } -} - -impl Drop for NetDevice { - fn drop(&mut self) { - unsafe { - libc::close(self.fd); - } - } -} diff --git a/arceos/tools/bwbench_client/src/main.rs b/arceos/tools/bwbench_client/src/main.rs deleted file mode 100644 index f9b24c69c..000000000 --- a/arceos/tools/bwbench_client/src/main.rs +++ /dev/null @@ -1,133 +0,0 @@ -//! A raw socket benchmark client. - -#![deny(warnings)] -#![deny(missing_docs)] -#![allow(dead_code, unused_variables)] - -use crate::device::NetDevice; -use chrono::Local; -use std::env; -use std::fmt::Display; - -mod device; - -const STANDARD_MTU: usize = 1500; - -const MAX_BYTES: usize = 10 * GB; -const MB: usize = 1000 * 1000; -const GB: usize = 1000 * MB; - -struct EthernetMacAddress([u8; 6]); - -impl Display for EthernetMacAddress { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mac = self.0; - write!( - f, - "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] - ) - } -} - -enum Client { - Sender, - Receiver, -} - -fn transmit_benchmark(interface: &str) { - println!("Sender Mode!"); - let mut dev = NetDevice::new(interface).unwrap(); - - let mut tx_buf = [1u8; STANDARD_MTU]; - // ether type: IPv4 - tx_buf[12..14].copy_from_slice(&[0x08, 0x00]); - - let mut send_bytes = 0; - let mut past_send_bytes = 0; - let mut past_time = Local::now(); - - loop { - if let Ok(len) = dev.send(&tx_buf[..]) { - send_bytes += len; - let current_time = Local::now(); - if current_time.signed_duration_since(past_time).num_seconds() == 1 { - let gb = ((send_bytes - past_send_bytes) * 8) / GB; - let mb = (((send_bytes - past_send_bytes) * 8) % GB) / MB; - let gib = (send_bytes - past_send_bytes) / GB; - let mib = ((send_bytes - past_send_bytes) % GB) / MB; - println!( - "Transfer: {}.{:03}GBytes, Bandwidth: {}.{:03}Gbits/sec.", - gib, mib, gb, mb - ); - past_send_bytes = send_bytes; - past_time = current_time; - } - } - - if send_bytes >= MAX_BYTES { - break; - } - } -} - -fn receive_benchmark(interface: &str) { - println!("Receiver Mode!"); - let mut dev = NetDevice::new(interface).unwrap(); - - let mut receive_bytes = 0; - let mut past_receive_bytes = 0; - let mut past_time = Local::now(); - - let mut rx_buffer = [0; STANDARD_MTU]; - - loop { - if let Ok(len) = dev.recv(&mut rx_buffer) { - receive_bytes += len; - } - - let current_time = Local::now(); - if current_time.signed_duration_since(past_time).num_seconds() == 1 { - let gb = ((receive_bytes - past_receive_bytes) * 8) / GB; - let mb = (((receive_bytes - past_receive_bytes) * 8) % GB) / MB; - let gib = (receive_bytes - past_receive_bytes) / GB; - let mib = ((receive_bytes - past_receive_bytes) % GB) / MB; - println!( - "Receive: {}.{:03}GBytes, Bandwidth: {}.{:03}Gbits/sec.", - gib, mib, gb, mb - ); - past_receive_bytes = receive_bytes; - past_time = current_time; - } - - if receive_bytes >= MAX_BYTES { - break; - } - } -} - -fn benchmark_bandwidth(client: Client, interface: &str) { - match client { - Client::Sender => transmit_benchmark(interface), - Client::Receiver => receive_benchmark(interface), - } -} - -fn main() { - let args: Vec = env::args().collect(); - - if args.len() < 3 { - panic!("Usage: cargo run --release [send|receive] "); - } - - let kind = args[1].as_str(); - let client = match kind.chars().next().unwrap() { - 's' => Client::Sender, - 'r' => Client::Receiver, - _ => panic!("Unknown Mode!"), - }; - - let interface = args[2].as_str(); - - benchmark_bandwidth(client, interface); -} diff --git a/arceos/tools/deptool/Cargo.toml b/arceos/tools/deptool/Cargo.toml deleted file mode 100644 index 3a2e95435..000000000 --- a/arceos/tools/deptool/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "deptool" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] - clap = {version = "4.3.5"} -[workspace] diff --git a/arceos/tools/deptool/Makefile b/arceos/tools/deptool/Makefile deleted file mode 100644 index e046bbeb9..000000000 --- a/arceos/tools/deptool/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -FEATURES ?= default -DEFAULT ?= y -FORMAT ?= mermaid -TARGET ?= helloworld -SAVE_PATH ?= output.txt -_DEFAULT_OPT = -_FEATURES_OPT = -BUILD_DIR = ./target - -ifeq ($(DEFAULT), y) - _DEFAULT_OPT = --no-default -endif - -ifneq ($(FEATURES), default) - _FEATURES_OPT = --name $(FEATURES) -endif - -ifeq ($(TARGET),) - $(error must specify a target using TARGET=... which should be a valid module, crate or app path) -endif - -clean: - cargo clean - rm $(SAVE_PATH) - -run: - @cargo build - @./target/debug/deptool $(_DEFAULT_OPT) \ - $(_FEATURES_OPT) \ - --format $(FORMAT) \ - --target $(TARGET) \ - --save-path $(SAVE_PATH) - -.PHONY: build run clean diff --git a/arceos/tools/deptool/README.md b/arceos/tools/deptool/README.md deleted file mode 100644 index 0d43a5718..000000000 --- a/arceos/tools/deptool/README.md +++ /dev/null @@ -1,17 +0,0 @@ -## Usage of this tool - -``` -make run FORMAT=mermaid FEATURES=f1,f2,f3 DEFAULT=n -``` - -the `FORMAT` can be either **mermaid** or **d2** (default is mermaid), it will out put the result under the deptool directory. - -the `TARGET` should be any existed crate or module name, or the path under app directory: eg helloworld, net/httpserver - -the `FEATURES` should be the features you want to use, this should be separated by "," - -the `DEFAULT` is used to control enable default features or not **n** for no and **y** for yes - -the first time you run this tool to analyze a crate/module/app will be slow or blocked for downloading the needed crates for the target - -if you think this makefile too naive, you can just run `cargo build`, and then use `./target/debug/deptool -h` to see the available options to use diff --git a/arceos/tools/deptool/src/cmd_builder.rs b/arceos/tools/deptool/src/cmd_builder.rs deleted file mode 100644 index 5a6b389d7..000000000 --- a/arceos/tools/deptool/src/cmd_builder.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::Config; - -pub fn build_cargo_tree_cmd(cfg: &Config) -> String { - let default_opt = match cfg.no_default { - true => "", - false => "--no-default-features" - }; - - let features_opt = match cfg.features.len() { - 0 => "".to_string(), - _ => "-F ".to_string() + cfg.features.join(" ").as_str() - }; - let path = &cfg.loc; - let cmd_str = format!( - "cd {path} && cargo tree -e normal,build {default_opt} {features_opt} --format {{p}} --prefix depth", - ); - cmd_str.to_string() -} diff --git a/arceos/tools/deptool/src/cmd_parser.rs b/arceos/tools/deptool/src/cmd_parser.rs deleted file mode 100644 index d3bc109bc..000000000 --- a/arceos/tools/deptool/src/cmd_parser.rs +++ /dev/null @@ -1,91 +0,0 @@ -use std::{fs, path::Path}; -use clap::{Arg, ArgAction, Command}; -use crate::{Config, GraphFormat}; - -static APP_ROOT: &str = "../../apps/"; -static CRATE_ROOT: &str = "../../crates/"; -static MODULE_ROOT: &str = "../../modules/"; -static ULIB_ROOT: &str = "../../ulib/"; - - -/// Ex: exe --default=false --format=mermaid --features=f1 f2 f3 -pub fn parse_cmd() -> Result { - let matches = Command::new("Dependency analysis tool for Arceos") - .version("1.0") - .author("ctr") - .about("Generate d2 or mermaid dependency graph for Arceos based on cargo tree") - .arg( - Arg::new("no-default").short('d').long("no-default").action(ArgAction::SetFalse) - ) - .arg( - Arg::new("features").short('f').long("name").action(ArgAction::Append) - ) - .arg( - Arg::new("format").short('o').long("format").default_value("mermaid") - ) - .arg( - Arg::new("target").short('t').long("target").required(true) - ) - .arg( - Arg::new("save-path").short('s').long("save-path").default_value("out.txt") - ) - .get_matches(); - - let is_default = matches.get_flag("no-default"); - let features = matches.get_many::("features").unwrap_or_default() - .map(|f| f.to_string()) - .collect(); - let format = match matches.get_one::("format").unwrap().as_str() { - "d2" => GraphFormat::D2, - _ => GraphFormat::Mermaid - }; - let target = matches.get_one::("target").unwrap().to_string(); - if !is_arceos_crate(&target) { - return Err("target not exist, should be valid arceos crate, module or app"); - } - - let loc; - if check_crate_name(&target) { - loc = CRATE_ROOT.to_string() + ⌖ - } else if check_module_name(&target) { - loc = MODULE_ROOT.to_string() + ⌖ - } else { - loc = APP_ROOT.to_string() + ⌖ - } - let output_loc = matches.get_one::("save-path").unwrap().to_string(); - Ok(gen_config(is_default, features, format, loc, output_loc)) -} - -fn gen_config(is_default: bool, features: Vec::, format: GraphFormat, loc: String, output_loc: String) -> Config { - Config::build(is_default, features, format, loc, output_loc) -} - -pub fn check_crate_name(name: &String) -> bool { - let crates = fs::read_dir(CRATE_ROOT).unwrap(); - crates.into_iter().map(|p| p.unwrap().file_name()).any(|n| n.to_str().unwrap() == name) -} - -pub fn check_module_name(name: &String) -> bool { - let crates = fs::read_dir(MODULE_ROOT).unwrap(); - crates.into_iter().map(|p| p.unwrap().file_name()).any(|n| n.to_str().unwrap() == name) -} - -pub fn check_app_name(name: &String) -> bool { - Path::new(&(APP_ROOT.to_string() + name)).exists() -} - -pub fn check_lib_name(name: &String) -> bool { - Path::new(&(ULIB_ROOT.to_string() + name)).exists() -} - -pub fn is_arceos_crate(name: &String) -> bool { - check_crate_name(&name) || check_module_name(&name) || check_app_name(name) || check_lib_name(name) -} - -pub fn build_loc(name: &String) -> String { - if check_module_name(name) { - MODULE_ROOT.to_string() + name - } else { - CRATE_ROOT.to_string() + name - } -} diff --git a/arceos/tools/deptool/src/d2_generator.rs b/arceos/tools/deptool/src/d2_generator.rs deleted file mode 100644 index 0a76e107f..000000000 --- a/arceos/tools/deptool/src/d2_generator.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::collections::HashMap; - -use crate::{parse_deps, cmd_parser::is_arceos_crate}; - -/// without further exploiting the feature of d2 graph, this is almost the same syntax with mermaid -/// except that d2 use " -> ", instead of "-->" -pub fn gen_d2_script(deps: &String, result: &mut String) { - let deps_parsed = parse_deps(&deps); - let dep_root = &deps_parsed[0]; - - let mut parsed_crates: Vec<&String> = Vec::new(); - let mut lastest_dep_map: HashMap = HashMap::new(); - let mut idx: usize = 1; - - lastest_dep_map.insert(0, &dep_root.1); - while idx < deps_parsed.len() { - let (level, name) = deps_parsed.get(idx).unwrap(); - if !is_arceos_crate(&name) { - idx += 1; - continue; - } - *result += &format!("{} -> {}\n", lastest_dep_map[&(level - 1)], name); - if parsed_crates.contains(&name) { - let mut skip_idx: usize = idx + 1; - if skip_idx >= deps_parsed.len() { - break; - } - while deps_parsed.get(skip_idx).unwrap().0 > *level { - idx += 1; - skip_idx += 1; - } - idx += 1; - } else { - parsed_crates.push(&name); - lastest_dep_map.insert(*level, name); - idx += 1; - } - } -} diff --git a/arceos/tools/deptool/src/lib.rs b/arceos/tools/deptool/src/lib.rs deleted file mode 100644 index aa24bc2f0..000000000 --- a/arceos/tools/deptool/src/lib.rs +++ /dev/null @@ -1,100 +0,0 @@ -mod cmd_parser; -mod cmd_builder; -mod mermaid_generator; -mod d2_generator; - -use std::process::Command; -use std::fs::File; -use std::io::Write; - -use cmd_builder::build_cargo_tree_cmd; -pub use cmd_parser::{parse_cmd, build_loc}; -use d2_generator::gen_d2_script; -use mermaid_generator::gen_mermaid_script; - -#[derive(Clone, Copy, Debug)] -pub enum GraphFormat { - Mermaid, - D2, -} - -#[derive(Debug)] -pub struct Config { - pub no_default: bool, - pub format: GraphFormat, - pub features: Vec::, - loc: String, - output_loc: String -} - -impl Config { - pub fn build(no_default: bool, features: Vec::, format: GraphFormat, loc: String, output_loc: String) -> Config { - Config { no_default, format, features, loc, output_loc } - } -} - -fn get_deps_by_crate_name(cfg: &Config) -> String { - let cmd_ct = build_cargo_tree_cmd(&cfg); - let cmds = ["-c", &cmd_ct]; - let output = if cfg!(target_os = "windows") { - Command::new("cmd") - .args(cmds) - .output() - .expect("failed to execute process") - } else { - Command::new("sh") - .args(cmds) - .output() - .expect("failed to execute process") - }; - - let deps = output.stdout; - String::from_utf8(deps).unwrap() -} - -fn parse_deps(deps: &String) -> Vec<(i32, String)> { - let mut rst = vec!(); - for line in deps.lines() { - let level_name = line.split_whitespace().next().unwrap(); - let level = level_name.get(0..1).unwrap().parse().unwrap(); - let name = level_name.get(1..).unwrap(); - rst.push((level, name.to_string())); - } - rst -} - -fn generate_mermaid(config: &Config) -> String { - let mut result = String::from(""); - let deps = get_deps_by_crate_name(config); - gen_mermaid_script(&deps, &mut result); - "graph TD;\n".to_string() + &result -} - -fn generate_d2(config: &Config) -> String { - let mut result = String::from(""); - let deps = get_deps_by_crate_name(config); - gen_d2_script(&deps, &mut result); - result -} - -fn generate_deps_graph(config: &Config) -> String { - match config.format { - GraphFormat::D2 => generate_d2(config), - _ => generate_mermaid(config) - } -} - -fn output_deps_graph(rst: &String) -> std::io::Result<()> { - let mut file = File::create("output.txt")?; - file.write_all(rst.as_bytes())?; - Ok(()) -} - -pub fn run(config: &Config) { - let rst = generate_deps_graph(config); - print!("{}", rst); - match output_deps_graph(&rst) { - Ok(()) => {}, - Err(error) => println!("Error during writing file {}, {}", config.output_loc, error) - } -} diff --git a/arceos/tools/deptool/src/main.rs b/arceos/tools/deptool/src/main.rs deleted file mode 100644 index b6b0fb75f..000000000 --- a/arceos/tools/deptool/src/main.rs +++ /dev/null @@ -1,11 +0,0 @@ -use deptool::{run, parse_cmd}; -use std::process; - -fn main() { - let config = parse_cmd().unwrap_or_else(|err| { - eprintln!("problem parsinig arguments: {err}"); - process::exit(1); - }); - - run(&config); -} diff --git a/arceos/tools/deptool/src/mermaid_generator.rs b/arceos/tools/deptool/src/mermaid_generator.rs deleted file mode 100644 index bb43552b2..000000000 --- a/arceos/tools/deptool/src/mermaid_generator.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::collections::HashMap; - -use crate::{parse_deps, cmd_parser::is_arceos_crate}; - -pub fn gen_mermaid_script(deps: &String, result: &mut String) { - let deps_parsed = parse_deps(&deps); - let dep_root = &deps_parsed[0]; - - let mut parsed_crates: Vec<&String> = Vec::new(); - let mut lastest_dep_map: HashMap = HashMap::new(); - let mut idx: usize = 1; - - lastest_dep_map.insert(0, &dep_root.1); - while idx < deps_parsed.len() { - let (level, name) = deps_parsed.get(idx).unwrap(); - if !is_arceos_crate(&name) { - idx += 1; - continue; - } - *result += &format!("{}-->{}\n", lastest_dep_map[&(level - 1)], name); - if parsed_crates.contains(&name) { - let mut skip_idx: usize = idx + 1; - if skip_idx >= deps_parsed.len() { - break; - } - while deps_parsed.get(skip_idx).unwrap().0 > *level { - idx += 1; - skip_idx += 1; - } - idx += 1; - } else { - parsed_crates.push(&name); - lastest_dep_map.insert(*level, name); - idx += 1; - } - } -} diff --git a/arceos/tools/raspi4/chainloader/.gitignore b/arceos/tools/raspi4/chainloader/.gitignore deleted file mode 100644 index 2f7896d1d..000000000 --- a/arceos/tools/raspi4/chainloader/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/arceos/tools/raspi4/chainloader/.vscode/settings.json b/arceos/tools/raspi4/chainloader/.vscode/settings.json deleted file mode 100644 index bfa278e9a..000000000 --- a/arceos/tools/raspi4/chainloader/.vscode/settings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false -} diff --git a/arceos/tools/raspi4/chainloader/Cargo.toml b/arceos/tools/raspi4/chainloader/Cargo.toml deleted file mode 100644 index 1fe55455e..000000000 --- a/arceos/tools/raspi4/chainloader/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "mingo" -version = "0.6.0" -authors = ["Andre Richter "] -edition = "2021" - -[profile.release] -lto = true - -[features] -default = [] -bsp_rpi3 = ["tock-registers"] -bsp_rpi4 = ["tock-registers"] -enable_jtag_debug = [] - -[[bin]] -name = "kernel" -path = "src/main.rs" - -##-------------------------------------------------------------------------------------------------- -## Dependencies -##-------------------------------------------------------------------------------------------------- - -[dependencies] - -# Optional dependencies -tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } - -# Platform specific dependencies -[target.'cfg(target_arch = "aarch64")'.dependencies] -aarch64-cpu = { version = "9.x.x" } - -[workspace] diff --git a/arceos/tools/raspi4/chainloader/Makefile b/arceos/tools/raspi4/chainloader/Makefile deleted file mode 100644 index 2c3620ca9..000000000 --- a/arceos/tools/raspi4/chainloader/Makefile +++ /dev/null @@ -1,236 +0,0 @@ -## SPDX-License-Identifier: MIT OR Apache-2.0 -## -## Copyright (c) 2018-2023 Andre Richter - -include ../common/docker.mk -include ../common/format.mk -include ../common/operating_system.mk - -##-------------------------------------------------------------------------------------------------- -## Optional, user-provided configuration values -##-------------------------------------------------------------------------------------------------- - -# Default to the RPi3. -BSP ?= rpi4 - -# Default to a serial device name that is common in Linux. -DEV_SERIAL ?= /dev/ttyUSB0 - -# Default not to enable jtag debug -JTAG ?= n - -##-------------------------------------------------------------------------------------------------- -## BSP-specific configuration values -##-------------------------------------------------------------------------------------------------- -QEMU_MISSING_STRING = "This board is not yet supported for QEMU." - -TARGET = aarch64-unknown-none-softfloat -KERNEL_BIN = kernel8.img -QEMU_BINARY = qemu-system-aarch64 -QEMU_MACHINE_TYPE = -QEMU_RELEASE_ARGS = -serial stdio -display none -OBJDUMP_BINARY = aarch64-none-elf-objdump -NM_BINARY = aarch64-none-elf-nm -READELF_BINARY = aarch64-none-elf-readelf -LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi -RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 -CHAINBOOT_DEMO_PAYLOAD = demo_payload_rpi4.img - -# Export for build.rs. -export LD_SCRIPT_PATH - - - -##-------------------------------------------------------------------------------------------------- -## Targets and Prerequisites -##-------------------------------------------------------------------------------------------------- -KERNEL_MANIFEST = Cargo.toml -KERNEL_LINKER_SCRIPT = kernel.ld -LAST_BUILD_CONFIG = target/$(BSP).build_config - -KERNEL_ELF = target/$(TARGET)/release/kernel -# This parses cargo's dep-info file. -# https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) - - - -##-------------------------------------------------------------------------------------------------- -## Command building blocks -##-------------------------------------------------------------------------------------------------- -RUSTFLAGS = $(RUSTC_MISC_ARGS) \ - -C link-arg=--library-path=$(LD_SCRIPT_PATH) \ - -C link-arg=--script=$(KERNEL_LINKER_SCRIPT) - -RUSTFLAGS_PEDANTIC = $(RUSTFLAGS) \ - -D warnings \ - -D missing_docs - -FEATURES = --features bsp_$(BSP) -ifeq ($(JTAG),y) - FEATURES += --features enable_jtag_debug -endif -COMPILER_ARGS = --target=$(TARGET) \ - $(FEATURES) \ - --release - -RUSTC_CMD = cargo rustc $(COMPILER_ARGS) -DOC_CMD = cargo doc $(COMPILER_ARGS) -CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -OBJCOPY_CMD = rust-objcopy \ - --strip-all \ - -O binary - -EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) -EXEC_TEST_MINIPUSH = ruby tests/chainboot_test.rb -EXEC_MINIPUSH = ruby ../common/serial/minipush.rb - -##------------------------------------------------------------------------------ -## Dockerization -##------------------------------------------------------------------------------ -DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial -DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i -DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common -DOCKER_ARG_DEV = --privileged -v /dev:/dev - -# DOCKER_IMAGE defined in include file (see top of this file). -DOCKER_QEMU = $(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE) -DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) -DOCKER_TEST = $(DOCKER_CMD) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) - -# Dockerize commands, which require USB device passthrough, only on Linux. -ifeq ($(shell uname -s),Linux) - DOCKER_CMD_DEV = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DEV) - - DOCKER_CHAINBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) -endif - - - -##-------------------------------------------------------------------------------------------------- -## Targets -##-------------------------------------------------------------------------------------------------- -.PHONY: all doc qemu chainboot clippy clean readelf objdump nm check - -all: clean $(KERNEL_BIN) - -##------------------------------------------------------------------------------ -## Save the configuration as a file, so make understands if it changed. -##------------------------------------------------------------------------------ -$(LAST_BUILD_CONFIG): - @rm -f target/*.build_config - @mkdir -p target - @touch $(LAST_BUILD_CONFIG) - -##------------------------------------------------------------------------------ -## Compile the kernel ELF -##------------------------------------------------------------------------------ -$(KERNEL_ELF): $(KERNEL_ELF_DEPS) - $(call color_header, "Compiling kernel ELF - $(BSP)") - @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD) - -##------------------------------------------------------------------------------ -## Generate the stripped kernel binary -##------------------------------------------------------------------------------ -$(KERNEL_BIN): $(KERNEL_ELF) - $(call color_header, "Generating stripped binary") - @$(OBJCOPY_CMD) $(KERNEL_ELF) $(KERNEL_BIN) - $(call color_progress_prefix, "Name") - @echo $(KERNEL_BIN) - $(call color_progress_prefix, "Size") - $(call disk_usage_KiB, $(KERNEL_BIN)) - -##------------------------------------------------------------------------------ -## Generate the documentation -##------------------------------------------------------------------------------ -doc: - $(call color_header, "Generating docs") - @$(DOC_CMD) --document-private-items --open - -##------------------------------------------------------------------------------ -## Run the kernel in QEMU -##------------------------------------------------------------------------------ -ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. - -qemu qemuasm: - $(call color_header, "$(QEMU_MISSING_STRING)") - -else # QEMU is supported. - -qemu: $(KERNEL_BIN) - $(call color_header, "Launching QEMU") - @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) - -qemuasm: $(KERNEL_BIN) - $(call color_header, "Launching QEMU with ASM output") - @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) -d in_asm - -endif - -##------------------------------------------------------------------------------ -## Push the kernel to the real HW target -##------------------------------------------------------------------------------ -chainboot: $(KERNEL_BIN) - @$(DOCKER_CHAINBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(CHAINBOOT_DEMO_PAYLOAD) - -##------------------------------------------------------------------------------ -## Run clippy -##------------------------------------------------------------------------------ -clippy: - @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) - -##------------------------------------------------------------------------------ -## Clean -##------------------------------------------------------------------------------ -clean: - rm -rf target $(KERNEL_BIN) - -##------------------------------------------------------------------------------ -## Run readelf -##------------------------------------------------------------------------------ -readelf: $(KERNEL_ELF) - $(call color_header, "Launching readelf") - @$(DOCKER_TOOLS) $(READELF_BINARY) --headers $(KERNEL_ELF) - -##------------------------------------------------------------------------------ -## Run objdump -##------------------------------------------------------------------------------ -objdump: $(KERNEL_ELF) - $(call color_header, "Launching objdump") - @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ - --section .text \ - --section .rodata \ - $(KERNEL_ELF) | rustfilt - -##------------------------------------------------------------------------------ -## Run nm -##------------------------------------------------------------------------------ -nm: $(KERNEL_ELF) - $(call color_header, "Launching nm") - @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt - - - -##-------------------------------------------------------------------------------------------------- -## Testing targets -##-------------------------------------------------------------------------------------------------- -.PHONY: test test_boot - -ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. - -test_boot test: - $(call color_header, "$(QEMU_MISSING_STRING)") - -else # QEMU is supported. - -##------------------------------------------------------------------------------ -## Run boot test -##------------------------------------------------------------------------------ -test_boot: $(KERNEL_BIN) - $(call color_header, "Boot test - $(BSP)") - @$(DOCKER_TEST) $(EXEC_TEST_MINIPUSH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) \ - -kernel $(KERNEL_BIN) $(CHAINBOOT_DEMO_PAYLOAD) - -test: test_boot - -endif diff --git a/arceos/tools/raspi4/chainloader/README.CN.md b/arceos/tools/raspi4/chainloader/README.CN.md deleted file mode 100644 index de7f51114..000000000 --- a/arceos/tools/raspi4/chainloader/README.CN.md +++ /dev/null @@ -1,116 +0,0 @@ -# 教程06 - UART链加载器 - -## tl;dr - -- 从SD卡上运行是一次不错的体验,但是每次都为每个新的二进制文件这样做将非常繁琐。 - 因此,让我们编写一个[chainloader]。 -- 这将是您需要放在SD卡上的最后一个二进制文件。 - 每个后续的教程都将在`Makefile`中提供一个`chainboot`,让您方便地通过`UART`加载内核。 - -[chainloader]: https://en.wikipedia.org/wiki/Chain_loading - - -## 注意 - -请注意,这个教程中有一些内容仅通过查看源代码很难理解。 - -大致的意思是,在`boot.s`中,我们编写了一段[position independent code]代码, -它会自动确定固件加载二进制文件的位置(`0x8_0000`),以及链接到的位置(`0x200_0000`,参见 `kernel.ld`)。 -然后,二进制文件将自身从加载地址复制到链接地址(也就是"重定位"自身),然后跳转到`_start_rust()`的重定位版本。 - -由于链加载程序现在已经"脱离了路径",它现在可以从`UART`接收另一个内核二进制文件,并将其复制到RPi固件的标准加载地址`0x8_0000`。 -最后,它跳转到`0x8_0000`,新加载的二进制文件会透明地执行,就好像它一直从SD卡加载一样。 - -在我有时间详细写下这些内容之前,请耐心等待。目前,请将这个教程视为一种便利功能的启用程序,它允许快速启动以下教程。 -_对于那些渴望深入了解的人,可以直接跳到第[15章](../15_virtual_mem_part3_precomputed_tables),阅读README的前半部分, -其中讨论了`Load Address != Link Address`的问题_。 - -[position independent code]: https://en.wikipedia.org/wiki/Position-independent_code - -## 安装并测试它 - -我们的链加载程序称为`MiniLoad`,受到了[raspbootin]的启发。 - -您可以按照以下教程尝试它: -1. 根据您的目标硬件运行命令:`make`或`BSP=rpi4 make`。 -1. 将`kernel8.img`复制到SD卡中,并将SD卡重新插入您的RPi。 -1. 运行命令`make chainboot`或`BSP=rpi4 make chainboot`。 -1. 将USB串口连接到您的主机PC上。 - - 请参考[top-level README](../README.md#-usb-serial-output)中的接线图。 - - 确保您**没有**连接USB串口的电源引脚,只连接RX/TX和GND。 -1. 将RPi连接到(USB)电源线。 -1. 观察加载程序通过`UART`获取内核: - -> ❗ **注意**: `make chainboot`假设默认的串行设备名称为`/dev/ttyUSB0`。根据您的主机操作系统,设备名称可能会有所不同。 -> 例如,在`macOS`上,它可能是类似于`/dev/tty.usbserial-0001`的名称。 -> 在这种情况下,请明确给出设备名称: - - -```console -$ DEV_SERIAL=/dev/tty.usbserial-0001 make chainboot -``` - -[raspbootin]: https://github.com/mrvn/raspbootin - -```console -$ make chainboot -[...] -Minipush 1.0 - -[MP] ⏳ Waiting for /dev/ttyUSB0 -[MP] ✅ Serial connected -[MP] 🔌 Please power the target now - - __ __ _ _ _ _ -| \/ (_)_ _ (_) | ___ __ _ __| | -| |\/| | | ' \| | |__/ _ \/ _` / _` | -|_| |_|_|_||_|_|____\___/\__,_\__,_| - - Raspberry Pi 3 - -[ML] Requesting binary -[MP] ⏩ Pushing 7 KiB ==========================================🦀 100% 0 KiB/s Time: 00:00:00 -[ML] Loaded! Executing the payload now - -[0] mingo version 0.5.0 -[1] Booting on: Raspberry Pi 3 -[2] Drivers loaded: - 1. BCM PL011 UART - 2. BCM GPIO -[3] Chars written: 117 -[4] Echoing input now -``` - -在这个教程中,为了演示目的,加载了上一个教程中的内核版本。在后续的教程中,将使用工作目录的内核。 - -## 测试它 - -这个教程中的`Makefile`有一个额外的目标`qemuasm`,它可以让你很好地观察到内核在重新定位后如何从加载地址区域(`0x80_XXX`) -跳转到重新定位的代码(`0x0200_0XXX`): - -```console -$ make qemuasm -[...] -N: -0x00080030: 58000140 ldr x0, #0x80058 -0x00080034: 9100001f mov sp, x0 -0x00080038: 58000141 ldr x1, #0x80060 -0x0008003c: d61f0020 br x1 - ----------------- -IN: -0x02000070: 9400044c bl #0x20011a0 - ----------------- -IN: -0x020011a0: 90000008 adrp x8, #0x2001000 -0x020011a4: 90000009 adrp x9, #0x2001000 -0x020011a8: f9446508 ldr x8, [x8, #0x8c8] -0x020011ac: f9446929 ldr x9, [x9, #0x8d0] -0x020011b0: eb08013f cmp x9, x8 -0x020011b4: 54000109 b.ls #0x20011d4 -[...] -``` - -## 相比之前的变化(diff) -请检查[英文版本](README.md#diff-to-previous),这是最新的。 \ No newline at end of file diff --git a/arceos/tools/raspi4/chainloader/README.md b/arceos/tools/raspi4/chainloader/README.md deleted file mode 100644 index 5e4efe25d..000000000 --- a/arceos/tools/raspi4/chainloader/README.md +++ /dev/null @@ -1,670 +0,0 @@ -# Tutorial 06 - UART Chainloader - -## tl;dr - -- Running from an SD card was a nice experience, but it would be extremely tedious to do it for - every new binary. So let's write a [chainloader]. -- This will be the last binary you need to put on the SD card. Each following tutorial will provide - a `chainboot` target in the `Makefile` that lets you conveniently load the kernel over `UART`. - -[chainloader]: https://en.wikipedia.org/wiki/Chain_loading - - -## Note - -Please note that there is stuff going on in this tutorial that is very hard to grasp by only looking -at the source code changes. - -The gist of it is that in `boot.s`, we are writing a piece of [position independent code] which -automatically determines where the firmware has loaded the binary (`0x8_0000`), and where it was -linked to (`0x200_0000`, see `kernel.ld`). The binary then copies itself from loaded to linked -address (aka "relocating" itself), and then jumps to the relocated version of `_start_rust()`. - -Since the chainloader has put itself "out of the way" now, it can now receive another kernel binary -from the `UART` and copy it to the standard load address of the RPi firmware at `0x8_0000`. Finally, -it jumps to `0x8_0000` and the newly loaded binary transparently executes as if it had been loaded -from SD card all along. - -Please bear with me until I find the time to write it all down here elaborately. For the time being, -please see this tutorial as an enabler for a convenience feature that allows booting the following -tutorials in a quick manner. _For those keen to get a deeper understanding, it could make sense to -skip forward to [Chapter 15](../15_virtual_mem_part3_precomputed_tables) and read the first half of -the README, where `Load Address != Link Address` is discussed_. - -[position independent code]: https://en.wikipedia.org/wiki/Position-independent_code - -## Install and test it - -Our chainloader is called `MiniLoad` and is inspired by [raspbootin]. - -You can try it with this tutorial already: -1. Depending on your target hardware, run:`make` or `BSP=rpi4 make`. -1. Copy `kernel8.img` to the SD card and put the SD card back into your RPi. -1. Run `make chainboot` or `BSP=rpi4 make chainboot`. -1. Connect the USB serial to your host PC. - - Wiring diagram at [top-level README](../README.md#-usb-serial-output). - - Make sure that you **DID NOT** connect the power pin of the USB serial. Only RX/TX and GND. -1. Connect the RPi to the (USB) power cable. -1. Observe the loader fetching a kernel over `UART`: - -> ❗ **NOTE**: `make chainboot` assumes a default serial device name of `/dev/ttyUSB0`. Depending on -> your host operating system, the device name might differ. For example, on `macOS`, it might be -> something like `/dev/tty.usbserial-0001`. In this case, please give the name explicitly: - - -```console -$ DEV_SERIAL=/dev/tty.usbserial-0001 make chainboot -``` - -[raspbootin]: https://github.com/mrvn/raspbootin - -```console -$ make chainboot -[...] -Minipush 1.0 - -[MP] ⏳ Waiting for /dev/ttyUSB0 -[MP] ✅ Serial connected -[MP] 🔌 Please power the target now - - __ __ _ _ _ _ -| \/ (_)_ _ (_) | ___ __ _ __| | -| |\/| | | ' \| | |__/ _ \/ _` / _` | -|_| |_|_|_||_|_|____\___/\__,_\__,_| - - Raspberry Pi 3 - -[ML] Requesting binary -[MP] ⏩ Pushing 7 KiB ==========================================🦀 100% 0 KiB/s Time: 00:00:00 -[ML] Loaded! Executing the payload now - -[0] mingo version 0.5.0 -[1] Booting on: Raspberry Pi 3 -[2] Drivers loaded: - 1. BCM PL011 UART - 2. BCM GPIO -[3] Chars written: 117 -[4] Echoing input now -``` - -In this tutorial, a version of the kernel from the previous tutorial is loaded for demo purposes. In -subsequent tutorials, it will be the working directory's kernel. - -## Test it - -The `Makefile` in this tutorial has an additional target, `qemuasm`, that lets you nicely observe -how the kernel, after relocating itself, jumps the load address region (`0x80_XXX`) to the relocated -code at (`0x0200_0XXX`): - -```console -$ make qemuasm -[...] -N: -0x00080030: 58000140 ldr x0, #0x80058 -0x00080034: 9100001f mov sp, x0 -0x00080038: 58000141 ldr x1, #0x80060 -0x0008003c: d61f0020 br x1 - ----------------- -IN: -0x02000070: 9400044c bl #0x20011a0 - ----------------- -IN: -0x020011a0: 90000008 adrp x8, #0x2001000 -0x020011a4: 90000009 adrp x9, #0x2001000 -0x020011a8: f9446508 ldr x8, [x8, #0x8c8] -0x020011ac: f9446929 ldr x9, [x9, #0x8d0] -0x020011b0: eb08013f cmp x9, x8 -0x020011b4: 54000109 b.ls #0x20011d4 -[...] -``` - -## Diff to previous -```diff - -diff -uNr 05_drivers_gpio_uart/Cargo.toml 06_uart_chainloader/Cargo.toml ---- 05_drivers_gpio_uart/Cargo.toml -+++ 06_uart_chainloader/Cargo.toml -@@ -1,6 +1,6 @@ - [package] - name = "mingo" --version = "0.5.0" -+version = "0.6.0" - authors = ["Andre Richter "] - edition = "2021" - -Binary files 05_drivers_gpio_uart/demo_payload_rpi3.img and 06_uart_chainloader/demo_payload_rpi3.img differ -Binary files 05_drivers_gpio_uart/demo_payload_rpi4.img and 06_uart_chainloader/demo_payload_rpi4.img differ - -diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile ---- 05_drivers_gpio_uart/Makefile -+++ 06_uart_chainloader/Makefile -@@ -24,27 +24,29 @@ - QEMU_MISSING_STRING = "This board is not yet supported for QEMU." - - ifeq ($(BSP),rpi3) -- TARGET = aarch64-unknown-none-softfloat -- KERNEL_BIN = kernel8.img -- QEMU_BINARY = qemu-system-aarch64 -- QEMU_MACHINE_TYPE = raspi3 -- QEMU_RELEASE_ARGS = -serial stdio -display none -- OBJDUMP_BINARY = aarch64-none-elf-objdump -- NM_BINARY = aarch64-none-elf-nm -- READELF_BINARY = aarch64-none-elf-readelf -- LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi -- RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 -+ TARGET = aarch64-unknown-none-softfloat -+ KERNEL_BIN = kernel8.img -+ QEMU_BINARY = qemu-system-aarch64 -+ QEMU_MACHINE_TYPE = raspi3 -+ QEMU_RELEASE_ARGS = -serial stdio -display none -+ OBJDUMP_BINARY = aarch64-none-elf-objdump -+ NM_BINARY = aarch64-none-elf-nm -+ READELF_BINARY = aarch64-none-elf-readelf -+ LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi -+ RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 -+ CHAINBOOT_DEMO_PAYLOAD = demo_payload_rpi3.img - else ifeq ($(BSP),rpi4) -- TARGET = aarch64-unknown-none-softfloat -- KERNEL_BIN = kernel8.img -- QEMU_BINARY = qemu-system-aarch64 -- QEMU_MACHINE_TYPE = -- QEMU_RELEASE_ARGS = -serial stdio -display none -- OBJDUMP_BINARY = aarch64-none-elf-objdump -- NM_BINARY = aarch64-none-elf-nm -- READELF_BINARY = aarch64-none-elf-readelf -- LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi -- RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 -+ TARGET = aarch64-unknown-none-softfloat -+ KERNEL_BIN = kernel8.img -+ QEMU_BINARY = qemu-system-aarch64 -+ QEMU_MACHINE_TYPE = -+ QEMU_RELEASE_ARGS = -serial stdio -display none -+ OBJDUMP_BINARY = aarch64-none-elf-objdump -+ NM_BINARY = aarch64-none-elf-nm -+ READELF_BINARY = aarch64-none-elf-readelf -+ LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi -+ RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 -+ CHAINBOOT_DEMO_PAYLOAD = demo_payload_rpi4.img - endif - - # Export for build.rs. -@@ -90,8 +92,8 @@ - -O binary - - EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) --EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb --EXEC_MINITERM = ruby ../common/serial/miniterm.rb -+EXEC_TEST_MINIPUSH = ruby tests/chainboot_test.rb -+EXEC_MINIPUSH = ruby ../common/serial/minipush.rb - - ##------------------------------------------------------------------------------ - ## Dockerization -@@ -110,7 +112,7 @@ - ifeq ($(shell uname -s),Linux) - DOCKER_CMD_DEV = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DEV) - -- DOCKER_MINITERM = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) -+ DOCKER_CHAINBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) - endif - - -@@ -118,7 +120,7 @@ - ##-------------------------------------------------------------------------------------------------- - ## Targets - ##-------------------------------------------------------------------------------------------------- --.PHONY: all doc qemu miniterm clippy clean readelf objdump nm check -+.PHONY: all doc qemu chainboot clippy clean readelf objdump nm check - - all: $(KERNEL_BIN) - -@@ -160,7 +162,7 @@ - ##------------------------------------------------------------------------------ - ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. - --qemu: -+qemu qemuasm: - $(call color_header, "$(QEMU_MISSING_STRING)") - - else # QEMU is supported. -@@ -169,13 +171,17 @@ - $(call color_header, "Launching QEMU") - @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) - -+qemuasm: $(KERNEL_BIN) -+ $(call color_header, "Launching QEMU with ASM output") -+ @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) -d in_asm -+ - endif - ##------------------------------------------------------------------------------ --## Connect to the target's serial -+## Push the kernel to the real HW target - ##------------------------------------------------------------------------------ --miniterm: -- @$(DOCKER_MINITERM) $(EXEC_MINITERM) $(DEV_SERIAL) -+chainboot: $(KERNEL_BIN) -+ @$(DOCKER_CHAINBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(CHAINBOOT_DEMO_PAYLOAD) - - ##------------------------------------------------------------------------------ - ## Run clippy -@@ -232,7 +238,8 @@ - ##------------------------------------------------------------------------------ - test_boot: $(KERNEL_BIN) - $(call color_header, "Boot test - $(BSP)") -- @$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) -+ @$(DOCKER_TEST) $(EXEC_TEST_MINIPUSH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) \ -+ -kernel $(KERNEL_BIN) $(CHAINBOOT_DEMO_PAYLOAD) - - test: test_boot - - -diff -uNr 05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s 06_uart_chainloader/src/_arch/aarch64/cpu/boot.s ---- 05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s -+++ 06_uart_chainloader/src/_arch/aarch64/cpu/boot.s -@@ -18,6 +18,17 @@ - add \register, \register, #:lo12:\symbol - .endm - -+// Load the address of a symbol into a register, absolute. -+// -+// # Resources -+// -+// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html -+.macro ADR_ABS register, symbol -+ movz \register, #:abs_g2:\symbol -+ movk \register, #:abs_g1_nc:\symbol -+ movk \register, #:abs_g0_nc:\symbol -+.endm -+ - //-------------------------------------------------------------------------------------------------- - // Public Code - //-------------------------------------------------------------------------------------------------- -@@ -37,23 +48,35 @@ - // If execution reaches here, it is the boot core. - - // Initialize DRAM. -- ADR_REL x0, __bss_start -- ADR_REL x1, __bss_end_exclusive -+ ADR_ABS x0, __bss_start -+ ADR_ABS x1, __bss_end_exclusive - - .L_bss_init_loop: - cmp x0, x1 -- b.eq .L_prepare_rust -+ b.eq .L_relocate_binary - stp xzr, xzr, [x0], #16 - b .L_bss_init_loop - -+ // Next, relocate the binary. -+.L_relocate_binary: -+ ADR_REL x0, __binary_nonzero_start // The address the binary got loaded to. -+ ADR_ABS x1, __binary_nonzero_start // The address the binary was linked to. -+ ADR_ABS x2, __binary_nonzero_end_exclusive -+ -+.L_copy_loop: -+ ldr x3, [x0], #8 -+ str x3, [x1], #8 -+ cmp x1, x2 -+ b.lo .L_copy_loop -+ - // Prepare the jump to Rust code. --.L_prepare_rust: - // Set the stack pointer. -- ADR_REL x0, __boot_core_stack_end_exclusive -+ ADR_ABS x0, __boot_core_stack_end_exclusive - mov sp, x0 - -- // Jump to Rust code. -- b _start_rust -+ // Jump to the relocated Rust code. -+ ADR_ABS x1, _start_rust -+ br x1 - - // Infinitely wait for events (aka "park the core"). - .L_parking_loop: - -diff -uNr 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs ---- 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -+++ 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -@@ -275,7 +275,7 @@ - } - - /// Retrieve a character. -- fn read_char_converting(&mut self, blocking_mode: BlockingMode) -> Option { -+ fn read_char(&mut self, blocking_mode: BlockingMode) -> Option { - // If RX FIFO is empty, - if self.registers.FR.matches_all(FR::RXFE::SET) { - // immediately return in non-blocking mode. -@@ -290,12 +290,7 @@ - } - - // Read one character. -- let mut ret = self.registers.DR.get() as u8 as char; -- -- // Convert carrige return to newline. -- if ret == '\r' { -- ret = '\n' -- } -+ let ret = self.registers.DR.get() as u8 as char; - - // Update statistics. - self.chars_read += 1; -@@ -381,14 +376,14 @@ - impl console::interface::Read for PL011Uart { - fn read_char(&self) -> char { - self.inner -- .lock(|inner| inner.read_char_converting(BlockingMode::Blocking).unwrap()) -+ .lock(|inner| inner.read_char(BlockingMode::Blocking).unwrap()) - } - - fn clear_rx(&self) { - // Read from the RX FIFO until it is indicating empty. - while self - .inner -- .lock(|inner| inner.read_char_converting(BlockingMode::NonBlocking)) -+ .lock(|inner| inner.read_char(BlockingMode::NonBlocking)) - .is_some() - {} - } - -diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs 06_uart_chainloader/src/bsp/raspberrypi/console.rs ---- 05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs -+++ 06_uart_chainloader/src/bsp/raspberrypi/console.rs -@@ -1,16 +0,0 @@ --// SPDX-License-Identifier: MIT OR Apache-2.0 --// --// Copyright (c) 2018-2023 Andre Richter -- --//! BSP console facilities. -- --use crate::console; -- --//-------------------------------------------------------------------------------------------------- --// Public Code --//-------------------------------------------------------------------------------------------------- -- --/// Return a reference to the console. --pub fn console() -> &'static dyn console::interface::All { -- &super::driver::PL011_UART --} - -diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld ---- 05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld -+++ 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld -@@ -3,8 +3,6 @@ - * Copyright (c) 2018-2023 Andre Richter - */ - --__rpi_phys_dram_start_addr = 0; -- - /* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */ - __rpi_phys_binary_load_addr = 0x80000; - -@@ -28,7 +26,8 @@ - - SECTIONS - { -- . = __rpi_phys_dram_start_addr; -+ /* Set the link address to 32 MiB */ -+ . = 0x2000000; - - /*********************************************************************************************** - * Boot Core Stack -@@ -45,6 +44,7 @@ - /*********************************************************************************************** - * Code + RO Data + Global Offset Table - ***********************************************************************************************/ -+ __binary_nonzero_start = .; - .text : - { - KEEP(*(.text._start)) -@@ -60,6 +60,10 @@ - ***********************************************************************************************/ - .data : { *(.data*) } :segment_data - -+ /* Fill up to 8 byte, b/c relocating the binary is done in u64 chunks */ -+ . = ALIGN(8); -+ __binary_nonzero_end_exclusive = .; -+ - /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */ - .bss (NOLOAD) : ALIGN(16) - { - -diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs 06_uart_chainloader/src/bsp/raspberrypi/memory.rs ---- 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs -+++ 06_uart_chainloader/src/bsp/raspberrypi/memory.rs -@@ -11,6 +11,7 @@ - /// The board's physical memory map. - #[rustfmt::skip] - pub(super) mod map { -+ pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x8_0000; - - pub const GPIO_OFFSET: usize = 0x0020_0000; - pub const UART_OFFSET: usize = 0x0020_1000; -@@ -35,3 +36,13 @@ - pub const PL011_UART_START: usize = START + UART_OFFSET; - } - } -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// The address on which the Raspberry firmware loads every binary by default. -+#[inline(always)] -+pub fn board_default_load_addr() -> *const u64 { -+ map::BOARD_DEFAULT_LOAD_ADDRESS as _ -+} - -diff -uNr 05_drivers_gpio_uart/src/driver.rs 06_uart_chainloader/src/driver.rs ---- 05_drivers_gpio_uart/src/driver.rs -+++ 06_uart_chainloader/src/driver.rs -@@ -4,10 +4,7 @@ - - //! Driver support. - --use crate::{ -- println, -- synchronization::{interface::Mutex, NullLock}, --}; -+use crate::synchronization::{interface::Mutex, NullLock}; - - //-------------------------------------------------------------------------------------------------- - // Private Definitions -@@ -154,14 +151,4 @@ - } - }); - } -- -- /// Enumerate all registered device drivers. -- pub fn enumerate(&self) { -- let mut i: usize = 1; -- self.for_each_descriptor(|descriptor| { -- println!(" {}. {}", i, descriptor.device_driver.compatible()); -- -- i += 1; -- }); -- } - } - -diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs ---- 05_drivers_gpio_uart/src/main.rs -+++ 06_uart_chainloader/src/main.rs -@@ -142,27 +142,55 @@ - kernel_main() - } - -+const MINILOAD_LOGO: &str = r#" -+ __ __ _ _ _ _ -+| \/ (_)_ _ (_) | ___ __ _ __| | -+| |\/| | | ' \| | |__/ _ \/ _` / _` | -+|_| |_|_|_||_|_|____\___/\__,_\__,_| -+"#; -+ - /// The main function running after the early init. - fn kernel_main() -> ! { - use console::console; - -- println!( -- "[0] {} version {}", -- env!("CARGO_PKG_NAME"), -- env!("CARGO_PKG_VERSION") -- ); -- println!("[1] Booting on: {}", bsp::board_name()); -+ println!("{}", MINILOAD_LOGO); -+ println!("{:^37}", bsp::board_name()); -+ println!(); -+ println!("[ML] Requesting binary"); -+ console().flush(); - -- println!("[2] Drivers loaded:"); -- driver::driver_manager().enumerate(); -+ // Discard any spurious received characters before starting with the loader protocol. -+ console().clear_rx(); - -- println!("[3] Chars written: {}", console().chars_written()); -- println!("[4] Echoing input now"); -+ // Notify `Minipush` to send the binary. -+ for _ in 0..3 { -+ console().write_char(3 as char); -+ } - -- // Discard any spurious received characters before going into echo mode. -- console().clear_rx(); -- loop { -- let c = console().read_char(); -- console().write_char(c); -+ // Read the binary's size. -+ let mut size: u32 = u32::from(console().read_char() as u8); -+ size |= u32::from(console().read_char() as u8) << 8; -+ size |= u32::from(console().read_char() as u8) << 16; -+ size |= u32::from(console().read_char() as u8) << 24; -+ -+ // Trust it's not too big. -+ console().write_char('O'); -+ console().write_char('K'); -+ -+ let kernel_addr: *mut u8 = bsp::memory::board_default_load_addr() as *mut u8; -+ unsafe { -+ // Read the kernel byte by byte. -+ for i in 0..size { -+ core::ptr::write_volatile(kernel_addr.offset(i as isize), console().read_char() as u8) -+ } - } -+ -+ println!("[ML] Loaded! Executing the payload now\n"); -+ console().flush(); -+ -+ // Use black magic to create a function pointer. -+ let kernel: fn() -> ! = unsafe { core::mem::transmute(kernel_addr) }; -+ -+ // Jump to loaded kernel! -+ kernel() - } - -diff -uNr 05_drivers_gpio_uart/tests/boot_test_string.rb 06_uart_chainloader/tests/boot_test_string.rb ---- 05_drivers_gpio_uart/tests/boot_test_string.rb -+++ 06_uart_chainloader/tests/boot_test_string.rb -@@ -1,3 +0,0 @@ --# frozen_string_literal: true -- --EXPECTED_PRINT = 'Echoing input now' - -diff -uNr 05_drivers_gpio_uart/tests/chainboot_test.rb 06_uart_chainloader/tests/chainboot_test.rb ---- 05_drivers_gpio_uart/tests/chainboot_test.rb -+++ 06_uart_chainloader/tests/chainboot_test.rb -@@ -0,0 +1,78 @@ -+# frozen_string_literal: true -+ -+# SPDX-License-Identifier: MIT OR Apache-2.0 -+# -+# Copyright (c) 2020-2023 Andre Richter -+ -+require_relative '../../common/serial/minipush' -+require_relative '../../common/tests/boot_test' -+require 'pty' -+ -+# Match for the last print that 'demo_payload_rpiX.img' produces. -+EXPECTED_PRINT = 'Echoing input now' -+ -+# Wait for request to power the target. -+class PowerTargetRequestTest < SubtestBase -+ MINIPUSH_POWER_TARGET_REQUEST = 'Please power the target now' -+ -+ def initialize(qemu_cmd, pty_main) -+ super() -+ @qemu_cmd = qemu_cmd -+ @pty_main = pty_main -+ end -+ -+ def name -+ 'Waiting for request to power target' -+ end -+ -+ def run(qemu_out, _qemu_in) -+ expect_or_raise(qemu_out, MINIPUSH_POWER_TARGET_REQUEST) -+ -+ # Now is the time to start QEMU with the chainloader binary. QEMU's virtual tty connects to -+ # the MiniPush instance spawned on pty_main, so that the two processes talk to each other. -+ Process.spawn(@qemu_cmd, in: @pty_main, out: @pty_main, err: '/dev/null') -+ end -+end -+ -+# Extend BootTest so that it listens on the output of a MiniPush instance, which is itself connected -+# to a QEMU instance instead of a real HW. -+class ChainbootTest < BootTest -+ MINIPUSH = '../common/serial/minipush.rb' -+ -+ def initialize(qemu_cmd, payload_path) -+ super(qemu_cmd, EXPECTED_PRINT) -+ -+ @test_name = 'Boot test using Minipush' -+ -+ @payload_path = payload_path -+ end -+ -+ private -+ -+ # override -+ def setup -+ pty_main, pty_secondary = PTY.open -+ mp_out, _mp_in = PTY.spawn("ruby #{MINIPUSH} #{pty_secondary.path} #{@payload_path}") -+ -+ # The subtests (from this class and the parents) listen on @qemu_out_wrapped. Hence, point -+ # it to MiniPush's output. -+ @qemu_out_wrapped = PTYLoggerWrapper.new(mp_out, "\r\n") -+ -+ # Important: Run this subtest before the one in the parent class. -+ @console_subtests.prepend(PowerTargetRequestTest.new(@qemu_cmd, pty_main)) -+ end -+ -+ # override -+ def finish -+ super() -+ @test_output.map! { |x| x.gsub(/.*\r/, ' ') } -+ end -+end -+ -+##-------------------------------------------------------------------------------------------------- -+## Execution starts here -+##-------------------------------------------------------------------------------------------------- -+payload_path = ARGV.pop -+qemu_cmd = ARGV.join(' ') -+ -+ChainbootTest.new(qemu_cmd, payload_path).run - -diff -uNr 05_drivers_gpio_uart/update.sh 06_uart_chainloader/update.sh ---- 05_drivers_gpio_uart/update.sh -+++ 06_uart_chainloader/update.sh -@@ -0,0 +1,8 @@ -+#!/usr/bin/env bash -+ -+cd ../05_drivers_gpio_uart -+BSP=rpi4 make -+cp kernel8.img ../06_uart_chainloader/demo_payload_rpi4.img -+make -+cp kernel8.img ../06_uart_chainloader/demo_payload_rpi3.img -+rm kernel8.img - -``` diff --git a/arceos/tools/raspi4/chainloader/build.rs b/arceos/tools/raspi4/chainloader/build.rs deleted file mode 100644 index cab00bb37..000000000 --- a/arceos/tools/raspi4/chainloader/build.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::{env, fs, process}; - -fn main() { - let ld_script_path = match env::var("LD_SCRIPT_PATH") { - Ok(var) => var, - _ => process::exit(0), - }; - - let files = fs::read_dir(ld_script_path).unwrap(); - files - .filter_map(Result::ok) - .filter(|d| { - if let Some(e) = d.path().extension() { - e == "ld" - } else { - false - } - }) - .for_each(|f| println!("cargo:rerun-if-changed={}", f.path().display())); -} diff --git a/arceos/tools/raspi4/chainloader/src/_arch/aarch64/cpu.rs b/arceos/tools/raspi4/chainloader/src/_arch/aarch64/cpu.rs deleted file mode 100644 index f1f1e9aff..000000000 --- a/arceos/tools/raspi4/chainloader/src/_arch/aarch64/cpu.rs +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! Architectural processor code. -//! -//! # Orientation -//! -//! Since arch modules are imported into generic modules using the path attribute, the path of this -//! file is: -//! -//! crate::cpu::arch_cpu - -use aarch64_cpu::asm; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -pub use asm::nop; - -/// Spin for `n` cycles. -#[cfg(feature = "bsp_rpi3")] -#[inline(always)] -pub fn spin_for_cycles(n: usize) { - for _ in 0..n { - asm::nop(); - } -} - -/// Pause execution on the core. -#[inline(always)] -pub fn wait_forever() -> ! { - loop { - asm::wfe() - } -} diff --git a/arceos/tools/raspi4/chainloader/src/_arch/aarch64/cpu/boot.rs b/arceos/tools/raspi4/chainloader/src/_arch/aarch64/cpu/boot.rs deleted file mode 100644 index 2a6c46492..000000000 --- a/arceos/tools/raspi4/chainloader/src/_arch/aarch64/cpu/boot.rs +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2021-2023 Andre Richter - -//! Architectural boot code. -//! -//! # Orientation -//! -//! Since arch modules are imported into generic modules using the path attribute, the path of this -//! file is: -//! -//! crate::cpu::boot::arch_boot - -use core::arch::global_asm; - -// Assembly counterpart to this file. -global_asm!( - include_str!("boot.s"), - CONST_CORE_ID_MASK = const 0b11 -); - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// The Rust entry of the `kernel` binary. -/// -/// The function is called from the assembly `_start` function. -#[no_mangle] -pub unsafe fn _start_rust() -> ! { - crate::kernel_init() -} diff --git a/arceos/tools/raspi4/chainloader/src/_arch/aarch64/cpu/boot.s b/arceos/tools/raspi4/chainloader/src/_arch/aarch64/cpu/boot.s deleted file mode 100644 index 3ed0d4941..000000000 --- a/arceos/tools/raspi4/chainloader/src/_arch/aarch64/cpu/boot.s +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2021-2022 Andre Richter - -//-------------------------------------------------------------------------------------------------- -// Definitions -//-------------------------------------------------------------------------------------------------- - -// Load the address of a symbol into a register, PC-relative. -// -// The symbol must lie within +/- 4 GiB of the Program Counter. -// -// # Resources -// -// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html -.macro ADR_REL register, symbol - adrp \register, \symbol - add \register, \register, #:lo12:\symbol -.endm - -// Load the address of a symbol into a register, absolute. -// -// # Resources -// -// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html -.macro ADR_ABS register, symbol - movz \register, #:abs_g2:\symbol - movk \register, #:abs_g1_nc:\symbol - movk \register, #:abs_g0_nc:\symbol -.endm - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- -.section .text._start - -//------------------------------------------------------------------------------ -// fn _start() -//------------------------------------------------------------------------------ -_start: - // Only proceed on the boot core. Park it otherwise. - mrs x0, MPIDR_EL1 - and x0, x0, {CONST_CORE_ID_MASK} - ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs - cmp x0, x1 - b.ne .L_parking_loop - - // If execution reaches here, it is the boot core. - - // Initialize DRAM. - ADR_ABS x0, __bss_start - ADR_ABS x1, __bss_end_exclusive - -.L_bss_init_loop: - cmp x0, x1 - b.eq .L_relocate_binary - stp xzr, xzr, [x0], #16 - b .L_bss_init_loop - - // Next, relocate the binary. -.L_relocate_binary: - ADR_REL x0, __binary_nonzero_start // The address the binary got loaded to. - ADR_ABS x1, __binary_nonzero_start // The address the binary was linked to. - ADR_ABS x2, __binary_nonzero_end_exclusive - -.L_copy_loop: - ldr x3, [x0], #8 - str x3, [x1], #8 - cmp x1, x2 - b.lo .L_copy_loop - - // Prepare the jump to Rust code. - // Set the stack pointer. - ADR_ABS x0, __boot_core_stack_end_exclusive - mov sp, x0 - - // Jump to the relocated Rust code. - ADR_ABS x1, _start_rust - br x1 - - // Infinitely wait for events (aka "park the core"). -.L_parking_loop: - wfe - b .L_parking_loop - -.size _start, . - _start -.type _start, function -.global _start diff --git a/arceos/tools/raspi4/chainloader/src/bsp.rs b/arceos/tools/raspi4/chainloader/src/bsp.rs deleted file mode 100644 index 246973bc0..000000000 --- a/arceos/tools/raspi4/chainloader/src/bsp.rs +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! Conditional reexporting of Board Support Packages. - -mod device_driver; - -#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] -mod raspberrypi; - -#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] -pub use raspberrypi::*; diff --git a/arceos/tools/raspi4/chainloader/src/bsp/device_driver.rs b/arceos/tools/raspi4/chainloader/src/bsp/device_driver.rs deleted file mode 100644 index 64049a4cf..000000000 --- a/arceos/tools/raspi4/chainloader/src/bsp/device_driver.rs +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! Device driver. - -#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] -mod bcm; -mod common; - -#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] -pub use bcm::*; diff --git a/arceos/tools/raspi4/chainloader/src/bsp/device_driver/bcm.rs b/arceos/tools/raspi4/chainloader/src/bsp/device_driver/bcm.rs deleted file mode 100644 index 1c343d1d7..000000000 --- a/arceos/tools/raspi4/chainloader/src/bsp/device_driver/bcm.rs +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! BCM driver top level. - -mod bcm2xxx_gpio; -mod bcm2xxx_pl011_uart; - -pub use bcm2xxx_gpio::*; -pub use bcm2xxx_pl011_uart::*; diff --git a/arceos/tools/raspi4/chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/arceos/tools/raspi4/chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs deleted file mode 100644 index 920b4c00c..000000000 --- a/arceos/tools/raspi4/chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ /dev/null @@ -1,228 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! GPIO Driver. - -use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, synchronization, - synchronization::NullLock, -}; -use tock_registers::{ - interfaces::{ReadWriteable, Writeable}, - register_bitfields, register_structs, - registers::ReadWrite, -}; - -//-------------------------------------------------------------------------------------------------- -// Private Definitions -//-------------------------------------------------------------------------------------------------- - -// GPIO registers. -// -// Descriptions taken from -// - https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -// - https://datasheets.raspberrypi.org/bcm2711/bcm2711-peripherals.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - AltFunc0 = 0b100 // PL011 UART RX - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - AltFunc0 = 0b100 // PL011 UART TX - ] - ], - - /// GPIO Pull-up/down Register - /// - /// BCM2837 only. - GPPUD [ - /// Controls the actuation of the internal pull-up/down control line to ALL the GPIO pins. - PUD OFFSET(0) NUMBITS(2) [ - Off = 0b00, - PullDown = 0b01, - PullUp = 0b10 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - /// - /// BCM2837 only. - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ], - - /// GPIO Pull-up / Pull-down Register 0 - /// - /// BCM2711 only. - GPIO_PUP_PDN_CNTRL_REG0 [ - /// Pin 15 - GPIO_PUP_PDN_CNTRL15 OFFSET(30) NUMBITS(2) [ - NoResistor = 0b00, - PullUp = 0b01 - ], - - /// Pin 14 - GPIO_PUP_PDN_CNTRL14 OFFSET(28) NUMBITS(2) [ - NoResistor = 0b00, - PullUp = 0b01 - ] - ] -} - -register_structs! { - #[allow(non_snake_case)] - RegisterBlock { - (0x00 => _reserved1), - (0x04 => GPFSEL1: ReadWrite), - (0x08 => _reserved2), - (0x94 => GPPUD: ReadWrite), - (0x98 => GPPUDCLK0: ReadWrite), - (0x9C => _reserved3), - (0xE4 => GPIO_PUP_PDN_CNTRL_REG0: ReadWrite), - (0xE8 => @END), - } -} - -/// Abstraction for the associated MMIO registers. -type Registers = MMIODerefWrapper; - -struct GPIOInner { - registers: Registers, -} - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -/// Representation of the GPIO HW. -pub struct GPIO { - inner: NullLock, -} - -//-------------------------------------------------------------------------------------------------- -// Private Code -//-------------------------------------------------------------------------------------------------- - -impl GPIOInner { - /// Create an instance. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { - Self { - registers: Registers::new(mmio_start_addr), - } - } - - /// Disable pull-up/down on pins 14 and 15. - #[cfg(feature = "bsp_rpi3")] - fn disable_pud_14_15_bcm2837(&mut self) { - use crate::cpu; - - // Make an educated guess for a good delay value (Sequence described in the BCM2837 - // peripherals PDF). - // - // - According to Wikipedia, the fastest RPi4 clocks around 1.5 GHz. - // - The Linux 2837 GPIO driver waits 1 µs between the steps. - // - // So lets try to be on the safe side and default to 2000 cycles, which would equal 1 µs - // would the CPU be clocked at 2 GHz. - const DELAY: usize = 2000; - - self.registers.GPPUD.write(GPPUD::PUD::Off); - cpu::spin_for_cycles(DELAY); - - self.registers - .GPPUDCLK0 - .write(GPPUDCLK0::PUDCLK15::AssertClock + GPPUDCLK0::PUDCLK14::AssertClock); - cpu::spin_for_cycles(DELAY); - - self.registers.GPPUD.write(GPPUD::PUD::Off); - self.registers.GPPUDCLK0.set(0); - } - - /// Disable pull-up/down on pins 14 and 15. - #[cfg(feature = "bsp_rpi4")] - fn disable_pud_14_15_bcm2711(&mut self) { - self.registers.GPIO_PUP_PDN_CNTRL_REG0.write( - GPIO_PUP_PDN_CNTRL_REG0::GPIO_PUP_PDN_CNTRL15::PullUp - + GPIO_PUP_PDN_CNTRL_REG0::GPIO_PUP_PDN_CNTRL14::PullUp, - ); - } - - /// Map PL011 UART as standard output. - /// - /// TX to pin 14 - /// RX to pin 15 - pub fn map_pl011_uart(&mut self) { - // Select the UART on pins 14 and 15. - self.registers - .GPFSEL1 - .modify(GPFSEL1::FSEL15::AltFunc0 + GPFSEL1::FSEL14::AltFunc0); - - // Disable pull-up/down on pins 14 and 15. - #[cfg(feature = "bsp_rpi3")] - self.disable_pud_14_15_bcm2837(); - - #[cfg(feature = "bsp_rpi4")] - self.disable_pud_14_15_bcm2711(); - } -} - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -impl GPIO { - pub const COMPATIBLE: &'static str = "BCM GPIO"; - - /// Create an instance. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { - Self { - inner: NullLock::new(GPIOInner::new(mmio_start_addr)), - } - } - - /// Concurrency safe version of `GPIOInner.map_pl011_uart()` - pub fn map_pl011_uart(&self) { - self.inner.lock(|inner| inner.map_pl011_uart()) - } -} - -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use synchronization::interface::Mutex; - -impl driver::interface::DeviceDriver for GPIO { - fn compatible(&self) -> &'static str { - Self::COMPATIBLE - } -} diff --git a/arceos/tools/raspi4/chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/arceos/tools/raspi4/chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs deleted file mode 100644 index 50a069ea1..000000000 --- a/arceos/tools/raspi4/chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ /dev/null @@ -1,402 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! PL011 UART driver. -//! -//! # Resources -//! -//! - -//! - - -use crate::{ - bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, synchronization, - synchronization::NullLock, -}; -use core::fmt; -use tock_registers::{ - interfaces::{Readable, Writeable}, - register_bitfields, register_structs, - registers::{ReadOnly, ReadWrite, WriteOnly}, -}; - -//-------------------------------------------------------------------------------------------------- -// Private Definitions -//-------------------------------------------------------------------------------------------------- - -// PL011 UART registers. -// -// Descriptions taken from "PrimeCell UART (PL011) Technical Reference Manual" r1p5. -register_bitfields! { - u32, - - /// Flag Register. - FR [ - /// Transmit FIFO empty. The meaning of this bit depends on the state of the FEN bit in the - /// Line Control Register, LCR_H. - /// - /// - If the FIFO is disabled, this bit is set when the transmit holding register is empty. - /// - If the FIFO is enabled, the TXFE bit is set when the transmit FIFO is empty. - /// - This bit does not indicate if there is data in the transmit shift register. - TXFE OFFSET(7) NUMBITS(1) [], - - /// Transmit FIFO full. The meaning of this bit depends on the state of the FEN bit in the - /// LCR_H Register. - /// - /// - If the FIFO is disabled, this bit is set when the transmit holding register is full. - /// - If the FIFO is enabled, the TXFF bit is set when the transmit FIFO is full. - TXFF OFFSET(5) NUMBITS(1) [], - - /// Receive FIFO empty. The meaning of this bit depends on the state of the FEN bit in the - /// LCR_H Register. - /// - /// - If the FIFO is disabled, this bit is set when the receive holding register is empty. - /// - If the FIFO is enabled, the RXFE bit is set when the receive FIFO is empty. - RXFE OFFSET(4) NUMBITS(1) [], - - /// UART busy. If this bit is set to 1, the UART is busy transmitting data. This bit remains - /// set until the complete byte, including all the stop bits, has been sent from the shift - /// register. - /// - /// This bit is set as soon as the transmit FIFO becomes non-empty, regardless of whether - /// the UART is enabled or not. - BUSY OFFSET(3) NUMBITS(1) [] - ], - - /// Integer Baud Rate Divisor. - IBRD [ - /// The integer baud rate divisor. - BAUD_DIVINT OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud Rate Divisor. - FBRD [ - /// The fractional baud rate divisor. - BAUD_DIVFRAC OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control Register. - LCR_H [ - /// Word length. These bits indicate the number of data bits transmitted or received in a - /// frame. - #[allow(clippy::enum_variant_names)] - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ], - - /// Enable FIFOs: - /// - /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become 1-byte-deep holding - /// registers. - /// - /// 1 = Transmit and receive FIFO buffers are enabled (FIFO mode). - FEN OFFSET(4) NUMBITS(1) [ - FifosDisabled = 0, - FifosEnabled = 1 - ] - ], - - /// Control Register. - CR [ - /// Receive enable. If this bit is set to 1, the receive section of the UART is enabled. - /// Data reception occurs for either UART signals or SIR signals depending on the setting of - /// the SIREN bit. When the UART is disabled in the middle of reception, it completes the - /// current character before stopping. - RXE OFFSET(9) NUMBITS(1) [ - Disabled = 0, - Enabled = 1 - ], - - /// Transmit enable. If this bit is set to 1, the transmit section of the UART is enabled. - /// Data transmission occurs for either UART signals, or SIR signals depending on the - /// setting of the SIREN bit. When the UART is disabled in the middle of transmission, it - /// completes the current character before stopping. - TXE OFFSET(8) NUMBITS(1) [ - Disabled = 0, - Enabled = 1 - ], - - /// UART enable: - /// - /// 0 = UART is disabled. If the UART is disabled in the middle of transmission or - /// reception, it completes the current character before stopping. - /// - /// 1 = The UART is enabled. Data transmission and reception occurs for either UART signals - /// or SIR signals depending on the setting of the SIREN bit - UARTEN OFFSET(0) NUMBITS(1) [ - /// If the UART is disabled in the middle of transmission or reception, it completes the - /// current character before stopping. - Disabled = 0, - Enabled = 1 - ] - ], - - /// Interrupt Clear Register. - ICR [ - /// Meta field for all pending interrupts. - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -register_structs! { - #[allow(non_snake_case)] - pub RegisterBlock { - (0x00 => DR: ReadWrite), - (0x04 => _reserved1), - (0x18 => FR: ReadOnly), - (0x1c => _reserved2), - (0x24 => IBRD: WriteOnly), - (0x28 => FBRD: WriteOnly), - (0x2c => LCR_H: WriteOnly), - (0x30 => CR: WriteOnly), - (0x34 => _reserved3), - (0x44 => ICR: WriteOnly), - (0x48 => @END), - } -} - -/// Abstraction for the associated MMIO registers. -type Registers = MMIODerefWrapper; - -#[derive(PartialEq)] -enum BlockingMode { - Blocking, - NonBlocking, -} - -struct PL011UartInner { - registers: Registers, - chars_written: usize, - chars_read: usize, -} - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -/// Representation of the UART. -pub struct PL011Uart { - inner: NullLock, -} - -//-------------------------------------------------------------------------------------------------- -// Private Code -//-------------------------------------------------------------------------------------------------- - -impl PL011UartInner { - /// Create an instance. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { - Self { - registers: Registers::new(mmio_start_addr), - chars_written: 0, - chars_read: 0, - } - } - - /// Set up baud rate and characteristics. - /// - /// This results in 8N1 and 921_600 baud. - /// - /// The calculation for the BRD is (we set the clock to 48 MHz in config.txt): - /// `(48_000_000 / 16) / 921_600 = 3.2552083`. - /// - /// This means the integer part is `3` and goes into the `IBRD`. - /// The fractional part is `0.2552083`. - /// - /// `FBRD` calculation according to the PL011 Technical Reference Manual: - /// `INTEGER((0.2552083 * 64) + 0.5) = 16`. - /// - /// Therefore, the generated baud rate divider is: `3 + 16/64 = 3.25`. Which results in a - /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. - /// - /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. - pub fn init(&mut self) { - // Execution can arrive here while there are still characters queued in the TX FIFO and - // actively being sent out by the UART hardware. If the UART is turned off in this case, - // those queued characters would be lost. - // - // For example, this can happen during runtime on a call to panic!(), because panic!() - // initializes its own UART instance and calls init(). - // - // Hence, flush first to ensure all pending characters are transmitted. - self.flush(); - - // Turn the UART off temporarily. - self.registers.CR.set(0); - - // Clear all pending interrupts. - self.registers.ICR.write(ICR::ALL::CLEAR); - - // From the PL011 Technical Reference Manual: - // - // The LCR_H, IBRD, and FBRD registers form the single 30-bit wide LCR Register that is - // updated on a single write strobe generated by a LCR_H write. So, to internally update the - // contents of IBRD or FBRD, a LCR_H write must always be performed at the end. - // - // Set the baud rate, 8N1 and FIFO enabled. - self.registers.IBRD.write(IBRD::BAUD_DIVINT.val(3)); - self.registers.FBRD.write(FBRD::BAUD_DIVFRAC.val(16)); - self.registers - .LCR_H - .write(LCR_H::WLEN::EightBit + LCR_H::FEN::FifosEnabled); - - // Turn the UART on. - self.registers - .CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - } - - /// Send a character. - fn write_char(&mut self, c: char) { - // Spin while TX FIFO full is set, waiting for an empty slot. - while self.registers.FR.matches_all(FR::TXFF::SET) { - cpu::nop(); - } - - // Write the character to the buffer. - self.registers.DR.set(c as u32); - - self.chars_written += 1; - } - - /// Block execution until the last buffered character has been physically put on the TX wire. - fn flush(&self) { - // Spin until the busy bit is cleared. - while self.registers.FR.matches_all(FR::BUSY::SET) { - cpu::nop(); - } - } - - /// Retrieve a character. - fn read_char(&mut self, blocking_mode: BlockingMode) -> Option { - // If RX FIFO is empty, - if self.registers.FR.matches_all(FR::RXFE::SET) { - // immediately return in non-blocking mode. - if blocking_mode == BlockingMode::NonBlocking { - return None; - } - - // Otherwise, wait until a char was received. - while self.registers.FR.matches_all(FR::RXFE::SET) { - cpu::nop(); - } - } - - // Read one character. - let ret = self.registers.DR.get() as u8 as char; - - // Update statistics. - self.chars_read += 1; - - Some(ret) - } -} - -/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are -/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`, -/// we get `write_fmt()` automatically. -/// -/// The function takes an `&mut self`, so it must be implemented for the inner struct. -/// -/// See [`src/print.rs`]. -/// -/// [`src/print.rs`]: ../../print/index.html -impl fmt::Write for PL011UartInner { - fn write_str(&mut self, s: &str) -> fmt::Result { - for c in s.chars() { - self.write_char(c); - } - - Ok(()) - } -} - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -impl PL011Uart { - pub const COMPATIBLE: &'static str = "BCM PL011 UART"; - - /// Create an instance. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { - Self { - inner: NullLock::new(PL011UartInner::new(mmio_start_addr)), - } - } -} - -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use synchronization::interface::Mutex; - -impl driver::interface::DeviceDriver for PL011Uart { - fn compatible(&self) -> &'static str { - Self::COMPATIBLE - } - - unsafe fn init(&self) -> Result<(), &'static str> { - self.inner.lock(|inner| inner.init()); - - Ok(()) - } -} - -impl console::interface::Write for PL011Uart { - /// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to - /// serialize access. - fn write_char(&self, c: char) { - self.inner.lock(|inner| inner.write_char(c)); - } - - fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase - // readability. - self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) - } - - fn flush(&self) { - // Spin until TX FIFO empty is set. - self.inner.lock(|inner| inner.flush()); - } -} - -impl console::interface::Read for PL011Uart { - fn read_char(&self) -> char { - self.inner - .lock(|inner| inner.read_char(BlockingMode::Blocking).unwrap()) - } - - fn clear_rx(&self) { - // Read from the RX FIFO until it is indicating empty. - while self - .inner - .lock(|inner| inner.read_char(BlockingMode::NonBlocking)) - .is_some() - {} - } -} - -impl console::interface::Statistics for PL011Uart { - fn chars_written(&self) -> usize { - self.inner.lock(|inner| inner.chars_written) - } - - fn chars_read(&self) -> usize { - self.inner.lock(|inner| inner.chars_read) - } -} - -impl console::interface::All for PL011Uart {} diff --git a/arceos/tools/raspi4/chainloader/src/bsp/device_driver/common.rs b/arceos/tools/raspi4/chainloader/src/bsp/device_driver/common.rs deleted file mode 100644 index dfe7d8ef3..000000000 --- a/arceos/tools/raspi4/chainloader/src/bsp/device_driver/common.rs +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2020-2023 Andre Richter - -//! Common device driver code. - -use core::{marker::PhantomData, ops}; - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct MMIODerefWrapper { - start_addr: usize, - phantom: PhantomData T>, -} - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -impl MMIODerefWrapper { - /// Create an instance. - pub const unsafe fn new(start_addr: usize) -> Self { - Self { - start_addr, - phantom: PhantomData, - } - } -} - -impl ops::Deref for MMIODerefWrapper { - type Target = T; - - fn deref(&self) -> &Self::Target { - unsafe { &*(self.start_addr as *const _) } - } -} diff --git a/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi.rs b/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi.rs deleted file mode 100644 index 3ea864dc7..000000000 --- a/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi.rs +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! Top-level BSP file for the Raspberry Pi 3 and 4. - -pub mod cpu; -pub mod driver; -pub mod memory; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Board identification. -pub fn board_name() -> &'static str { - #[cfg(feature = "bsp_rpi3")] - { - "Raspberry Pi 3" - } - - #[cfg(feature = "bsp_rpi4")] - { - "Raspberry Pi 4" - } -} diff --git a/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi/cpu.rs b/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi/cpu.rs deleted file mode 100644 index 65cf5abbe..000000000 --- a/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi/cpu.rs +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! BSP Processor code. - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -/// Used by `arch` code to find the early boot core. -#[no_mangle] -#[link_section = ".text._start_arguments"] -pub static BOOT_CORE_ID: u64 = 0; diff --git a/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi/driver.rs b/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi/driver.rs deleted file mode 100644 index 2a80ee2c5..000000000 --- a/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi/driver.rs +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! BSP driver support. - -use super::memory::map::mmio; -use crate::{bsp::device_driver, console, driver as generic_driver}; -use core::sync::atomic::{AtomicBool, Ordering}; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; -static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; - -//-------------------------------------------------------------------------------------------------- -// Private Code -//-------------------------------------------------------------------------------------------------- - -/// This must be called only after successful init of the UART driver. -fn post_init_uart() -> Result<(), &'static str> { - console::register_console(&PL011_UART); - - Ok(()) -} - -/// This must be called only after successful init of the GPIO driver. -fn post_init_gpio() -> Result<(), &'static str> { - GPIO.map_pl011_uart(); - Ok(()) -} - -fn driver_uart() -> Result<(), &'static str> { - let uart_descriptor = - generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart)); - generic_driver::driver_manager().register_driver(uart_descriptor); - - Ok(()) -} - -fn driver_gpio() -> Result<(), &'static str> { - let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio)); - generic_driver::driver_manager().register_driver(gpio_descriptor); - - Ok(()) -} - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Initialize the driver subsystem. -/// -/// # Safety -/// -/// See child function calls. -pub unsafe fn init() -> Result<(), &'static str> { - static INIT_DONE: AtomicBool = AtomicBool::new(false); - if INIT_DONE.load(Ordering::Relaxed) { - return Err("Init already done"); - } - - driver_uart()?; - driver_gpio()?; - - INIT_DONE.store(true, Ordering::Relaxed); - Ok(()) -} diff --git a/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi/kernel.ld b/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi/kernel.ld deleted file mode 100644 index c84b62381..000000000 --- a/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi/kernel.ld +++ /dev/null @@ -1,83 +0,0 @@ -/* SPDX-License-Identifier: MIT OR Apache-2.0 - * - * Copyright (c) 2018-2022 Andre Richter - */ - -/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */ -__rpi_phys_binary_load_addr = 0x80000; - - -ENTRY(__rpi_phys_binary_load_addr) - -/* Flags: - * 4 == R - * 5 == RX - * 6 == RW - * - * Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses. - * It doesn't mean all of them need actually be loaded. - */ -PHDRS -{ - segment_boot_core_stack PT_LOAD FLAGS(6); - segment_code PT_LOAD FLAGS(5); - segment_data PT_LOAD FLAGS(6); -} - -SECTIONS -{ - /* Set the link address to 32 MiB */ - . = 0x2000000; - - /*********************************************************************************************** - * Boot Core Stack - ***********************************************************************************************/ - .boot_core_stack (NOLOAD) : - { - /* ^ */ - /* | stack */ - . += __rpi_phys_binary_load_addr; /* | growth */ - /* | direction */ - __boot_core_stack_end_exclusive = .; /* | */ - } :segment_boot_core_stack - - /*********************************************************************************************** - * Code + RO Data + Global Offset Table - ***********************************************************************************************/ - __binary_nonzero_start = .; - .text : - { - KEEP(*(.text._start)) - *(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */ - *(.text._start_rust) /* The Rust entry point */ - *(.text*) /* Everything else */ - } :segment_code - - .rodata : ALIGN(8) { *(.rodata*) } :segment_code - - /*********************************************************************************************** - * Data + BSS - ***********************************************************************************************/ - .data : { *(.data*) } :segment_data - - /* Fill up to 8 byte, b/c relocating the binary is done in u64 chunks */ - . = ALIGN(8); - __binary_nonzero_end_exclusive = .; - - /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */ - .bss (NOLOAD) : ALIGN(16) - { - __bss_start = .; - *(.bss*); - . = ALIGN(16); - __bss_end_exclusive = .; - } :segment_data - - /*********************************************************************************************** - * Misc - ***********************************************************************************************/ - .got : { *(.got*) } - ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") - - /DISCARD/ : { *(.comment*) } -} diff --git a/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi/memory.rs b/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi/memory.rs deleted file mode 100644 index ee72b27a0..000000000 --- a/arceos/tools/raspi4/chainloader/src/bsp/raspberrypi/memory.rs +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! BSP Memory Management. - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -/// The board's physical memory map. -#[rustfmt::skip] -pub(super) mod map { - pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x8_0000; - - pub const GPIO_OFFSET: usize = 0x0020_0000; - pub const UART_OFFSET: usize = 0x0020_1000; - - /// Physical devices. - #[cfg(feature = "bsp_rpi3")] - pub mod mmio { - use super::*; - - pub const START: usize = 0x3F00_0000; - pub const GPIO_START: usize = START + GPIO_OFFSET; - pub const PL011_UART_START: usize = START + UART_OFFSET; - } - - /// Physical devices. - #[cfg(feature = "bsp_rpi4")] - pub mod mmio { - use super::*; - - pub const START: usize = 0xFE00_0000; - pub const GPIO_START: usize = START + GPIO_OFFSET; - pub const PL011_UART_START: usize = START + UART_OFFSET; - } -} - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// The address on which the Raspberry firmware loads every binary by default. -#[inline(always)] -pub fn board_default_load_addr() -> *const u64 { - map::BOARD_DEFAULT_LOAD_ADDRESS as _ -} diff --git a/arceos/tools/raspi4/chainloader/src/console.rs b/arceos/tools/raspi4/chainloader/src/console.rs deleted file mode 100644 index a83f86fe0..000000000 --- a/arceos/tools/raspi4/chainloader/src/console.rs +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! System console. - -mod null_console; - -use crate::synchronization::{self, NullLock}; - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -/// Console interfaces. -pub mod interface { - use core::fmt; - - /// Console write functions. - pub trait Write { - /// Write a single character. - fn write_char(&self, c: char); - - /// Write a Rust format string. - fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result; - - /// Block until the last buffered character has been physically put on the TX wire. - fn flush(&self); - } - - /// Console read functions. - pub trait Read { - /// Read a single character. - fn read_char(&self) -> char { - ' ' - } - - /// Clear RX buffers, if any. - fn clear_rx(&self); - } - - /// Console statistics. - pub trait Statistics { - /// Return the number of characters written. - fn chars_written(&self) -> usize { - 0 - } - - /// Return the number of characters read. - fn chars_read(&self) -> usize { - 0 - } - } - - /// Trait alias for a full-fledged console. - pub trait All: Write + Read + Statistics {} -} - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static CUR_CONSOLE: NullLock<&'static (dyn interface::All + Sync)> = - NullLock::new(&null_console::NULL_CONSOLE); - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- -use synchronization::interface::Mutex; - -/// Register a new console. -pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { - CUR_CONSOLE.lock(|con| *con = new_console); -} - -/// Return a reference to the currently registered console. -/// -/// This is the global console used by all printing macros. -pub fn console() -> &'static dyn interface::All { - CUR_CONSOLE.lock(|con| *con) -} diff --git a/arceos/tools/raspi4/chainloader/src/console/null_console.rs b/arceos/tools/raspi4/chainloader/src/console/null_console.rs deleted file mode 100644 index e92a022b6..000000000 --- a/arceos/tools/raspi4/chainloader/src/console/null_console.rs +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2022-2023 Andre Richter - -//! Null console. - -use super::interface; -use core::fmt; - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct NullConsole; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -pub static NULL_CONSOLE: NullConsole = NullConsole {}; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -impl interface::Write for NullConsole { - fn write_char(&self, _c: char) {} - - fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { - fmt::Result::Ok(()) - } - - fn flush(&self) {} -} - -impl interface::Read for NullConsole { - fn clear_rx(&self) {} -} - -impl interface::Statistics for NullConsole {} -impl interface::All for NullConsole {} diff --git a/arceos/tools/raspi4/chainloader/src/cpu.rs b/arceos/tools/raspi4/chainloader/src/cpu.rs deleted file mode 100644 index eacb8924a..000000000 --- a/arceos/tools/raspi4/chainloader/src/cpu.rs +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2020-2023 Andre Richter - -//! Processor code. - -#[cfg(target_arch = "aarch64")] -#[path = "_arch/aarch64/cpu.rs"] -mod arch_cpu; - -mod boot; - -//-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports -//-------------------------------------------------------------------------------------------------- -pub use arch_cpu::{nop, wait_forever}; - -#[cfg(feature = "bsp_rpi3")] -pub use arch_cpu::spin_for_cycles; diff --git a/arceos/tools/raspi4/chainloader/src/cpu/boot.rs b/arceos/tools/raspi4/chainloader/src/cpu/boot.rs deleted file mode 100644 index b1e98328a..000000000 --- a/arceos/tools/raspi4/chainloader/src/cpu/boot.rs +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2021-2023 Andre Richter - -//! Boot code. - -#[cfg(target_arch = "aarch64")] -#[path = "../_arch/aarch64/cpu/boot.rs"] -mod arch_boot; diff --git a/arceos/tools/raspi4/chainloader/src/driver.rs b/arceos/tools/raspi4/chainloader/src/driver.rs deleted file mode 100644 index 53592c66b..000000000 --- a/arceos/tools/raspi4/chainloader/src/driver.rs +++ /dev/null @@ -1,154 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! Driver support. - -use crate::synchronization::{interface::Mutex, NullLock}; - -//-------------------------------------------------------------------------------------------------- -// Private Definitions -//-------------------------------------------------------------------------------------------------- - -const NUM_DRIVERS: usize = 5; - -struct DriverManagerInner { - next_index: usize, - descriptors: [Option; NUM_DRIVERS], -} - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -/// Driver interfaces. -pub mod interface { - /// Device Driver functions. - pub trait DeviceDriver { - /// Return a compatibility string for identifying the driver. - fn compatible(&self) -> &'static str; - - /// Called by the kernel to bring up the device. - /// - /// # Safety - /// - /// - During init, drivers might do stuff with system-wide impact. - unsafe fn init(&self) -> Result<(), &'static str> { - Ok(()) - } - } -} - -/// Tpye to be used as an optional callback after a driver's init() has run. -pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; - -/// A descriptor for device drivers. -#[derive(Copy, Clone)] -pub struct DeviceDriverDescriptor { - device_driver: &'static (dyn interface::DeviceDriver + Sync), - post_init_callback: Option, -} - -/// Provides device driver management functions. -pub struct DriverManager { - inner: NullLock, -} - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static DRIVER_MANAGER: DriverManager = DriverManager::new(); - -//-------------------------------------------------------------------------------------------------- -// Private Code -//-------------------------------------------------------------------------------------------------- - -impl DriverManagerInner { - /// Create an instance. - pub const fn new() -> Self { - Self { - next_index: 0, - descriptors: [None; NUM_DRIVERS], - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -impl DeviceDriverDescriptor { - /// Create an instance. - pub fn new( - device_driver: &'static (dyn interface::DeviceDriver + Sync), - post_init_callback: Option, - ) -> Self { - Self { - device_driver, - post_init_callback, - } - } -} - -/// Return a reference to the global DriverManager. -pub fn driver_manager() -> &'static DriverManager { - &DRIVER_MANAGER -} - -impl DriverManager { - /// Create an instance. - pub const fn new() -> Self { - Self { - inner: NullLock::new(DriverManagerInner::new()), - } - } - - /// Register a device driver with the kernel. - pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { - self.inner.lock(|inner| { - inner.descriptors[inner.next_index] = Some(descriptor); - inner.next_index += 1; - }) - } - - /// Helper for iterating over registered drivers. - fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { - self.inner.lock(|inner| { - inner - .descriptors - .iter() - .filter_map(|x| x.as_ref()) - .for_each(f) - }) - } - - /// Fully initialize all drivers. - /// - /// # Safety - /// - /// - During init, drivers might do stuff with system-wide impact. - pub unsafe fn init_drivers(&self) { - self.for_each_descriptor(|descriptor| { - // 1. Initialize driver. - if let Err(x) = descriptor.device_driver.init() { - panic!( - "Error initializing driver: {}: {}", - descriptor.device_driver.compatible(), - x - ); - } - - // 2. Call corresponding post init callback. - if let Some(callback) = &descriptor.post_init_callback { - if let Err(x) = callback() { - panic!( - "Error during driver post-init callback: {}: {}", - descriptor.device_driver.compatible(), - x - ); - } - } - }); - } -} diff --git a/arceos/tools/raspi4/chainloader/src/main.rs b/arceos/tools/raspi4/chainloader/src/main.rs deleted file mode 100644 index a7c8d2eee..000000000 --- a/arceos/tools/raspi4/chainloader/src/main.rs +++ /dev/null @@ -1,221 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -// Rust embedded logo for `make doc`. -#![doc( - html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" -)] - -//! The `kernel` binary. -//! -//! # Code organization and architecture -//! -//! The code is divided into different *modules*, each representing a typical **subsystem** of the -//! `kernel`. Top-level module files of subsystems reside directly in the `src` folder. For example, -//! `src/memory.rs` contains code that is concerned with all things memory management. -//! -//! ## Visibility of processor architecture code -//! -//! Some of the `kernel`'s subsystems depend on low-level code that is specific to the target -//! processor architecture. For each supported processor architecture, there exists a subfolder in -//! `src/_arch`, for example, `src/_arch/aarch64`. -//! -//! The architecture folders mirror the subsystem modules laid out in `src`. For example, -//! architectural code that belongs to the `kernel`'s MMU subsystem (`src/memory/mmu.rs`) would go -//! into `src/_arch/aarch64/memory/mmu.rs`. The latter file is loaded as a module in -//! `src/memory/mmu.rs` using the `path attribute`. Usually, the chosen module name is the generic -//! module's name prefixed with `arch_`. -//! -//! For example, this is the top of `src/memory/mmu.rs`: -//! -//! ``` -//! #[cfg(target_arch = "aarch64")] -//! #[path = "../_arch/aarch64/memory/mmu.rs"] -//! mod arch_mmu; -//! ``` -//! -//! Often times, items from the `arch_ module` will be publicly reexported by the parent module. -//! This way, each architecture specific module can provide its implementation of an item, while the -//! caller must not be concerned which architecture has been conditionally compiled. -//! -//! ## BSP code -//! -//! `BSP` stands for Board Support Package. `BSP` code is organized under `src/bsp.rs` and contains -//! target board specific definitions and functions. These are things such as the board's memory map -//! or instances of drivers for devices that are featured on the respective board. -//! -//! Just like processor architecture code, the `BSP` code's module structure tries to mirror the -//! `kernel`'s subsystem modules, but there is no reexporting this time. That means whatever is -//! provided must be called starting from the `bsp` namespace, e.g. `bsp::driver::driver_manager()`. -//! -//! ## Kernel interfaces -//! -//! Both `arch` and `bsp` contain code that is conditionally compiled depending on the actual target -//! and board for which the kernel is compiled. For example, the `interrupt controller` hardware of -//! the `Raspberry Pi 3` and the `Raspberry Pi 4` is different, but we want the rest of the `kernel` -//! code to play nicely with any of the two without much hassle. -//! -//! In order to provide a clean abstraction between `arch`, `bsp` and `generic kernel code`, -//! `interface` traits are provided *whenever possible* and *where it makes sense*. They are defined -//! in the respective subsystem module and help to enforce the idiom of *program to an interface, -//! not an implementation*. For example, there will be a common IRQ handling interface which the two -//! different interrupt controller `drivers` of both Raspberrys will implement, and only export the -//! interface to the rest of the `kernel`. -//! -//! ``` -//! +-------------------+ -//! | Interface (Trait) | -//! | | -//! +--+-------------+--+ -//! ^ ^ -//! | | -//! | | -//! +----------+--+ +--+----------+ -//! | kernel code | | bsp code | -//! | | | arch code | -//! +-------------+ +-------------+ -//! ``` -//! -//! # Summary -//! -//! For a logical `kernel` subsystem, corresponding code can be distributed over several physical -//! locations. Here is an example for the **memory** subsystem: -//! -//! - `src/memory.rs` and `src/memory/**/*` -//! - Common code that is agnostic of target processor architecture and `BSP` characteristics. -//! - Example: A function to zero a chunk of memory. -//! - Interfaces for the memory subsystem that are implemented by `arch` or `BSP` code. -//! - Example: An `MMU` interface that defines `MMU` function prototypes. -//! - `src/bsp/__board_name__/memory.rs` and `src/bsp/__board_name__/memory/**/*` -//! - `BSP` specific code. -//! - Example: The board's memory map (physical addresses of DRAM and MMIO devices). -//! - `src/_arch/__arch_name__/memory.rs` and `src/_arch/__arch_name__/memory/**/*` -//! - Processor architecture specific code. -//! - Example: Implementation of the `MMU` interface for the `__arch_name__` processor -//! architecture. -//! -//! From a namespace perspective, **memory** subsystem code lives in: -//! -//! - `crate::memory::*` -//! - `crate::bsp::memory::*` -//! -//! # Boot flow -//! -//! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`. -//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. -//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. - -#![allow(clippy::upper_case_acronyms)] -#![feature(asm_const)] -#![feature(format_args_nl)] -#![feature(panic_info_message)] -#![feature(trait_alias)] -#![no_main] -#![no_std] - -mod bsp; -mod console; -mod cpu; -mod driver; -mod panic_wait; -mod print; -mod synchronization; - -/// Early init code. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -/// - The init calls in this function must appear in the correct order. -unsafe fn kernel_init() -> ! { - // Initialize the BSP driver subsystem. - if let Err(x) = bsp::driver::init() { - panic!("Error initializing BSP driver subsystem: {}", x); - } - - // Initialize all device drivers. - driver::driver_manager().init_drivers(); - // println! is usable from here on. - - // Transition from unsafe to safe. - kernel_main() -} - -const MINILOAD_LOGO: &str = r#" - __ __ _ _ _ _ -| \/ (_)_ _ (_) | ___ __ _ __| | -| |\/| | | ' \| | |__/ _ \/ _` / _` | -|_| |_|_|_||_|_|____\___/\__,_\__,_| -"#; - -/// The main function running after the early init. -fn kernel_main() -> ! { - use console::console; - - println!("{}", MINILOAD_LOGO); - println!("{:^37}", bsp::board_name()); - println!(); - println!("[ML] Requesting binary"); - console().flush(); - - // Discard any spurious received characters before starting with the loader protocol. - console().clear_rx(); - - // Notify `Minipush` to send the binary. - for _ in 0..3 { - console().write_char(3 as char); - } - - // Read the binary's size. - let mut size: u32 = u32::from(console().read_char() as u8); - size |= u32::from(console().read_char() as u8) << 8; - size |= u32::from(console().read_char() as u8) << 16; - size |= u32::from(console().read_char() as u8) << 24; - - // Trust it's not too big. - console().write_char('O'); - console().write_char('K'); - - let kernel_addr: *mut u8 = bsp::memory::board_default_load_addr() as *mut u8; - unsafe { - // Read the kernel byte by byte. - for i in 0..size { - core::ptr::write_volatile(kernel_addr.offset(i as isize), console().read_char() as u8) - } - } - - println!("[ML] Loaded! Executing the payload now\n"); - console().flush(); - - #[cfg(feature = "enable_jtag_debug")] - print_jtag_info_and_wait_forever(); - - println!("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - println!("@ You're using chainboot image . @"); - println!("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - // Use black magic to create a function pointer. - let kernel: fn() -> ! = unsafe { core::mem::transmute(kernel_addr) }; - - // Jump to loaded kernel! - kernel() -} - -#[cfg(feature = "enable_jtag_debug")] -fn print_jtag_info_and_wait_forever() { - println!("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - println!("@ You're using a JTAG debug image. @"); - println!("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - println!("@ 1. open openocd, gdb @"); - println!("@ 2. target extended-remote :3333; @"); - println!("@ 3. set $pc=0x80000 @"); - println!("@ 4. break rust_entry/others @"); - println!("@ 5. break $previous_addr @"); - println!("@ 6. delete 1 @"); - println!("@ 7. load @"); - println!("@ 8. continue @"); - println!("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - - // wait for gdb connect - cpu::wait_forever() -} diff --git a/arceos/tools/raspi4/chainloader/src/panic_wait.rs b/arceos/tools/raspi4/chainloader/src/panic_wait.rs deleted file mode 100644 index 5bb0896e4..000000000 --- a/arceos/tools/raspi4/chainloader/src/panic_wait.rs +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! A panic handler that infinitely waits. - -use crate::{cpu, println}; -use core::panic::PanicInfo; - -//-------------------------------------------------------------------------------------------------- -// Private Code -//-------------------------------------------------------------------------------------------------- - -/// Stop immediately if called a second time. -/// -/// # Note -/// -/// Using atomics here relieves us from needing to use `unsafe` for the static variable. -/// -/// On `AArch64`, which is the only implemented architecture at the time of writing this, -/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store -/// instructions. They are therefore safe to use even with MMU + caching deactivated. -/// -/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load -/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store -fn panic_prevent_reenter() { - use core::sync::atomic::{AtomicBool, Ordering}; - - #[cfg(not(target_arch = "aarch64"))] - compile_error!("Add the target_arch to above's check if the following code is safe to use"); - - static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); - - if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { - PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); - - return; - } - - cpu::wait_forever() -} - -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - // Protect against panic infinite loops if any of the following code panics itself. - panic_prevent_reenter(); - - let (location, line, column) = match info.location() { - Some(loc) => (loc.file(), loc.line(), loc.column()), - _ => ("???", 0, 0), - }; - - println!( - "Kernel panic!\n\n\ - Panic location:\n File '{}', line {}, column {}\n\n\ - {}", - location, - line, - column, - info.message().unwrap_or(&format_args!("")), - ); - - cpu::wait_forever() -} diff --git a/arceos/tools/raspi4/chainloader/src/print.rs b/arceos/tools/raspi4/chainloader/src/print.rs deleted file mode 100644 index 6de99572d..000000000 --- a/arceos/tools/raspi4/chainloader/src/print.rs +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2023 Andre Richter - -//! Printing. - -use crate::console; -use core::fmt; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -#[doc(hidden)] -pub fn _print(args: fmt::Arguments) { - console::console().write_fmt(args).unwrap(); -} - -/// Prints without a newline. -/// -/// Carbon copy from -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*))); -} - -/// Prints with a newline. -/// -/// Carbon copy from -#[macro_export] -macro_rules! println { - () => ($crate::print!("\n")); - ($($arg:tt)*) => ({ - $crate::print::_print(format_args_nl!($($arg)*)); - }) -} diff --git a/arceos/tools/raspi4/chainloader/src/synchronization.rs b/arceos/tools/raspi4/chainloader/src/synchronization.rs deleted file mode 100644 index 94c83de1c..000000000 --- a/arceos/tools/raspi4/chainloader/src/synchronization.rs +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2020-2023 Andre Richter - -//! Synchronization primitives. -//! -//! # Resources -//! -//! - -//! - -//! - - -use core::cell::UnsafeCell; - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -/// Synchronization interfaces. -pub mod interface { - - /// Any object implementing this trait guarantees exclusive access to the data wrapped within - /// the Mutex for the duration of the provided closure. - pub trait Mutex { - /// The type of the data that is wrapped by this mutex. - type Data; - - /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; - } -} - -/// A pseudo-lock for teaching purposes. -/// -/// In contrast to a real Mutex implementation, does not protect against concurrent access from -/// other cores to the contained data. This part is preserved for later lessons. -/// -/// The lock will only be used as long as it is safe to do so, i.e. as long as the kernel is -/// executing single-threaded, aka only running on a single core with interrupts disabled. -pub struct NullLock -where - T: ?Sized, -{ - data: UnsafeCell, -} - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -unsafe impl Send for NullLock where T: ?Sized + Send {} -unsafe impl Sync for NullLock where T: ?Sized + Send {} - -impl NullLock { - /// Create an instance. - pub const fn new(data: T) -> Self { - Self { - data: UnsafeCell::new(data), - } - } -} - -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ - -impl interface::Mutex for NullLock { - type Data = T; - - fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { - // In a real lock, there would be code encapsulating this line that ensures that this - // mutable reference will ever only be given out once at a time. - let data = unsafe { &mut *self.data.get() }; - - f(data) - } -} diff --git a/arceos/tools/raspi4/chainloader/tests/chainboot_test.rb b/arceos/tools/raspi4/chainloader/tests/chainboot_test.rb deleted file mode 100644 index 00de42a36..000000000 --- a/arceos/tools/raspi4/chainloader/tests/chainboot_test.rb +++ /dev/null @@ -1,78 +0,0 @@ -# frozen_string_literal: true - -# SPDX-License-Identifier: MIT OR Apache-2.0 -# -# Copyright (c) 2020-2023 Andre Richter - -require_relative '../../common/serial/minipush' -require_relative '../../common/tests/boot_test' -require 'pty' - -# Match for the last print that 'demo_payload_rpiX.img' produces. -EXPECTED_PRINT = 'Echoing input now' - -# Wait for request to power the target. -class PowerTargetRequestTest < SubtestBase - MINIPUSH_POWER_TARGET_REQUEST = 'Please power the target now' - - def initialize(qemu_cmd, pty_main) - super() - @qemu_cmd = qemu_cmd - @pty_main = pty_main - end - - def name - 'Waiting for request to power target' - end - - def run(qemu_out, _qemu_in) - expect_or_raise(qemu_out, MINIPUSH_POWER_TARGET_REQUEST) - - # Now is the time to start QEMU with the chainloader binary. QEMU's virtual tty connects to - # the MiniPush instance spawned on pty_main, so that the two processes talk to each other. - Process.spawn(@qemu_cmd, in: @pty_main, out: @pty_main, err: '/dev/null') - end -end - -# Extend BootTest so that it listens on the output of a MiniPush instance, which is itself connected -# to a QEMU instance instead of a real HW. -class ChainbootTest < BootTest - MINIPUSH = '../common/serial/minipush.rb' - - def initialize(qemu_cmd, payload_path) - super(qemu_cmd, EXPECTED_PRINT) - - @test_name = 'Boot test using Minipush' - - @payload_path = payload_path - end - - private - - # override - def setup - pty_main, pty_secondary = PTY.open - mp_out, _mp_in = PTY.spawn("ruby #{MINIPUSH} #{pty_secondary.path} #{@payload_path}") - - # The subtests (from this class and the parents) listen on @qemu_out_wrapped. Hence, point - # it to MiniPush's output. - @qemu_out_wrapped = PTYLoggerWrapper.new(mp_out, "\r\n") - - # Important: Run this subtest before the one in the parent class. - @console_subtests.prepend(PowerTargetRequestTest.new(@qemu_cmd, pty_main)) - end - - # override - def finish - super() - @test_output.map! { |x| x.gsub(/.*\r/, ' ') } - end -end - -## ------------------------------------------------------------------------------------------------- -## Execution starts here -## ------------------------------------------------------------------------------------------------- -payload_path = ARGV.pop -qemu_cmd = ARGV.join(' ') - -ChainbootTest.new(qemu_cmd, payload_path).run diff --git a/arceos/tools/raspi4/chainloader/update.sh b/arceos/tools/raspi4/chainloader/update.sh deleted file mode 100755 index 5fac48ba0..000000000 --- a/arceos/tools/raspi4/chainloader/update.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -cd ../05_drivers_gpio_uart -BSP=rpi4 make -cp kernel8.img ../06_uart_chainloader/demo_payload_rpi4.img -make -cp kernel8.img ../06_uart_chainloader/demo_payload_rpi3.img -rm kernel8.img diff --git a/arceos/tools/raspi4/common/docker.mk b/arceos/tools/raspi4/common/docker.mk deleted file mode 100644 index 61355768f..000000000 --- a/arceos/tools/raspi4/common/docker.mk +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE := rustembedded/osdev-utils:2021.12 diff --git a/arceos/tools/raspi4/common/format.mk b/arceos/tools/raspi4/common/format.mk deleted file mode 100644 index e392304ad..000000000 --- a/arceos/tools/raspi4/common/format.mk +++ /dev/null @@ -1,12 +0,0 @@ -define color_header - @tput setaf 6 2> /dev/null || true - @printf '\n%s\n' $(1) - @tput sgr0 2> /dev/null || true -endef - -define color_progress_prefix - @tput setaf 2 2> /dev/null || true - @tput bold 2 2> /dev/null || true - @printf '%12s ' $(1) - @tput sgr0 2> /dev/null || true -endef diff --git a/arceos/tools/raspi4/common/operating_system.mk b/arceos/tools/raspi4/common/operating_system.mk deleted file mode 100644 index 90172f775..000000000 --- a/arceos/tools/raspi4/common/operating_system.mk +++ /dev/null @@ -1,9 +0,0 @@ -ifeq ($(shell uname -s),Linux) - DU_ARGUMENTS = --block-size=1024 --apparent-size -else ifeq ($(shell uname -s),Darwin) - DU_ARGUMENTS = -k -A -endif - -define disk_usage_KiB - @printf '%s KiB\n' `du $(DU_ARGUMENTS) $(1) | cut -f1` -endef diff --git a/arceos/tools/raspi4/common/serial/minipush.rb b/arceos/tools/raspi4/common/serial/minipush.rb deleted file mode 100755 index 262ce20a0..000000000 --- a/arceos/tools/raspi4/common/serial/minipush.rb +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -# SPDX-License-Identifier: MIT OR Apache-2.0 -# -# Copyright (c) 2020-2022 Andre Richter - -require_relative 'miniterm' -require 'ruby-progressbar' -require_relative 'minipush/progressbar_patch' -require 'timeout' - -class ProtocolError < StandardError; end - -# The main class -class MiniPush < MiniTerm - def initialize(serial_name, payload_path) - super(serial_name) - - @name_short = 'MP' # override - @payload_path = payload_path - @payload_size = nil - @payload_data = nil - end - - private - - # The three characters signaling the request token form the consecutive sequence "\x03\x03\x03". - def wait_for_payload_request - puts "[#{@name_short}] 🔌 Please power the target now" - - # Timeout for the request token starts after the first sign of life was received. - received = @target_serial.readpartial(4096) - Timeout.timeout(10) do - count = 0 - - loop do - raise ProtocolError if received.nil? - - received.chars.each do |c| - if c == "\u{3}" - count += 1 - return true if count == 3 - else - # A normal character resets token counting. - count = 0 - - print c - end - end - - received = @target_serial.readpartial(4096) - end - end - end - - def load_payload - @payload_size = File.size(@payload_path) - @payload_data = File.binread(@payload_path) - end - - def send_size - @target_serial.print([@payload_size].pack('L<')) - raise ProtocolError if @target_serial.read(2) != 'OK' - end - - def send_payload - pb = ProgressBar.create( - total: @payload_size, - format: "[#{@name_short}] ⏩ Pushing %k KiB %b🦀%i %p%% %r KiB/s %a", - rate_scale: ->(rate) { rate / 1024 }, - length: 92, - output: $stdout - ) - - # Send in 512 byte chunks. - while pb.progress < pb.total - part = @payload_data.slice(pb.progress, 512) - pb.progress += @target_serial.write(part) - end - end - - # override - def handle_reconnect(_error) - connection_reset - - puts - puts "[#{@name_short}] ⚡ " \ - "#{'Connection or protocol Error: '.light_red}" \ - "#{'Remove power and USB serial. Reinsert serial first, then power'.light_red}" - sleep(1) while serial_connected? - end - - public - - # override - def run - open_serial - wait_for_payload_request - load_payload - send_size - send_payload - terminal - rescue ConnectionError, EOFError, Errno::EIO, ProtocolError, Timeout::Error => e - handle_reconnect(e) - retry - rescue StandardError => e - handle_unexpected(e) - ensure - connection_reset - puts - puts "[#{@name_short}] Bye 👋" - end -end - -##-------------------------------------------------------------------------------------------------- -## Execution starts here -##-------------------------------------------------------------------------------------------------- -if __FILE__ == $PROGRAM_NAME - puts - puts 'Minipush 1.0'.cyan - puts - - # CTRL + C handler. Only here to suppress Ruby's default exception print. - trap('INT') do - # The `ensure` block from `MiniPush::run` will run after exit, restoring console state. - exit - end - - MiniPush.new(ARGV[0], ARGV[1]).run -end diff --git a/arceos/tools/raspi4/common/serial/minipush/progressbar_patch.rb b/arceos/tools/raspi4/common/serial/minipush/progressbar_patch.rb deleted file mode 100644 index 1862a234c..000000000 --- a/arceos/tools/raspi4/common/serial/minipush/progressbar_patch.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -# SPDX-License-Identifier: MIT OR Apache-2.0 -# -# Copyright (c) 2020-2022 Andre Richter - -# Monkey-patch ruby-progressbar so that it supports reporting the progress in KiB instead of Byte. - -class ProgressBar - # Add kibi version of progress - class Progress - def progress_kibi - @progress / 1024 - end - end - - module Format - # Add new formatting option - class Molecule - MOLECULES_EXTENDED = MOLECULES.dup - MOLECULES_EXTENDED[:k] = %i[progressable progress_kibi] - - def initialize(letter) - self.key = letter - self.method_name = MOLECULES_EXTENDED.fetch(key.to_sym) - end - end - end -end diff --git a/arceos/tools/raspi4/common/serial/miniterm.rb b/arceos/tools/raspi4/common/serial/miniterm.rb deleted file mode 100755 index 038ed978f..000000000 --- a/arceos/tools/raspi4/common/serial/miniterm.rb +++ /dev/null @@ -1,144 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -# SPDX-License-Identifier: MIT OR Apache-2.0 -# -# Copyright (c) 2020-2022 Andre Richter - -require 'rubygems' -require 'bundler/setup' - -require 'colorize' -require 'io/console' -require 'serialport' - -SERIAL_BAUD = 921_600 - -class ConnectionError < StandardError; end - -# The main class -class MiniTerm - def initialize(serial_name) - @name_short = 'MT' - @target_serial_name = serial_name - @target_serial = nil - @host_console = IO.console - end - - private - - def serial_connected? - File.exist?(@target_serial_name) - end - - def wait_for_serial - return if serial_connected? - - puts "[#{@name_short}] ⏳ Waiting for #{@target_serial_name}" - loop do - sleep(1) - break if serial_connected? - end - end - - def open_serial - wait_for_serial - - @target_serial = SerialPort.new(@target_serial_name, SERIAL_BAUD, 8, 1, SerialPort::NONE) - - # Ensure all output is immediately flushed to the device. - @target_serial.sync = true - rescue Errno::EACCES => e - puts "[#{@name_short}] 🚫 #{e.message} - Maybe try with 'sudo'" - exit - else - puts "[#{@name_short}] ✅ Serial connected" - end - - def terminal - @host_console.raw! - - Thread.abort_on_exception = true - Thread.report_on_exception = false - - # Receive from target and print on host console. - target_to_host = Thread.new do - loop do - char = @target_serial.getc - - raise ConnectionError if char.nil? - - # Translate incoming newline to newline + carriage return. - @host_console.putc("\r") if char == "\n" - @host_console.putc(char) - end - end - - # Transmit host console input to target. - loop do - c = @host_console.getc - - # CTRL + C in raw mode was pressed. - if c == "\u{3}" - target_to_host.kill - break - end - - @target_serial.putc(c) - end - end - - def connection_reset - @target_serial&.close - @target_serial = nil - @host_console.cooked! - end - - # When the serial lost power or was removed during R/W operation. - def handle_reconnect(_error) - connection_reset - - puts - puts "[#{@name_short}] ⚡ #{'Connection Error: Reinsert the USB serial again'.light_red}" - end - - def handle_unexpected(error) - connection_reset - - puts - puts "[#{@name_short}] ⚡ #{"Unexpected Error: #{error.inspect}".light_red}" - end - - public - - def run - open_serial - terminal - rescue ConnectionError, EOFError, Errno::EIO => e - handle_reconnect(e) - retry - rescue StandardError => e - handle_unexpected(e) - ensure - connection_reset - puts - puts "[#{@name_short}] Bye 👋" - end -end - -##-------------------------------------------------------------------------------------------------- -## Execution starts here -##-------------------------------------------------------------------------------------------------- -if __FILE__ == $PROGRAM_NAME - puts - puts 'Miniterm 1.0'.cyan - puts - - # CTRL + C handler. Only here to suppress Ruby's default exception print. - trap('INT') do - # The `ensure` block from `MiniTerm::run` will run after exit, restoring console state. - exit - end - - MiniTerm.new(ARGV[0]).run -end diff --git a/arceos/tour-README.md b/arceos/tour-README.md deleted file mode 100644 index 3dce1df08..000000000 --- a/arceos/tour-README.md +++ /dev/null @@ -1,111 +0,0 @@ -# Quick Start - -## 1. Install Build Dependencies - -Install [cargo-binutils](https://github.com/rust-embedded/cargo-binutils) to use `rust-objcopy` and `rust-objdump` tools: - -```bash -cargo install cargo-binutils -``` - -#### Dependencies for C apps, qemu tools - -Install `libclang-dev`, `qemu-system-riscv64`, `dosfstools`, `wget`: - -```bash -sudo apt install libclang-dev qemu-system-misc dosfstools wget -``` - -Download & install [musl](https://musl.cc) toolchains: - -```bash -# download -wget https://musl.cc/riscv64-linux-musl-cross.tgz -# install -tar zxf riscv64-linux-musl-cross.tgz -# exec below command in bash OR add below info in ~/.bashrc -export PATH=`pwd`/riscv64-linux-musl-cross/bin:$PATH -``` - -## 2. Build and Run -### goto arceos directory -``` -cd arceos -``` -### clean up images of pflash and disk -``` -rm pflash.img -rm disk.img -``` -### build pflash and disk images -``` -make pflash_img -make disk_img -``` - -### run tour/u_X_0 -``` -make run A=tour/u_1_0 -make run A=tour/u_2_0 -make run A=tour/u_3_0 -make run A=tour/u_4_0 -make run A=tour/u_5_0 -make run A=tour/u_6_0 -make run A=tour/u_6_1 -make run A=tour/u_7_0 BLK=y -make run A=tour/u_8_0 BLK=y -``` - -### run tour/m_X_0 -#### m_1_0 m_1_1 m_2_0 -``` -make payload -./update_disk.sh ./payload/origin/origin -make run A=tour/m_1_0 BLK=y -make run A=tour/m_1_1 BLK=y -make run A=tour/m_2_0 BLK=y -``` -#### m_3_0 -``` -make payload -./update_disk.sh payload/hello_c/hello -make run A=tour/m_3_0 BLK=y -``` -#### m_3_1 -``` -make payload -./update_disk.sh payload/fileops_c/fileops -make run A=tour/m_3_1 BLK=y -``` - -### run tour/h_X_0 -#### h_1_0 -``` -make payload -./update_disk.sh payload/skernel/skernel -make run A=tour/h_1_0/ BLK=y -``` - -#### h_2_0 -``` -make pflash_img -make disk_img (在 disk.img 不存在时执行) -make A=tour/u_3_0/ -./update_disk.sh tour/u_3_0/u_3_0_riscv64-qemu-virt.bin -make run A=tour/h_2_0/ BLK=y -``` - -#### h_3_0 -``` -make A=tour/u_6_0/ -./update_disk.sh tour/u_6_0/u_6_0_riscv64-qemu-virt.bin -make run A=tour/h_3_0 BLK=y LOG=info -``` - -#### h_4_0 -``` -make A=tour/m_1_1 -./update_disk.sh ./tour/m_1_1/m_1_1_riscv64-qemu-virt.bin -make run A=tour/h_4_0 BLK=y -``` - diff --git a/arceos/tour/h_1_0/Cargo.toml b/arceos/tour/h_1_0/Cargo.toml deleted file mode 100644 index 8d0d2924d..000000000 --- a/arceos/tour/h_1_0/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "h_1_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask", "sched_cfs", "fs"], optional = true } -axhal = { workspace = true } -axmm = { workspace = true } -axtask = { workspace = true } -axsync = { workspace = true } -axerrno = "0.1" -sbi-spec = { version = "0.0.6", features = ["legacy"] } -riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } -sbi-rt = { version = "0.0.2", features = ["integer-impls", "legacy"] } -tock-registers = "0.8.1" -memoffset = { version = ">=0.6.5", features = ["unstable_const"] } -axlog = { workspace = true } diff --git a/arceos/tour/h_1_0/src/csrs.rs b/arceos/tour/h_1_0/src/csrs.rs deleted file mode 100644 index 6053f7881..000000000 --- a/arceos/tour/h_1_0/src/csrs.rs +++ /dev/null @@ -1,312 +0,0 @@ -#![allow(dead_code)] - -use defs::*; -use tock_registers::interfaces::{Readable, Writeable}; -use tock_registers::RegisterLongName; - -/// Define each registers of hypervisor using. -pub struct CSR { - pub sie: ReadWriteCsr, - pub hstatus: ReadWriteCsr, - pub hedeleg: ReadWriteCsr, - pub hideleg: ReadWriteCsr, - pub hcounteren: ReadWriteCsr, - pub hvip: ReadWriteCsr, -} - -#[allow(clippy::identity_op, clippy::erasing_op)] -pub const CSR: &CSR = &CSR { - sie: ReadWriteCsr::new(), - hstatus: ReadWriteCsr::new(), - hedeleg: ReadWriteCsr::new(), - hideleg: ReadWriteCsr::new(), - hcounteren: ReadWriteCsr::new(), - hvip: ReadWriteCsr::new(), -}; - -/// Trait defining the possible operations on a RISC-V CSR. -pub trait RiscvCsrTrait { - type R: RegisterLongName; - /// Reads the value of the CSR. - fn get_value(&self) -> usize; - - /// Writes the value of the CSR. - fn write_value(&self, value: usize); - - /// Atomicllt swaps the value of CSRs. - fn atomic_replace(&self, value: usize) -> usize; - - /// Atomically read a CSR and set bits specified in a bitmask - fn read_and_set_bits(&self, bitmasks: usize) -> usize; - - /// Atomically read a CSR and set bits specified in a bitmask - fn read_and_clear_bits(&self, bitmasks: usize) -> usize; -} - -/// Read/Write register. -pub struct ReadWriteCsr { - associated_register: core::marker::PhantomData, -} - -impl ReadWriteCsr { - pub const fn new() -> Self { - Self { - associated_register: core::marker::PhantomData, - } - } -} - -impl RiscvCsrTrait for ReadWriteCsr { - type R = R; - - fn get_value(&self) -> usize { - let r: usize; - unsafe { - core::arch::asm!("csrr {rd}, {csr}", rd = out(reg) r, csr = const V); - } - r - } - - fn write_value(&self, value: usize) { - unsafe { - core::arch::asm!("csrw {csr}, {rs}", csr = const V, rs = in(reg) value); - } - } - - fn atomic_replace(&self, value: usize) -> usize { - let r: usize; - unsafe { - core::arch::asm!("csrrw {rd}, {csr}, {rs}", rd = out(reg) r, csr = const V, rs = in(reg) value); - } - r - } - - fn read_and_set_bits(&self, bitmask: usize) -> usize { - let r: usize; - unsafe { - core::arch::asm!("csrrs {rd}, {csr}, {rs}", rd = out(reg) r, csr = const V, rs = in(reg) bitmask); - } - r - } - - fn read_and_clear_bits(&self, bitmask: usize) -> usize { - let r: usize; - unsafe { - core::arch::asm!("csrrc {rd}, {csr}, {rs}", rd = out(reg) r, csr = const V, rs = in(reg) bitmask); - } - r - } -} - -// The Readable and Writeable traits aren't object-safe so unfortunately we can't implement them -// for RiscvCsrInterface. -impl Readable for ReadWriteCsr { - type T = usize; - type R = R; - - fn get(&self) -> usize { - self.get_value() - } -} - -impl Writeable for ReadWriteCsr { - type T = usize; - type R = R; - - fn set(&self, val_to_set: usize) { - self.write_value(val_to_set); - } -} - -pub mod defs { - use tock_registers::register_bitfields; - pub const CSR_SSTATUS: u16 = 0x100; - pub const CSR_SEDELEG: u16 = 0x102; - pub const CSR_SIDELEG: u16 = 0x103; - pub const CSR_SIE: u16 = 0x104; - pub const CSR_STVEC: u16 = 0x105; - pub const CSR_SCOUNTEREN: u16 = 0x106; - pub const CSR_SENVCFG: u16 = 0x10a; - pub const CSR_SSCRATCH: u16 = 0x140; - pub const CSR_SEPC: u16 = 0x141; - pub const CSR_SCAUSE: u16 = 0x142; - pub const CSR_STVAL: u16 = 0x143; - pub const CSR_SIP: u16 = 0x144; - pub const CSR_STIMECMP: u16 = 0x14d; - pub const CSR_SISELECT: u16 = 0x150; - pub const CSR_SIREG: u16 = 0x151; - pub const CSR_STOPEI: u16 = 0x15c; - pub const CSR_SATP: u16 = 0x180; - pub const CSR_STOPI: u16 = 0xdb0; - pub const CSR_SCONTEXT: u16 = 0x5a8; - pub const CSR_VSSTATUS: u16 = 0x200; - pub const CSR_VSIE: u16 = 0x204; - pub const CSR_VSTVEC: u16 = 0x205; - pub const CSR_VSSCRATCH: u16 = 0x240; - pub const CSR_VSEPC: u16 = 0x241; - pub const CSR_VSCAUSE: u16 = 0x242; - pub const CSR_VSTVAL: u16 = 0x243; - pub const CSR_VSIP: u16 = 0x244; - pub const CSR_VSTIMECMP: u16 = 0x24d; - pub const CSR_VSISELECT: u16 = 0x250; - pub const CSR_VSIREG: u16 = 0x251; - pub const CSR_VSTOPEI: u16 = 0x25c; - pub const CSR_VSATP: u16 = 0x280; - pub const CSR_VSTOPI: u16 = 0xeb0; - pub const CSR_HSTATUS: u16 = 0x600; - pub const CSR_HEDELEG: u16 = 0x602; - pub const CSR_HIDELEG: u16 = 0x603; - pub const CSR_HIE: u16 = 0x604; - pub const CSR_HTIMEDELTA: u16 = 0x605; - pub const CSR_HCOUNTEREN: u16 = 0x606; - pub const CSR_HGEIE: u16 = 0x607; - pub const CSR_HVICTL: u16 = 0x609; - pub const CSR_HENVCFG: u16 = 0x60a; - pub const CSR_HTVAL: u16 = 0x643; - pub const CSR_HIP: u16 = 0x644; - pub const CSR_HVIP: u16 = 0x645; - pub const CSR_HTINST: u16 = 0x64a; - pub const CSR_HGATP: u16 = 0x680; - pub const CSR_HCONTEXT: u16 = 0x6a8; - pub const CSR_HGEIP: u16 = 0xe12; - - // Hypervisor exception delegation register. - register_bitfields![usize, - pub hedeleg [ - instr_misaligned OFFSET(0) NUMBITS(1) [], - instr_fault OFFSET(1) NUMBITS(1) [], - illegal_instr OFFSET(2) NUMBITS(1) [], - breakpoint OFFSET(3) NUMBITS(1) [], - load_misaligned OFFSET(4) NUMBITS(1) [], - load_fault OFFSET(5) NUMBITS(1) [], - store_misaligned OFFSET(6) NUMBITS(1) [], - store_fault OFFSET(7) NUMBITS(1) [], - u_ecall OFFSET(8) NUMBITS(1) [], - instr_page_fault OFFSET(12) NUMBITS(1) [], - load_page_fault OFFSET(13) NUMBITS(1) [], - store_page_fault OFFSET(15) NUMBITS(1) [], - ] - ]; - - // Supervisor interrupt enable register. - register_bitfields![usize, - pub sie [ - ssoft OFFSET(1) NUMBITS(1) [], - stimer OFFSET(5) NUMBITS(1) [], - sext OFFSET(9) NUMBITS(1) [], - ] - ]; - - // Hypervisor status register. - register_bitfields![usize, - pub hstatus [ - // VS mode endianness control. - vsbe OFFSET(6) NUMBITS(1) [], - // A guest virtual address was written to stval as a result of the trap. - gva OFFSET(6) NUMBITS(1) [], - // Virtualization mode at time of trap. - spv OFFSET(7) NUMBITS(1) [ - Host = 0, - Guest = 1, - ], - // Privilege level the virtual hart was executing before entering HS-mode. - spvp OFFSET(8) NUMBITS(1) [ - User = 0, - Supervisor = 1, - ], - // Allow hypervisor instructions in U-mode. - hu OFFSET(9) NUMBITS(1) [], - // Selects the guest external interrupt source for VS external interrupts. - vgein OFFSET(12) NUMBITS(6) [], - // Trap on SFENCE, SINVAL, or changes to vsatp. - vtvm OFFSET(20) NUMBITS(1) [], - // Trap on WFI timeout. - vtw OFFSET(21) NUMBITS(1) [], - // Trap SRET instruction. - vtsr OFFSET(22) NUMBITS(1) [], - // Native base integer ISA width for VS-mode. - vsxl OFFSET(32) NUMBITS(2) [ - Xlen32 = 1, - Xlen64 = 2, - ], - ] - ]; - - // Hypervisor interrupt delegation register. - register_bitfields![usize, - pub hideleg [ - vssoft OFFSET(2) NUMBITS(1) [], - vstimer OFFSET(6) NUMBITS(1) [], - vsext OFFSET(10) NUMBITS(1) [], - ] - ]; - - // Hypervisor interrupt enable register. - register_bitfields![usize, - pub hie [ - vssoft OFFSET(2) NUMBITS(1) [], - vstimer OFFSET(6) NUMBITS(1) [], - vsext OFFSET(10) NUMBITS(1) [], - sgext OFFSET(12) NUMBITS(1) [], - ] - ]; - - // VS-mode counter availability control. - register_bitfields![usize, - pub hcounteren [ - cycle OFFSET(0) NUMBITS(1) [], - time OFFSET(1) NUMBITS(1) [], - instret OFFSET(2) NUMBITS(1) [], - hpm OFFSET(3) NUMBITS(29) [], - ] - ]; - - // Hypervisor virtual interrupt pending. - register_bitfields![usize, - pub hvip [ - vssoft OFFSET(2) NUMBITS(1) [], - vstimer OFFSET(6) NUMBITS(1) [], - vsext OFFSET(10) NUMBITS(1) [], - ] - ]; -} - -pub mod traps { - pub mod interrupt { - pub const USER_SOFT: usize = 1 << 0; - pub const SUPERVISOR_SOFT: usize = 1 << 1; - pub const VIRTUAL_SUPERVISOR_SOFT: usize = 1 << 2; - pub const MACHINE_SOFT: usize = 1 << 3; - pub const USER_TIMER: usize = 1 << 4; - pub const SUPERVISOR_TIMER: usize = 1 << 5; - pub const VIRTUAL_SUPERVISOR_TIMER: usize = 1 << 6; - pub const MACHINE_TIMER: usize = 1 << 7; - pub const USER_EXTERNAL: usize = 1 << 8; - pub const SUPERVISOR_EXTERNAL: usize = 1 << 9; - pub const VIRTUAL_SUPERVISOR_EXTERNAL: usize = 1 << 10; - pub const MACHINEL_EXTERNAL: usize = 1 << 11; - pub const SUPERVISOR_GUEST_EXTERNEL: usize = 1 << 12; - } - - pub mod exception { - pub const INST_ADDR_MISALIGN: usize = 1 << 0; - pub const INST_ACCESSS_FAULT: usize = 1 << 1; - pub const ILLEGAL_INST: usize = 1 << 2; - pub const BREAKPOINT: usize = 1 << 3; - pub const LOAD_ADDR_MISALIGNED: usize = 1 << 4; - pub const LOAD_ACCESS_FAULT: usize = 1 << 5; - pub const STORE_ADDR_MISALIGNED: usize = 1 << 6; - pub const STORE_ACCESS_FAULT: usize = 1 << 7; - pub const ENV_CALL_FROM_U_OR_VU: usize = 1 << 8; - pub const ENV_CALL_FROM_HS: usize = 1 << 9; - pub const ENV_CALL_FROM_VS: usize = 1 << 10; - pub const ENV_CALL_FROM_M: usize = 1 << 11; - pub const INST_PAGE_FAULT: usize = 1 << 12; - pub const LOAD_PAGE_FAULT: usize = 1 << 13; - pub const STORE_PAGE_FAULT: usize = 1 << 15; - pub const INST_GUEST_PAGE_FAULT: usize = 1 << 20; - pub const LOAD_GUEST_PAGE_FAULT: usize = 1 << 21; - pub const VIRTUAL_INST: usize = 1 << 22; - pub const STORE_GUEST_PAGE_FAULT: usize = 1 << 23; - } -} diff --git a/arceos/tour/h_1_0/src/guest.S b/arceos/tour/h_1_0/src/guest.S deleted file mode 100644 index 60ab203fa..000000000 --- a/arceos/tour/h_1_0/src/guest.S +++ /dev/null @@ -1,181 +0,0 @@ - -/// Enter the guest given in `VmCpuRegisters` from `a0` -.global _run_guest -_run_guest: - /* Save hypervisor state */ - - /* Save hypervisor GPRs (except T0-T6 and a0, which is GuestInfo and stashed in sscratch) */ - sd ra, ({hyp_ra})(a0) - sd gp, ({hyp_gp})(a0) - sd tp, ({hyp_tp})(a0) - sd s0, ({hyp_s0})(a0) - sd s1, ({hyp_s1})(a0) - sd a1, ({hyp_a1})(a0) - sd a2, ({hyp_a2})(a0) - sd a3, ({hyp_a3})(a0) - sd a4, ({hyp_a4})(a0) - sd a5, ({hyp_a5})(a0) - sd a6, ({hyp_a6})(a0) - sd a7, ({hyp_a7})(a0) - sd s2, ({hyp_s2})(a0) - sd s3, ({hyp_s3})(a0) - sd s4, ({hyp_s4})(a0) - sd s5, ({hyp_s5})(a0) - sd s6, ({hyp_s6})(a0) - sd s7, ({hyp_s7})(a0) - sd s8, ({hyp_s8})(a0) - sd s9, ({hyp_s9})(a0) - sd s10, ({hyp_s10})(a0) - sd s11, ({hyp_s11})(a0) - sd sp, ({hyp_sp})(a0) - - /* Swap in guest CSRs. */ - ld t1, ({guest_sstatus})(a0) - csrrw t1, sstatus, t1 - sd t1, ({hyp_sstatus})(a0) - - ld t1, ({guest_hstatus})(a0) - csrrw t1, hstatus, t1 - - ld t1, ({guest_scounteren})(a0) - csrrw t1, scounteren, t1 - sd t1, ({hyp_scounteren})(a0) - - ld t1, ({guest_sepc})(a0) - csrw sepc, t1 - - /* Set stvec so that hypervisor resumes after the sret when the guest exits. */ - la t1, _guest_exit - csrrw t1, stvec, t1 - sd t1, ({hyp_stvec})(a0) - - /* Save sscratch and replace with pointer to GuestInfo. */ - csrrw t1, sscratch, a0 - sd t1, ({hyp_sscratch})(a0) - - /* Restore the gprs from this GuestInfo */ - ld ra, ({guest_ra})(a0) - ld gp, ({guest_gp})(a0) - ld tp, ({guest_tp})(a0) - ld s0, ({guest_s0})(a0) - ld s1, ({guest_s1})(a0) - ld a1, ({guest_a1})(a0) - ld a2, ({guest_a2})(a0) - ld a3, ({guest_a3})(a0) - ld a4, ({guest_a4})(a0) - ld a5, ({guest_a5})(a0) - ld a6, ({guest_a6})(a0) - ld a7, ({guest_a7})(a0) - ld s2, ({guest_s2})(a0) - ld s3, ({guest_s3})(a0) - ld s4, ({guest_s4})(a0) - ld s5, ({guest_s5})(a0) - ld s6, ({guest_s6})(a0) - ld s7, ({guest_s7})(a0) - ld s8, ({guest_s8})(a0) - ld s9, ({guest_s9})(a0) - ld s10, ({guest_s10})(a0) - ld s11, ({guest_s11})(a0) - ld t0, ({guest_t0})(a0) - ld t1, ({guest_t1})(a0) - ld t2, ({guest_t2})(a0) - ld t3, ({guest_t3})(a0) - ld t4, ({guest_t4})(a0) - ld t5, ({guest_t5})(a0) - ld t6, ({guest_t6})(a0) - ld sp, ({guest_sp})(a0) - ld a0, ({guest_a0})(a0) - - sret - -.align 2 -_guest_exit: - /* Pull GuestInfo out of sscratch, swapping with guest's a0 */ - csrrw a0, sscratch, a0 - - /* Save guest GPRs. */ - sd ra, ({guest_ra})(a0) - sd gp, ({guest_gp})(a0) - sd tp, ({guest_tp})(a0) - sd s0, ({guest_s0})(a0) - sd s1, ({guest_s1})(a0) - sd a1, ({guest_a1})(a0) - sd a2, ({guest_a2})(a0) - sd a3, ({guest_a3})(a0) - sd a4, ({guest_a4})(a0) - sd a5, ({guest_a5})(a0) - sd a6, ({guest_a6})(a0) - sd a7, ({guest_a7})(a0) - sd s2, ({guest_s2})(a0) - sd s3, ({guest_s3})(a0) - sd s4, ({guest_s4})(a0) - sd s5, ({guest_s5})(a0) - sd s6, ({guest_s6})(a0) - sd s7, ({guest_s7})(a0) - sd s8, ({guest_s8})(a0) - sd s9, ({guest_s9})(a0) - sd s10, ({guest_s10})(a0) - sd s11, ({guest_s11})(a0) - sd t0, ({guest_t0})(a0) - sd t1, ({guest_t1})(a0) - sd t2, ({guest_t2})(a0) - sd t3, ({guest_t3})(a0) - sd t4, ({guest_t4})(a0) - sd t5, ({guest_t5})(a0) - sd t6, ({guest_t6})(a0) - sd sp, ({guest_sp})(a0) - - /* Save Guest a0 after recovering from sscratch. */ - csrr t0, sscratch - sd t0, ({guest_a0})(a0) - -_restore_csrs: - /* Swap in hypervisor CSRs. */ - ld t1, ({hyp_sstatus})(a0) - csrrw t1, sstatus, t1 - sd t1, ({guest_sstatus})(a0) - - csrr t1, hstatus - sd t1, ({guest_hstatus})(a0) - - ld t1, ({hyp_scounteren})(a0) - csrrw t1, scounteren, t1 - sd t1, ({guest_scounteren})(a0) - - ld t1, ({hyp_stvec})(a0) - csrw stvec, t1 - - ld t1, ({hyp_sscratch})(a0) - csrw sscratch, t1 - - /* Save guest EPC. */ - csrr t1, sepc - sd t1, ({guest_sepc})(a0) - - - /* Restore hypervisor GPRs. */ - ld ra, ({hyp_ra})(a0) - ld gp, ({hyp_gp})(a0) - ld tp, ({hyp_tp})(a0) - ld s0, ({hyp_s0})(a0) - ld s1, ({hyp_s1})(a0) - ld a1, ({hyp_a1})(a0) - ld a2, ({hyp_a2})(a0) - ld a3, ({hyp_a3})(a0) - ld a4, ({hyp_a4})(a0) - ld a5, ({hyp_a5})(a0) - ld a6, ({hyp_a6})(a0) - ld a7, ({hyp_a7})(a0) - ld s2, ({hyp_s2})(a0) - ld s3, ({hyp_s3})(a0) - ld s4, ({hyp_s4})(a0) - ld s5, ({hyp_s5})(a0) - ld s6, ({hyp_s6})(a0) - ld s7, ({hyp_s7})(a0) - ld s8, ({hyp_s8})(a0) - ld s9, ({hyp_s9})(a0) - ld s10, ({hyp_s10})(a0) - ld s11, ({hyp_s11})(a0) - ld sp, ({hyp_sp})(a0) - - ret diff --git a/arceos/tour/h_1_0/src/loader.rs b/arceos/tour/h_1_0/src/loader.rs deleted file mode 100644 index 0721fbfaa..000000000 --- a/arceos/tour/h_1_0/src/loader.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::io::{self, Read}; -use std::fs::File; -use axhal::paging::MappingFlags; -use axhal::mem::{PAGE_SIZE_4K, phys_to_virt}; -use axmm::AddrSpace; -use crate::VM_ENTRY; - -pub fn load_vm_image(fname: &str, uspace: &mut AddrSpace) -> io::Result<()> { - let mut buf = [0u8; 64]; - load_file(fname, &mut buf)?; - - uspace.map_alloc(VM_ENTRY.into(), PAGE_SIZE_4K, MappingFlags::READ|MappingFlags::WRITE|MappingFlags::EXECUTE|MappingFlags::USER, true).unwrap(); - - let (paddr, _, _) = uspace - .page_table() - .query(VM_ENTRY.into()) - .unwrap_or_else(|_| panic!("Mapping failed for segment: {:#x}", VM_ENTRY)); - - ax_println!("paddr: {:#x}", paddr); - - unsafe { - core::ptr::copy_nonoverlapping( - buf.as_ptr(), - phys_to_virt(paddr).as_mut_ptr(), - PAGE_SIZE_4K, - ); - } - - Ok(()) -} - -fn load_file(fname: &str, buf: &mut [u8]) -> io::Result { - ax_println!("app: {}", fname); - let mut file = File::open(fname)?; - let n = file.read(buf)?; - Ok(n) -} diff --git a/arceos/tour/h_1_0/src/main.rs b/arceos/tour/h_1_0/src/main.rs deleted file mode 100644 index 031990a01..000000000 --- a/arceos/tour/h_1_0/src/main.rs +++ /dev/null @@ -1,124 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] -#![feature(asm_const)] -#![feature(riscv_ext_intrinsics)] - -#[cfg(feature = "axstd")] -extern crate axstd as std; -extern crate alloc; -#[macro_use] -extern crate axlog; - -mod task; -mod vcpu; -mod regs; -mod csrs; -mod sbi; -mod loader; - -use vcpu::VmCpuRegisters; -use riscv::register::{scause, sstatus}; -use csrs::defs::hstatus; -use tock_registers::LocalRegisterCopy; -use csrs::{RiscvCsrTrait, CSR}; -use vcpu::_run_guest; -use sbi::SbiMessage; -use loader::load_vm_image; -use axhal::mem::PhysAddr; - -const VM_ENTRY: usize = 0x8020_0000; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - ax_println!("Hypervisor ..."); - - // A new address space for vm. - let mut uspace = axmm::new_user_aspace().unwrap(); - - // Load vm binary file into address space. - if let Err(e) = load_vm_image("/sbin/skernel", &mut uspace) { - panic!("Cannot load app! {:?}", e); - } - - // Setup context to prepare to enter guest mode. - let mut ctx = VmCpuRegisters::default(); - prepare_guest_context(&mut ctx); - - // Setup pagetable for 2nd address mapping. - let ept_root = uspace.page_table_root(); - prepare_vm_pgtable(ept_root); - - // Kick off vm and wait for it to exit. - run_guest(&mut ctx); - - panic!("Hypervisor ok!"); -} - -fn prepare_vm_pgtable(ept_root: PhysAddr) { - let hgatp = 8usize << 60 | usize::from(ept_root) >> 12; - unsafe { - core::arch::asm!( - "csrw hgatp, {hgatp}", - hgatp = in(reg) hgatp, - ); - core::arch::riscv64::hfence_gvma_all(); - } -} - -fn run_guest(ctx: &mut VmCpuRegisters) { - unsafe { - _run_guest(ctx); - } - - vmexit_handler(ctx) -} - -fn vmexit_handler(ctx: &VmCpuRegisters) { - use scause::{Exception, Trap}; - - let scause = scause::read(); - match scause.cause() { - Trap::Exception(Exception::VirtualSupervisorEnvCall) => { - let sbi_msg = SbiMessage::from_regs(ctx.guest_regs.gprs.a_regs()).ok(); - ax_println!("VmExit Reason: VSuperEcall: {:?}", sbi_msg); - if let Some(msg) = sbi_msg { - match msg { - SbiMessage::Reset(_) => { - ax_println!("Shutdown vm normally!"); - }, - _ => todo!(), - } - } else { - panic!("bad sbi message! "); - } - }, - _ => { - panic!( - "Unhandled trap: {:?}, sepc: {:#x}, stval: {:#x}", - scause.cause(), - ctx.guest_regs.sepc, - ctx.trap_csrs.stval - ); - } - } -} - -fn prepare_guest_context(ctx: &mut VmCpuRegisters) { - // Set hstatus - let mut hstatus = LocalRegisterCopy::::new( - riscv::register::hstatus::read().bits(), - ); - // Set Guest bit in order to return to guest mode. - hstatus.modify(hstatus::spv::Guest); - // Set SPVP bit in order to accessing VS-mode memory from HS-mode. - hstatus.modify(hstatus::spvp::Supervisor); - CSR.hstatus.write_value(hstatus.get()); - ctx.guest_regs.hstatus = hstatus.get(); - - // Set sstatus in guest mode. - let mut sstatus = sstatus::read(); - sstatus.set_spp(sstatus::SPP::Supervisor); - ctx.guest_regs.sstatus = sstatus.bits(); - // Return to entry to start vm. - ctx.guest_regs.sepc = VM_ENTRY; -} diff --git a/arceos/tour/h_1_0/src/regs.rs b/arceos/tour/h_1_0/src/regs.rs deleted file mode 100644 index 5d7aadccc..000000000 --- a/arceos/tour/h_1_0/src/regs.rs +++ /dev/null @@ -1,114 +0,0 @@ -#[derive(Default)] -#[repr(C)] -pub struct GeneralPurposeRegisters([usize; 32]); - -/// Index of risc-v general purpose registers in `GeneralPurposeRegisters`. -#[allow(missing_docs)] -#[repr(u32)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum GprIndex { - Zero = 0, - RA, - SP, - GP, - TP, - T0, - T1, - T2, - S0, - S1, - A0, - A1, - A2, - A3, - A4, - A5, - A6, - A7, - S2, - S3, - S4, - S5, - S6, - S7, - S8, - S9, - S10, - S11, - T3, - T4, - T5, - T6, -} - -impl GprIndex { - /// Get register index from raw value. - pub fn from_raw(raw: u32) -> Option { - use GprIndex::*; - let index = match raw { - 0 => Zero, - 1 => RA, - 2 => SP, - 3 => GP, - 4 => TP, - 5 => T0, - 6 => T1, - 7 => T2, - 8 => S0, - 9 => S1, - 10 => A0, - 11 => A1, - 12 => A2, - 13 => A3, - 14 => A4, - 15 => A5, - 16 => A6, - 17 => A7, - 18 => S2, - 19 => S3, - 20 => S4, - 21 => S5, - 22 => S6, - 23 => S7, - 24 => S8, - 25 => S9, - 26 => S10, - 27 => S11, - 28 => T3, - 29 => T4, - 30 => T5, - 31 => T6, - _ => { - return None; - } - }; - Some(index) - } -} - -impl GeneralPurposeRegisters { - /// Returns the value of the given register. - pub fn reg(&self, reg_index: GprIndex) -> usize { - self.0[reg_index as usize] - } - - /// Sets the value of the given register. - pub fn set_reg(&mut self, reg_index: GprIndex, val: usize) { - if reg_index == GprIndex::Zero { - return; - } - - self.0[reg_index as usize] = val; - } - - /// Returns the argument registers. - /// This is avoids many calls when an SBI handler needs all of the argmuent regs. - pub fn a_regs(&self) -> &[usize] { - &self.0[GprIndex::A0 as usize..=GprIndex::A7 as usize] - } - - /// Returns the arguments register as a mutable. - pub fn a_regs_mut(&mut self) -> &mut [usize] { - &mut self.0[GprIndex::A0 as usize..=GprIndex::A7 as usize] - } -} diff --git a/arceos/tour/h_1_0/src/sbi/base.rs b/arceos/tour/h_1_0/src/sbi/base.rs deleted file mode 100644 index 4fe4ba931..000000000 --- a/arceos/tour/h_1_0/src/sbi/base.rs +++ /dev/null @@ -1,35 +0,0 @@ -use axerrno::{AxError, AxResult}; - -/// Functions defined for the Base extension -#[derive(Clone, Copy, Debug)] -pub enum BaseFunction { - /// Returns the implemented version of the SBI standard. - GetSepcificationVersion, - /// Returns the ID of the SBI implementation. - GetImplementationID, - /// Returns the version of the SBI implementation. - GetImplementationVersion, - /// Checks if the given SBI extension is supported. - ProbeSbiExtension(u64), - /// Returns the vendor that produced this machine(`mvendorid`). - GetMachineVendorID, - /// Returns the architecture implementation ID of this machine(`marchid`). - GetMachineArchitectureID, - /// Returns the ID of this machine(`mimpid`). - GetMachineImplementationID, -} - -impl BaseFunction { - pub(crate) fn from_regs(args: &[usize]) -> AxResult { - match args[6] { - 0 => Ok(BaseFunction::GetSepcificationVersion), - 1 => Ok(BaseFunction::GetImplementationID), - 2 => Ok(BaseFunction::GetImplementationVersion), - 3 => Ok(BaseFunction::ProbeSbiExtension(args[0] as u64)), - 4 => Ok(BaseFunction::GetMachineVendorID), - 5 => Ok(BaseFunction::GetMachineArchitectureID), - 6 => Ok(BaseFunction::GetMachineImplementationID), - _ => Err(AxError::NotFound), - } - } -} diff --git a/arceos/tour/h_1_0/src/sbi/dbcn.rs b/arceos/tour/h_1_0/src/sbi/dbcn.rs deleted file mode 100644 index cde124639..000000000 --- a/arceos/tour/h_1_0/src/sbi/dbcn.rs +++ /dev/null @@ -1,11 +0,0 @@ -/// Functions for the Debug Console extension -#[derive(Copy, Clone, Debug)] -pub enum DebugConsoleFunction { - /// Prints the given string to the system console. - PutString { - /// The length of the string to print. - len: u64, - /// The address of the string. - addr: u64, - }, -} diff --git a/arceos/tour/h_1_0/src/sbi/mod.rs b/arceos/tour/h_1_0/src/sbi/mod.rs deleted file mode 100644 index 0e377e045..000000000 --- a/arceos/tour/h_1_0/src/sbi/mod.rs +++ /dev/null @@ -1,90 +0,0 @@ -#![allow(dead_code)] - -mod base; -mod dbcn; -mod pmu; -mod rfnc; -mod srst; - -use axerrno::{AxError, AxResult}; -pub use base::BaseFunction; -use dbcn::DebugConsoleFunction; -pub use pmu::PmuFunction; -pub use rfnc::RemoteFenceFunction; -use sbi_spec; -pub use srst::ResetFunction; - -pub const SBI_SUCCESS: usize = 0; -pub const SBI_ERR_FAILUER: isize = -1; -pub const SBI_ERR_NOT_SUPPORTED: isize = -2; -pub const SBI_ERR_INAVLID_PARAM: isize = -3; -pub const SBI_ERR_DENIED: isize = -4; -pub const SBI_ERR_INVALID_ADDRESS: isize = -5; -pub const SBI_ERR_ALREADY_AVAILABLE: isize = -6; - -/// The values returned from an SBI function call. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct SbiReturn { - /// The error code(0 for success) - pub error_code: i64, - /// The return value if the operation is successful - pub return_value: i64, -} - -/// SBI return value conventions -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum SbiReturnTyoe { - /// Legacy(v0.1) extensions return a single value in A0, usually with the convention that 0 - /// is success and < 0 is an implementation defined error code. - Legacy(u64), - /// Modern extensions use the standard error code values enumerated above. - Standard(SbiReturn), -} - -/// SBI Message used to invoke the specfified SBI extension in the firmware. -#[derive(Clone, Copy, Debug)] -pub enum SbiMessage { - /// The base SBI extension functions. - Base(BaseFunction), - /// The legacy GetChar extension. - GetChar, - /// The legacy PutChar extension. - PutChar(usize), - /// The SetTimer Extension - SetTimer(usize), - /// Handles output to the console for debug - DebugConsole(DebugConsoleFunction), - /// Handles system reset - Reset(ResetFunction), - /// The RemoteFence Extension. - RemoteFence(RemoteFenceFunction), - /// The PMU Extension - PMU(PmuFunction), -} - -impl SbiMessage { - /// Creates an SbiMessage struct from the given GPRs. Intended for use from the ECALL handler - /// and passed the saved register state from the calling OS. A7 must contain a valid SBI - /// extension and the other A* registers will be interpreted based on the extension A7 selects. - pub fn from_regs(args: &[usize]) -> AxResult { - match args[7] { - sbi_spec::base::EID_BASE => BaseFunction::from_regs(args).map(SbiMessage::Base), - sbi_spec::legacy::LEGACY_CONSOLE_PUTCHAR => Ok(SbiMessage::PutChar(args[0])), - sbi_spec::legacy::LEGACY_CONSOLE_GETCHAR => Ok(SbiMessage::GetChar), - sbi_spec::legacy::LEGACY_SET_TIMER => Ok(SbiMessage::SetTimer(args[0])), - sbi_spec::legacy::LEGACY_SHUTDOWN => Ok(SbiMessage::Reset(ResetFunction::shutdown())), - sbi_spec::time::EID_TIME => Ok(SbiMessage::SetTimer(args[0])), - sbi_spec::srst::EID_SRST => ResetFunction::from_regs(args).map(SbiMessage::Reset), - sbi_spec::rfnc::EID_RFNC => { - RemoteFenceFunction::from_args(args).map(SbiMessage::RemoteFence) - } - sbi_spec::pmu::EID_PMU => PmuFunction::from_regs(args).map(SbiMessage::PMU), - _ => { - error!("args: {:?}", args); - error!("args[7]: {:#x}", args[7]); - error!("EID_RFENCE: {:#x}", sbi_spec::rfnc::EID_RFNC); - Err(AxError::NotFound) - } - } - } -} diff --git a/arceos/tour/h_1_0/src/sbi/pmu.rs b/arceos/tour/h_1_0/src/sbi/pmu.rs deleted file mode 100644 index 990d2780e..000000000 --- a/arceos/tour/h_1_0/src/sbi/pmu.rs +++ /dev/null @@ -1,34 +0,0 @@ -use axerrno::AxResult; - -#[derive(Clone, Copy, Debug)] -pub enum PmuFunction { - /// Returns the total of performance counters (hardware and fireware). - GetNumCounters, - /// Returns information about hardware counter specified by the inner value. - GetCounterInfo(u64), - /// Stops the couters selected by counter_index and counter_mask. - /// See the sbi_pmu_counter_stop documentation for details. - StopCounter { - /// Countert index base. - counter_index: u64, - /// Counter index mask. - counter_mask: u64, - /// Counter stop flags. - stop_flags: u64, - }, -} - -impl PmuFunction { - pub(crate) fn from_regs(args: &[usize]) -> AxResult { - match args[6] { - 0 => Ok(Self::GetNumCounters), - 1 => Ok(Self::GetCounterInfo(args[0] as u64)), - 4 => Ok(Self::StopCounter { - counter_index: args[0] as u64, - counter_mask: args[1] as u64, - stop_flags: args[2] as u64, - }), - _ => panic!("Unsupported yet!"), - } - } -} diff --git a/arceos/tour/h_1_0/src/sbi/rfnc.rs b/arceos/tour/h_1_0/src/sbi/rfnc.rs deleted file mode 100644 index 249803462..000000000 --- a/arceos/tour/h_1_0/src/sbi/rfnc.rs +++ /dev/null @@ -1,35 +0,0 @@ -use sbi_spec::rfnc::{REMOTE_FENCE_I, REMOTE_SFENCE_VMA}; - -use axerrno::AxResult; - -#[derive(Clone, Copy, Debug)] -pub enum RemoteFenceFunction { - FenceI { - hart_mask: u64, - hart_mask_base: u64, - }, - RemoteSFenceVMA { - hart_mask: u64, - hart_mask_base: u64, - start_addr: u64, - size: u64, - }, -} - -impl RemoteFenceFunction { - pub fn from_args(args: &[usize]) -> AxResult { - match args[6] { - REMOTE_FENCE_I => Ok(Self::FenceI { - hart_mask: args[0] as u64, - hart_mask_base: args[1] as u64, - }), - REMOTE_SFENCE_VMA => Ok(Self::RemoteSFenceVMA { - hart_mask: args[0] as u64, - hart_mask_base: args[1] as u64, - start_addr: args[2] as u64, - size: args[3] as u64, - }), - _ => panic!("Unsupported yet!"), - } - } -} diff --git a/arceos/tour/h_1_0/src/sbi/srst.rs b/arceos/tour/h_1_0/src/sbi/srst.rs deleted file mode 100644 index d6512ae93..000000000 --- a/arceos/tour/h_1_0/src/sbi/srst.rs +++ /dev/null @@ -1,84 +0,0 @@ -use axerrno::{AxError, AxResult}; - -/// Functions for the Reset extension -#[derive(Copy, Clone, Debug)] -pub enum ResetFunction { - /// Performs a system reset. - Reset { - /// Determines the type of reset to perform. - reset_type: ResetType, - /// Represents the reason for system reset. - reason: ResetReason, - }, -} - -/// The types of reset a supervisor can request. -#[repr(usize)] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum ResetType { - /// Powers down the system. - Shutdown = 0, - /// Powers down, then reboots. - ColdReset = 1, - /// Reboots, doesn't power down. - WarmReset = 2, -} - -impl ResetType { - // Creates a reset type from the a0 register value or returns an error if no mapping is - // known for the given value. - fn from_reg(a0: usize) -> AxResult { - use ResetType::*; - Ok(match a0 { - 0 => Shutdown, - 1 => ColdReset, - 2 => WarmReset, - _ => return Err(AxError::InvalidInput), - }) - } -} - -/// Reasons why a supervisor requests a reset. -#[repr(u64)] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum ResetReason { - /// Used for normal resets. - NoReason = 0, - /// Used when the system has failed. - SystemFailure = 1, -} - -impl ResetReason { - // Creates a reset reason from the a1 register value or returns an error if no mapping is - // known for the given value. - fn from_reg(a1: usize) -> AxResult { - use ResetReason::*; - Ok(match a1 { - 0 => NoReason, - 1 => SystemFailure, - _ => return Err(AxError::InvalidInput), - }) - } -} -impl ResetFunction { - /// Attempts to parse `Self` from the passed in `a0-a7`. - pub(crate) fn from_regs(args: &[usize]) -> AxResult { - use ResetFunction::*; - - Ok(match args[6] { - 0 => Reset { - reset_type: ResetType::from_reg(args[0])?, - reason: ResetReason::from_reg(args[1])?, - }, - _ => return Err(AxError::InvalidInput), - }) - } - - /// Creates an operation to shutdown the machine. - pub fn shutdown() -> Self { - ResetFunction::Reset { - reset_type: ResetType::Shutdown, - reason: ResetReason::NoReason, - } - } -} diff --git a/arceos/tour/h_1_0/src/task.rs b/arceos/tour/h_1_0/src/task.rs deleted file mode 100644 index 8374f4fea..000000000 --- a/arceos/tour/h_1_0/src/task.rs +++ /dev/null @@ -1,24 +0,0 @@ -use alloc::sync::Arc; - -use axmm::AddrSpace; -use axsync::Mutex; -use crate::vcpu::VmCpuRegisters; - -/// Task extended data for the monolithic kernel. -pub struct TaskExt { - /// The vcpu. - pub vcpu: VmCpuRegisters, - /// The virtual memory address space. - pub aspace: Arc>, -} - -impl TaskExt { - pub const fn new(vcpu: VmCpuRegisters, aspace: Arc>) -> Self { - Self { - vcpu, - aspace, - } - } -} - -axtask::def_task_ext!(TaskExt); diff --git a/arceos/tour/h_1_0/src/vcpu.rs b/arceos/tour/h_1_0/src/vcpu.rs deleted file mode 100644 index 6cdbe5cc1..000000000 --- a/arceos/tour/h_1_0/src/vcpu.rs +++ /dev/null @@ -1,186 +0,0 @@ -use core::arch::global_asm; -use core::mem::size_of; - -use memoffset::offset_of; -use super::regs::{GeneralPurposeRegisters, GprIndex}; - -/// Hypervisor GPR and CSR state which must be saved/restored when entering/exiting virtualization. -#[derive(Default)] -#[repr(C)] -struct HypervisorCpuState { - gprs: GeneralPurposeRegisters, - sstatus: usize, - scounteren: usize, - stvec: usize, - sscratch: usize, -} - -/// Guest GPR and CSR state which must be saved/restored when exiting/entering virtualization. -#[derive(Default)] -#[repr(C)] -pub struct GuestCpuState { - pub gprs: GeneralPurposeRegisters, - pub sstatus: usize, - pub hstatus: usize, - pub scounteren: usize, - pub sepc: usize, -} - -/// The CSRs that are only in effect when virtualization is enabled (V=1) and must be saved and -/// restored whenever we switch between VMs. -#[derive(Default)] -#[repr(C)] -pub struct GuestVsCsrs { - htimedelta: usize, - vsstatus: usize, - vsie: usize, - vstvec: usize, - vsscratch: usize, - vsepc: usize, - vscause: usize, - vstval: usize, - vsatp: usize, - vstimecmp: usize, -} - -/// Virtualized HS-level CSRs that are used to emulate (part of) the hypervisor extension for the -/// guest. -#[derive(Default)] -#[repr(C)] -pub struct GuestVirtualHsCsrs { - hie: usize, - hgeie: usize, - hgatp: usize, -} - -/// CSRs written on an exit from virtualization that are used by the hypervisor to determine the cause -/// of the trap. -#[derive(Default, Clone)] -#[repr(C)] -pub struct VmCpuTrapState { - pub scause: usize, - pub stval: usize, - pub htval: usize, - pub htinst: usize, -} - -/// (v)CPU register state that must be saved or restored when entering/exiting a VM or switching -/// between VMs. -#[derive(Default)] -#[repr(C)] -pub struct VmCpuRegisters { - // CPU state that's shared between our's and the guest's execution environment. Saved/restored - // when entering/exiting a VM. - hyp_regs: HypervisorCpuState, - pub guest_regs: GuestCpuState, - - // CPU state that only applies when V=1, e.g. the VS-level CSRs. Saved/restored on activation of - // the vCPU. - vs_csrs: GuestVsCsrs, - - // Virtualized HS-level CPU state. - virtual_hs_csrs: GuestVirtualHsCsrs, - - // Read on VM exit. - pub trap_csrs: VmCpuTrapState, -} - -#[allow(dead_code)] -const fn hyp_gpr_offset(index: GprIndex) -> usize { - offset_of!(VmCpuRegisters, hyp_regs) - + offset_of!(HypervisorCpuState, gprs) - + (index as usize) * size_of::() -} - -#[allow(dead_code)] -const fn guest_gpr_offset(index: GprIndex) -> usize { - offset_of!(VmCpuRegisters, guest_regs) - + offset_of!(GuestCpuState, gprs) - + (index as usize) * size_of::() -} - -#[allow(unused_macros)] -macro_rules! hyp_csr_offset { - ($reg:tt) => { - offset_of!(VmCpuRegisters, hyp_regs) + offset_of!(HypervisorCpuState, $reg) - }; -} - -#[allow(unused_macros)] -macro_rules! guest_csr_offset { - ($reg:tt) => { - offset_of!(VmCpuRegisters, guest_regs) + offset_of!(GuestCpuState, $reg) - }; -} - -global_asm!( - include_str!("guest.S"), - hyp_ra = const hyp_gpr_offset(GprIndex::RA), - hyp_gp = const hyp_gpr_offset(GprIndex::GP), - hyp_tp = const hyp_gpr_offset(GprIndex::TP), - hyp_s0 = const hyp_gpr_offset(GprIndex::S0), - hyp_s1 = const hyp_gpr_offset(GprIndex::S1), - hyp_a1 = const hyp_gpr_offset(GprIndex::A1), - hyp_a2 = const hyp_gpr_offset(GprIndex::A2), - hyp_a3 = const hyp_gpr_offset(GprIndex::A3), - hyp_a4 = const hyp_gpr_offset(GprIndex::A4), - hyp_a5 = const hyp_gpr_offset(GprIndex::A5), - hyp_a6 = const hyp_gpr_offset(GprIndex::A6), - hyp_a7 = const hyp_gpr_offset(GprIndex::A7), - hyp_s2 = const hyp_gpr_offset(GprIndex::S2), - hyp_s3 = const hyp_gpr_offset(GprIndex::S3), - hyp_s4 = const hyp_gpr_offset(GprIndex::S4), - hyp_s5 = const hyp_gpr_offset(GprIndex::S5), - hyp_s6 = const hyp_gpr_offset(GprIndex::S6), - hyp_s7 = const hyp_gpr_offset(GprIndex::S7), - hyp_s8 = const hyp_gpr_offset(GprIndex::S8), - hyp_s9 = const hyp_gpr_offset(GprIndex::S9), - hyp_s10 = const hyp_gpr_offset(GprIndex::S10), - hyp_s11 = const hyp_gpr_offset(GprIndex::S11), - hyp_sp = const hyp_gpr_offset(GprIndex::SP), - hyp_sstatus = const hyp_csr_offset!(sstatus), - hyp_scounteren = const hyp_csr_offset!(scounteren), - hyp_stvec = const hyp_csr_offset!(stvec), - hyp_sscratch = const hyp_csr_offset!(sscratch), - guest_ra = const guest_gpr_offset(GprIndex::RA), - guest_gp = const guest_gpr_offset(GprIndex::GP), - guest_tp = const guest_gpr_offset(GprIndex::TP), - guest_s0 = const guest_gpr_offset(GprIndex::S0), - guest_s1 = const guest_gpr_offset(GprIndex::S1), - guest_a0 = const guest_gpr_offset(GprIndex::A0), - guest_a1 = const guest_gpr_offset(GprIndex::A1), - guest_a2 = const guest_gpr_offset(GprIndex::A2), - guest_a3 = const guest_gpr_offset(GprIndex::A3), - guest_a4 = const guest_gpr_offset(GprIndex::A4), - guest_a5 = const guest_gpr_offset(GprIndex::A5), - guest_a6 = const guest_gpr_offset(GprIndex::A6), - guest_a7 = const guest_gpr_offset(GprIndex::A7), - guest_s2 = const guest_gpr_offset(GprIndex::S2), - guest_s3 = const guest_gpr_offset(GprIndex::S3), - guest_s4 = const guest_gpr_offset(GprIndex::S4), - guest_s5 = const guest_gpr_offset(GprIndex::S5), - guest_s6 = const guest_gpr_offset(GprIndex::S6), - guest_s7 = const guest_gpr_offset(GprIndex::S7), - guest_s8 = const guest_gpr_offset(GprIndex::S8), - guest_s9 = const guest_gpr_offset(GprIndex::S9), - guest_s10 = const guest_gpr_offset(GprIndex::S10), - guest_s11 = const guest_gpr_offset(GprIndex::S11), - guest_t0 = const guest_gpr_offset(GprIndex::T0), - guest_t1 = const guest_gpr_offset(GprIndex::T1), - guest_t2 = const guest_gpr_offset(GprIndex::T2), - guest_t3 = const guest_gpr_offset(GprIndex::T3), - guest_t4 = const guest_gpr_offset(GprIndex::T4), - guest_t5 = const guest_gpr_offset(GprIndex::T5), - guest_t6 = const guest_gpr_offset(GprIndex::T6), - guest_sp = const guest_gpr_offset(GprIndex::SP), - - guest_sstatus = const guest_csr_offset!(sstatus), - guest_hstatus = const guest_csr_offset!(hstatus), - guest_scounteren = const guest_csr_offset!(scounteren), - guest_sepc = const guest_csr_offset!(sepc), - -); - -extern "C" { - pub fn _run_guest(state: *mut VmCpuRegisters); -} diff --git a/arceos/tour/h_2_0/Cargo.toml b/arceos/tour/h_2_0/Cargo.toml deleted file mode 100644 index 91bdb0253..000000000 --- a/arceos/tour/h_2_0/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "h_2_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -log = "0.4.21" -axstd = { workspace = true, features = ["alloc", "paging", "fs", "multitask", "irq"] } -axhal = { workspace = true } -axmm = { workspace = true } -riscv_vcpu = { path = "../../modules/riscv_vcpu" } -axerrno = "0.1" -memory_addr = "0.3" diff --git a/arceos/tour/h_2_0/src/main.rs b/arceos/tour/h_2_0/src/main.rs deleted file mode 100644 index 0ae2f0e49..000000000 --- a/arceos/tour/h_2_0/src/main.rs +++ /dev/null @@ -1,136 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate log; -#[macro_use] -extern crate alloc; -extern crate axstd as std; -use alloc::string::ToString; -use riscv_vcpu::AxVCpuExitReason; -use axerrno::{ax_err_type, AxResult}; -use memory_addr::VirtAddr; -use alloc::string::String; -use std::fs::File; -use riscv_vcpu::RISCVVCpu; -use riscv_vcpu::AxVCpuExitReason::NestedPageFault; - -const VM_ASPACE_BASE: usize = 0x0; -const VM_ASPACE_SIZE: usize = 0x7fff_ffff_f000; -const PHY_MEM_START: usize = 0x8000_0000; -const PHY_MEM_SIZE: usize = 0x100_0000; -const KERNEL_BASE: usize = 0x8020_0000; - -use axmm::AddrSpace; -use axhal::paging::MappingFlags; - -#[no_mangle] -fn main() { - info!("Starting virtualization..."); - unsafe { - riscv_vcpu::setup_csrs(); - } - - // Setup AddressSpace and regions. - let mut aspace = AddrSpace::new_empty(VirtAddr::from(VM_ASPACE_BASE), VM_ASPACE_SIZE).unwrap(); - - // Physical memory region. Full access flags. - let mapping_flags = MappingFlags::from_bits(0xf).unwrap(); - aspace.map_alloc(PHY_MEM_START.into(), PHY_MEM_SIZE, mapping_flags, true).unwrap(); - - // Load corresponding images for VM. - info!("VM created success, loading images..."); - let image_fname = "/sbin/u_3_0_riscv64-qemu-virt.bin"; - load_vm_image(image_fname.to_string(), KERNEL_BASE.into(), &aspace).expect("Failed to load VM images"); - - // Create VCpus. - let mut arch_vcpu = RISCVVCpu::init(); - - // Setup VCpus. - info!("bsp_entry: {:#x}; ept: {:#x}", KERNEL_BASE, aspace.page_table_root()); - arch_vcpu.set_entry(KERNEL_BASE.into()).unwrap(); - arch_vcpu.set_ept_root(aspace.page_table_root()).unwrap(); - - loop { - match vcpu_run(&mut arch_vcpu) { - Ok(exit_reason) => match exit_reason { - AxVCpuExitReason::Nothing => {}, - NestedPageFault{addr, access_flags} => { - debug!("addr {:#x} access {:#x}", addr, access_flags); - assert_eq!(addr, 0x2200_0000.into(), "Now we ONLY handle pflash#2."); - let mapping_flags = MappingFlags::from_bits(0xf).unwrap(); - // Passthrough-Mode - let _ = aspace.map_linear(addr, addr.as_usize().into(), 4096, mapping_flags); - - /* - // Emulator-Mode - // Pretend to load file to fill buffer. - let buf = "pfld"; - aspace.map_alloc(addr, 4096, mapping_flags, true); - aspace.write(addr, buf.as_bytes()); - */ - }, - _ => { - panic!("Unhandled VM-Exit: {:?}", exit_reason); - } - }, - Err(err) => { - panic!("run VCpu get error {:?}", err); - } - } - } -} - -fn load_vm_image(image_path: String, image_load_gpa: VirtAddr, aspace: &AddrSpace) -> AxResult { - use std::io::{BufReader, Read}; - let (image_file, image_size) = open_image_file(image_path.as_str())?; - - let image_load_regions = aspace - .translated_byte_buffer(image_load_gpa, image_size) - .expect("Failed to translate kernel image load address"); - let mut file = BufReader::new(image_file); - - for buffer in image_load_regions { - file.read_exact(buffer).map_err(|err| { - ax_err_type!( - Io, - format!("Failed in reading from file {}, err {:?}", image_path, err) - ) - })? - } - - Ok(()) -} - -fn vcpu_run(arch_vcpu: &mut RISCVVCpu) -> AxResult { - use axhal::arch::{local_irq_save_and_disable, local_irq_restore}; - let flags = local_irq_save_and_disable(); - let ret = arch_vcpu.run(); - local_irq_restore(flags); - ret -} - -fn open_image_file(file_name: &str) -> AxResult<(File, usize)> { - let file = File::open(file_name).map_err(|err| { - ax_err_type!( - NotFound, - format!( - "Failed to open {}, err {:?}, please check your disk.img", - file_name, err - ) - ) - })?; - let file_size = file - .metadata() - .map_err(|err| { - ax_err_type!( - Io, - format!( - "Failed to get metadate of file {}, err {:?}", - file_name, err - ) - ) - })? - .size() as usize; - Ok((file, file_size)) -} diff --git a/arceos/tour/h_3_0/Cargo.toml b/arceos/tour/h_3_0/Cargo.toml deleted file mode 100644 index f58dadb44..000000000 --- a/arceos/tour/h_3_0/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "h_3_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -log = "0.4.21" -axstd = { workspace = true, features = ["alloc", "paging", "fs", "multitask", "irq"] } -axhal = { workspace = true } -axmm = { workspace = true } -riscv_vcpu = { path = "../../modules/riscv_vcpu" } -axerrno = "0.1" -memory_addr = "0.3" diff --git a/arceos/tour/h_3_0/src/main.rs b/arceos/tour/h_3_0/src/main.rs deleted file mode 100644 index 4a1020c5d..000000000 --- a/arceos/tour/h_3_0/src/main.rs +++ /dev/null @@ -1,136 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate log; -#[macro_use] -extern crate alloc; -extern crate axstd as std; -use alloc::string::ToString; -use riscv_vcpu::AxVCpuExitReason; -use axerrno::{ax_err_type, AxResult}; -use memory_addr::VirtAddr; -use alloc::string::String; -use std::fs::File; -use riscv_vcpu::RISCVVCpu; -use riscv_vcpu::AxVCpuExitReason::NestedPageFault; - -const VM_ASPACE_BASE: usize = 0x0; -const VM_ASPACE_SIZE: usize = 0x7fff_ffff_f000; -const PHY_MEM_START: usize = 0x8000_0000; -const PHY_MEM_SIZE: usize = 0x100_0000; -const KERNEL_BASE: usize = 0x8020_0000; - -use axmm::AddrSpace; -use axhal::paging::MappingFlags; - -#[no_mangle] -fn main() { - info!("Starting virtualization..."); - unsafe { - riscv_vcpu::setup_csrs(); - } - - // Setup AddressSpace and regions. - let mut aspace = AddrSpace::new_empty(VirtAddr::from(VM_ASPACE_BASE), VM_ASPACE_SIZE).unwrap(); - - // Physical memory region. Full access flags. - let mapping_flags = MappingFlags::from_bits(0xf).unwrap(); - aspace.map_alloc(PHY_MEM_START.into(), PHY_MEM_SIZE, mapping_flags, true).unwrap(); - - // Load corresponding images for VM. - info!("VM created success, loading images..."); - let image_fname = "/sbin/u_6_0_riscv64-qemu-virt.bin"; - load_vm_image(image_fname.to_string(), KERNEL_BASE.into(), &aspace).expect("Failed to load VM images"); - - // Create VCpus. - let mut arch_vcpu = RISCVVCpu::init(); - - // Setup VCpus. - info!("bsp_entry: {:#x}; ept: {:#x}", KERNEL_BASE, aspace.page_table_root()); - arch_vcpu.set_entry(KERNEL_BASE.into()).unwrap(); - arch_vcpu.set_ept_root(aspace.page_table_root()).unwrap(); - - loop { - match vcpu_run(&mut arch_vcpu) { - Ok(exit_reason) => match exit_reason { - AxVCpuExitReason::Nothing => {}, - NestedPageFault{addr, access_flags} => { - debug!("addr {:#x} access {:#x}", addr, access_flags); - assert_eq!(addr, 0x2200_0000.into(), "Now we ONLY handle pflash#2."); - let mapping_flags = MappingFlags::from_bits(0xf).unwrap(); - // Passthrough-Mode - let _ = aspace.map_linear(addr, addr.as_usize().into(), 4096, mapping_flags); - - /* - // Emulator-Mode - // Pretend to load file to fill buffer. - let buf = "pfld"; - aspace.map_alloc(addr, 4096, mapping_flags, true); - aspace.write(addr, buf.as_bytes()); - */ - }, - _ => { - panic!("Unhandled VM-Exit: {:?}", exit_reason); - } - }, - Err(err) => { - panic!("run VCpu get error {:?}", err); - } - } - } -} - -fn load_vm_image(image_path: String, image_load_gpa: VirtAddr, aspace: &AddrSpace) -> AxResult { - use std::io::{BufReader, Read}; - let (image_file, image_size) = open_image_file(image_path.as_str())?; - - let image_load_regions = aspace - .translated_byte_buffer(image_load_gpa, image_size) - .expect("Failed to translate kernel image load address"); - let mut file = BufReader::new(image_file); - - for buffer in image_load_regions { - file.read_exact(buffer).map_err(|err| { - ax_err_type!( - Io, - format!("Failed in reading from file {}, err {:?}", image_path, err) - ) - })? - } - - Ok(()) -} - -fn vcpu_run(arch_vcpu: &mut RISCVVCpu) -> AxResult { - use axhal::arch::{local_irq_save_and_disable, local_irq_restore}; - let flags = local_irq_save_and_disable(); - let ret = arch_vcpu.run(); - local_irq_restore(flags); - ret -} - -fn open_image_file(file_name: &str) -> AxResult<(File, usize)> { - let file = File::open(file_name).map_err(|err| { - ax_err_type!( - NotFound, - format!( - "Failed to open {}, err {:?}, please check your disk.img", - file_name, err - ) - ) - })?; - let file_size = file - .metadata() - .map_err(|err| { - ax_err_type!( - Io, - format!( - "Failed to get metadate of file {}, err {:?}", - file_name, err - ) - ) - })? - .size() as usize; - Ok((file, file_size)) -} diff --git a/arceos/tour/h_4_0/Cargo.toml b/arceos/tour/h_4_0/Cargo.toml deleted file mode 100644 index 271cc739c..000000000 --- a/arceos/tour/h_4_0/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "h_4_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -log = "0.4.21" -axstd = { workspace = true, features = ["alloc", "paging", "fs", "multitask", "irq"] } -axhal = { workspace = true } -axmm = { workspace = true } -riscv_vcpu = { path = "../../modules/riscv_vcpu" } -axerrno = "0.1" -memory_addr = "0.3" diff --git a/arceos/tour/h_4_0/src/main.rs b/arceos/tour/h_4_0/src/main.rs deleted file mode 100644 index e80a5a038..000000000 --- a/arceos/tour/h_4_0/src/main.rs +++ /dev/null @@ -1,138 +0,0 @@ -#![no_std] -#![no_main] - -mod vmdev; - -#[macro_use] -extern crate log; -#[macro_use] -extern crate alloc; -extern crate axstd as std; -use alloc::string::ToString; -use riscv_vcpu::AxVCpuExitReason; -use axerrno::{ax_err_type, AxResult}; -use memory_addr::VirtAddr; -use alloc::string::String; -use std::fs::File; -use riscv_vcpu::RISCVVCpu; -use riscv_vcpu::AxVCpuExitReason::NestedPageFault; - -use axmm::AddrSpace; -use axhal::paging::MappingFlags; -use vmdev::VmDevGroup; - -const VM_ASPACE_BASE: usize = 0x0; -const VM_ASPACE_SIZE: usize = 0x7fff_ffff_f000; -const PHY_MEM_START: usize = 0x8000_0000; -const PHY_MEM_SIZE: usize = 0x100_0000; -const KERNEL_BASE: usize = 0x8020_0000; - -#[no_mangle] -fn main() { - info!("Starting virtualization..."); - unsafe { - riscv_vcpu::setup_csrs(); - } - - // Setup AddressSpace and regions. - let mut aspace = AddrSpace::new_empty(VirtAddr::from(VM_ASPACE_BASE), VM_ASPACE_SIZE).unwrap(); - - // Physical memory region. Full access flags. - let mapping_flags = MappingFlags::from_bits(0xf).unwrap(); - aspace.map_alloc(PHY_MEM_START.into(), PHY_MEM_SIZE, mapping_flags, true).unwrap(); - - // Load corresponding images for VM. - info!("VM created success, loading images..."); - let image_fname = "/sbin/m_1_1_riscv64-qemu-virt.bin"; - load_vm_image(image_fname.to_string(), KERNEL_BASE.into(), &aspace).expect("Failed to load VM images"); - - // Register pflash device into vm. - let mut vmdevs = VmDevGroup::new(); - vmdevs.add_dev(0x2200_0000.into(), 0x200_0000); - - // Create VCpus. - let mut arch_vcpu = RISCVVCpu::init(); - - // Setup VCpus. - info!("bsp_entry: {:#x}; ept: {:#x}", KERNEL_BASE, aspace.page_table_root()); - arch_vcpu.set_entry(KERNEL_BASE.into()).unwrap(); - arch_vcpu.set_ept_root(aspace.page_table_root()).unwrap(); - - loop { - match vcpu_run(&mut arch_vcpu) { - Ok(exit_reason) => match exit_reason { - AxVCpuExitReason::Nothing => {}, - NestedPageFault{addr, access_flags} => { - debug!("addr {:#x} access {:#x}", addr, access_flags); - if addr < PHY_MEM_START.into() { - // Find dev and handle mmio region. - let dev = vmdevs.find_dev(addr).expect("No dev."); - dev.handle_mmio(addr, &mut aspace).unwrap(); - } else { - unimplemented!("Handle #PF for memory region."); - } - }, - _ => { - panic!("Unhandled VM-Exit: {:?}", exit_reason); - } - }, - Err(err) => { - panic!("run VCpu get error {:?}", err); - } - } - } -} - -fn load_vm_image(image_path: String, image_load_gpa: VirtAddr, aspace: &AddrSpace) -> AxResult { - use std::io::{BufReader, Read}; - let (image_file, image_size) = open_image_file(image_path.as_str())?; - - let image_load_regions = aspace - .translated_byte_buffer(image_load_gpa, image_size) - .expect("Failed to translate kernel image load address"); - let mut file = BufReader::new(image_file); - - for buffer in image_load_regions { - file.read_exact(buffer).map_err(|err| { - ax_err_type!( - Io, - format!("Failed in reading from file {}, err {:?}", image_path, err) - ) - })? - } - - Ok(()) -} - -fn vcpu_run(arch_vcpu: &mut RISCVVCpu) -> AxResult { - use axhal::arch::{local_irq_save_and_disable, local_irq_restore}; - let flags = local_irq_save_and_disable(); - let ret = arch_vcpu.run(); - local_irq_restore(flags); - ret -} - -fn open_image_file(file_name: &str) -> AxResult<(File, usize)> { - let file = File::open(file_name).map_err(|err| { - ax_err_type!( - NotFound, - format!( - "Failed to open {}, err {:?}, please check your disk.img", - file_name, err - ) - ) - })?; - let file_size = file - .metadata() - .map_err(|err| { - ax_err_type!( - Io, - format!( - "Failed to get metadate of file {}, err {:?}", - file_name, err - ) - ) - })? - .size() as usize; - Ok((file, file_size)) -} diff --git a/arceos/tour/h_4_0/src/vmdev.rs b/arceos/tour/h_4_0/src/vmdev.rs deleted file mode 100644 index bf982db93..000000000 --- a/arceos/tour/h_4_0/src/vmdev.rs +++ /dev/null @@ -1,49 +0,0 @@ -use alloc::vec::Vec; -use alloc::sync::Arc; -use axerrno::AxResult; -use memory_addr::VirtAddr; -use axhal::paging::MappingFlags; -use axmm::AddrSpace; - -pub struct VmDev { - start: VirtAddr, - size: usize, -} - -impl VmDev { - pub fn new(start: VirtAddr, size: usize) -> Self { - Self { start, size } - } - - pub fn handle_mmio(&self, addr: VirtAddr , aspace: &mut AddrSpace) -> AxResult { - let mapping_flags = MappingFlags::from_bits(0xf).unwrap(); - // Passthrough-Mode - aspace.map_linear(addr, addr.as_usize().into(), 4096, mapping_flags) - } - - pub fn check_addr(&self, addr: VirtAddr) -> bool { - addr >= self.start && addr < (self.start + self.size) - } -} - -pub struct VmDevGroup { - devices: Vec> -} - -impl VmDevGroup { - pub fn new() -> Self { - Self { devices: Vec::new() } - } - - pub fn add_dev(&mut self, addr: VirtAddr, size: usize) { - let dev = VmDev::new(addr, size); - self.devices.push(Arc::new(dev)); - } - - pub fn find_dev(&self, addr: VirtAddr) -> Option> { - self.devices - .iter() - .find(|&dev| dev.check_addr(addr)) - .cloned() - } -} diff --git a/arceos/tour/m_1_0/Cargo.toml b/arceos/tour/m_1_0/Cargo.toml deleted file mode 100644 index 7b551d53c..000000000 --- a/arceos/tour/m_1_0/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "m_1_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask", "sched_cfs", "fs"], optional = true } -axmm = { workspace = true } -axhal = { workspace = true, features = ["uspace"] } -axsync = { workspace = true } -axtask = { workspace = true } -axlog = { workspace = true } -axerrno = "0.1" -linkme = "0.3" diff --git a/arceos/tour/m_1_0/src/loader.rs b/arceos/tour/m_1_0/src/loader.rs deleted file mode 100644 index 0f4ad5d3a..000000000 --- a/arceos/tour/m_1_0/src/loader.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::io::{self, Read}; -use std::fs::File; -use axhal::paging::MappingFlags; -use axhal::mem::{PAGE_SIZE_4K, phys_to_virt}; -use axmm::AddrSpace; -use crate::APP_ENTRY; - -pub fn load_user_app(fname: &str, uspace: &mut AddrSpace) -> io::Result<()> { - let mut buf = [0u8; 64]; - load_file(fname, &mut buf)?; - - uspace.map_alloc(APP_ENTRY.into(), PAGE_SIZE_4K, MappingFlags::READ|MappingFlags::WRITE|MappingFlags::EXECUTE|MappingFlags::USER, true).unwrap(); - - let (paddr, _, _) = uspace - .page_table() - .query(APP_ENTRY.into()) - .unwrap_or_else(|_| panic!("Mapping failed for segment: {:#x}", APP_ENTRY)); - - ax_println!("paddr: {:#x}", paddr); - - unsafe { - core::ptr::copy_nonoverlapping( - buf.as_ptr(), - phys_to_virt(paddr).as_mut_ptr(), - PAGE_SIZE_4K, - ); - } - - Ok(()) -} - -fn load_file(fname: &str, buf: &mut [u8]) -> io::Result { - ax_println!("app: {}", fname); - let mut file = File::open(fname)?; - let n = file.read(buf)?; - Ok(n) -} diff --git a/arceos/tour/m_1_0/src/main.rs b/arceos/tour/m_1_0/src/main.rs deleted file mode 100644 index bb58187f8..000000000 --- a/arceos/tour/m_1_0/src/main.rs +++ /dev/null @@ -1,67 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[cfg(feature = "axstd")] -extern crate axstd as std; -extern crate alloc; - -#[macro_use] -extern crate axlog; - -mod task; -mod syscall; -mod loader; - -use axstd::io; -use axhal::paging::MappingFlags; -use axhal::arch::UspaceContext; -use axhal::mem::VirtAddr; -use axsync::Mutex; -use alloc::sync::Arc; -use axmm::AddrSpace; -use loader::load_user_app; - -const USER_STACK_SIZE: usize = 0x10000; -const KERNEL_STACK_SIZE: usize = 0x40000; // 256 KiB -const APP_ENTRY: usize = 0x1000; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - // A new address space for user app. - let mut uspace = axmm::new_user_aspace().unwrap(); - - // Load user app binary file into address space. - if let Err(e) = load_user_app("/sbin/origin", &mut uspace) { - panic!("Cannot load app! {:?}", e); - } - - // Init user stack. - let ustack_top = init_user_stack(&mut uspace, true).unwrap(); - ax_println!("New user address space: {:#x?}", uspace); - - // Let's kick off the user process. - let user_task = task::spawn_user_task( - Arc::new(Mutex::new(uspace)), - UspaceContext::new(APP_ENTRY.into(), ustack_top), - ); - - // Wait for user process to exit ... - let exit_code = user_task.join(); - ax_println!("monolithic kernel exit [{:?}] normally!", exit_code); -} - -fn init_user_stack(uspace: &mut AddrSpace, populating: bool) -> io::Result { - let ustack_top = uspace.end(); - let ustack_vaddr = ustack_top - crate::USER_STACK_SIZE; - ax_println!( - "Mapping user stack: {:#x?} -> {:#x?}", - ustack_vaddr, ustack_top - ); - uspace.map_alloc( - ustack_vaddr, - crate::USER_STACK_SIZE, - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER, - populating, - ).unwrap(); - Ok(ustack_top) -} diff --git a/arceos/tour/m_1_0/src/syscall.rs b/arceos/tour/m_1_0/src/syscall.rs deleted file mode 100644 index 20105e826..000000000 --- a/arceos/tour/m_1_0/src/syscall.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![allow(dead_code)] - -use axhal::arch::TrapFrame; -use axhal::trap::{register_trap_handler, SYSCALL}; -use axerrno::LinuxError; - -const SYS_EXIT: usize = 93; - -#[register_trap_handler(SYSCALL)] -fn handle_syscall(tf: &TrapFrame, syscall_num: usize) -> isize { - ax_println!("handle_syscall ..."); - let ret = match syscall_num { - SYS_EXIT => { - ax_println!("[SYS_EXIT]: process is exiting .."); - axtask::exit(tf.arg0() as _) - }, - _ => { - ax_println!("Unimplemented syscall: {}", syscall_num); - -LinuxError::ENOSYS.code() as _ - } - }; - ret -} diff --git a/arceos/tour/m_1_0/src/task.rs b/arceos/tour/m_1_0/src/task.rs deleted file mode 100644 index 3c20cd0d4..000000000 --- a/arceos/tour/m_1_0/src/task.rs +++ /dev/null @@ -1,50 +0,0 @@ -use alloc::sync::Arc; - -use axhal::arch::UspaceContext; -use axmm::AddrSpace; -use axsync::Mutex; -use axtask::{AxTaskRef, TaskExtRef, TaskInner}; - -/// Task extended data for the monolithic kernel. -pub struct TaskExt { - /// The process ID. - pub proc_id: usize, - /// The user space context. - pub uctx: UspaceContext, - /// The virtual memory address space. - pub aspace: Arc>, -} - -impl TaskExt { - pub const fn new(uctx: UspaceContext, aspace: Arc>) -> Self { - Self { - proc_id: 1, - uctx, - aspace, - } - } -} - -axtask::def_task_ext!(TaskExt); - -pub fn spawn_user_task(aspace: Arc>, uctx: UspaceContext) -> AxTaskRef { - let mut task = TaskInner::new( - || { - let curr = axtask::current(); - let kstack_top = curr.kernel_stack_top().unwrap(); - ax_println!( - "Enter user space: entry={:#x}, ustack={:#x}, kstack={:#x}", - curr.task_ext().uctx.get_ip(), - curr.task_ext().uctx.get_sp(), - kstack_top, - ); - unsafe { curr.task_ext().uctx.enter_uspace(kstack_top) }; - }, - "userboot".into(), - crate::KERNEL_STACK_SIZE, - ); - task.ctx_mut() - .set_page_table_root(aspace.lock().page_table_root()); - task.init_task_ext(TaskExt::new(uctx, aspace)); - axtask::spawn_task(task) -} diff --git a/arceos/tour/m_1_1/Cargo.toml b/arceos/tour/m_1_1/Cargo.toml deleted file mode 100644 index edb3b7375..000000000 --- a/arceos/tour/m_1_1/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "m_1_1" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask", "sched_cfs"], optional = true } -axmm = { workspace = true } -axhal = { workspace = true, features = ["uspace"] } -axsync = { workspace = true } -axtask = { workspace = true } -axlog = { workspace = true } -axerrno = "0.1" -linkme = "0.3" diff --git a/arceos/tour/m_1_1/src/loader.rs b/arceos/tour/m_1_1/src/loader.rs deleted file mode 100644 index 163d62805..000000000 --- a/arceos/tour/m_1_1/src/loader.rs +++ /dev/null @@ -1,65 +0,0 @@ -use core::{mem, slice}; -use axstd::io; -use axhal::paging::MappingFlags; -use axhal::mem::{PAGE_SIZE_4K, phys_to_virt}; -use axmm::AddrSpace; -use crate::APP_ENTRY; -use alloc::vec; -use alloc::vec::Vec; - -const PFLASH_START: usize = 0x2200_0000; -const MAGIC: u32 = 0x64_6C_66_70; -const VERSION: u32 = 0x01; - -struct PayloadHead { - _magic: u32, - _version: u32, - _size: u32, - _pad: u32, -} - -pub fn load_user_app(uspace: &mut AddrSpace) -> io::Result<()> { - let buf = load_pflash(); - - uspace.map_alloc(APP_ENTRY.into(), PAGE_SIZE_4K, MappingFlags::READ|MappingFlags::WRITE|MappingFlags::EXECUTE|MappingFlags::USER, true).unwrap(); - - let (paddr, _, _) = uspace - .page_table() - .query(APP_ENTRY.into()) - .unwrap_or_else(|_| panic!("Mapping failed for segment: {:#x}", APP_ENTRY)); - - ax_println!("paddr: {:#x}", paddr); - - unsafe { - core::ptr::copy_nonoverlapping( - buf.as_ptr(), - phys_to_virt(paddr).as_mut_ptr(), - buf.len(), - ); - } - - Ok(()) -} - -pub fn load_pflash() -> Vec { - let va = phys_to_virt(PFLASH_START.into()); - let data = va.as_usize() as *const u32; - let data = unsafe { - slice::from_raw_parts(data, mem::size_of::()) - }; - assert_eq!(data[0], MAGIC); - assert_eq!(data[1].to_be(), VERSION); - - let size = data[2].to_be() as usize; - let start = va + mem::size_of::(); - ax_println!("Pflash: start {:#X} size {}", start, size); - let mut buf = vec![0u8; size]; - unsafe { - core::ptr::copy_nonoverlapping( - start.as_usize() as *const u8, - buf.as_mut_ptr(), - size, - ); - } - buf -} diff --git a/arceos/tour/m_1_1/src/main.rs b/arceos/tour/m_1_1/src/main.rs deleted file mode 100644 index cbd85d964..000000000 --- a/arceos/tour/m_1_1/src/main.rs +++ /dev/null @@ -1,67 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[cfg(feature = "axstd")] -extern crate axstd as std; -extern crate alloc; - -#[macro_use] -extern crate axlog; - -mod task; -mod syscall; -mod loader; - -use axstd::io; -use axhal::paging::MappingFlags; -use axhal::arch::UspaceContext; -use axhal::mem::VirtAddr; -use axsync::Mutex; -use alloc::sync::Arc; -use axmm::AddrSpace; -use loader::load_user_app; - -const USER_STACK_SIZE: usize = 0x10000; -const KERNEL_STACK_SIZE: usize = 0x40000; // 256 KiB -const APP_ENTRY: usize = 0x1000; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - // A new address space for user app. - let mut uspace = axmm::new_user_aspace().unwrap(); - - // Load user app binary file into address space. - if let Err(e) = load_user_app(&mut uspace) { - panic!("Cannot load app! {:?}", e); - } - - // Init user stack. - let ustack_top = init_user_stack(&mut uspace, true).unwrap(); - ax_println!("New user address space: {:#x?}", uspace); - - // Let's kick off the user process. - let user_task = task::spawn_user_task( - Arc::new(Mutex::new(uspace)), - UspaceContext::new(APP_ENTRY.into(), ustack_top), - ); - - // Wait for user process to exit ... - let exit_code = user_task.join(); - ax_println!("monolithic kernel exit [{:?}] normally!", exit_code); -} - -fn init_user_stack(uspace: &mut AddrSpace, populating: bool) -> io::Result { - let ustack_top = uspace.end(); - let ustack_vaddr = ustack_top - crate::USER_STACK_SIZE; - ax_println!( - "Mapping user stack: {:#x?} -> {:#x?}", - ustack_vaddr, ustack_top - ); - uspace.map_alloc( - ustack_vaddr, - crate::USER_STACK_SIZE, - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER, - populating, - ).unwrap(); - Ok(ustack_top) -} diff --git a/arceos/tour/m_1_1/src/syscall.rs b/arceos/tour/m_1_1/src/syscall.rs deleted file mode 100644 index 20105e826..000000000 --- a/arceos/tour/m_1_1/src/syscall.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![allow(dead_code)] - -use axhal::arch::TrapFrame; -use axhal::trap::{register_trap_handler, SYSCALL}; -use axerrno::LinuxError; - -const SYS_EXIT: usize = 93; - -#[register_trap_handler(SYSCALL)] -fn handle_syscall(tf: &TrapFrame, syscall_num: usize) -> isize { - ax_println!("handle_syscall ..."); - let ret = match syscall_num { - SYS_EXIT => { - ax_println!("[SYS_EXIT]: process is exiting .."); - axtask::exit(tf.arg0() as _) - }, - _ => { - ax_println!("Unimplemented syscall: {}", syscall_num); - -LinuxError::ENOSYS.code() as _ - } - }; - ret -} diff --git a/arceos/tour/m_1_1/src/task.rs b/arceos/tour/m_1_1/src/task.rs deleted file mode 100644 index 3c20cd0d4..000000000 --- a/arceos/tour/m_1_1/src/task.rs +++ /dev/null @@ -1,50 +0,0 @@ -use alloc::sync::Arc; - -use axhal::arch::UspaceContext; -use axmm::AddrSpace; -use axsync::Mutex; -use axtask::{AxTaskRef, TaskExtRef, TaskInner}; - -/// Task extended data for the monolithic kernel. -pub struct TaskExt { - /// The process ID. - pub proc_id: usize, - /// The user space context. - pub uctx: UspaceContext, - /// The virtual memory address space. - pub aspace: Arc>, -} - -impl TaskExt { - pub const fn new(uctx: UspaceContext, aspace: Arc>) -> Self { - Self { - proc_id: 1, - uctx, - aspace, - } - } -} - -axtask::def_task_ext!(TaskExt); - -pub fn spawn_user_task(aspace: Arc>, uctx: UspaceContext) -> AxTaskRef { - let mut task = TaskInner::new( - || { - let curr = axtask::current(); - let kstack_top = curr.kernel_stack_top().unwrap(); - ax_println!( - "Enter user space: entry={:#x}, ustack={:#x}, kstack={:#x}", - curr.task_ext().uctx.get_ip(), - curr.task_ext().uctx.get_sp(), - kstack_top, - ); - unsafe { curr.task_ext().uctx.enter_uspace(kstack_top) }; - }, - "userboot".into(), - crate::KERNEL_STACK_SIZE, - ); - task.ctx_mut() - .set_page_table_root(aspace.lock().page_table_root()); - task.init_task_ext(TaskExt::new(uctx, aspace)); - axtask::spawn_task(task) -} diff --git a/arceos/tour/m_2_0/Cargo.toml b/arceos/tour/m_2_0/Cargo.toml deleted file mode 100644 index f0743d8a5..000000000 --- a/arceos/tour/m_2_0/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "m_2_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask", "sched_cfs", "fs"], optional = true } -axmm = { workspace = true } -axhal = { workspace = true, features = ["uspace"] } -axsync = { workspace = true } -axtask = { workspace = true } -axlog = { workspace = true } -axerrno = "0.1" -linkme = "0.3" diff --git a/arceos/tour/m_2_0/src/loader.rs b/arceos/tour/m_2_0/src/loader.rs deleted file mode 100644 index 0f4ad5d3a..000000000 --- a/arceos/tour/m_2_0/src/loader.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::io::{self, Read}; -use std::fs::File; -use axhal::paging::MappingFlags; -use axhal::mem::{PAGE_SIZE_4K, phys_to_virt}; -use axmm::AddrSpace; -use crate::APP_ENTRY; - -pub fn load_user_app(fname: &str, uspace: &mut AddrSpace) -> io::Result<()> { - let mut buf = [0u8; 64]; - load_file(fname, &mut buf)?; - - uspace.map_alloc(APP_ENTRY.into(), PAGE_SIZE_4K, MappingFlags::READ|MappingFlags::WRITE|MappingFlags::EXECUTE|MappingFlags::USER, true).unwrap(); - - let (paddr, _, _) = uspace - .page_table() - .query(APP_ENTRY.into()) - .unwrap_or_else(|_| panic!("Mapping failed for segment: {:#x}", APP_ENTRY)); - - ax_println!("paddr: {:#x}", paddr); - - unsafe { - core::ptr::copy_nonoverlapping( - buf.as_ptr(), - phys_to_virt(paddr).as_mut_ptr(), - PAGE_SIZE_4K, - ); - } - - Ok(()) -} - -fn load_file(fname: &str, buf: &mut [u8]) -> io::Result { - ax_println!("app: {}", fname); - let mut file = File::open(fname)?; - let n = file.read(buf)?; - Ok(n) -} diff --git a/arceos/tour/m_2_0/src/main.rs b/arceos/tour/m_2_0/src/main.rs deleted file mode 100644 index 08d5aec32..000000000 --- a/arceos/tour/m_2_0/src/main.rs +++ /dev/null @@ -1,89 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[cfg(feature = "axstd")] -extern crate axstd as std; -extern crate alloc; - -#[macro_use] -extern crate axlog; - -mod task; -mod syscall; -mod loader; - -use axstd::io; -use axhal::paging::MappingFlags; -use axhal::arch::UspaceContext; -use axhal::mem::VirtAddr; -use axsync::Mutex; -use alloc::sync::Arc; -use axmm::AddrSpace; -use loader::load_user_app; -use axtask::TaskExtRef; -use axhal::trap::{register_trap_handler, PAGE_FAULT}; - -const USER_STACK_SIZE: usize = 0x10000; -const KERNEL_STACK_SIZE: usize = 0x40000; // 256 KiB -const APP_ENTRY: usize = 0x1000; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - // A new address space for user app. - let mut uspace = axmm::new_user_aspace().unwrap(); - - // Load user app binary file into address space. - if let Err(e) = load_user_app("/sbin/origin", &mut uspace) { - panic!("Cannot load app! {:?}", e); - } - - // Init user stack. - let ustack_top = init_user_stack(&mut uspace, false).unwrap(); - ax_println!("New user address space: {:#x?}", uspace); - - // Let's kick off the user process. - let user_task = task::spawn_user_task( - Arc::new(Mutex::new(uspace)), - UspaceContext::new(APP_ENTRY.into(), ustack_top), - ); - - // Wait for user process to exit ... - let exit_code = user_task.join(); - ax_println!("monolithic kernel exit [{:?}] normally!", exit_code); -} - -fn init_user_stack(uspace: &mut AddrSpace, populating: bool) -> io::Result { - let ustack_top = uspace.end(); - let ustack_vaddr = ustack_top - crate::USER_STACK_SIZE; - ax_println!( - "Mapping user stack: {:#x?} -> {:#x?}", - ustack_vaddr, ustack_top - ); - uspace.map_alloc( - ustack_vaddr, - crate::USER_STACK_SIZE, - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER, - populating, - ).unwrap(); - Ok(ustack_top) -} - -#[register_trap_handler(PAGE_FAULT)] -fn handle_page_fault(vaddr: VirtAddr, access_flags: MappingFlags, is_user: bool) -> bool { - if is_user { - if !axtask::current() - .task_ext() - .aspace - .lock() - .handle_page_fault(vaddr, access_flags) - { - ax_println!("{}: segmentation fault, exit!", axtask::current().id_name()); - axtask::exit(-1); - } else { - ax_println!("{}: handle page fault OK!", axtask::current().id_name()); - } - true - } else { - false - } -} diff --git a/arceos/tour/m_2_0/src/syscall.rs b/arceos/tour/m_2_0/src/syscall.rs deleted file mode 100644 index 0a336d9ce..000000000 --- a/arceos/tour/m_2_0/src/syscall.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![allow(dead_code)] - -use axhal::arch::TrapFrame; -use axhal::trap::{register_trap_handler, SYSCALL}; -use axerrno::LinuxError; - -const SYS_EXIT: usize = 93; - -#[register_trap_handler(SYSCALL)] -fn handle_syscall(tf: &TrapFrame, syscall_num: usize) -> isize { - ax_println!("handle_syscall ..."); - let ret = match syscall_num { - SYS_EXIT => { - ax_println!("[SYS_EXIT]: system is exiting .."); - axtask::exit(tf.arg0() as _) - }, - _ => { - ax_println!("Unimplemented syscall: {}", syscall_num); - -LinuxError::ENOSYS.code() as _ - } - }; - ret -} diff --git a/arceos/tour/m_2_0/src/task.rs b/arceos/tour/m_2_0/src/task.rs deleted file mode 100644 index 3c20cd0d4..000000000 --- a/arceos/tour/m_2_0/src/task.rs +++ /dev/null @@ -1,50 +0,0 @@ -use alloc::sync::Arc; - -use axhal::arch::UspaceContext; -use axmm::AddrSpace; -use axsync::Mutex; -use axtask::{AxTaskRef, TaskExtRef, TaskInner}; - -/// Task extended data for the monolithic kernel. -pub struct TaskExt { - /// The process ID. - pub proc_id: usize, - /// The user space context. - pub uctx: UspaceContext, - /// The virtual memory address space. - pub aspace: Arc>, -} - -impl TaskExt { - pub const fn new(uctx: UspaceContext, aspace: Arc>) -> Self { - Self { - proc_id: 1, - uctx, - aspace, - } - } -} - -axtask::def_task_ext!(TaskExt); - -pub fn spawn_user_task(aspace: Arc>, uctx: UspaceContext) -> AxTaskRef { - let mut task = TaskInner::new( - || { - let curr = axtask::current(); - let kstack_top = curr.kernel_stack_top().unwrap(); - ax_println!( - "Enter user space: entry={:#x}, ustack={:#x}, kstack={:#x}", - curr.task_ext().uctx.get_ip(), - curr.task_ext().uctx.get_sp(), - kstack_top, - ); - unsafe { curr.task_ext().uctx.enter_uspace(kstack_top) }; - }, - "userboot".into(), - crate::KERNEL_STACK_SIZE, - ); - task.ctx_mut() - .set_page_table_root(aspace.lock().page_table_root()); - task.init_task_ext(TaskExt::new(uctx, aspace)); - axtask::spawn_task(task) -} diff --git a/arceos/tour/m_3_0/Cargo.toml b/arceos/tour/m_3_0/Cargo.toml deleted file mode 100644 index 50170f3eb..000000000 --- a/arceos/tour/m_3_0/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "m_3_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask", "sched_cfs", "fs"], optional = true } -axmm = { workspace = true } -axhal = { workspace = true, features = ["uspace"] } -axsync = { workspace = true } -axtask = { workspace = true } -axlog = { workspace = true } -elf = { workspace = true } -axerrno = "0.1" -linkme = "0.3" -kernel-elf-parser = "0.1.0" -arceos_posix_api = { workspace = true } diff --git a/arceos/tour/m_3_0/src/loader.rs b/arceos/tour/m_3_0/src/loader.rs deleted file mode 100644 index f95f8f5f8..000000000 --- a/arceos/tour/m_3_0/src/loader.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::io::{self, Read}; -use std::io::SeekFrom; -use std::io::Seek; -use std::fs::File; -use alloc::vec::Vec; -use alloc::vec; -use axhal::paging::MappingFlags; -use axhal::mem::{PAGE_SIZE_4K, VirtAddr, MemoryAddr}; -use axmm::AddrSpace; - -use elf::abi::{PT_INTERP, PT_LOAD}; -use elf::endian::AnyEndian; -use elf::parse::ParseAt; -use elf::segment::ProgramHeader; -use elf::segment::SegmentTable; -use elf::ElfBytes; - -const ELF_HEAD_BUF_SIZE: usize = 256; - -pub fn load_user_app(fname: &str, uspace: &mut AddrSpace) -> io::Result { - let mut file = File::open(fname)?; - let (phdrs, entry, _, _) = load_elf_phdrs(&mut file)?; - - for phdr in &phdrs { - ax_println!( - "phdr: offset: {:#X}=>{:#X} size: {:#X}=>{:#X}", - phdr.p_offset, phdr.p_vaddr, phdr.p_filesz, phdr.p_memsz - ); - - let vaddr = VirtAddr::from(phdr.p_vaddr as usize).align_down_4k(); - let vaddr_end = VirtAddr::from((phdr.p_vaddr+phdr.p_memsz) as usize) - .align_up_4k(); - - ax_println!("{:#x} - {:#x}", vaddr, vaddr_end); - uspace.map_alloc(vaddr, vaddr_end-vaddr, MappingFlags::READ|MappingFlags::WRITE|MappingFlags::EXECUTE|MappingFlags::USER, true)?; - - let mut data = vec![0u8; phdr.p_memsz as usize]; - file.seek(SeekFrom::Start(phdr.p_offset))?; - - let filesz = phdr.p_filesz as usize; - let mut index = 0; - while index < filesz { - let n = file.read(&mut data[index..filesz])?; - index += n; - } - assert_eq!(index, filesz); - uspace.write(VirtAddr::from(phdr.p_vaddr as usize), &data)?; - } - - Ok(entry) -} - -fn load_elf_phdrs(file: &mut File) -> io::Result<(Vec, usize, usize, usize)> { - let mut buf: [u8; ELF_HEAD_BUF_SIZE] = [0; ELF_HEAD_BUF_SIZE]; - file.read(&mut buf)?; - - let ehdr = ElfBytes::::parse_elf_header(&buf[..]).unwrap(); - info!("e_entry: {:#X}", ehdr.e_entry); - - let phnum = ehdr.e_phnum as usize; - // Validate phentsize before trying to read the table so that we can error early for corrupted files - let entsize = ProgramHeader::validate_entsize(ehdr.class, ehdr.e_phentsize as usize).unwrap(); - let size = entsize.checked_mul(phnum).unwrap(); - assert!(size > 0 && size <= PAGE_SIZE_4K); - let phoff = ehdr.e_phoff; - let mut buf = alloc::vec![0u8; size]; - let _ = file.seek(SeekFrom::Start(phoff)); - file.read(&mut buf)?; - let phdrs = SegmentTable::new(ehdr.endianness, ehdr.class, &buf[..]); - - let phdrs: Vec = phdrs - .iter() - .filter(|phdr| phdr.p_type == PT_LOAD || phdr.p_type == PT_INTERP) - .collect(); - Ok((phdrs, ehdr.e_entry as usize, ehdr.e_phoff as usize, ehdr.e_phnum as usize)) -} diff --git a/arceos/tour/m_3_0/src/main.rs b/arceos/tour/m_3_0/src/main.rs deleted file mode 100644 index 6a9f18043..000000000 --- a/arceos/tour/m_3_0/src/main.rs +++ /dev/null @@ -1,82 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[cfg(feature = "axstd")] -extern crate axstd as std; -extern crate alloc; - -#[macro_use] -extern crate axlog; - -mod task; -mod syscall; -mod loader; - -use axstd::io; -use axhal::paging::MappingFlags; -use axhal::arch::UspaceContext; -use axhal::mem::VirtAddr; -use axsync::Mutex; -use alloc::sync::Arc; -use alloc::string::String; -use alloc::collections::BTreeMap; -use axmm::AddrSpace; -use loader::load_user_app; - -const USER_STACK_SIZE: usize = 0x10000; -const KERNEL_STACK_SIZE: usize = 0x40000; // 256 KiB - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - // A new address space for user app. - let mut uspace = axmm::new_user_aspace().unwrap(); - - // Load user app binary file into address space. - let entry = match load_user_app("/sbin/hello", &mut uspace) { - Ok(e) => e, - Err(err) => panic!("Cannot load app! {:?}", err), - }; - ax_println!("entry: {:#x}", entry); - - // Init user stack. - let ustack_top = init_user_stack(&mut uspace, true).unwrap(); - ax_println!("New user address space: {:#x?}", uspace); - - // Let's kick off the user process. - let user_task = task::spawn_user_task( - Arc::new(Mutex::new(uspace)), - UspaceContext::new(entry, ustack_top), - ); - - // Wait for user process to exit ... - let exit_code = user_task.join(); - ax_println!("monolithic kernel exit [{:?}] normally!", exit_code); -} - -fn init_user_stack(uspace: &mut AddrSpace, populating: bool) -> io::Result { - let ustack_top = uspace.end(); - let ustack_vaddr = ustack_top - crate::USER_STACK_SIZE; - ax_println!( - "Mapping user stack: {:#x?} -> {:#x?}", - ustack_vaddr, ustack_top - ); - uspace.map_alloc( - ustack_vaddr, - crate::USER_STACK_SIZE, - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER, - populating, - ).unwrap(); - - let app_name = "hello"; - let av = BTreeMap::new(); - let (stack_data, ustack_pointer) = kernel_elf_parser::get_app_stack_region( - &[String::from(app_name)], - &[], - &av, - ustack_vaddr, - crate::USER_STACK_SIZE, - ); - uspace.write(VirtAddr::from_usize(ustack_pointer), stack_data.as_slice())?; - - Ok(ustack_pointer.into()) -} diff --git a/arceos/tour/m_3_0/src/syscall.rs b/arceos/tour/m_3_0/src/syscall.rs deleted file mode 100644 index 7e75bbc15..000000000 --- a/arceos/tour/m_3_0/src/syscall.rs +++ /dev/null @@ -1,53 +0,0 @@ -#![allow(dead_code)] - -use core::ffi::c_void; -use axhal::arch::TrapFrame; -use axhal::trap::{register_trap_handler, SYSCALL}; -use axerrno::LinuxError; -use axtask::current; -use axtask::TaskExtRef; -use arceos_posix_api as api; - -const SYS_IOCTL: usize = 29; -const SYS_WRITEV: usize = 66; -const SYS_EXIT: usize = 93; -const SYS_EXIT_GROUP: usize = 94; -const SYS_SET_TID_ADDRESS: usize = 96; - -#[register_trap_handler(SYSCALL)] -fn handle_syscall(tf: &TrapFrame, syscall_num: usize) -> isize { - ax_println!("handle_syscall [{}] ...", syscall_num); - let ret = match syscall_num { - SYS_IOCTL => sys_ioctl(tf.arg0() as _, tf.arg1() as _, tf.arg2() as _) as _, - SYS_SET_TID_ADDRESS => sys_set_tid_address(tf.arg0() as _), - SYS_WRITEV => sys_writev(tf.arg0() as _, tf.arg1() as _, tf.arg2() as _), - SYS_EXIT_GROUP => { - ax_println!("[SYS_EXIT_GROUP]: system is exiting .."); - axtask::exit(tf.arg0() as _) - }, - SYS_EXIT => { - ax_println!("[SYS_EXIT]: system is exiting .."); - axtask::exit(tf.arg0() as _) - }, - _ => { - ax_println!("Unimplemented syscall: {}", syscall_num); - -LinuxError::ENOSYS.code() as _ - } - }; - ret -} - -fn sys_writev(fd: i32, iov: *const api::ctypes::iovec, iocnt: i32) -> isize { - unsafe { api::sys_writev(fd, iov, iocnt) } -} - -pub(crate) fn sys_set_tid_address(tid_ptd: *const i32) -> isize { - let curr = current(); - curr.task_ext().set_clear_child_tid(tid_ptd as _); - curr.id().as_u64() as isize -} - -fn sys_ioctl(_fd: i32, _op: usize, _argp: *mut c_void) -> i32 { - ax_println!("Unimplemented syscall: SYS_IOCTL"); - 0 -} diff --git a/arceos/tour/m_3_0/src/task.rs b/arceos/tour/m_3_0/src/task.rs deleted file mode 100644 index d5372dd6a..000000000 --- a/arceos/tour/m_3_0/src/task.rs +++ /dev/null @@ -1,71 +0,0 @@ -#![allow(dead_code)] - -use core::sync::atomic::AtomicU64; - -use alloc::sync::Arc; - -use axhal::arch::UspaceContext; -use axmm::AddrSpace; -use axsync::Mutex; -use axtask::{AxTaskRef, TaskExtRef, TaskInner}; - -/// Task extended data for the monolithic kernel. -pub struct TaskExt { - /// The process ID. - pub proc_id: usize, - /// The clear thread tid field - /// - /// See - /// - /// When the thread exits, the kernel clears the word at this address if it is not NULL. - clear_child_tid: AtomicU64, - /// The user space context. - pub uctx: UspaceContext, - /// The virtual memory address space. - pub aspace: Arc>, -} - -impl TaskExt { - pub const fn new(uctx: UspaceContext, aspace: Arc>) -> Self { - Self { - proc_id: 233, - uctx, - clear_child_tid: AtomicU64::new(0), - aspace, - } - } - - pub(crate) fn clear_child_tid(&self) -> u64 { - self.clear_child_tid - .load(core::sync::atomic::Ordering::Relaxed) - } - - pub(crate) fn set_clear_child_tid(&self, clear_child_tid: u64) { - self.clear_child_tid - .store(clear_child_tid, core::sync::atomic::Ordering::Relaxed); - } -} - -axtask::def_task_ext!(TaskExt); - -pub fn spawn_user_task(aspace: Arc>, uctx: UspaceContext) -> AxTaskRef { - let mut task = TaskInner::new( - || { - let curr = axtask::current(); - let kstack_top = curr.kernel_stack_top().unwrap(); - info!( - "Enter user space: entry={:#x}, ustack={:#x}, kstack={:#x}", - curr.task_ext().uctx.get_ip(), - curr.task_ext().uctx.get_sp(), - kstack_top, - ); - unsafe { curr.task_ext().uctx.enter_uspace(kstack_top) }; - }, - "userboot".into(), - crate::KERNEL_STACK_SIZE, - ); - task.ctx_mut() - .set_page_table_root(aspace.lock().page_table_root()); - task.init_task_ext(TaskExt::new(uctx, aspace)); - axtask::spawn_task(task) -} diff --git a/arceos/tour/m_3_1/Cargo.toml b/arceos/tour/m_3_1/Cargo.toml deleted file mode 100644 index 80c964bb8..000000000 --- a/arceos/tour/m_3_1/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "m_3_1" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask", "sched_cfs", "fs"], optional = true } -axmm = { workspace = true } -axhal = { workspace = true, features = ["uspace"] } -axsync = { workspace = true } -axtask = { workspace = true } -axlog = { workspace = true } -elf = { workspace = true } -axerrno = "0.1" -linkme = "0.3" -kernel-elf-parser = "0.1.0" -arceos_posix_api = { workspace = true } diff --git a/arceos/tour/m_3_1/src/loader.rs b/arceos/tour/m_3_1/src/loader.rs deleted file mode 100644 index f95f8f5f8..000000000 --- a/arceos/tour/m_3_1/src/loader.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::io::{self, Read}; -use std::io::SeekFrom; -use std::io::Seek; -use std::fs::File; -use alloc::vec::Vec; -use alloc::vec; -use axhal::paging::MappingFlags; -use axhal::mem::{PAGE_SIZE_4K, VirtAddr, MemoryAddr}; -use axmm::AddrSpace; - -use elf::abi::{PT_INTERP, PT_LOAD}; -use elf::endian::AnyEndian; -use elf::parse::ParseAt; -use elf::segment::ProgramHeader; -use elf::segment::SegmentTable; -use elf::ElfBytes; - -const ELF_HEAD_BUF_SIZE: usize = 256; - -pub fn load_user_app(fname: &str, uspace: &mut AddrSpace) -> io::Result { - let mut file = File::open(fname)?; - let (phdrs, entry, _, _) = load_elf_phdrs(&mut file)?; - - for phdr in &phdrs { - ax_println!( - "phdr: offset: {:#X}=>{:#X} size: {:#X}=>{:#X}", - phdr.p_offset, phdr.p_vaddr, phdr.p_filesz, phdr.p_memsz - ); - - let vaddr = VirtAddr::from(phdr.p_vaddr as usize).align_down_4k(); - let vaddr_end = VirtAddr::from((phdr.p_vaddr+phdr.p_memsz) as usize) - .align_up_4k(); - - ax_println!("{:#x} - {:#x}", vaddr, vaddr_end); - uspace.map_alloc(vaddr, vaddr_end-vaddr, MappingFlags::READ|MappingFlags::WRITE|MappingFlags::EXECUTE|MappingFlags::USER, true)?; - - let mut data = vec![0u8; phdr.p_memsz as usize]; - file.seek(SeekFrom::Start(phdr.p_offset))?; - - let filesz = phdr.p_filesz as usize; - let mut index = 0; - while index < filesz { - let n = file.read(&mut data[index..filesz])?; - index += n; - } - assert_eq!(index, filesz); - uspace.write(VirtAddr::from(phdr.p_vaddr as usize), &data)?; - } - - Ok(entry) -} - -fn load_elf_phdrs(file: &mut File) -> io::Result<(Vec, usize, usize, usize)> { - let mut buf: [u8; ELF_HEAD_BUF_SIZE] = [0; ELF_HEAD_BUF_SIZE]; - file.read(&mut buf)?; - - let ehdr = ElfBytes::::parse_elf_header(&buf[..]).unwrap(); - info!("e_entry: {:#X}", ehdr.e_entry); - - let phnum = ehdr.e_phnum as usize; - // Validate phentsize before trying to read the table so that we can error early for corrupted files - let entsize = ProgramHeader::validate_entsize(ehdr.class, ehdr.e_phentsize as usize).unwrap(); - let size = entsize.checked_mul(phnum).unwrap(); - assert!(size > 0 && size <= PAGE_SIZE_4K); - let phoff = ehdr.e_phoff; - let mut buf = alloc::vec![0u8; size]; - let _ = file.seek(SeekFrom::Start(phoff)); - file.read(&mut buf)?; - let phdrs = SegmentTable::new(ehdr.endianness, ehdr.class, &buf[..]); - - let phdrs: Vec = phdrs - .iter() - .filter(|phdr| phdr.p_type == PT_LOAD || phdr.p_type == PT_INTERP) - .collect(); - Ok((phdrs, ehdr.e_entry as usize, ehdr.e_phoff as usize, ehdr.e_phnum as usize)) -} diff --git a/arceos/tour/m_3_1/src/main.rs b/arceos/tour/m_3_1/src/main.rs deleted file mode 100644 index 1d2ba9aee..000000000 --- a/arceos/tour/m_3_1/src/main.rs +++ /dev/null @@ -1,82 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[cfg(feature = "axstd")] -extern crate axstd as std; -extern crate alloc; - -#[macro_use] -extern crate axlog; - -mod task; -mod syscall; -mod loader; - -use axstd::io; -use axhal::paging::MappingFlags; -use axhal::arch::UspaceContext; -use axhal::mem::VirtAddr; -use axsync::Mutex; -use alloc::sync::Arc; -use alloc::string::String; -use alloc::collections::BTreeMap; -use axmm::AddrSpace; -use loader::load_user_app; - -const USER_STACK_SIZE: usize = 0x10000; -const KERNEL_STACK_SIZE: usize = 0x40000; // 256 KiB - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - // A new address space for user app. - let mut uspace = axmm::new_user_aspace().unwrap(); - - // Load user app binary file into address space. - let entry = match load_user_app("/sbin/fileops", &mut uspace) { - Ok(e) => e, - Err(err) => panic!("Cannot load app! {:?}", err), - }; - ax_println!("entry: {:#x}", entry); - - // Init user stack. - let ustack_top = init_user_stack(&mut uspace, true).unwrap(); - ax_println!("New user address space: {:#x?}", uspace); - - // Let's kick off the user process. - let user_task = task::spawn_user_task( - Arc::new(Mutex::new(uspace)), - UspaceContext::new(entry, ustack_top), - ); - - // Wait for user process to exit ... - let exit_code = user_task.join(); - ax_println!("monolithic kernel exit [{:?}] normally!", exit_code); -} - -fn init_user_stack(uspace: &mut AddrSpace, populating: bool) -> io::Result { - let ustack_top = uspace.end(); - let ustack_vaddr = ustack_top - crate::USER_STACK_SIZE; - ax_println!( - "Mapping user stack: {:#x?} -> {:#x?}", - ustack_vaddr, ustack_top - ); - uspace.map_alloc( - ustack_vaddr, - crate::USER_STACK_SIZE, - MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER, - populating, - ).unwrap(); - - let app_name = "hello"; - let av = BTreeMap::new(); - let (stack_data, ustack_pointer) = kernel_elf_parser::get_app_stack_region( - &[String::from(app_name)], - &[], - &av, - ustack_vaddr, - crate::USER_STACK_SIZE, - ); - uspace.write(VirtAddr::from_usize(ustack_pointer), stack_data.as_slice())?; - - Ok(ustack_pointer.into()) -} diff --git a/arceos/tour/m_3_1/src/syscall.rs b/arceos/tour/m_3_1/src/syscall.rs deleted file mode 100644 index e821c6453..000000000 --- a/arceos/tour/m_3_1/src/syscall.rs +++ /dev/null @@ -1,80 +0,0 @@ -#![allow(dead_code)] - -use core::ffi::{c_void, c_char, c_int}; -use axhal::arch::TrapFrame; -use axhal::trap::{register_trap_handler, SYSCALL}; -use axerrno::LinuxError; -use axtask::current; -use axtask::TaskExtRef; -use arceos_posix_api as api; - -const SYS_IOCTL: usize = 29; -const SYS_OPENAT: usize = 56; -const SYS_CLOSE: usize = 57; -const SYS_READ: usize = 63; -const SYS_WRITE: usize = 64; -const SYS_WRITEV: usize = 66; -const SYS_EXIT: usize = 93; -const SYS_EXIT_GROUP: usize = 94; -const SYS_SET_TID_ADDRESS: usize = 96; - -const AT_FDCWD: i32 = -100; - -#[register_trap_handler(SYSCALL)] -fn handle_syscall(tf: &TrapFrame, syscall_num: usize) -> isize { - ax_println!("handle_syscall [{}] ...", syscall_num); - let ret = match syscall_num { - SYS_IOCTL => sys_ioctl(tf.arg0() as _, tf.arg1() as _, tf.arg2() as _) as _, - SYS_SET_TID_ADDRESS => sys_set_tid_address(tf.arg0() as _), - SYS_OPENAT => sys_openat(tf.arg0() as _, tf.arg1() as _, tf.arg2() as _, tf.arg3() as _), - SYS_CLOSE => sys_close(tf.arg0() as _), - SYS_READ => sys_read(tf.arg0() as _, tf.arg1() as _, tf.arg2() as _), - SYS_WRITE => sys_write(tf.arg0() as _, tf.arg1() as _, tf.arg2() as _), - SYS_WRITEV => sys_writev(tf.arg0() as _, tf.arg1() as _, tf.arg2() as _), - SYS_EXIT_GROUP => { - ax_println!("[SYS_EXIT_GROUP]: system is exiting .."); - axtask::exit(tf.arg0() as _) - }, - SYS_EXIT => { - ax_println!("[SYS_EXIT]: system is exiting .."); - axtask::exit(tf.arg0() as _) - }, - _ => { - ax_println!("Unimplemented syscall: {}", syscall_num); - -LinuxError::ENOSYS.code() as _ - } - }; - ret -} - -fn sys_openat(dfd: c_int, fname: *const c_char, flags: c_int, mode: api::ctypes::mode_t) -> isize { - assert_eq!(dfd, AT_FDCWD); - api::sys_open(fname, flags, mode) as isize -} - -fn sys_close(fd: i32) -> isize { - api::sys_close(fd) as isize -} - -fn sys_read(fd: i32, buf: *mut c_void, count: usize) -> isize { - api::sys_read(fd, buf, count) -} - -fn sys_write(fd: i32, buf: *const c_void, count: usize) -> isize { - api::sys_write(fd, buf, count) -} - -fn sys_writev(fd: i32, iov: *const api::ctypes::iovec, iocnt: i32) -> isize { - unsafe { api::sys_writev(fd, iov, iocnt) } -} - -fn sys_set_tid_address(tid_ptd: *const i32) -> isize { - let curr = current(); - curr.task_ext().set_clear_child_tid(tid_ptd as _); - curr.id().as_u64() as isize -} - -fn sys_ioctl(_fd: i32, _op: usize, _argp: *mut c_void) -> i32 { - ax_println!("Ignore SYS_IOCTL"); - 0 -} diff --git a/arceos/tour/m_3_1/src/task.rs b/arceos/tour/m_3_1/src/task.rs deleted file mode 100644 index d5372dd6a..000000000 --- a/arceos/tour/m_3_1/src/task.rs +++ /dev/null @@ -1,71 +0,0 @@ -#![allow(dead_code)] - -use core::sync::atomic::AtomicU64; - -use alloc::sync::Arc; - -use axhal::arch::UspaceContext; -use axmm::AddrSpace; -use axsync::Mutex; -use axtask::{AxTaskRef, TaskExtRef, TaskInner}; - -/// Task extended data for the monolithic kernel. -pub struct TaskExt { - /// The process ID. - pub proc_id: usize, - /// The clear thread tid field - /// - /// See - /// - /// When the thread exits, the kernel clears the word at this address if it is not NULL. - clear_child_tid: AtomicU64, - /// The user space context. - pub uctx: UspaceContext, - /// The virtual memory address space. - pub aspace: Arc>, -} - -impl TaskExt { - pub const fn new(uctx: UspaceContext, aspace: Arc>) -> Self { - Self { - proc_id: 233, - uctx, - clear_child_tid: AtomicU64::new(0), - aspace, - } - } - - pub(crate) fn clear_child_tid(&self) -> u64 { - self.clear_child_tid - .load(core::sync::atomic::Ordering::Relaxed) - } - - pub(crate) fn set_clear_child_tid(&self, clear_child_tid: u64) { - self.clear_child_tid - .store(clear_child_tid, core::sync::atomic::Ordering::Relaxed); - } -} - -axtask::def_task_ext!(TaskExt); - -pub fn spawn_user_task(aspace: Arc>, uctx: UspaceContext) -> AxTaskRef { - let mut task = TaskInner::new( - || { - let curr = axtask::current(); - let kstack_top = curr.kernel_stack_top().unwrap(); - info!( - "Enter user space: entry={:#x}, ustack={:#x}, kstack={:#x}", - curr.task_ext().uctx.get_ip(), - curr.task_ext().uctx.get_sp(), - kstack_top, - ); - unsafe { curr.task_ext().uctx.enter_uspace(kstack_top) }; - }, - "userboot".into(), - crate::KERNEL_STACK_SIZE, - ); - task.ctx_mut() - .set_page_table_root(aspace.lock().page_table_root()); - task.init_task_ext(TaskExt::new(uctx, aspace)); - axtask::spawn_task(task) -} diff --git a/arceos/tour/u_1_0/Cargo.toml b/arceos/tour/u_1_0/Cargo.toml deleted file mode 100644 index 623f5c414..000000000 --- a/arceos/tour/u_1_0/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "u_1_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, optional = true } diff --git a/arceos/tour/u_1_0/src/main.rs b/arceos/tour/u_1_0/src/main.rs deleted file mode 100644 index 6d268a8fc..000000000 --- a/arceos/tour/u_1_0/src/main.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[cfg(feature = "axstd")] -use axstd::println; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - println!("Hello, Arceos!"); -} diff --git a/arceos/tour/u_2_0/Cargo.toml b/arceos/tour/u_2_0/Cargo.toml deleted file mode 100644 index c16c72c3f..000000000 --- a/arceos/tour/u_2_0/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "u_2_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc"], optional = true } diff --git a/arceos/tour/u_2_0/src/main.rs b/arceos/tour/u_2_0/src/main.rs deleted file mode 100644 index ba6031902..000000000 --- a/arceos/tour/u_2_0/src/main.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; -extern crate alloc; - -use alloc::string::String; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - let s = String::from("Hello, axalloc!"); - println!("Alloc String: \"{}\"", s); - - let mut vec = vec![0, 1, 2]; - vec.push(3); - println!("Alloc Vec: {:?}", vec); -} diff --git a/arceos/tour/u_3_0/Cargo.toml b/arceos/tour/u_3_0/Cargo.toml deleted file mode 100644 index c99d44ff9..000000000 --- a/arceos/tour/u_3_0/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "u_3_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging"], optional = true } diff --git a/arceos/tour/u_3_0/src/main.rs b/arceos/tour/u_3_0/src/main.rs deleted file mode 100644 index 516a4017e..000000000 --- a/arceos/tour/u_3_0/src/main.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; - -use core::{mem, str}; -use std::os::arceos::modules::axhal::mem::phys_to_virt; - -/// Physical address for pflash#1 -const PFLASH_START: usize = 0x2200_0000; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - // Makesure that we can access pflash region. - let va = phys_to_virt(PFLASH_START.into()).as_usize(); - let ptr = va as *const u32; - unsafe { - println!("Try to access dev region [{:#X}], got {:#X}", va, *ptr); - let magic = mem::transmute::(*ptr); - println!("Got pflash magic: {}", str::from_utf8(&magic).unwrap()); - } -} diff --git a/arceos/tour/u_4_0/Cargo.toml b/arceos/tour/u_4_0/Cargo.toml deleted file mode 100644 index c1afd3137..000000000 --- a/arceos/tour/u_4_0/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "u_4_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask"], optional = true } diff --git a/arceos/tour/u_4_0/src/main.rs b/arceos/tour/u_4_0/src/main.rs deleted file mode 100644 index a85c60eef..000000000 --- a/arceos/tour/u_4_0/src/main.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; - -use core::{mem, str}; -use std::thread; -use std::os::arceos::modules::axhal::mem::phys_to_virt; - -/// Physical address for pflash#1 -const PFLASH_START: usize = 0x2200_0000; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - println!("Multi-task is starting ..."); - - let worker = thread::spawn(move || { - println!("Spawned-thread ..."); - - // Makesure that we can access pflash region. - let va = phys_to_virt(PFLASH_START.into()).as_usize(); - let ptr = va as *const u32; - let magic = unsafe { - mem::transmute::(*ptr) - }; - if let Ok(s) = str::from_utf8(&magic) { - println!("Got pflash magic: {s}"); - 0 - } else { - -1 - } - }); - - let ret = worker.join(); - // Makesure that worker has finished its work. - assert_eq!(ret, Ok(0)); - - println!("Multi-task OK!"); -} diff --git a/arceos/tour/u_5_0/Cargo.toml b/arceos/tour/u_5_0/Cargo.toml deleted file mode 100644 index b20580e67..000000000 --- a/arceos/tour/u_5_0/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "u_5_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask"], optional = true } diff --git a/arceos/tour/u_5_0/src/main.rs b/arceos/tour/u_5_0/src/main.rs deleted file mode 100644 index c87586ada..000000000 --- a/arceos/tour/u_5_0/src/main.rs +++ /dev/null @@ -1,56 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; - -use std::thread; -use std::collections::VecDeque; -use std::sync::Arc; -use std::os::arceos::modules::axsync::spin::SpinNoIrq; - -const LOOP_NUM: usize = 64; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - println!("Multi-task is starting ..."); - - let q1 = Arc::new(SpinNoIrq::new(VecDeque::new())); - let q2 = q1.clone(); - - let worker1 = thread::spawn(move || { - println!("worker1 ..."); - for i in 0..=LOOP_NUM { - println!("worker1 [{i}]"); - q1.lock().push_back(i); - // NOTE: If worker1 doesn't yield, others have - // no chance to run until it exits! - thread::yield_now(); - } - println!("worker1 ok!"); - }); - - let worker2 = thread::spawn(move || { - println!("worker2 ..."); - loop { - if let Some(num) = q2.lock().pop_front() { - println!("worker2 [{num}]"); - if num == LOOP_NUM { - break; - } - } else { - println!("worker2: nothing to do!"); - // TODO: it should sleep and wait for notify! - thread::yield_now(); - } - } - println!("worker2 ok!"); - }); - - println!("Wait for workers to exit ..."); - let _ = worker1.join(); - let _ = worker2.join(); - - println!("Multi-task OK!"); -} diff --git a/arceos/tour/u_6_0/Cargo.toml b/arceos/tour/u_6_0/Cargo.toml deleted file mode 100644 index de01c0795..000000000 --- a/arceos/tour/u_6_0/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "u_6_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask", "sched_cfs"], optional = true } -axlog = { workspace = true } diff --git a/arceos/tour/u_6_0/src/main.rs b/arceos/tour/u_6_0/src/main.rs deleted file mode 100644 index 87c468f6d..000000000 --- a/arceos/tour/u_6_0/src/main.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[cfg(feature = "axstd")] -extern crate axstd as std; -#[macro_use] -extern crate axlog; - -use std::thread; -use std::collections::VecDeque; -use std::sync::Arc; -use std::os::arceos::modules::axsync::spin::SpinNoIrq; - -const LOOP_NUM: usize = 256; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - ax_println!("Multi-task(Preemptible) is starting ..."); - - let q1 = Arc::new(SpinNoIrq::new(VecDeque::new())); - let q2 = q1.clone(); - - let worker1 = thread::spawn(move || { - ax_println!("worker1 ... {:?}", thread::current().id()); - for i in 0..=LOOP_NUM { - ax_println!("worker1 [{i}]"); - q1.lock().push_back(i); - } - ax_println!("worker1 ok!"); - }); - - let worker2 = thread::spawn(move || { - ax_println!("worker2 ... {:?}", thread::current().id()); - loop { - if let Some(num) = q2.lock().pop_front() { - ax_println!("worker2 [{num}]"); - if num == LOOP_NUM { - break; - } - } else { - ax_println!("worker2: nothing to do!"); - // TODO: it should sleep and wait for notify! - thread::yield_now(); - } - } - ax_println!("worker2 ok!"); - }); - - ax_println!("Wait for workers to exit ..."); - let _ = worker1.join(); - let _ = worker2.join(); - - ax_println!("Multi-task(Preemptible) ok!"); -} diff --git a/arceos/tour/u_6_1/Cargo.toml b/arceos/tour/u_6_1/Cargo.toml deleted file mode 100644 index bbeaf2ad5..000000000 --- a/arceos/tour/u_6_1/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "u_6_1" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask", "sched_cfs"], optional = true } -axlog = { workspace = true } diff --git a/arceos/tour/u_6_1/src/main.rs b/arceos/tour/u_6_1/src/main.rs deleted file mode 100644 index 0ab900d0b..000000000 --- a/arceos/tour/u_6_1/src/main.rs +++ /dev/null @@ -1,56 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[cfg(feature = "axstd")] -extern crate axstd as std; -#[macro_use] -extern crate axlog; - -use std::thread; -use std::collections::VecDeque; -use std::sync::Arc; -use std::sync::Mutex; -use std::os::arceos::modules::axtask::WaitQueue; - -const LOOP_NUM: usize = 256; -static WQ: WaitQueue = WaitQueue::new(); - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - ax_println!("WaitQ is starting ..."); - - let q1 = Arc::new(Mutex::new(VecDeque::new())); - let q2 = q1.clone(); - - let worker1 = thread::spawn(move || { - ax_println!("worker1 ..."); - for i in 0..=LOOP_NUM { - ax_println!("worker1 [{i}]"); - q1.lock().push_back(i); - WQ.notify_one(true); - } - ax_println!("worker1 ok!"); - }); - - let worker2 = thread::spawn(move || { - ax_println!("worker2 ..."); - loop { - if let Some(num) = q2.lock().pop_front() { - ax_println!("worker2 [{num}]"); - if num == LOOP_NUM { - break; - } - continue; - } - - WQ.wait(); - } - ax_println!("worker2 ok!"); - }); - - ax_println!("Wait for workers to exit ..."); - let _ = worker1.join(); - let _ = worker2.join(); - - ax_println!("WaitQ ok!"); -} diff --git a/arceos/tour/u_7_0/Cargo.toml b/arceos/tour/u_7_0/Cargo.toml deleted file mode 100644 index 410557ed5..000000000 --- a/arceos/tour/u_7_0/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "u_7_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask", "sched_cfs"], optional = true } -axdriver = { workspace = true, features = ["virtio-blk"] } diff --git a/arceos/tour/u_7_0/src/main.rs b/arceos/tour/u_7_0/src/main.rs deleted file mode 100644 index 8f1725dda..000000000 --- a/arceos/tour/u_7_0/src/main.rs +++ /dev/null @@ -1,43 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; - -use std::thread; -use axdriver::prelude::{DeviceType, BaseDriverOps, BlockDriverOps}; - -const DISK_SIZE: usize = 0x400_0000; // 64M -const BLOCK_SIZE: usize = 0x200; // 512-bytes in default - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - println!("Load app from disk ..."); - - let mut alldevs = axdriver::init_drivers(); - let mut disk = alldevs.block.take_one().expect("No block dev!"); - - assert_eq!(disk.device_type(), DeviceType::Block); - assert_eq!(disk.device_name(), "virtio-blk"); - assert_eq!(disk.block_size(), BLOCK_SIZE); - assert_eq!(disk.num_blocks() as usize, DISK_SIZE/BLOCK_SIZE); - - let mut buf = vec![0u8; BLOCK_SIZE]; - assert!(disk.read_block(0, &mut buf).is_ok()); - - let worker1 = thread::spawn(move || { - println!("worker1 checks head:"); - let head = core::str::from_utf8(&buf[3..11]) - .unwrap_or_else(|e| { - panic!("bad disk head: {:?}. err {:?}", &buf[0..16], e); - }); - println!("[{}]", head); - println!("\nworker1 ok!"); - }); - - println!("Wait for workers to exit ..."); - let _ = worker1.join(); - - println!("Load app from disk ok!"); -} diff --git a/arceos/tour/u_8_0/Cargo.toml b/arceos/tour/u_8_0/Cargo.toml deleted file mode 100644 index ff2d39685..000000000 --- a/arceos/tour/u_8_0/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "u_8_0" -version = "0.1.0" -edition = "2021" - -[dependencies] -axstd = { workspace = true, features = ["alloc", "paging", "multitask", "sched_cfs", "fs"], optional = true } diff --git a/arceos/tour/u_8_0/src/main.rs b/arceos/tour/u_8_0/src/main.rs deleted file mode 100644 index 3de8407ce..000000000 --- a/arceos/tour/u_8_0/src/main.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![cfg_attr(feature = "axstd", no_std)] -#![cfg_attr(feature = "axstd", no_main)] - -#[macro_use] -#[cfg(feature = "axstd")] -extern crate axstd as std; - -use std::thread; -use std::io::{self, prelude::*}; -use std::fs::File; - -#[cfg_attr(feature = "axstd", no_mangle)] -fn main() { - println!("Load app from fat-fs ..."); - - let mut buf = [0u8; 64]; - if let Err(e) = load_app("/sbin/origin.bin", &mut buf) { - panic!("Cannot load app! {:?}", e); - } - - let worker1 = thread::spawn(move || { - println!("worker1 checks code: "); - for i in 0..8 { - print!("{:#x} ", buf[i]); - } - println!("\nworker1 ok!"); - }); - - println!("Wait for workers to exit ..."); - let _ = worker1.join(); - - println!("Load app from disk ok!"); -} - -fn load_app(fname: &str, buf: &mut [u8]) -> io::Result { - println!("fname: {}", fname); - let mut file = File::open(fname)?; - let n = file.read(buf)?; - Ok(n) -} diff --git a/arceos/ulib/axlibc/.gitignore b/arceos/ulib/axlibc/.gitignore deleted file mode 100644 index b5b452628..000000000 --- a/arceos/ulib/axlibc/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -src/libctypes_gen.rs -include/ax_pthread_mutex.h -build_* diff --git a/arceos/ulib/axlibc/Cargo.toml b/arceos/ulib/axlibc/Cargo.toml deleted file mode 100644 index 8ffae102b..000000000 --- a/arceos/ulib/axlibc/Cargo.toml +++ /dev/null @@ -1,60 +0,0 @@ -[package] -name = "axlibc" -version.workspace = true -edition = "2021" -authors = [ - "Yuekai Jia ", - "yanjuguang ", - "wudashuai ", - "yfblock <321353225@qq.com>", - "scPointer ", - "Shiping Yuan ", -] -description = "ArceOS user program library for C apps" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/ulib/axlibc" -documentation = "https://arceos-org.github.io/arceos/axlibc/index.html" - -[lib] -crate-type = ["staticlib"] - -[features] -default = [] - -# Multicore -smp = ["arceos_posix_api/smp"] - -# Floating point/SIMD -fp_simd = ["axfeat/fp_simd"] - -# Interrupts -irq = ["arceos_posix_api/irq", "axfeat/irq"] - -# Memory -alloc = ["arceos_posix_api/alloc"] -tls = ["alloc", "axfeat/tls"] - -# Multi-task -multitask = ["arceos_posix_api/multitask"] - -# File system -fs = ["arceos_posix_api/fs", "fd"] - -# Networking -net = ["arceos_posix_api/net", "fd"] - -# Libc features -fd = [] -pipe = ["arceos_posix_api/pipe"] -select = ["arceos_posix_api/select"] -epoll = ["arceos_posix_api/epoll"] - -[dependencies] -axfeat = { workspace = true } -arceos_posix_api = { workspace = true } -axio = "0.1" -axerrno = "0.1" - -[build-dependencies] -bindgen ={ version = "0.69" } diff --git a/arceos/ulib/axlibc/build.rs b/arceos/ulib/axlibc/build.rs deleted file mode 100644 index 6c33c929c..000000000 --- a/arceos/ulib/axlibc/build.rs +++ /dev/null @@ -1,24 +0,0 @@ -fn main() { - fn gen_c_to_rust_bindings(in_file: &str, out_file: &str) { - println!("cargo:rerun-if-changed={in_file}"); - - let allow_types = ["tm", "jmp_buf"]; - let mut builder = bindgen::Builder::default() - .header(in_file) - .clang_arg("-I./include") - .derive_default(true) - .size_t_is_usize(false) - .use_core(); - for ty in allow_types { - builder = builder.allowlist_type(ty); - } - - builder - .generate() - .expect("Unable to generate c->rust bindings") - .write_to_file(out_file) - .expect("Couldn't write bindings!"); - } - - gen_c_to_rust_bindings("ctypes.h", "src/libctypes_gen.rs"); -} diff --git a/arceos/ulib/axlibc/c/assert.c b/arceos/ulib/axlibc/c/assert.c deleted file mode 100644 index ee071677d..000000000 --- a/arceos/ulib/axlibc/c/assert.c +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include - -_Noreturn void __assert_fail(const char *expr, const char *file, int line, const char *func) -{ - fprintf(stderr, "Assertion failed: %s (%s: %s: %d)\n", expr, file, func, line); - abort(); -} diff --git a/arceos/ulib/axlibc/c/ctype.c b/arceos/ulib/axlibc/c/ctype.c deleted file mode 100644 index 08e8e5e07..000000000 --- a/arceos/ulib/axlibc/c/ctype.c +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include -#include - -int tolower(int c) -{ - if (isupper(c)) - return c | 32; - return c; -} - -int toupper(int c) -{ - if (islower(c)) - return c & 0x5f; - return c; -} diff --git a/arceos/ulib/axlibc/c/dirent.c b/arceos/ulib/axlibc/c/dirent.c deleted file mode 100644 index a69094a7d..000000000 --- a/arceos/ulib/axlibc/c/dirent.c +++ /dev/null @@ -1,98 +0,0 @@ -#ifdef AX_CONFIG_FS - -#include -#include -#include -#include -#include -#include -#include -#include - -int closedir(DIR *dir) -{ - int ret = close(dir->fd); - free(dir); - return ret; -} - -DIR *fdopendir(int fd) -{ - DIR *dir; - struct stat st; - - if (fstat(fd, &st) < 0) { - return 0; - } - if (fcntl(fd, F_GETFL) & O_PATH) { - errno = EBADF; - return 0; - } - if (!S_ISDIR(st.st_mode)) { - errno = ENOTDIR; - return 0; - } - if (!(dir = calloc(1, sizeof(*dir)))) { - return 0; - } - - fcntl(fd, F_SETFD, FD_CLOEXEC); - dir->fd = fd; - return dir; -} - -int dirfd(DIR *d) -{ - return d->fd; -} - -// TODO -DIR *opendir(const char *__name) -{ - unimplemented(); - return NULL; -} - -// TODO -struct dirent *readdir(DIR *__dirp) -{ - unimplemented(); - return NULL; -} - -// TODO -int readdir_r(DIR *restrict dir, struct dirent *restrict buf, struct dirent **restrict result) -{ - struct dirent *de; - int errno_save = errno; - int ret; - - // LOCK(dir->lock); - errno = 0; - de = readdir(dir); - if ((ret = errno)) { - // UNLOCK(dir->lock); - return ret; - } - errno = errno_save; - if (de) - memcpy(buf, de, de->d_reclen); - else - buf = NULL; - - // UNLOCK(dir->lock); - *result = buf; - return 0; -} - -// TODO -void rewinddir(DIR *dir) -{ - // LOCK(dir->lock); - lseek(dir->fd, 0, SEEK_SET); - dir->buf_pos = dir->buf_end = 0; - dir->tell = 0; - // UNLOCK(dir->lock); -} - -#endif // AX_CONFIG_FS diff --git a/arceos/ulib/axlibc/c/dlfcn.c b/arceos/ulib/axlibc/c/dlfcn.c deleted file mode 100644 index a539e7d0c..000000000 --- a/arceos/ulib/axlibc/c/dlfcn.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -#include - -// TODO -int dladdr(const void *__address, Dl_info *__info) -{ - unimplemented(); - return 0; -} - -// TODO -void *dlopen(const char *__file, int __mode) -{ - unimplemented(); - return NULL; -} - -// TODO -char *dlerror() -{ - unimplemented(); - return NULL; -} - -// TODO -void *dlsym(void *__restrict__ __handle, const char *__restrict__ __name) -{ - - unimplemented(); - return NULL; -} - -// TODO -int dlclose(void *p) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/c/env.c b/arceos/ulib/axlibc/c/env.c deleted file mode 100644 index a0505a9ee..000000000 --- a/arceos/ulib/axlibc/c/env.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include -#include - -char *environ_[2] = {"dummy", NULL}; -char **environ = (char **)environ_; - -char *getenv(const char *name) -{ - size_t l = strchrnul(name, '=') - name; - if (l && !name[l] && environ) - for (char **e = environ; *e; e++) - if (!strncmp(name, *e, l) && l[*e] == '=') - return *e + l + 1; - return 0; -} - -// TODO -int setenv(const char *__name, const char *__value, int __replace) -{ - unimplemented(); - return 0; -} - -// TODO -int unsetenv(const char *__name) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/c/fcntl.c b/arceos/ulib/axlibc/c/fcntl.c deleted file mode 100644 index fa9091713..000000000 --- a/arceos/ulib/axlibc/c/fcntl.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include - -#ifdef AX_CONFIG_FD - -// TODO: remove this function in future work -int ax_fcntl(int fd, int cmd, size_t arg); - -int fcntl(int fd, int cmd, ... /* arg */) -{ - unsigned long arg; - va_list ap; - va_start(ap, cmd); - arg = va_arg(ap, unsigned long); - va_end(ap); - - return ax_fcntl(fd, cmd, arg); -} - -#endif // AX_CONFIG_FD - -#ifdef AX_CONFIG_FS - -// TODO: remove this function in future work -int ax_open(const char *filename, int flags, mode_t mode); - -int open(const char *filename, int flags, ...) -{ - mode_t mode = 0; - - if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) { - va_list ap; - va_start(ap, flags); - mode = va_arg(ap, mode_t); - va_end(ap); - } - - return ax_open(filename, flags, mode); -} - -// TODO -int posix_fadvise(int __fd, unsigned long __offset, unsigned long __len, int __advise) -{ - unimplemented(); - return 0; -} - -// TODO -int sync_file_range(int fd, off_t pos, off_t len, unsigned flags) -{ - unimplemented(); - return 0; -} - -#endif // AX_CONFIG_FS diff --git a/arceos/ulib/axlibc/c/flock.c b/arceos/ulib/axlibc/c/flock.c deleted file mode 100644 index 8ac9beec5..000000000 --- a/arceos/ulib/axlibc/c/flock.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -// TODO -int flock(int __fd, int __operation) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/c/fnmatch.c b/arceos/ulib/axlibc/c/fnmatch.c deleted file mode 100644 index 3895fa2c8..000000000 --- a/arceos/ulib/axlibc/c/fnmatch.c +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include - -#define END 0 -#define UNMATCHABLE -2 -#define BRACKET -3 -#define QUESTION -4 -#define STAR -5 - -// TODO -int fnmatch(const char *pat, const char *str, int flags) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/c/glob.c b/arceos/ulib/axlibc/c/glob.c deleted file mode 100644 index 841a226dd..000000000 --- a/arceos/ulib/axlibc/c/glob.c +++ /dev/null @@ -1,329 +0,0 @@ -#ifdef AX_CONFIG_FS - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct match { - struct match *next; - char name[]; -}; - -static int append(struct match **tail, const char *name, size_t len, int mark) -{ - struct match *new = malloc(sizeof(struct match) + len + 2); - if (!new) - return -1; - (*tail)->next = new; - new->next = NULL; - memcpy(new->name, name, len + 1); - if (mark && len && name[len - 1] != '/') { - new->name[len] = '/'; - new->name[len + 1] = 0; - } - *tail = new; - return 0; -} - -static int do_glob(char *buf, size_t pos, int type, char *pat, int flags, - int (*errfunc)(const char *path, int err), struct match **tail) -{ - /* If GLOB_MARK is unused, we don't care about type. */ - if (!type && !(flags & GLOB_MARK)) - type = DT_REG; - - /* Special-case the remaining pattern being all slashes, in - * which case we can use caller-passed type if it's a dir. */ - if (*pat && type != DT_DIR) - type = 0; - while (pos + 1 < PATH_MAX && *pat == '/') buf[pos++] = *pat++; - - /* Consume maximal [escaped-]literal prefix of pattern, copying - * and un-escaping it to the running buffer as we go. */ - long i = 0, j = 0; - int in_bracket = 0, overflow = 0; - for (; pat[i] != '*' && pat[i] != '?' && (!in_bracket || pat[i] != ']'); i++) { - if (!pat[i]) { - if (overflow) - return 0; - pat += i; - pos += j; - i = j = 0; - break; - } else if (pat[i] == '[') { - in_bracket = 1; - } else if (pat[i] == '\\' && !(flags & GLOB_NOESCAPE)) { - /* Backslashes inside a bracket are (at least by - * our interpretation) non-special, so if next - * char is ']' we have a complete expression. */ - if (in_bracket && pat[i + 1] == ']') - break; - /* Unpaired final backslash never matches. */ - if (!pat[i + 1]) - return 0; - i++; - } - if (pat[i] == '/') { - if (overflow) - return 0; - in_bracket = 0; - pat += i + 1; - i = -1; - pos += j + 1; - j = -1; - } - /* Only store a character if it fits in the buffer, but if - * a potential bracket expression is open, the overflow - * must be remembered and handled later only if the bracket - * is unterminated (and thereby a literal), so as not to - * disallow long bracket expressions with short matches. */ - if (pos + (j + 1) < PATH_MAX) { - buf[pos + j++] = pat[i]; - } else if (in_bracket) { - overflow = 1; - } else { - return 0; - } - /* If we consume any new components, the caller-passed type - * or dummy type from above is no longer valid. */ - type = 0; - } - buf[pos] = 0; - if (!*pat) { - /* If we consumed any components above, or if GLOB_MARK is - * requested and we don't yet know if the match is a dir, - * we must confirm the file exists and/or determine its type. - * - * If marking dirs, symlink type is inconclusive; we need the - * type for the symlink target, and therefore must try stat - * first unless type is known not to be a symlink. Otherwise, - * or if that fails, use lstat for determining existence to - * avoid false negatives in the case of broken symlinks. */ - struct stat st; - if ((flags & GLOB_MARK) && (!type || type == DT_LNK) && !stat(buf, &st)) { - if (S_ISDIR(st.st_mode)) - type = DT_DIR; - else - type = DT_REG; - } - if (!type && lstat(buf, &st)) { - if (errno != ENOENT && (errfunc(buf, errno) || (flags & GLOB_ERR))) - return GLOB_ABORTED; - return 0; - } - if (append(tail, buf, pos, (flags & GLOB_MARK) && type == DT_DIR)) - return GLOB_NOSPACE; - return 0; - } - char *p2 = strchr(pat, '/'), saved_sep = '/'; - /* Check if the '/' was escaped and, if so, remove the escape char - * so that it will not be unpaired when passed to fnmatch. */ - if (p2 && !(flags & GLOB_NOESCAPE)) { - char *p; - for (p = p2; p > pat && p[-1] == '\\'; p--) - ; - if ((p2 - p) % 2) { - p2--; - saved_sep = '\\'; - } - } - DIR *dir = opendir(pos ? buf : "."); - if (!dir) { - if (errfunc(buf, errno) || (flags & GLOB_ERR)) - return GLOB_ABORTED; - return 0; - } - int old_errno = errno; - struct dirent *de; - while (errno = 0, de = readdir(dir)) { - /* Quickly skip non-directories when there's pattern left. */ - if (p2 && de->d_type && de->d_type != DT_DIR && de->d_type != DT_LNK) - continue; - - size_t l = strlen(de->d_name); - if (l >= PATH_MAX - pos) - continue; - - if (p2) - *p2 = 0; - - int fnm_flags = ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) | - ((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0); - - if (fnmatch(pat, de->d_name, fnm_flags)) - continue; - - /* With GLOB_PERIOD, don't allow matching . or .. unless - * fnmatch would match them with FNM_PERIOD rules in effect. */ - if (p2 && (flags & GLOB_PERIOD) && de->d_name[0] == '.' && - (!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2])) && - fnmatch(pat, de->d_name, fnm_flags | FNM_PERIOD)) - continue; - - memcpy(buf + pos, de->d_name, l + 1); - if (p2) - *p2 = saved_sep; - int r = do_glob(buf, pos + l, de->d_type, p2 ? p2 : "", flags, errfunc, tail); - if (r) { - closedir(dir); - return r; - } - } - int readerr = errno; - if (p2) - *p2 = saved_sep; - closedir(dir); - if (readerr && (errfunc(buf, errno) || (flags & GLOB_ERR))) - return GLOB_ABORTED; - errno = old_errno; - return 0; -} - -static int ignore_err(const char *path, int err) -{ - return 0; -} - -static void freelist(struct match *head) -{ - struct match *match, *next; - for (match = head->next; match; match = next) { - next = match->next; - free(match); - } -} - -static int sort(const void *a, const void *b) -{ - return strcmp(*(const char **)a, *(const char **)b); -} - -static int expand_tilde(char **pat, char *buf, size_t *pos) -{ - char *p = *pat + 1; - size_t i = 0; - - char delim, *name_end = strchrnul(p, '/'); - if ((delim = *name_end)) - *name_end++ = 0; - *pat = name_end; - - char *home = *p ? NULL : getenv("HOME"); - if (!home) { - struct passwd pw, *res; - switch (*p ? getpwnam_r(p, &pw, buf, PATH_MAX, &res) - : getpwuid_r(getuid(), &pw, buf, PATH_MAX, &res)) { - case ENOMEM: - return GLOB_NOSPACE; - case 0: - if (!res) - default: - return GLOB_NOMATCH; - } - home = pw.pw_dir; - } - while (i < PATH_MAX - 2 && *home) buf[i++] = *home++; - if (*home) - return GLOB_NOMATCH; - if ((buf[i] = delim)) - buf[++i] = 0; - *pos = i; - return 0; -} - -int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, int err), - glob_t *restrict g) -{ - struct match head = {.next = NULL}, *tail = &head; - size_t cnt, i; - size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0; - int error = 0; - char buf[PATH_MAX]; - - if (!errfunc) - errfunc = ignore_err; - - if (!(flags & GLOB_APPEND)) { - g->gl_offs = offs; - g->gl_pathc = 0; - g->gl_pathv = NULL; - } - - if (*pat) { - char *p = strdup(pat); - if (!p) - return GLOB_NOSPACE; - buf[0] = 0; - size_t pos = 0; - char *s = p; - if ((flags & (GLOB_TILDE | GLOB_TILDE_CHECK)) && *p == '~') - error = expand_tilde(&s, buf, &pos); - if (!error) - error = do_glob(buf, pos, 0, s, flags, errfunc, &tail); - free(p); - } - - if (error == GLOB_NOSPACE) { - freelist(&head); - return error; - } - - for (cnt = 0, tail = head.next; tail; tail = tail->next, cnt++) - ; - if (!cnt) { - if (flags & GLOB_NOCHECK) { - tail = &head; - if (append(&tail, pat, strlen(pat), 0)) - return GLOB_NOSPACE; - cnt++; - } else - return GLOB_NOMATCH; - } - - if (flags & GLOB_APPEND) { - char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *)); - if (!pathv) { - freelist(&head); - return GLOB_NOSPACE; - } - g->gl_pathv = pathv; - offs += g->gl_pathc; - } else { - g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *)); - if (!g->gl_pathv) { - freelist(&head); - return GLOB_NOSPACE; - } - for (i = 0; i < offs; i++) g->gl_pathv[i] = NULL; - } - for (i = 0, tail = head.next; i < cnt; tail = tail->next, i++) - g->gl_pathv[offs + i] = tail->name; - g->gl_pathv[offs + i] = NULL; - g->gl_pathc += cnt; - - if (!(flags & GLOB_NOSORT)) - qsort(g->gl_pathv + offs, cnt, sizeof(char *), sort); - - return error; -} - -void globfree(glob_t *g) -{ - size_t i; - for (i = 0; i < g->gl_pathc; i++) - free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name)); - free(g->gl_pathv); - g->gl_pathc = 0; - g->gl_pathv = NULL; -} - -#endif // AX_CONFIG_FS diff --git a/arceos/ulib/axlibc/c/ioctl.c b/arceos/ulib/axlibc/c/ioctl.c deleted file mode 100644 index df2aad167..000000000 --- a/arceos/ulib/axlibc/c/ioctl.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -// TODO -int ioctl(int __fd, int __request, ...) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/c/libgen.c b/arceos/ulib/axlibc/c/libgen.c deleted file mode 100644 index fbce88154..000000000 --- a/arceos/ulib/axlibc/c/libgen.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include - -char *dirname(char *s) -{ - size_t i; - if (!s || !*s) - return "."; - i = strlen(s) - 1; - for (; s[i] == '/'; i--) - if (!i) - return "/"; - for (; s[i] != '/'; i--) - if (!i) - return "."; - for (; s[i] == '/'; i--) - if (!i) - return "/"; - s[i + 1] = 0; - return s; -} - -char *basename(char *s) -{ - size_t i; - if (!s || !*s) - return "."; - i = strlen(s) - 1; - for (; i && s[i] == '/'; i--) s[i] = 0; - for (; i && s[i - 1] != '/'; i--) - ; - return s + i; -} diff --git a/arceos/ulib/axlibc/c/libm.c b/arceos/ulib/axlibc/c/libm.c deleted file mode 100644 index c8420112e..000000000 --- a/arceos/ulib/axlibc/c/libm.c +++ /dev/null @@ -1,17 +0,0 @@ -#ifdef AX_CONFIG_FP_SIMD - -#include - -#include "libm.h" - -double __math_divzero(uint32_t sign) -{ - return fp_barrier(sign ? -1.0 : 1.0) / 0.0; -} - -double __math_invalid(double x) -{ - return (x - x) / (x - x); -} - -#endif // AX_CONFIG_FP_SIMD diff --git a/arceos/ulib/axlibc/c/libm.h b/arceos/ulib/axlibc/c/libm.h deleted file mode 100644 index ac9130d7b..000000000 --- a/arceos/ulib/axlibc/c/libm.h +++ /dev/null @@ -1,233 +0,0 @@ -#ifndef _LIBM_H -#define _LIBM_H - -#if AX_CONFIG_FP_SIMD - -#include -#include -#include - -#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 -#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN -union ldshape { - long double f; - struct { - uint64_t m; - uint16_t se; - } i; -}; -#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN -/* This is the m68k variant of 80-bit long double, and this definition only works - * on archs where the alignment requirement of uint64_t is <= 4. */ -union ldshape { - long double f; - struct { - uint16_t se; - uint16_t pad; - uint64_t m; - } i; -}; -#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN -union ldshape { - long double f; - struct { - uint64_t lo; - uint32_t mid; - uint16_t top; - uint16_t se; - } i; - struct { - uint64_t lo; - uint64_t hi; - } i2; -}; -#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN -union ldshape { - long double f; - struct { - uint16_t se; - uint16_t top; - uint32_t mid; - uint64_t lo; - } i; - struct { - uint64_t hi; - uint64_t lo; - } i2; -}; -#else -#error Unsupported long double representation -#endif - -/* Support non-nearest rounding mode. */ -#define WANT_ROUNDING 1 -/* Support signaling NaNs. */ -#define WANT_SNAN 0 - -#if WANT_SNAN -#error SNaN is unsupported -#else -#define issignalingf_inline(x) 0 -#define issignaling_inline(x) 0 -#endif - -#ifndef TOINT_INTRINSICS -#define TOINT_INTRINSICS 0 -#endif - -#if TOINT_INTRINSICS -/* Round x to nearest int in all rounding modes, ties have to be rounded - consistently with converttoint so the results match. If the result - would be outside of [-2^31, 2^31-1] then the semantics is unspecified. */ -static double_t roundtoint(double_t); - -/* Convert x to nearest int in all rounding modes, ties have to be rounded - consistently with roundtoint. If the result is not representible in an - int32_t then the semantics is unspecified. */ -static int32_t converttoint(double_t); -#endif - -/* Helps static branch prediction so hot path can be better optimized. */ -#ifdef __GNUC__ -#define predict_true(x) __builtin_expect(!!(x), 1) -#define predict_false(x) __builtin_expect(x, 0) -#else -#define predict_true(x) (x) -#define predict_false(x) (x) -#endif - -/* Evaluate an expression as the specified type. With standard excess - precision handling a type cast or assignment is enough (with - -ffloat-store an assignment is required, in old compilers argument - passing and return statement may not drop excess precision). */ - -static inline float eval_as_float(float x) -{ - float y = x; - return y; -} - -static inline double eval_as_double(double x) -{ - double y = x; - return y; -} - -/* fp_barrier returns its input, but limits code transformations - as if it had a side-effect (e.g. observable io) and returned - an arbitrary value. */ - -#ifndef fp_barrierf -#define fp_barrierf fp_barrierf -static inline float fp_barrierf(float x) -{ - volatile float y = x; - return y; -} -#endif - -#ifndef fp_barrier -#define fp_barrier fp_barrier -static inline double fp_barrier(double x) -{ - volatile double y = x; - return y; -} -#endif - -#ifndef fp_barrierl -#define fp_barrierl fp_barrierl -static inline long double fp_barrierl(long double x) -{ - volatile long double y = x; - return y; -} -#endif - -/* fp_force_eval ensures that the input value is computed when that's - otherwise unused. To prevent the constant folding of the input - expression, an additional fp_barrier may be needed or a compilation - mode that does so (e.g. -frounding-math in gcc). Then it can be - used to evaluate an expression for its fenv side-effects only. */ - -#ifndef fp_force_evalf -#define fp_force_evalf fp_force_evalf -static inline void fp_force_evalf(float x) -{ - volatile float y; - y = x; -} -#endif - -#ifndef fp_force_eval -#define fp_force_eval fp_force_eval -static inline void fp_force_eval(double x) -{ - volatile double y; - y = x; -} -#endif - -#ifndef fp_force_evall -#define fp_force_evall fp_force_evall -static inline void fp_force_evall(long double x) -{ - volatile long double y; - y = x; -} -#endif - -#define FORCE_EVAL(x) \ - do { \ - if (sizeof(x) == sizeof(float)) { \ - fp_force_evalf(x); \ - } else if (sizeof(x) == sizeof(double)) { \ - fp_force_eval(x); \ - } else { \ - fp_force_evall(x); \ - } \ - } while (0) - -#define asuint(f) \ - ((union { \ - float _f; \ - uint32_t _i; \ - }){f}) \ - ._i -#define asfloat(i) \ - ((union { \ - uint32_t _i; \ - float _f; \ - }){i}) \ - ._f -#define asuint64(f) \ - ((union { \ - double _f; \ - uint64_t _i; \ - }){f}) \ - ._i -#define asdouble(i) \ - ((union { \ - uint64_t _i; \ - double _f; \ - }){i}) \ - ._f - -/* error handling functions */ -float __math_xflowf(uint32_t, float); -float __math_uflowf(uint32_t); -float __math_oflowf(uint32_t); -float __math_divzerof(uint32_t); -float __math_invalidf(float); -double __math_xflow(uint32_t, double); -double __math_uflow(uint32_t); -double __math_oflow(uint32_t); -double __math_divzero(uint32_t); -double __math_invalid(double); -#if LDBL_MANT_DIG != DBL_MANT_DIG -long double __math_invalidl(long double); -#endif - -#endif // AX_CONFIG_FP_SIMD - -#endif // _LIBM_H diff --git a/arceos/ulib/axlibc/c/locale.c b/arceos/ulib/axlibc/c/locale.c deleted file mode 100644 index 9c535ac3d..000000000 --- a/arceos/ulib/axlibc/c/locale.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include - -// TODO -char *setlocale(int __category, const char *__locale) -{ - unimplemented(); - return NULL; -} - -static const struct lconv posix_lconv = { - .decimal_point = ".", - .thousands_sep = "", - .grouping = "", - .int_curr_symbol = "", - .currency_symbol = "", - .mon_decimal_point = "", - .mon_thousands_sep = "", - .mon_grouping = "", - .positive_sign = "", - .negative_sign = "", - .int_frac_digits = CHAR_MAX, - .frac_digits = CHAR_MAX, - .p_cs_precedes = CHAR_MAX, - .p_sep_by_space = CHAR_MAX, - .n_cs_precedes = CHAR_MAX, - .n_sep_by_space = CHAR_MAX, - .p_sign_posn = CHAR_MAX, - .n_sign_posn = CHAR_MAX, - .int_p_cs_precedes = CHAR_MAX, - .int_p_sep_by_space = CHAR_MAX, - .int_n_cs_precedes = CHAR_MAX, - .int_n_sep_by_space = CHAR_MAX, - .int_p_sign_posn = CHAR_MAX, - .int_n_sign_posn = CHAR_MAX, -}; - -struct lconv *localeconv(void) -{ - return (void *)&posix_lconv; -} diff --git a/arceos/ulib/axlibc/c/log.c b/arceos/ulib/axlibc/c/log.c deleted file mode 100644 index 4e34aa0ac..000000000 --- a/arceos/ulib/axlibc/c/log.c +++ /dev/null @@ -1,395 +0,0 @@ -#ifdef AX_CONFIG_FP_SIMD - -#include -#include -#include -#include - -#include "libm.h" - -struct log_data { - double ln2hi; - double ln2lo; - double poly[LOG_POLY_ORDER - 1]; - double poly1[LOG_POLY1_ORDER - 1]; - struct { - double invc, logc; - } tab[1 << LOG_TABLE_BITS]; -#if !__FP_FAST_FMA - struct { - double chi, clo; - } tab2[1 << LOG_TABLE_BITS]; -#endif -}; - -const struct log_data __log_data = { - .ln2hi = 0x1.62e42fefa3800p-1, - .ln2lo = 0x1.ef35793c76730p-45, - .poly1 = - { - -0x1p-1, - 0x1.5555555555577p-2, - -0x1.ffffffffffdcbp-3, - 0x1.999999995dd0cp-3, - -0x1.55555556745a7p-3, - 0x1.24924a344de3p-3, - -0x1.fffffa4423d65p-4, - 0x1.c7184282ad6cap-4, - -0x1.999eb43b068ffp-4, - 0x1.78182f7afd085p-4, - -0x1.5521375d145cdp-4, - }, - .poly = - { - -0x1.0000000000001p-1, - 0x1.555555551305bp-2, - -0x1.fffffffeb459p-3, - 0x1.999b324f10111p-3, - -0x1.55575e506c89fp-3, - }, - .tab = - { - {0x1.734f0c3e0de9fp+0, -0x1.7cc7f79e69000p-2}, - {0x1.713786a2ce91fp+0, -0x1.76feec20d0000p-2}, - {0x1.6f26008fab5a0p+0, -0x1.713e31351e000p-2}, - {0x1.6d1a61f138c7dp+0, -0x1.6b85b38287800p-2}, - {0x1.6b1490bc5b4d1p+0, -0x1.65d5590807800p-2}, - {0x1.69147332f0cbap+0, -0x1.602d076180000p-2}, - {0x1.6719f18224223p+0, -0x1.5a8ca86909000p-2}, - {0x1.6524f99a51ed9p+0, -0x1.54f4356035000p-2}, - {0x1.63356aa8f24c4p+0, -0x1.4f637c36b4000p-2}, - {0x1.614b36b9ddc14p+0, -0x1.49da7fda85000p-2}, - {0x1.5f66452c65c4cp+0, -0x1.445923989a800p-2}, - {0x1.5d867b5912c4fp+0, -0x1.3edf439b0b800p-2}, - {0x1.5babccb5b90dep+0, -0x1.396ce448f7000p-2}, - {0x1.59d61f2d91a78p+0, -0x1.3401e17bda000p-2}, - {0x1.5805612465687p+0, -0x1.2e9e2ef468000p-2}, - {0x1.56397cee76bd3p+0, -0x1.2941b3830e000p-2}, - {0x1.54725e2a77f93p+0, -0x1.23ec58cda8800p-2}, - {0x1.52aff42064583p+0, -0x1.1e9e129279000p-2}, - {0x1.50f22dbb2bddfp+0, -0x1.1956d2b48f800p-2}, - {0x1.4f38f4734ded7p+0, -0x1.141679ab9f800p-2}, - {0x1.4d843cfde2840p+0, -0x1.0edd094ef9800p-2}, - {0x1.4bd3ec078a3c8p+0, -0x1.09aa518db1000p-2}, - {0x1.4a27fc3e0258ap+0, -0x1.047e65263b800p-2}, - {0x1.4880524d48434p+0, -0x1.feb224586f000p-3}, - {0x1.46dce1b192d0bp+0, -0x1.f474a7517b000p-3}, - {0x1.453d9d3391854p+0, -0x1.ea4443d103000p-3}, - {0x1.43a2744b4845ap+0, -0x1.e020d44e9b000p-3}, - {0x1.420b54115f8fbp+0, -0x1.d60a22977f000p-3}, - {0x1.40782da3ef4b1p+0, -0x1.cc00104959000p-3}, - {0x1.3ee8f5d57fe8fp+0, -0x1.c202956891000p-3}, - {0x1.3d5d9a00b4ce9p+0, -0x1.b81178d811000p-3}, - {0x1.3bd60c010c12bp+0, -0x1.ae2c9ccd3d000p-3}, - {0x1.3a5242b75dab8p+0, -0x1.a45402e129000p-3}, - {0x1.38d22cd9fd002p+0, -0x1.9a877681df000p-3}, - {0x1.3755bc5847a1cp+0, -0x1.90c6d69483000p-3}, - {0x1.35dce49ad36e2p+0, -0x1.87120a645c000p-3}, - {0x1.34679984dd440p+0, -0x1.7d68fb4143000p-3}, - {0x1.32f5cceffcb24p+0, -0x1.73cb83c627000p-3}, - {0x1.3187775a10d49p+0, -0x1.6a39a9b376000p-3}, - {0x1.301c8373e3990p+0, -0x1.60b3154b7a000p-3}, - {0x1.2eb4ebb95f841p+0, -0x1.5737d76243000p-3}, - {0x1.2d50a0219a9d1p+0, -0x1.4dc7b8fc23000p-3}, - {0x1.2bef9a8b7fd2ap+0, -0x1.4462c51d20000p-3}, - {0x1.2a91c7a0c1babp+0, -0x1.3b08abc830000p-3}, - {0x1.293726014b530p+0, -0x1.31b996b490000p-3}, - {0x1.27dfa5757a1f5p+0, -0x1.2875490a44000p-3}, - {0x1.268b39b1d3bbfp+0, -0x1.1f3b9f879a000p-3}, - {0x1.2539d838ff5bdp+0, -0x1.160c8252ca000p-3}, - {0x1.23eb7aac9083bp+0, -0x1.0ce7f57f72000p-3}, - {0x1.22a012ba940b6p+0, -0x1.03cdc49fea000p-3}, - {0x1.2157996cc4132p+0, -0x1.f57bdbc4b8000p-4}, - {0x1.201201dd2fc9bp+0, -0x1.e370896404000p-4}, - {0x1.1ecf4494d480bp+0, -0x1.d17983ef94000p-4}, - {0x1.1d8f5528f6569p+0, -0x1.bf9674ed8a000p-4}, - {0x1.1c52311577e7cp+0, -0x1.adc79202f6000p-4}, - {0x1.1b17c74cb26e9p+0, -0x1.9c0c3e7288000p-4}, - {0x1.19e010c2c1ab6p+0, -0x1.8a646b372c000p-4}, - {0x1.18ab07bb670bdp+0, -0x1.78d01b3ac0000p-4}, - {0x1.1778a25efbcb6p+0, -0x1.674f145380000p-4}, - {0x1.1648d354c31dap+0, -0x1.55e0e6d878000p-4}, - {0x1.151b990275fddp+0, -0x1.4485cdea1e000p-4}, - {0x1.13f0ea432d24cp+0, -0x1.333d94d6aa000p-4}, - {0x1.12c8b7210f9dap+0, -0x1.22079f8c56000p-4}, - {0x1.11a3028ecb531p+0, -0x1.10e4698622000p-4}, - {0x1.107fbda8434afp+0, -0x1.ffa6c6ad20000p-5}, - {0x1.0f5ee0f4e6bb3p+0, -0x1.dda8d4a774000p-5}, - {0x1.0e4065d2a9fcep+0, -0x1.bbcece4850000p-5}, - {0x1.0d244632ca521p+0, -0x1.9a1894012c000p-5}, - {0x1.0c0a77ce2981ap+0, -0x1.788583302c000p-5}, - {0x1.0af2f83c636d1p+0, -0x1.5715e67d68000p-5}, - {0x1.09ddb98a01339p+0, -0x1.35c8a49658000p-5}, - {0x1.08cabaf52e7dfp+0, -0x1.149e364154000p-5}, - {0x1.07b9f2f4e28fbp+0, -0x1.e72c082eb8000p-6}, - {0x1.06ab58c358f19p+0, -0x1.a55f152528000p-6}, - {0x1.059eea5ecf92cp+0, -0x1.63d62cf818000p-6}, - {0x1.04949cdd12c90p+0, -0x1.228fb8caa0000p-6}, - {0x1.038c6c6f0ada9p+0, -0x1.c317b20f90000p-7}, - {0x1.02865137932a9p+0, -0x1.419355daa0000p-7}, - {0x1.0182427ea7348p+0, -0x1.81203c2ec0000p-8}, - {0x1.008040614b195p+0, -0x1.0040979240000p-9}, - {0x1.fe01ff726fa1ap-1, 0x1.feff384900000p-9}, - {0x1.fa11cc261ea74p-1, 0x1.7dc41353d0000p-7}, - {0x1.f6310b081992ep-1, 0x1.3cea3c4c28000p-6}, - {0x1.f25f63ceeadcdp-1, 0x1.b9fc114890000p-6}, - {0x1.ee9c8039113e7p-1, 0x1.1b0d8ce110000p-5}, - {0x1.eae8078cbb1abp-1, 0x1.58a5bd001c000p-5}, - {0x1.e741aa29d0c9bp-1, 0x1.95c8340d88000p-5}, - {0x1.e3a91830a99b5p-1, 0x1.d276aef578000p-5}, - {0x1.e01e009609a56p-1, 0x1.07598e598c000p-4}, - {0x1.dca01e577bb98p-1, 0x1.253f5e30d2000p-4}, - {0x1.d92f20b7c9103p-1, 0x1.42edd8b380000p-4}, - {0x1.d5cac66fb5ccep-1, 0x1.606598757c000p-4}, - {0x1.d272caa5ede9dp-1, 0x1.7da76356a0000p-4}, - {0x1.cf26e3e6b2ccdp-1, 0x1.9ab434e1c6000p-4}, - {0x1.cbe6da2a77902p-1, 0x1.b78c7bb0d6000p-4}, - {0x1.c8b266d37086dp-1, 0x1.d431332e72000p-4}, - {0x1.c5894bd5d5804p-1, 0x1.f0a3171de6000p-4}, - {0x1.c26b533bb9f8cp-1, 0x1.067152b914000p-3}, - {0x1.bf583eeece73fp-1, 0x1.147858292b000p-3}, - {0x1.bc4fd75db96c1p-1, 0x1.2266ecdca3000p-3}, - {0x1.b951e0c864a28p-1, 0x1.303d7a6c55000p-3}, - {0x1.b65e2c5ef3e2cp-1, 0x1.3dfc33c331000p-3}, - {0x1.b374867c9888bp-1, 0x1.4ba366b7a8000p-3}, - {0x1.b094b211d304ap-1, 0x1.5933928d1f000p-3}, - {0x1.adbe885f2ef7ep-1, 0x1.66acd2418f000p-3}, - {0x1.aaf1d31603da2p-1, 0x1.740f8ec669000p-3}, - {0x1.a82e63fd358a7p-1, 0x1.815c0f51af000p-3}, - {0x1.a5740ef09738bp-1, 0x1.8e92954f68000p-3}, - {0x1.a2c2a90ab4b27p-1, 0x1.9bb3602f84000p-3}, - {0x1.a01a01393f2d1p-1, 0x1.a8bed1c2c0000p-3}, - {0x1.9d79f24db3c1bp-1, 0x1.b5b515c01d000p-3}, - {0x1.9ae2505c7b190p-1, 0x1.c2967ccbcc000p-3}, - {0x1.9852ef297ce2fp-1, 0x1.cf635d5486000p-3}, - {0x1.95cbaeea44b75p-1, 0x1.dc1bd3446c000p-3}, - {0x1.934c69de74838p-1, 0x1.e8c01b8cfe000p-3}, - {0x1.90d4f2f6752e6p-1, 0x1.f5509c0179000p-3}, - {0x1.8e6528effd79dp-1, 0x1.00e6c121fb800p-2}, - {0x1.8bfce9fcc007cp-1, 0x1.071b80e93d000p-2}, - {0x1.899c0dabec30ep-1, 0x1.0d46b9e867000p-2}, - {0x1.87427aa2317fbp-1, 0x1.13687334bd000p-2}, - {0x1.84f00acb39a08p-1, 0x1.1980d67234800p-2}, - {0x1.82a49e8653e55p-1, 0x1.1f8ffe0cc8000p-2}, - {0x1.8060195f40260p-1, 0x1.2595fd7636800p-2}, - {0x1.7e22563e0a329p-1, 0x1.2b9300914a800p-2}, - {0x1.7beb377dcb5adp-1, 0x1.3187210436000p-2}, - {0x1.79baa679725c2p-1, 0x1.377266dec1800p-2}, - {0x1.77907f2170657p-1, 0x1.3d54ffbaf3000p-2}, - {0x1.756cadbd6130cp-1, 0x1.432eee32fe000p-2}, - }, -#if !__FP_FAST_FMA - .tab2 = - { - {0x1.61000014fb66bp-1, 0x1.e026c91425b3cp-56}, - {0x1.63000034db495p-1, 0x1.dbfea48005d41p-55}, - {0x1.650000d94d478p-1, 0x1.e7fa786d6a5b7p-55}, - {0x1.67000074e6fadp-1, 0x1.1fcea6b54254cp-57}, - {0x1.68ffffedf0faep-1, -0x1.c7e274c590efdp-56}, - {0x1.6b0000763c5bcp-1, -0x1.ac16848dcda01p-55}, - {0x1.6d0001e5cc1f6p-1, 0x1.33f1c9d499311p-55}, - {0x1.6efffeb05f63ep-1, -0x1.e80041ae22d53p-56}, - {0x1.710000e86978p-1, 0x1.bff6671097952p-56}, - {0x1.72ffffc67e912p-1, 0x1.c00e226bd8724p-55}, - {0x1.74fffdf81116ap-1, -0x1.e02916ef101d2p-57}, - {0x1.770000f679c9p-1, -0x1.7fc71cd549c74p-57}, - {0x1.78ffffa7ec835p-1, 0x1.1bec19ef50483p-55}, - {0x1.7affffe20c2e6p-1, -0x1.07e1729cc6465p-56}, - {0x1.7cfffed3fc9p-1, -0x1.08072087b8b1cp-55}, - {0x1.7efffe9261a76p-1, 0x1.dc0286d9df9aep-55}, - {0x1.81000049ca3e8p-1, 0x1.97fd251e54c33p-55}, - {0x1.8300017932c8fp-1, -0x1.afee9b630f381p-55}, - {0x1.850000633739cp-1, 0x1.9bfbf6b6535bcp-55}, - {0x1.87000204289c6p-1, -0x1.bbf65f3117b75p-55}, - {0x1.88fffebf57904p-1, -0x1.9006ea23dcb57p-55}, - {0x1.8b00022bc04dfp-1, -0x1.d00df38e04b0ap-56}, - {0x1.8cfffe50c1b8ap-1, -0x1.8007146ff9f05p-55}, - {0x1.8effffc918e43p-1, 0x1.3817bd07a7038p-55}, - {0x1.910001efa5fc7p-1, 0x1.93e9176dfb403p-55}, - {0x1.9300013467bb9p-1, 0x1.f804e4b980276p-56}, - {0x1.94fffe6ee076fp-1, -0x1.f7ef0d9ff622ep-55}, - {0x1.96fffde3c12d1p-1, -0x1.082aa962638bap-56}, - {0x1.98ffff4458a0dp-1, -0x1.7801b9164a8efp-55}, - {0x1.9afffdd982e3ep-1, -0x1.740e08a5a9337p-55}, - {0x1.9cfffed49fb66p-1, 0x1.fce08c19bep-60}, - {0x1.9f00020f19c51p-1, -0x1.a3faa27885b0ap-55}, - {0x1.a10001145b006p-1, 0x1.4ff489958da56p-56}, - {0x1.a300007bbf6fap-1, 0x1.cbeab8a2b6d18p-55}, - {0x1.a500010971d79p-1, 0x1.8fecadd78793p-55}, - {0x1.a70001df52e48p-1, -0x1.f41763dd8abdbp-55}, - {0x1.a90001c593352p-1, -0x1.ebf0284c27612p-55}, - {0x1.ab0002a4f3e4bp-1, -0x1.9fd043cff3f5fp-57}, - {0x1.acfffd7ae1ed1p-1, -0x1.23ee7129070b4p-55}, - {0x1.aefffee510478p-1, 0x1.a063ee00edea3p-57}, - {0x1.b0fffdb650d5bp-1, 0x1.a06c8381f0ab9p-58}, - {0x1.b2ffffeaaca57p-1, -0x1.9011e74233c1dp-56}, - {0x1.b4fffd995badcp-1, -0x1.9ff1068862a9fp-56}, - {0x1.b7000249e659cp-1, 0x1.aff45d0864f3ep-55}, - {0x1.b8ffff987164p-1, 0x1.cfe7796c2c3f9p-56}, - {0x1.bafffd204cb4fp-1, -0x1.3ff27eef22bc4p-57}, - {0x1.bcfffd2415c45p-1, -0x1.cffb7ee3bea21p-57}, - {0x1.beffff86309dfp-1, -0x1.14103972e0b5cp-55}, - {0x1.c0fffe1b57653p-1, 0x1.bc16494b76a19p-55}, - {0x1.c2ffff1fa57e3p-1, -0x1.4feef8d30c6edp-57}, - {0x1.c4fffdcbfe424p-1, -0x1.43f68bcec4775p-55}, - {0x1.c6fffed54b9f7p-1, 0x1.47ea3f053e0ecp-55}, - {0x1.c8fffeb998fd5p-1, 0x1.383068df992f1p-56}, - {0x1.cb0002125219ap-1, -0x1.8fd8e64180e04p-57}, - {0x1.ccfffdd94469cp-1, 0x1.e7ebe1cc7ea72p-55}, - {0x1.cefffeafdc476p-1, 0x1.ebe39ad9f88fep-55}, - {0x1.d1000169af82bp-1, 0x1.57d91a8b95a71p-56}, - {0x1.d30000d0ff71dp-1, 0x1.9c1906970c7dap-55}, - {0x1.d4fffea790fc4p-1, -0x1.80e37c558fe0cp-58}, - {0x1.d70002edc87e5p-1, -0x1.f80d64dc10f44p-56}, - {0x1.d900021dc82aap-1, -0x1.47c8f94fd5c5cp-56}, - {0x1.dafffd86b0283p-1, 0x1.c7f1dc521617ep-55}, - {0x1.dd000296c4739p-1, 0x1.8019eb2ffb153p-55}, - {0x1.defffe54490f5p-1, 0x1.e00d2c652cc89p-57}, - {0x1.e0fffcdabf694p-1, -0x1.f8340202d69d2p-56}, - {0x1.e2fffdb52c8ddp-1, 0x1.b00c1ca1b0864p-56}, - {0x1.e4ffff24216efp-1, 0x1.2ffa8b094ab51p-56}, - {0x1.e6fffe88a5e11p-1, -0x1.7f673b1efbe59p-58}, - {0x1.e9000119eff0dp-1, -0x1.4808d5e0bc801p-55}, - {0x1.eafffdfa51744p-1, 0x1.80006d54320b5p-56}, - {0x1.ed0001a127fa1p-1, -0x1.002f860565c92p-58}, - {0x1.ef00007babcc4p-1, -0x1.540445d35e611p-55}, - {0x1.f0ffff57a8d02p-1, -0x1.ffb3139ef9105p-59}, - {0x1.f30001ee58ac7p-1, 0x1.a81acf2731155p-55}, - {0x1.f4ffff5823494p-1, 0x1.a3f41d4d7c743p-55}, - {0x1.f6ffffca94c6bp-1, -0x1.202f41c987875p-57}, - {0x1.f8fffe1f9c441p-1, 0x1.77dd1f477e74bp-56}, - {0x1.fafffd2e0e37ep-1, -0x1.f01199a7ca331p-57}, - {0x1.fd0001c77e49ep-1, 0x1.181ee4bceacb1p-56}, - {0x1.feffff7e0c331p-1, -0x1.e05370170875ap-57}, - {0x1.00ffff465606ep+0, -0x1.a7ead491c0adap-55}, - {0x1.02ffff3867a58p+0, -0x1.77f69c3fcb2ep-54}, - {0x1.04ffffdfc0d17p+0, 0x1.7bffe34cb945bp-54}, - {0x1.0700003cd4d82p+0, 0x1.20083c0e456cbp-55}, - {0x1.08ffff9f2cbe8p+0, -0x1.dffdfbe37751ap-57}, - {0x1.0b000010cda65p+0, -0x1.13f7faee626ebp-54}, - {0x1.0d00001a4d338p+0, 0x1.07dfa79489ff7p-55}, - {0x1.0effffadafdfdp+0, -0x1.7040570d66bcp-56}, - {0x1.110000bbafd96p+0, 0x1.e80d4846d0b62p-55}, - {0x1.12ffffae5f45dp+0, 0x1.dbffa64fd36efp-54}, - {0x1.150000dd59ad9p+0, 0x1.a0077701250aep-54}, - {0x1.170000f21559ap+0, 0x1.dfdf9e2e3deeep-55}, - {0x1.18ffffc275426p+0, 0x1.10030dc3b7273p-54}, - {0x1.1b000123d3c59p+0, 0x1.97f7980030188p-54}, - {0x1.1cffff8299eb7p+0, -0x1.5f932ab9f8c67p-57}, - {0x1.1effff48ad4p+0, 0x1.37fbf9da75bebp-54}, - {0x1.210000c8b86a4p+0, 0x1.f806b91fd5b22p-54}, - {0x1.2300003854303p+0, 0x1.3ffc2eb9fbf33p-54}, - {0x1.24fffffbcf684p+0, 0x1.601e77e2e2e72p-56}, - {0x1.26ffff52921d9p+0, 0x1.ffcbb767f0c61p-56}, - {0x1.2900014933a3cp+0, -0x1.202ca3c02412bp-56}, - {0x1.2b00014556313p+0, -0x1.2808233f21f02p-54}, - {0x1.2cfffebfe523bp+0, -0x1.8ff7e384fdcf2p-55}, - {0x1.2f0000bb8ad96p+0, -0x1.5ff51503041c5p-55}, - {0x1.30ffffb7ae2afp+0, -0x1.10071885e289dp-55}, - {0x1.32ffffeac5f7fp+0, -0x1.1ff5d3fb7b715p-54}, - {0x1.350000ca66756p+0, 0x1.57f82228b82bdp-54}, - {0x1.3700011fbf721p+0, 0x1.000bac40dd5ccp-55}, - {0x1.38ffff9592fb9p+0, -0x1.43f9d2db2a751p-54}, - {0x1.3b00004ddd242p+0, 0x1.57f6b707638e1p-55}, - {0x1.3cffff5b2c957p+0, 0x1.a023a10bf1231p-56}, - {0x1.3efffeab0b418p+0, 0x1.87f6d66b152bp-54}, - {0x1.410001532aff4p+0, 0x1.7f8375f198524p-57}, - {0x1.4300017478b29p+0, 0x1.301e672dc5143p-55}, - {0x1.44fffe795b463p+0, 0x1.9ff69b8b2895ap-55}, - {0x1.46fffe80475ep+0, -0x1.5c0b19bc2f254p-54}, - {0x1.48fffef6fc1e7p+0, 0x1.b4009f23a2a72p-54}, - {0x1.4afffe5bea704p+0, -0x1.4ffb7bf0d7d45p-54}, - {0x1.4d000171027dep+0, -0x1.9c06471dc6a3dp-54}, - {0x1.4f0000ff03ee2p+0, 0x1.77f890b85531cp-54}, - {0x1.5100012dc4bd1p+0, 0x1.004657166a436p-57}, - {0x1.530001605277ap+0, -0x1.6bfcece233209p-54}, - {0x1.54fffecdb704cp+0, -0x1.902720505a1d7p-55}, - {0x1.56fffef5f54a9p+0, 0x1.bbfe60ec96412p-54}, - {0x1.5900017e61012p+0, 0x1.87ec581afef9p-55}, - {0x1.5b00003c93e92p+0, -0x1.f41080abf0ccp-54}, - {0x1.5d0001d4919bcp+0, -0x1.8812afb254729p-54}, - {0x1.5efffe7b87a89p+0, -0x1.47eb780ed6904p-54}, - }, -#endif -}; - -#define T __log_data.tab -#define T2 __log_data.tab2 -#define B __log_data.poly1 -#define A __log_data.poly -#define Ln2hi __log_data.ln2hi -#define Ln2lo __log_data.ln2lo -#define N (1 << LOG_TABLE_BITS) -#define OFF 0x3fe6000000000000 - -static inline uint32_t top16(double x) -{ - return asuint64(x) >> 48; -} - -double log(double x) -{ - double_t w, z, r, r2, r3, y, invc, logc, kd, hi, lo; - uint64_t ix, iz, tmp; - uint32_t top; - int k, i; - - ix = asuint64(x); - top = top16(x); -#define LO asuint64(1.0 - 0x1p-4) -#define HI asuint64(1.0 + 0x1.09p-4) - if (predict_false(ix - LO < HI - LO)) { - if (WANT_ROUNDING && predict_false(ix == asuint64(1.0))) - return 0; - r = x - 1.0; - r2 = r * r; - r3 = r * r2; - y = r3 * - (B[1] + r * B[2] + r2 * B[3] + - r3 * (B[4] + r * B[5] + r2 * B[6] + r3 * (B[7] + r * B[8] + r2 * B[9] + r3 * B[10]))); - w = r * 0x1p27; - double_t rhi = r + w - w; - double_t rlo = r - rhi; - w = rhi * rhi * B[0]; - hi = r + w; - lo = r - hi + w; - lo += B[0] * rlo * (rhi + r); - y += lo; - y += hi; - return eval_as_double(y); - } - if (predict_false(top - 0x0010 >= 0x7ff0 - 0x0010)) { - if (ix * 2 == 0) - return __math_divzero(1); - if (ix == asuint64(INFINITY)) - return x; - if ((top & 0x8000) || (top & 0x7ff0) == 0x7ff0) - return __math_invalid(x); - ix = asuint64(x * 0x1p52); - ix -= 52ULL << 52; - } - - tmp = ix - OFF; - i = (tmp >> (52 - LOG_TABLE_BITS)) % N; - k = (int64_t)tmp >> 52; - iz = ix - (tmp & 0xfffULL << 52); - invc = T[i].invc; - logc = T[i].logc; - z = asdouble(iz); - -#if __FP_FAST_FMA - r = __builtin_fma(z, invc, -1.0); -#else - r = (z - T2[i].chi - T2[i].clo) * invc; -#endif - - kd = (double_t)k; - w = kd * Ln2hi + logc; - hi = w + r; - lo = w - hi + r + kd * Ln2lo; - r2 = r * r; - y = lo + r2 * A[0] + r * r2 * (A[1] + r * A[2] + r2 * (A[3] + r * A[4])) + hi; - return eval_as_double(y); -} - -#endif // AX_CONFIG_FP_SIMD diff --git a/arceos/ulib/axlibc/c/math.c b/arceos/ulib/axlibc/c/math.c deleted file mode 100644 index 04ee1e7c3..000000000 --- a/arceos/ulib/axlibc/c/math.c +++ /dev/null @@ -1,571 +0,0 @@ -#ifdef AX_CONFIG_FP_SIMD - -#include -#include -#include -#include - -#include "libm.h" - -int __fpclassify(double x) -{ - union { - double f; - uint64_t i; - } u = {x}; - int e = u.i >> 52 & 0x7ff; - if (!e) - return u.i << 1 ? FP_SUBNORMAL : FP_ZERO; - if (e == 0x7ff) - return u.i << 12 ? FP_NAN : FP_INFINITE; - return FP_NORMAL; -} - -int __fpclassifyf(float x) -{ - union { - float f; - uint32_t i; - } u = {x}; - int e = u.i >> 23 & 0xff; - if (!e) - return u.i << 1 ? FP_SUBNORMAL : FP_ZERO; - if (e == 0xff) - return u.i << 9 ? FP_NAN : FP_INFINITE; - return FP_NORMAL; -} - -#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 -int __fpclassifyl(long double x) -{ - return __fpclassify(x); -} -#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 -int __fpclassifyl(long double x) -{ - union ldshape u = {x}; - int e = u.i.se & 0x7fff; - int msb = u.i.m >> 63; - if (!e && !msb) - return u.i.m ? FP_SUBNORMAL : FP_ZERO; - if (e == 0x7fff) { - /* The x86 variant of 80-bit extended precision only admits - * one representation of each infinity, with the mantissa msb - * necessarily set. The version with it clear is invalid/nan. - * The m68k variant, however, allows either, and tooling uses - * the version with it clear. */ - if (__BYTE_ORDER == __LITTLE_ENDIAN && !msb) - return FP_NAN; - return u.i.m << 1 ? FP_NAN : FP_INFINITE; - } - if (!msb) - return FP_NAN; - return FP_NORMAL; -} -#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 -int __fpclassifyl(long double x) -{ - union ldshape u = {x}; - int e = u.i.se & 0x7fff; - u.i.se = 0; - if (!e) - return u.i2.lo | u.i2.hi ? FP_SUBNORMAL : FP_ZERO; - if (e == 0x7fff) - return u.i2.lo | u.i2.hi ? FP_NAN : FP_INFINITE; - return FP_NORMAL; -} -#endif - -double fabs(double x) -{ - union { - double f; - uint64_t i; - } u = {x}; - u.i &= -1ULL / 2; - return u.f; -} - -static const double toint = 1 / DBL_EPSILON; - -double floor(double x) -{ - union { - double f; - uint64_t i; - } u = {x}; - int e = u.i >> 52 & 0x7ff; - double y; - - if (e >= 0x3ff + 52 || x == 0) - return x; - /* y = int(x) - x, where int(x) is an integer neighbor of x */ - if (u.i >> 63) - y = x - toint + toint - x; - else - y = x + toint - toint - x; - /* special case because of non-nearest rounding modes */ - if (e <= 0x3ff - 1) { - FORCE_EVAL(y); - return u.i >> 63 ? -1 : 0; - } - if (y > 0) - return x + y - 1; - return x + y; -} - -double rint(double x) -{ - unimplemented(); - return 0; -} - -long long llrint(double x) -{ - return rint(x); -} - -double sqrt(double x) -{ - unimplemented(); - return 0; -} - -double round(double x) -{ - unimplemented(); - return x; -} - -long double roundl(long double x) -{ - unimplemented(); - return x; -} - -long long llroundl(long double x) -{ - unimplemented(); - return x; -} - -double cos(double __x) -{ - unimplemented(); - return 0; -} - -double ceil(double x) -{ - union { - double f; - uint64_t i; - } u = {x}; - int e = u.i >> 52 & 0x7ff; - double_t y; - - if (e >= 0x3ff + 52 || x == 0) - return x; - if (u.i >> 63) - y = x - toint + toint - x; - else - y = x + toint - toint - x; - if (e <= 0x3ff - 1) { - FORCE_EVAL(y); - return u.i >> 63 ? -0.0 : 1; - } - if (y < 0) - return x + y + 1; - return x + y; -} - -// TODO -double sin(double __x) -{ - unimplemented(); - return 0; -} - -// TODO -double asin(double __x) -{ - unimplemented(); - return 0; -} - -long double ceill(long double x) -{ - unimplemented(); - return x; -} - -double acos(double x) -{ - unimplemented(); - return 0; -} - -// TODO -double atan(double x) -{ - unimplemented(); - return 0; -} - -// TODO -double atan2(double y, double x) -{ - unimplemented(); - return 0; -} - -double cosh(double x) -{ - unimplemented(); - return 0; -} - -// TODO -double exp(double x) -{ - unimplemented(); - return 0; -} - -// TODO -double frexp(double x, int *e) -{ - unimplemented(); - return 0; -} - -double ldexp(double x, int n) -{ - unimplemented(); - return 0; -} - -// TODO -double log10(double x) -{ - unimplemented(); - return 0; -} - -// TODO -double modf(double x, double *iptr) -{ - unimplemented(); - return 0; -} - -double sinh(double x) -{ - unimplemented(); - return 0; -} - -// TODO -double tan(double x) -{ - unimplemented(); - return 0; -} - -// TODO -double tanh(double x) -{ - unimplemented(); - return 0; -} - -double copysign(double x, double y) -{ - union { - double f; - uint64_t i; - } ux = {x}, uy = {y}; - ux.i &= -1ULL / 2; - ux.i |= uy.i & 1ULL << 63; - return ux.f; -} - -#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 -long double copysignl(long double x, long double y) -{ - return copysign(x, y); -} -#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 -long double copysignl(long double x, long double y) -{ - union ldshape ux = {x}, uy = {y}; - ux.i.se &= 0x7fff; - ux.i.se |= uy.i.se & 0x8000; - return ux.f; -} -#endif - -double scalbn(double x, int n) -{ - union { - double f; - uint64_t i; - } u; - double_t y = x; - - if (n > 1023) { - y *= 0x1p1023; - n -= 1023; - if (n > 1023) { - y *= 0x1p1023; - n -= 1023; - if (n > 1023) - n = 1023; - } - } else if (n < -1022) { - /* make sure final n < -53 to avoid double - rounding in the subnormal range */ - y *= 0x1p-1022 * 0x1p53; - n += 1022 - 53; - if (n < -1022) { - y *= 0x1p-1022 * 0x1p53; - n += 1022 - 53; - if (n < -1022) - n = -1022; - } - } - u.i = (uint64_t)(0x3ff + n) << 52; - x = y * u.f; - return x; -} - -#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 -long double scalbnl(long double x, int n) -{ - return scalbn(x, n); -} -#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 -long double scalbnl(long double x, int n) -{ - union ldshape u; - - if (n > 16383) { - x *= 0x1p16383L; - n -= 16383; - if (n > 16383) { - x *= 0x1p16383L; - n -= 16383; - if (n > 16383) - n = 16383; - } - } else if (n < -16382) { - x *= 0x1p-16382L * 0x1p113L; - n += 16382 - 113; - if (n < -16382) { - x *= 0x1p-16382L * 0x1p113L; - n += 16382 - 113; - if (n < -16382) - n = -16382; - } - } - u.f = 1.0; - u.i.se = 0x3fff + n; - return x * u.f; -} -#endif - -double fmod(double x, double y) -{ - union { - double f; - uint64_t i; - } ux = {x}, uy = {y}; - int ex = ux.i >> 52 & 0x7ff; - int ey = uy.i >> 52 & 0x7ff; - int sx = ux.i >> 63; - uint64_t i; - - /* in the followings uxi should be ux.i, but then gcc wrongly adds */ - /* float load/store to inner loops ruining performance and code size */ - uint64_t uxi = ux.i; - - if (uy.i << 1 == 0 || isnan(y) || ex == 0x7ff) - return (x * y) / (x * y); - if (uxi << 1 <= uy.i << 1) { - if (uxi << 1 == uy.i << 1) - return 0 * x; - return x; - } - - /* normalize x and y */ - if (!ex) { - for (i = uxi << 12; i >> 63 == 0; ex--, i <<= 1) - ; - uxi <<= -ex + 1; - } else { - uxi &= -1ULL >> 12; - uxi |= 1ULL << 52; - } - if (!ey) { - for (i = uy.i << 12; i >> 63 == 0; ey--, i <<= 1) - ; - uy.i <<= -ey + 1; - } else { - uy.i &= -1ULL >> 12; - uy.i |= 1ULL << 52; - } - - /* x mod y */ - for (; ex > ey; ex--) { - i = uxi - uy.i; - if (i >> 63 == 0) { - if (i == 0) - return 0 * x; - uxi = i; - } - uxi <<= 1; - } - i = uxi - uy.i; - if (i >> 63 == 0) { - if (i == 0) - return 0 * x; - uxi = i; - } - for (; uxi >> 52 == 0; uxi <<= 1, ex--) - ; - - /* scale result */ - if (ex > 0) { - uxi -= 1ULL << 52; - uxi |= (uint64_t)ex << 52; - } else { - uxi >>= -ex + 1; - } - uxi |= (uint64_t)sx << 63; - ux.i = uxi; - return ux.f; -} - -// x86_64 has specific implementation -#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 -long double fmodl(long double x, long double y) -{ - return fmod(x, y); -} -#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 -long double fmodl(long double x, long double y) -{ - union ldshape ux = {x}, uy = {y}; - int ex = ux.i.se & 0x7fff; - int ey = uy.i.se & 0x7fff; - int sx = ux.i.se & 0x8000; - - if (y == 0 || isnan(y) || ex == 0x7fff) - return (x * y) / (x * y); - ux.i.se = ex; - uy.i.se = ey; - if (ux.f <= uy.f) { - if (ux.f == uy.f) - return 0 * x; - return x; - } - - /* normalize x and y */ - if (!ex) { - ux.f *= 0x1p120f; - ex = ux.i.se - 120; - } - if (!ey) { - uy.f *= 0x1p120f; - ey = uy.i.se - 120; - } - - /* x mod y */ -#if LDBL_MANT_DIG == 64 - uint64_t i, mx, my; - mx = ux.i.m; - my = uy.i.m; - for (; ex > ey; ex--) { - i = mx - my; - if (mx >= my) { - if (i == 0) - return 0 * x; - mx = 2 * i; - } else if (2 * mx < mx) { - mx = 2 * mx - my; - } else { - mx = 2 * mx; - } - } - i = mx - my; - if (mx >= my) { - if (i == 0) - return 0 * x; - mx = i; - } - for (; mx >> 63 == 0; mx *= 2, ex--) - ; - ux.i.m = mx; -#elif LDBL_MANT_DIG == 113 - uint64_t hi, lo, xhi, xlo, yhi, ylo; - xhi = (ux.i2.hi & -1ULL >> 16) | 1ULL << 48; - yhi = (uy.i2.hi & -1ULL >> 16) | 1ULL << 48; - xlo = ux.i2.lo; - ylo = uy.i2.lo; - for (; ex > ey; ex--) { - hi = xhi - yhi; - lo = xlo - ylo; - if (xlo < ylo) - hi -= 1; - if (hi >> 63 == 0) { - if ((hi | lo) == 0) - return 0 * x; - xhi = 2 * hi + (lo >> 63); - xlo = 2 * lo; - } else { - xhi = 2 * xhi + (xlo >> 63); - xlo = 2 * xlo; - } - } - hi = xhi - yhi; - lo = xlo - ylo; - if (xlo < ylo) - hi -= 1; - if (hi >> 63 == 0) { - if ((hi | lo) == 0) - return 0 * x; - xhi = hi; - xlo = lo; - } - for (; xhi >> 48 == 0; xhi = 2 * xhi + (xlo >> 63), xlo = 2 * xlo, ex--) - ; - ux.i2.hi = xhi; - ux.i2.lo = xlo; -#endif - - /* scale result */ - if (ex <= 0) { - ux.i.se = (ex + 120) | sx; - ux.f *= 0x1p-120f; - } else - ux.i.se = ex | sx; - return ux.f; -} -#endif - -#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 -long double fabsl(long double x) -{ - return fabs(x); -} -#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 -long double fabsl(long double x) -{ - union ldshape u = {x}; - - u.i.se &= 0x7fff; - return u.f; -} -#endif - -#endif // AX_CONFIG_FP_SIMD diff --git a/arceos/ulib/axlibc/c/mmap.c b/arceos/ulib/axlibc/c/mmap.c deleted file mode 100644 index e3204d714..000000000 --- a/arceos/ulib/axlibc/c/mmap.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -#include - -// TODO: -void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) -{ - unimplemented(); - return MAP_FAILED; -} - -// TODO: -int munmap(void *addr, size_t length) -{ - unimplemented(); - return 0; -} - -// TODO: -void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, - ... /* void *new_address */) -{ - unimplemented(); - return NULL; -} - -// TODO -int mprotect(void *addr, size_t len, int prot) -{ - unimplemented(); - return 0; -} - -// TODO -int madvise(void *addr, size_t len, int advice) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/c/network.c b/arceos/ulib/axlibc/c/network.c deleted file mode 100644 index 4c6beb845..000000000 --- a/arceos/ulib/axlibc/c/network.c +++ /dev/null @@ -1,226 +0,0 @@ -#ifdef AX_CONFIG_NET - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -int h_errno; - -static const char gai_msgs[] = "Invalid flags\0" - "Name does not resolve\0" - "Try again\0" - "Non-recoverable error\0" - "Unknown error\0" - "Unrecognized address family or invalid length\0" - "Unrecognized socket type\0" - "Unrecognized service\0" - "Unknown error\0" - "Out of memory\0" - "System error\0" - "Overflow\0" - "\0Unknown error"; - -const char *gai_strerror(int ecode) -{ - const char *s; - for (s = gai_msgs, ecode++; ecode && *s; ecode++, s++) - for (; *s; s++) - ; - if (!*s) - s++; - return s; -} - -static const char msgs[] = "Host not found\0" - "Try again\0" - "Non-recoverable error\0" - "Address not available\0" - "\0Unknown error"; - -const char *hstrerror(int ecode) -{ - const char *s; - for (s = msgs, ecode--; ecode && *s; ecode--, s++) - for (; *s; s++) - ; - if (!*s) - s++; - return s; -} - -static __inline uint16_t __bswap_16(uint16_t __x) -{ - return __x << 8 | __x >> 8; -} - -static __inline uint32_t __bswap_32(uint32_t __x) -{ - return __x >> 24 | (__x >> 8 & 0xff00) | (__x << 8 & 0xff0000) | __x << 24; -} - -uint32_t htonl(uint32_t n) -{ - union { - int i; - char c; - } u = {1}; - return u.c ? __bswap_32(n) : n; -} - -uint16_t htons(uint16_t n) -{ - union { - int i; - char c; - } u = {1}; - return u.c ? __bswap_16(n) : n; -} - -uint32_t ntohl(uint32_t n) -{ - union { - int i; - char c; - } u = {1}; - return u.c ? __bswap_32(n) : n; -} - -uint16_t ntohs(uint16_t n) -{ - union { - int i; - char c; - } u = {1}; - return u.c ? __bswap_16(n) : n; -} - -static int hexval(unsigned c) -{ - if (c - '0' < 10) - return c - '0'; - c |= 32; - if (c - 'a' < 6) - return c - 'a' + 10; - return -1; -} - -int inet_pton(int af, const char *__restrict s, void *__restrict a0) -{ - uint16_t ip[8]; - unsigned char *a = a0; - int i, j, v, d, brk = -1, need_v4 = 0; - - if (af == AF_INET) { - for (i = 0; i < 4; i++) { - for (v = j = 0; j < 3 && isdigit(s[j]); j++) v = 10 * v + s[j] - '0'; - if (j == 0 || (j > 1 && s[0] == '0') || v > 255) - return 0; - a[i] = v; - if (s[j] == 0 && i == 3) - return 1; - if (s[j] != '.') - return 0; - s += j + 1; - } - return 0; - } else if (af != AF_INET6) { - errno = EAFNOSUPPORT; - return -1; - } - - if (*s == ':' && *++s != ':') - return 0; - - for (i = 0;; i++) { - if (s[0] == ':' && brk < 0) { - brk = i; - ip[i & 7] = 0; - if (!*++s) - break; - if (i == 7) - return 0; - continue; - } - for (v = j = 0; j < 4 && (d = hexval(s[j])) >= 0; j++) v = 16 * v + d; - if (j == 0) - return 0; - ip[i & 7] = v; - if (!s[j] && (brk >= 0 || i == 7)) - break; - if (i == 7) - return 0; - if (s[j] != ':') { - if (s[j] != '.' || (i < 6 && brk < 0)) - return 0; - need_v4 = 1; - i++; - break; - } - s += j + 1; - } - if (brk >= 0) { - for (j = 0; j < 7 - i; j++) ip[brk + j] = 0; - memmove(ip + brk + 7 - i, ip + brk, 2 * (i + 1 - brk)); - } - for (j = 0; j < 8; j++) { - *a++ = ip[j] >> 8; - *a++ = ip[j]; - } - if (need_v4 && inet_pton(AF_INET, (void *)s, a - 4) <= 0) - return 0; - return 1; -} - -const char *inet_ntop(int af, const void *__restrict a0, char *__restrict s, socklen_t l) -{ - const unsigned char *a = a0; - int i, j, max, best; - char buf[100]; - - switch (af) { - case AF_INET: - if (snprintf(s, l, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]) < l) - return s; - break; - case AF_INET6: - if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\377\377", 12)) - snprintf(buf, sizeof buf, "%x:%x:%x:%x:%x:%x:%x:%x", 256 * a[0] + a[1], - 256 * a[2] + a[3], 256 * a[4] + a[5], 256 * a[6] + a[7], 256 * a[8] + a[9], - 256 * a[10] + a[11], 256 * a[12] + a[13], 256 * a[14] + a[15]); - else - snprintf(buf, sizeof buf, "%x:%x:%x:%x:%x:%x:%d.%d.%d.%d", 256 * a[0] + a[1], - 256 * a[2] + a[3], 256 * a[4] + a[5], 256 * a[6] + a[7], 256 * a[8] + a[9], - 256 * a[10] + a[11], a[12], a[13], a[14], a[15]); - /* Replace longest /(^0|:)[:0]{2,}/ with "::" */ - for (i = best = 0, max = 2; buf[i]; i++) { - if (i && buf[i] != ':') - continue; - j = strspn(buf + i, ":0"); - if (j > max) - best = i, max = j; - } - if (max > 3) { - buf[best] = buf[best + 1] = ':'; - memmove(buf + best + 2, buf + best + max, i - best - max + 1); - } - if (strlen(buf) < l) { - strcpy(s, buf); - return s; - } - break; - default: - errno = EAFNOSUPPORT; - return 0; - } - errno = ENOSPC; - return 0; -} - -#endif // AX_CONFIG_NET diff --git a/arceos/ulib/axlibc/c/poll.c b/arceos/ulib/axlibc/c/poll.c deleted file mode 100644 index 5474246f3..000000000 --- a/arceos/ulib/axlibc/c/poll.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -// TODO -int poll(struct pollfd *__fds, nfds_t __nfds, int __timeout) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/c/pow.c b/arceos/ulib/axlibc/c/pow.c deleted file mode 100644 index 217201176..000000000 --- a/arceos/ulib/axlibc/c/pow.c +++ /dev/null @@ -1,815 +0,0 @@ -#if defined(AX_CONFIG_FP_SIMD) - -#include -#include -#include -#include -#include - -#include "libm.h" - -#define OFF 0x3fe6955500000000 - -#define POW_LOG_TABLE_BITS 7 -#define POW_LOG_POLY_ORDER 8 -#define N (1 << POW_LOG_TABLE_BITS) -struct pow_log_data { - double ln2hi; - double ln2lo; - double poly[POW_LOG_POLY_ORDER - 1]; /* First coefficient is 1. */ - /* Note: the pad field is unused, but allows slightly faster indexing. */ - struct { - double invc, pad, logc, logctail; - } tab[1 << POW_LOG_TABLE_BITS]; -}; - -const struct - pow_log_data - __pow_log_data = - { - .ln2hi = 0x1.62e42fefa3800p-1, - .ln2lo = 0x1.ef35793c76730p-45, - .poly = - { - -0x1p-1, - 0x1.555555555556p-2 * -2, - -0x1.0000000000006p-2 * -2, - 0x1.999999959554ep-3 * 4, - -0x1.555555529a47ap-3 * 4, - 0x1.2495b9b4845e9p-3 * -8, - -0x1.0002b8b263fc3p-3 * -8, - }, - .tab = - { -#define A(a, b, c) {a, 0, b, c}, - A(0x1.6a00000000000p+0, -0x1.62c82f2b9c800p-2, 0x1.ab42428375680p-48) - A(0x1.6800000000000p+0, -0x1.5d1bdbf580800p-2, -0x1.ca508d8e0f720p-46) - A(0x1.6600000000000p+0, -0x1.5767717455800p-2, - -0x1.362a4d5b6506dp-45) - A(0x1.6400000000000p+0, -0x1.51aad872df800p-2, - -0x1.684e49eb067d5p-49) A(0x1.6200000000000p+0, - -0x1.4be5f95777800p-2, - -0x1.41b6993293ee0p-47) A(0x1.6000000000000p+0, -0x1.4618bc21c6000p-2, 0x1.3d82f484c84ccp-46) A(0x1.5e00000000000p+0, -0x1.404308686a800p-2, 0x1.c42f3ed820b3ap-50) A(0x1.5c00000000000p+0, -0x1.3a64c55694800p-2, 0x1.0b1c686519460p-45) A(0x1.5a00000000000p+0, -0x1.347dd9a988000p-2, 0x1.5594dd4c58092p-45) A(0x1.5800000000000p+0, -0x1.2e8e2bae12000p-2, 0x1.67b1e99b72bd8p-45) A(0x1.5600000000000p+0, - -0x1.2895a13de8800p-2, 0x1.5ca14b6cfb03fp-46) A(0x1.5600000000000p+0, - -0x1.2895a13de8800p-2, 0x1.5ca14b6cfb03fp-46) A(0x1.5400000000000p+0, - -0x1.22941fbcf7800p-2, - -0x1.65a242853da76p-46) A(0x1.5200000000000p+0, - -0x1.1c898c1699800p-2, - -0x1.fafbc68e75404p-46) A(0x1.5000000000000p+0, - -0x1.1675cababa800p-2, 0x1.f1fc63382a8f0p-46) A(0x1.4e00000000000p+0, - -0x1.1058bf9ae4800p-2, - -0x1.6a8c4fd055a66p-45) A(0x1.4c00000000000p+0, - -0x1.0a324e2739000p-2, -0x1.c6bee7ef4030ep-47) A(0x1.4a00000000000p+0, - -0x1.0402594b4d000p-2, -0x1.036b89ef42d7fp-48) A(0x1.4a00000000000p+0, - -0x1.0402594b4d000p-2, -0x1.036b89ef42d7fp-48) A(0x1.4800000000000p+0, - -0x1.fb9186d5e4000p-3, - 0x1.d572aab993c87p-47) A(0x1.4600000000000p+0, - -0x1.ef0adcbdc6000p-3, - 0x1.b26b79c86af24p-45) A(0x1.4400000000000p+0, - -0x1.e27076e2af000p-3, -0x1.72f4f543fff10p-46) A(0x1.4200000000000p+0, - -0x1.d5c216b4fc000p-3, 0x1.1ba91bbca681bp-45) A(0x1.4000000000000p+0, -0x1.c8ff7c79aa000p-3, 0x1.7794f689f8434p-45) A(0x1.4000000000000p+0, -0x1.c8ff7c79aa000p-3, 0x1.7794f689f8434p-45) A(0x1.3e00000000000p+0, - -0x1.bc286742d9000p-3, 0x1.94eb0318bb78fp-46) A(0x1.3c00000000000p+0, - -0x1.af3c94e80c000p-3, 0x1.a4e633fcd9066p-52) A(0x1.3a00000000000p+0, - -0x1.a23bc1fe2b000p-3, - -0x1.58c64dc46c1eap-45) A(0x1.3a00000000000p+0, - -0x1.a23bc1fe2b000p-3, -0x1.58c64dc46c1eap-45) A(0x1.3800000000000p+0, - -0x1.9525a9cf45000p-3, -0x1.ad1d904c1d4e3p-45) A(0x1.3600000000000p+0, - -0x1.87fa06520d000p-3, 0x1.bbdbf7fdbfa09p-45) A(0x1.3400000000000p+0, - -0x1.7ab890210e000p-3, 0x1.bdb9072534a58p-45) A(0x1.3400000000000p+0, - -0x1.7ab890210e000p-3, 0x1.bdb9072534a58p-45) A(0x1.3200000000000p+0, -0x1.6d60fe719d000p-3, -0x1.0e46aa3b2e266p-46) A(0x1.3000000000000p+0, - -0x1.5ff3070a79000p-3, -0x1.e9e439f105039p-46) A(0x1.3000000000000p+0, - -0x1.5ff3070a79000p-3, -0x1.e9e439f105039p-46) A(0x1.2e00000000000p+0, - -0x1.526e5e3a1b000p-3, -0x1.0de8b90075b8fp-45) A(0x1.2c00000000000p+0, - -0x1.44d2b6ccb8000p-3, 0x1.70cc16135783cp-46) A(0x1.2c00000000000p+0, -0x1.44d2b6ccb8000p-3, 0x1.70cc16135783cp-46) A(0x1.2a00000000000p+0, - -0x1.371fc201e9000p-3, 0x1.178864d27543ap-48) A(0x1.2800000000000p+0, - -0x1.29552f81ff000p-3, -0x1.48d301771c408p-45) A(0x1.2600000000000p+0, -0x1.1b72ad52f6000p-3, -0x1.e80a41811a396p-45) A(0x1.2600000000000p+0, -0x1.1b72ad52f6000p-3, -0x1.e80a41811a396p-45) A(0x1.2400000000000p+0, - -0x1.0d77e7cd09000p-3, - 0x1.a699688e85bf4p-47) A(0x1.2400000000000p+0, -0x1.0d77e7cd09000p-3, 0x1.a699688e85bf4p-47) A(0x1.2200000000000p+0, -0x1.fec9131dbe000p-4, -0x1.575545ca333f2p-45) A(0x1.2000000000000p+0, - -0x1.e27076e2b0000p-4, 0x1.a342c2af0003cp-45) A(0x1.2000000000000p+0, -0x1.e27076e2b0000p-4, 0x1.a342c2af0003cp-45) A(0x1.1e00000000000p+0, -0x1.c5e548f5bc000p-4, -0x1.d0c57585fbe06p-46) A(0x1.1c00000000000p+0, - -0x1.a926d3a4ae000p-4, 0x1.53935e85baac8p-45) A(0x1.1c00000000000p+0, - -0x1.a926d3a4ae000p-4, 0x1.53935e85baac8p-45) A(0x1.1a00000000000p+0, -0x1.8c345d631a000p-4, 0x1.37c294d2f5668p-46) A(0x1.1a00000000000p+0, - -0x1.8c345d631a000p-4, - 0x1.37c294d2f5668p-46) A(0x1.1800000000000p+0, -0x1.6f0d28ae56000p-4, - -0x1.69737c93373dap-45) A(0x1.1600000000000p+0, - -0x1.51b073f062000p-4, 0x1.f025b61c65e57p-46) A(0x1.1600000000000p+0, - -0x1.51b073f062000p-4, 0x1.f025b61c65e57p-46) A(0x1.1400000000000p+0, -0x1.341d7961be000p-4, 0x1.c5edaccf913dfp-45) A(0x1.1400000000000p+0, - -0x1.341d7961be000p-4, 0x1.c5edaccf913dfp-45) A(0x1.1200000000000p+0, -0x1.16536eea38000p-4, 0x1.47c5e768fa309p-46) A(0x1.1000000000000p+0, - -0x1.f0a30c0118000p-5, 0x1.d599e83368e91p-45) A(0x1.1000000000000p+0, -0x1.f0a30c0118000p-5, - 0x1.d599e83368e91p-45) A(0x1.0e00000000000p+0, - -0x1.b42dd71198000p-5, 0x1.c827ae5d6704cp-46) A(0x1.0e00000000000p+0, - -0x1.b42dd71198000p-5, 0x1.c827ae5d6704cp-46) A(0x1.0c00000000000p+0, - -0x1.77458f632c000p-5, -0x1.cfc4634f2a1eep-45) A(0x1.0c00000000000p+0, -0x1.77458f632c000p-5, -0x1.cfc4634f2a1eep-45) A(0x1.0a00000000000p+0, -0x1.39e87b9fec000p-5, 0x1.502b7f526feaap-48) A(0x1.0a00000000000p+0, - -0x1.39e87b9fec000p-5, 0x1.502b7f526feaap-48) A(0x1.0800000000000p+0, -0x1.f829b0e780000p-6, -0x1.980267c7e09e4p-45) A(0x1.0800000000000p+0, -0x1.f829b0e780000p-6, -0x1.980267c7e09e4p-45) A(0x1.0600000000000p+0, - -0x1.7b91b07d58000p-6, -0x1.88d5493faa639p-45) A(0x1.0400000000000p+0, - -0x1.fc0a8b0fc0000p-7, -0x1.f1e7cf6d3a69cp-50) A(0x1.0400000000000p+0, -0x1.fc0a8b0fc0000p-7, -0x1.f1e7cf6d3a69cp-50) A(0x1.0200000000000p+0, -0x1.fe02a6b100000p-8, -0x1.9e23f0dda40e4p-46) A(0x1.0200000000000p+0, - -0x1.fe02a6b100000p-8, - -0x1.9e23f0dda40e4p-46) A(0x1.0000000000000p+0, - 0x0.0000000000000p+0, 0x0.0000000000000p+0) A(0x1.0000000000000p+0, - 0x0.0000000000000p+0, - 0x0.0000000000000p+0) A(0x1.fc00000000000p-1, - 0x1.0101575890000p-7, -0x1.0c76b999d2be8p-46) A(0x1.f800000000000p-1, - 0x1.0205658938000p-6, -0x1.3dc5b06e2f7d2p-45) A(0x1.f400000000000p-1, - 0x1.8492528c90000p-6, - -0x1.aa0ba325a0c34p-45) A(0x1.f000000000000p-1, - 0x1.0415d89e74000p-5, - 0x1.111c05cf1d753p-47) A(0x1.ec00000000000p-1, 0x1.466aed42e0000p-5, -0x1.c167375bdfd28p-45) A(0x1.e800000000000p-1, - 0x1.894aa149fc000p-5, - -0x1.97995d05a267dp-46) A(0x1.e400000000000p-1, - 0x1.ccb73cdddc000p-5, -0x1.a68f247d82807p-46) A(0x1.e200000000000p-1, - 0x1.eea31c006c000p-5, - -0x1.e113e4fc93b7bp-47) A(0x1.de00000000000p-1, - 0x1.1973bd1466000p-4, - -0x1.5325d560d9e9bp-45) A(0x1.da00000000000p-1, 0x1.3bdf5a7d1e000p-4, 0x1.cc85ea5db4ed7p-45) A(0x1.d600000000000p-1, 0x1.5e95a4d97a000p-4, -0x1.c69063c5d1d1ep-45) A(0x1.d400000000000p-1, 0x1.700d30aeac000p-4, 0x1.c1e8da99ded32p-49) A(0x1.d000000000000p-1, - 0x1.9335e5d594000p-4, - 0x1.3115c3abd47dap-45) A(0x1.cc00000000000p-1, - 0x1.b6ac88dad6000p-4, - -0x1.390802bf768e5p-46) A(0x1.ca00000000000p-1, - 0x1.c885801bc4000p-4, - 0x1.646d1c65aacd3p-45) A(0x1.c600000000000p-1, - 0x1.ec739830a2000p-4, - -0x1.dc068afe645e0p-45) A(0x1.c400000000000p-1, - 0x1.fe89139dbe000p-4, - -0x1.534d64fa10afdp-45) A(0x1.c000000000000p-1, 0x1.1178e8227e000p-3, 0x1.1ef78ce2d07f2p-45) A(0x1.be00000000000p-1, 0x1.1aa2b7e23f000p-3, 0x1.ca78e44389934p-45) A(0x1.ba00000000000p-1, 0x1.2d1610c868000p-3, 0x1.39d6ccb81b4a1p-47) A(0x1.b800000000000p-1, 0x1.365fcb0159000p-3, 0x1.62fa8234b7289p-51) A(0x1.b400000000000p-1, 0x1.4913d8333b000p-3, 0x1.5837954fdb678p-45) A(0x1.b200000000000p-1, 0x1.527e5e4a1b000p-3, - 0x1.633e8e5697dc7p-45) A(0x1.ae00000000000p-1, - 0x1.6574ebe8c1000p-3, - 0x1.9cf8b2c3c2e78p-46) A(0x1.ac00000000000p-1, - 0x1.6f0128b757000p-3, -0x1.5118de59c21e1p-45) A(0x1.aa00000000000p-1, 0x1.7898d85445000p-3, -0x1.c661070914305p-46) A(0x1.a600000000000p-1, - 0x1.8beafeb390000p-3, -0x1.73d54aae92cd1p-47) A(0x1.a400000000000p-1, 0x1.95a5adcf70000p-3, 0x1.7f22858a0ff6fp-47) A(0x1.a000000000000p-1, 0x1.a93ed3c8ae000p-3, -0x1.8724350562169p-45) A(0x1.9e00000000000p-1, 0x1.b31d8575bd000p-3, -0x1.c358d4eace1aap-47) A(0x1.9c00000000000p-1, 0x1.bd087383be000p-3, -0x1.d4bc4595412b6p-45) A(0x1.9a00000000000p-1, 0x1.c6ffbc6f01000p-3, -0x1.1ec72c5962bd2p-48) A(0x1.9600000000000p-1, 0x1.db13db0d49000p-3, -0x1.aff2af715b035p-45) A(0x1.9400000000000p-1, - 0x1.e530effe71000p-3, - 0x1.212276041f430p-51) A(0x1.9200000000000p-1, 0x1.ef5ade4dd0000p-3, -0x1.a211565bb8e11p-51) A(0x1.9000000000000p-1, 0x1.f991c6cb3b000p-3, 0x1.bcbecca0cdf30p-46) A(0x1.8c00000000000p-1, 0x1.07138604d5800p-2, 0x1.89cdb16ed4e91p-48) A(0x1.8a00000000000p-1, - 0x1.0c42d67616000p-2, - 0x1.7188b163ceae9p-45) A(0x1.8800000000000p-1, 0x1.1178e8227e800p-2, -0x1.c210e63a5f01cp-45) A(0x1.8600000000000p-1, - 0x1.16b5ccbacf800p-2, - 0x1.b9acdf7a51681p-45) A(0x1.8400000000000p-1, - 0x1.1bf99635a6800p-2, - 0x1.ca6ed5147bdb7p-45) A(0x1.8200000000000p-1, - 0x1.214456d0eb800p-2, - 0x1.a87deba46baeap-47) A(0x1.7e00000000000p-1, - 0x1.2bef07cdc9000p-2, 0x1.a9cfa4a5004f4p-45) A(0x1.7c00000000000p-1, 0x1.314f1e1d36000p-2, -0x1.8e27ad3213cb8p-45) A(0x1.7a00000000000p-1, 0x1.36b6776be1000p-2, 0x1.16ecdb0f177c8p-46) A(0x1.7800000000000p-1, - 0x1.3c25277333000p-2, - 0x1.83b54b606bd5cp-46) A(0x1.7600000000000p-1, - 0x1.419b423d5e800p-2, - 0x1.8e436ec90e09dp-47) A(0x1.7400000000000p-1, 0x1.4718dc271c800p-2, -0x1.f27ce0967d675p-45) A(0x1.7200000000000p-1, 0x1.4c9e09e173000p-2, -0x1.e20891b0ad8a4p-45) A(0x1.7000000000000p-1, - 0x1.522ae0738a000p-2, - 0x1.ebe708164c759p-45) A(0x1.6e00000000000p-1, 0x1.57bf753c8d000p-2, 0x1.fadedee5d40efp-46) A(0x1.6c00000000000p-1, - 0x1.5d5bddf596000p-2, - -0x1.a0b2a08a465dcp-47)}, -}; - -#define T __pow_log_data.tab -#undef A -#define A __pow_log_data.poly -#define Ln2hi __pow_log_data.ln2hi -#define Ln2lo __pow_log_data.ln2lo - -/* Top 12 bits of a double (sign and exponent bits). */ -static inline uint32_t top12(double x) -{ - return asuint64(x) >> 52; -} - -/* Compute y+TAIL = log(x) where the rounded result is y and TAIL has about - additional 15 bits precision. IX is the bit representation of x, but - normalized in the subnormal range using the sign bit for the exponent. */ -static inline double_t log_inline(uint64_t ix, double_t *tail) -{ - /* double_t for better performance on targets with FLT_EVAL_METHOD==2. */ - double_t z, r, y, invc, logc, logctail, kd, hi, t1, t2, lo, lo1, lo2, p; - uint64_t iz, tmp; - int k, i; - - /* x = 2^k z; where z is in range [OFF,2*OFF) and exact. - The range is split into N subintervals. - The ith subinterval contains z and c is near its center. */ - tmp = ix - OFF; - i = (tmp >> (52 - POW_LOG_TABLE_BITS)) % N; - k = (int64_t)tmp >> 52; /* arithmetic shift */ - iz = ix - (tmp & 0xfffULL << 52); - z = asdouble(iz); - kd = (double_t)k; - - /* log(x) = k*Ln2 + log(c) + log1p(z/c-1). */ - invc = T[i].invc; - logc = T[i].logc; - logctail = T[i].logctail; - - /* Note: 1/c is j/N or j/N/2 where j is an integer in [N,2N) and - |z/c - 1| < 1/N, so r = z/c - 1 is exactly representible. */ -#if __FP_FAST_FMA - r = __builtin_fma(z, invc, -1.0); -#else - /* Split z such that rhi, rlo and rhi*rhi are exact and |rlo| <= |r|. */ - double_t zhi = asdouble((iz + (1ULL << 31)) & (-1ULL << 32)); - double_t zlo = z - zhi; - double_t rhi = zhi * invc - 1.0; - double_t rlo = zlo * invc; - r = rhi + rlo; -#endif - - /* k*Ln2 + log(c) + r. */ - t1 = kd * Ln2hi + logc; - t2 = t1 + r; - lo1 = kd * Ln2lo + logctail; - lo2 = t1 - t2 + r; - - /* Evaluation is optimized assuming superscalar pipelined execution. */ - double_t ar, ar2, ar3, lo3, lo4; - ar = A[0] * r; /* A[0] = -0.5. */ - ar2 = r * ar; - ar3 = r * ar2; - /* k*Ln2 + log(c) + r + A[0]*r*r. */ -#if __FP_FAST_FMA - hi = t2 + ar2; - lo3 = __builtin_fma(ar, r, -ar2); - lo4 = t2 - hi + ar2; -#else - double_t arhi = A[0] * rhi; - double_t arhi2 = rhi * arhi; - hi = t2 + arhi2; - lo3 = rlo * (ar + arhi); - lo4 = t2 - hi + arhi2; -#endif - /* p = log1p(r) - r - A[0]*r*r. */ - p = (ar3 * (A[1] + r * A[2] + ar2 * (A[3] + r * A[4] + ar2 * (A[5] + r * A[6])))); - lo = lo1 + lo2 + lo3 + lo4 + p; - y = hi + lo; - *tail = hi - y + lo; - return y; -} - -#undef N -#undef T -#define EXP_TABLE_BITS 7 -#define EXP_POLY_ORDER 5 -#define EXP_USE_TOINT_NARROW 0 -#define EXP2_POLY_ORDER 5 -struct exp_data { - double invln2N; - double shift; - double negln2hiN; - double negln2loN; - double poly[4]; /* Last four coefficients. */ - double exp2_shift; - double exp2_poly[EXP2_POLY_ORDER]; - uint64_t tab[2 * (1 << EXP_TABLE_BITS)]; -}; -#define N (1 << EXP_TABLE_BITS) - -const struct exp_data __exp_data = { - // N/ln2 - .invln2N = 0x1.71547652b82fep0 * N, - // -ln2/N - .negln2hiN = -0x1.62e42fefa0000p-8, - .negln2loN = -0x1.cf79abc9e3b3ap-47, -// Used for rounding when !TOINT_INTRINSICS -#if EXP_USE_TOINT_NARROW - .shift = 0x1800000000.8p0, -#else - .shift = 0x1.8p52, -#endif - // exp polynomial coefficients. - .poly = - { - // abs error: 1.555*2^-66 - // ulp error: 0.509 (0.511 without fma) - // if |x| < ln2/256+eps - // abs error if |x| < ln2/256+0x1p-15: 1.09*2^-65 - // abs error if |x| < ln2/128: 1.7145*2^-56 - 0x1.ffffffffffdbdp-2, - 0x1.555555555543cp-3, - 0x1.55555cf172b91p-5, - 0x1.1111167a4d017p-7, - }, - .exp2_shift = 0x1.8p52 / N, - // exp2 polynomial coefficients. - .exp2_poly = - { - // abs error: 1.2195*2^-65 - // ulp error: 0.507 (0.511 without fma) - // if |x| < 1/256 - // abs error if |x| < 1/128: 1.9941*2^-56 - 0x1.62e42fefa39efp-1, - 0x1.ebfbdff82c424p-3, - 0x1.c6b08d70cf4b5p-5, - 0x1.3b2abd24650ccp-7, - 0x1.5d7e09b4e3a84p-10, - }, - // 2^(k/N) ~= H[k]*(1 + T[k]) for int k in [0,N) - // tab[2*k] = asuint64(T[k]) - // tab[2*k+1] = asuint64(H[k]) - (k << 52)/N - .tab = - { - 0x0, - 0x3ff0000000000000, - 0x3c9b3b4f1a88bf6e, - 0x3feff63da9fb3335, - 0xbc7160139cd8dc5d, - 0x3fefec9a3e778061, - 0xbc905e7a108766d1, - 0x3fefe315e86e7f85, - 0x3c8cd2523567f613, - 0x3fefd9b0d3158574, - 0xbc8bce8023f98efa, - 0x3fefd06b29ddf6de, - 0x3c60f74e61e6c861, - 0x3fefc74518759bc8, - 0x3c90a3e45b33d399, - 0x3fefbe3ecac6f383, - 0x3c979aa65d837b6d, - 0x3fefb5586cf9890f, - 0x3c8eb51a92fdeffc, - 0x3fefac922b7247f7, - 0x3c3ebe3d702f9cd1, - 0x3fefa3ec32d3d1a2, - 0xbc6a033489906e0b, - 0x3fef9b66affed31b, - 0xbc9556522a2fbd0e, - 0x3fef9301d0125b51, - 0xbc5080ef8c4eea55, - 0x3fef8abdc06c31cc, - 0xbc91c923b9d5f416, - 0x3fef829aaea92de0, - 0x3c80d3e3e95c55af, - 0x3fef7a98c8a58e51, - 0xbc801b15eaa59348, - 0x3fef72b83c7d517b, - 0xbc8f1ff055de323d, - 0x3fef6af9388c8dea, - 0x3c8b898c3f1353bf, - 0x3fef635beb6fcb75, - 0xbc96d99c7611eb26, - 0x3fef5be084045cd4, - 0x3c9aecf73e3a2f60, - 0x3fef54873168b9aa, - 0xbc8fe782cb86389d, - 0x3fef4d5022fcd91d, - 0x3c8a6f4144a6c38d, - 0x3fef463b88628cd6, - 0x3c807a05b0e4047d, - 0x3fef3f49917ddc96, - 0x3c968efde3a8a894, - 0x3fef387a6e756238, - 0x3c875e18f274487d, - 0x3fef31ce4fb2a63f, - 0x3c80472b981fe7f2, - 0x3fef2b4565e27cdd, - 0xbc96b87b3f71085e, - 0x3fef24dfe1f56381, - 0x3c82f7e16d09ab31, - 0x3fef1e9df51fdee1, - 0xbc3d219b1a6fbffa, - 0x3fef187fd0dad990, - 0x3c8b3782720c0ab4, - 0x3fef1285a6e4030b, - 0x3c6e149289cecb8f, - 0x3fef0cafa93e2f56, - 0x3c834d754db0abb6, - 0x3fef06fe0a31b715, - 0x3c864201e2ac744c, - 0x3fef0170fc4cd831, - 0x3c8fdd395dd3f84a, - 0x3feefc08b26416ff, - 0xbc86a3803b8e5b04, - 0x3feef6c55f929ff1, - 0xbc924aedcc4b5068, - 0x3feef1a7373aa9cb, - 0xbc9907f81b512d8e, - 0x3feeecae6d05d866, - 0xbc71d1e83e9436d2, - 0x3feee7db34e59ff7, - 0xbc991919b3ce1b15, - 0x3feee32dc313a8e5, - 0x3c859f48a72a4c6d, - 0x3feedea64c123422, - 0xbc9312607a28698a, - 0x3feeda4504ac801c, - 0xbc58a78f4817895b, - 0x3feed60a21f72e2a, - 0xbc7c2c9b67499a1b, - 0x3feed1f5d950a897, - 0x3c4363ed60c2ac11, - 0x3feece086061892d, - 0x3c9666093b0664ef, - 0x3feeca41ed1d0057, - 0x3c6ecce1daa10379, - 0x3feec6a2b5c13cd0, - 0x3c93ff8e3f0f1230, - 0x3feec32af0d7d3de, - 0x3c7690cebb7aafb0, - 0x3feebfdad5362a27, - 0x3c931dbdeb54e077, - 0x3feebcb299fddd0d, - 0xbc8f94340071a38e, - 0x3feeb9b2769d2ca7, - 0xbc87deccdc93a349, - 0x3feeb6daa2cf6642, - 0xbc78dec6bd0f385f, - 0x3feeb42b569d4f82, - 0xbc861246ec7b5cf6, - 0x3feeb1a4ca5d920f, - 0x3c93350518fdd78e, - 0x3feeaf4736b527da, - 0x3c7b98b72f8a9b05, - 0x3feead12d497c7fd, - 0x3c9063e1e21c5409, - 0x3feeab07dd485429, - 0x3c34c7855019c6ea, - 0x3feea9268a5946b7, - 0x3c9432e62b64c035, - 0x3feea76f15ad2148, - 0xbc8ce44a6199769f, - 0x3feea5e1b976dc09, - 0xbc8c33c53bef4da8, - 0x3feea47eb03a5585, - 0xbc845378892be9ae, - 0x3feea34634ccc320, - 0xbc93cedd78565858, - 0x3feea23882552225, - 0x3c5710aa807e1964, - 0x3feea155d44ca973, - 0xbc93b3efbf5e2228, - 0x3feea09e667f3bcd, - 0xbc6a12ad8734b982, - 0x3feea012750bdabf, - 0xbc6367efb86da9ee, - 0x3fee9fb23c651a2f, - 0xbc80dc3d54e08851, - 0x3fee9f7df9519484, - 0xbc781f647e5a3ecf, - 0x3fee9f75e8ec5f74, - 0xbc86ee4ac08b7db0, - 0x3fee9f9a48a58174, - 0xbc8619321e55e68a, - 0x3fee9feb564267c9, - 0x3c909ccb5e09d4d3, - 0x3feea0694fde5d3f, - 0xbc7b32dcb94da51d, - 0x3feea11473eb0187, - 0x3c94ecfd5467c06b, - 0x3feea1ed0130c132, - 0x3c65ebe1abd66c55, - 0x3feea2f336cf4e62, - 0xbc88a1c52fb3cf42, - 0x3feea427543e1a12, - 0xbc9369b6f13b3734, - 0x3feea589994cce13, - 0xbc805e843a19ff1e, - 0x3feea71a4623c7ad, - 0xbc94d450d872576e, - 0x3feea8d99b4492ed, - 0x3c90ad675b0e8a00, - 0x3feeaac7d98a6699, - 0x3c8db72fc1f0eab4, - 0x3feeace5422aa0db, - 0xbc65b6609cc5e7ff, - 0x3feeaf3216b5448c, - 0x3c7bf68359f35f44, - 0x3feeb1ae99157736, - 0xbc93091fa71e3d83, - 0x3feeb45b0b91ffc6, - 0xbc5da9b88b6c1e29, - 0x3feeb737b0cdc5e5, - 0xbc6c23f97c90b959, - 0x3feeba44cbc8520f, - 0xbc92434322f4f9aa, - 0x3feebd829fde4e50, - 0xbc85ca6cd7668e4b, - 0x3feec0f170ca07ba, - 0x3c71affc2b91ce27, - 0x3feec49182a3f090, - 0x3c6dd235e10a73bb, - 0x3feec86319e32323, - 0xbc87c50422622263, - 0x3feecc667b5de565, - 0x3c8b1c86e3e231d5, - 0x3feed09bec4a2d33, - 0xbc91bbd1d3bcbb15, - 0x3feed503b23e255d, - 0x3c90cc319cee31d2, - 0x3feed99e1330b358, - 0x3c8469846e735ab3, - 0x3feede6b5579fdbf, - 0xbc82dfcd978e9db4, - 0x3feee36bbfd3f37a, - 0x3c8c1a7792cb3387, - 0x3feee89f995ad3ad, - 0xbc907b8f4ad1d9fa, - 0x3feeee07298db666, - 0xbc55c3d956dcaeba, - 0x3feef3a2b84f15fb, - 0xbc90a40e3da6f640, - 0x3feef9728de5593a, - 0xbc68d6f438ad9334, - 0x3feeff76f2fb5e47, - 0xbc91eee26b588a35, - 0x3fef05b030a1064a, - 0x3c74ffd70a5fddcd, - 0x3fef0c1e904bc1d2, - 0xbc91bdfbfa9298ac, - 0x3fef12c25bd71e09, - 0x3c736eae30af0cb3, - 0x3fef199bdd85529c, - 0x3c8ee3325c9ffd94, - 0x3fef20ab5fffd07a, - 0x3c84e08fd10959ac, - 0x3fef27f12e57d14b, - 0x3c63cdaf384e1a67, - 0x3fef2f6d9406e7b5, - 0x3c676b2c6c921968, - 0x3fef3720dcef9069, - 0xbc808a1883ccb5d2, - 0x3fef3f0b555dc3fa, - 0xbc8fad5d3ffffa6f, - 0x3fef472d4a07897c, - 0xbc900dae3875a949, - 0x3fef4f87080d89f2, - 0x3c74a385a63d07a7, - 0x3fef5818dcfba487, - 0xbc82919e2040220f, - 0x3fef60e316c98398, - 0x3c8e5a50d5c192ac, - 0x3fef69e603db3285, - 0x3c843a59ac016b4b, - 0x3fef7321f301b460, - 0xbc82d52107b43e1f, - 0x3fef7c97337b9b5f, - 0xbc892ab93b470dc9, - 0x3fef864614f5a129, - 0x3c74b604603a88d3, - 0x3fef902ee78b3ff6, - 0x3c83c5ec519d7271, - 0x3fef9a51fbc74c83, - 0xbc8ff7128fd391f0, - 0x3fefa4afa2a490da, - 0xbc8dae98e223747d, - 0x3fefaf482d8e67f1, - 0x3c8ec3bc41aa2008, - 0x3fefba1bee615a27, - 0x3c842b94c3a9eb32, - 0x3fefc52b376bba97, - 0x3c8a64a931d185ee, - 0x3fefd0765b6e4540, - 0xbc8e37bae43be3ed, - 0x3fefdbfdad9cbe14, - 0x3c77893b4d91cd9d, - 0x3fefe7c1819e90d8, - 0x3c5305c14160cc89, - 0x3feff3c22b8f71f1, - }, -}; - -#define InvLn2N __exp_data.invln2N -#define NegLn2hiN __exp_data.negln2hiN -#define NegLn2loN __exp_data.negln2loN -#define Shift __exp_data.shift -#define T __exp_data.tab -#define C2 __exp_data.poly[5 - EXP_POLY_ORDER] -#define C3 __exp_data.poly[6 - EXP_POLY_ORDER] -#define C4 __exp_data.poly[7 - EXP_POLY_ORDER] -#define C5 __exp_data.poly[8 - EXP_POLY_ORDER] -#define C6 __exp_data.poly[9 - EXP_POLY_ORDER] - -static inline double specialcase(double_t tmp, uint64_t sbits, uint64_t ki) -{ - double_t scale, y; - - if ((ki & 0x80000000) == 0) { - /* k > 0, the exponent of scale might have overflowed by <= 460. */ - sbits -= 1009ull << 52; - scale = asdouble(sbits); - y = 0x1p1009 * (scale + scale * tmp); - return eval_as_double(y); - } - /* k < 0, need special care in the subnormal range. */ - sbits += 1022ull << 52; - /* Note: sbits is signed scale. */ - scale = asdouble(sbits); - y = scale + scale * tmp; - if (fabs(y) < 1.0) { - /* Round y to the right precision before scaling it into the subnormal - range to avoid double rounding that can cause 0.5+E/2 ulp error where - E is the worst-case ulp error outside the subnormal range. So this - is only useful if the goal is better than 1 ulp worst-case error. */ - double_t hi, lo, one = 1.0; - if (y < 0.0) - one = -1.0; - lo = scale - y + scale * tmp; - hi = one + y; - lo = one - hi + y + lo; - y = eval_as_double(hi + lo) - one; - /* Fix the sign of 0. */ - if (y == 0.0) - y = asdouble(sbits & 0x8000000000000000); - /* The underflow exception needs to be signaled explicitly. */ - fp_force_eval(fp_barrier(0x1p-1022) * 0x1p-1022); - } - y = 0x1p-1022 * y; - return eval_as_double(y); -} - -#define SIGN_BIAS (0x800 << EXP_TABLE_BITS) - -double __math_xflow(uint32_t sign, double y) -{ - return eval_as_double(fp_barrier(sign ? -y : y) * y); -} - -double __math_uflow(uint32_t sign) -{ - return __math_xflow(sign, 0x1p-767); -} - -double __math_oflow(uint32_t sign) -{ - return __math_xflow(sign, 0x1p769); -} - -/* Computes sign*exp(x+xtail) where |xtail| < 2^-8/N and |xtail| <= |x|. - The sign_bias argument is SIGN_BIAS or 0 and sets the sign to -1 or 1. */ -static inline double exp_inline(double_t x, double_t xtail, uint32_t sign_bias) -{ - uint32_t abstop; - uint64_t ki, idx, top, sbits; - /* double_t for better performance on targets with FLT_EVAL_METHOD==2. */ - double_t kd, z, r, r2, scale, tail, tmp; - - abstop = top12(x) & 0x7ff; - if (predict_false(abstop - top12(0x1p-54) >= top12(512.0) - top12(0x1p-54))) { - if (abstop - top12(0x1p-54) >= 0x80000000) { - /* Avoid spurious underflow for tiny x. */ - /* Note: 0 is common input. */ - double_t one = WANT_ROUNDING ? 1.0 + x : 1.0; - return sign_bias ? -one : one; - } - if (abstop >= top12(1024.0)) { - /* Note: inf and nan are already handled. */ - if (asuint64(x) >> 63) - return __math_uflow(sign_bias); - else - return __math_oflow(sign_bias); - } - /* Large x is special cased below. */ - abstop = 0; - } - - /* exp(x) = 2^(k/N) * exp(r), with exp(r) in [2^(-1/2N),2^(1/2N)]. */ - /* x = ln2/N*k + r, with int k and r in [-ln2/2N, ln2/2N]. */ - z = InvLn2N * x; -#if TOINT_INTRINSICS - kd = roundtoint(z); - ki = converttoint(z); -#elif EXP_USE_TOINT_NARROW - /* z - kd is in [-0.5-2^-16, 0.5] in all rounding modes. */ - kd = eval_as_double(z + Shift); - ki = asuint64(kd) >> 16; - kd = (double_t)(int32_t)ki; -#else - /* z - kd is in [-1, 1] in non-nearest rounding modes. */ - kd = eval_as_double(z + Shift); - ki = asuint64(kd); - kd -= Shift; -#endif - r = x + kd * NegLn2hiN + kd * NegLn2loN; - /* The code assumes 2^-200 < |xtail| < 2^-8/N. */ - r += xtail; - /* 2^(k/N) ~= scale * (1 + tail). */ - idx = 2 * (ki % N); - top = (ki + sign_bias) << (52 - EXP_TABLE_BITS); - tail = asdouble(T[idx]); - /* This is only a valid scale when -1023*N < k < 1024*N. */ - sbits = T[idx + 1] + top; - /* exp(x) = 2^(k/N) * exp(r) ~= scale + scale * (tail + exp(r) - 1). */ - /* Evaluation is optimized assuming superscalar pipelined execution. */ - r2 = r * r; - /* Without fma the worst case error is 0.25/N ulp larger. */ - /* Worst case error is less than 0.5+1.11/N+(abs poly error * 2^53) ulp. */ - tmp = tail + r + r2 * (C2 + r * C3) + r2 * r2 * (C4 + r * C5); - if (predict_false(abstop == 0)) - return specialcase(tmp, sbits, ki); - scale = asdouble(sbits); - /* Note: tmp == 0 or |tmp| > 2^-200 and scale > 2^-739, so there - is no spurious underflow here even without fma. */ - return eval_as_double(scale + scale * tmp); -} - -/* Returns 0 if not int, 1 if odd int, 2 if even int. The argument is - the bit representation of a non-zero finite floating-point value. */ -static inline int checkint(uint64_t iy) -{ - int e = iy >> 52 & 0x7ff; - if (e < 0x3ff) - return 0; - if (e > 0x3ff + 52) - return 2; - if (iy & ((1ULL << (0x3ff + 52 - e)) - 1)) - return 0; - if (iy & (1ULL << (0x3ff + 52 - e))) - return 1; - return 2; -} - -#if 100 * __GNUC__ + __GNUC_MINOR__ >= 303 -#define NAN __builtin_nanf("") -#define INFINITY __builtin_inff() -#else -#define NAN (0.0f / 0.0f) -#define INFINITY 1e5000f -#endif - -static inline int zeroinfnan(uint64_t i) -{ - return 2 * i - 1 >= 2 * asuint64(INFINITY) - 1; -} - -#if WANT_SNAN -#error SNaN is unsupported -#else -#define issignalingf_inline(x) 0 -#define issignaling_inline(x) 0 -#endif - -double pow(double x, double y) -{ - uint32_t sign_bias = 0; - uint64_t ix, iy; - uint32_t topx, topy; - - ix = asuint64(x); - iy = asuint64(y); - topx = top12(x); - topy = top12(y); - if (predict_false(topx - 0x001 >= 0x7ff - 0x001 || (topy & 0x7ff) - 0x3be >= 0x43e - 0x3be)) { - /* Note: if |y| > 1075 * ln2 * 2^53 ~= 0x1.749p62 then pow(x,y) = inf/0 - and if |y| < 2^-54 / 1075 ~= 0x1.e7b6p-65 then pow(x,y) = +-1. */ - /* Special cases: (x < 0x1p-126 or inf or nan) or - (|y| < 0x1p-65 or |y| >= 0x1p63 or nan). */ - if (predict_false(zeroinfnan(iy))) { - if (2 * iy == 0) - return issignaling_inline(x) ? x + y : 1.0; - if (ix == asuint64(1.0)) - return issignaling_inline(y) ? x + y : 1.0; - if (2 * ix > 2 * asuint64(INFINITY) || 2 * iy > 2 * asuint64(INFINITY)) - return x + y; - if (2 * ix == 2 * asuint64(1.0)) - return 1.0; - if ((2 * ix < 2 * asuint64(1.0)) == !(iy >> 63)) - return 0.0; /* |x|<1 && y==inf or |x|>1 && y==-inf. */ - return y * y; - } - if (predict_false(zeroinfnan(ix))) { - double_t x2 = x * x; - if (ix >> 63 && checkint(iy) == 1) - x2 = -x2; - /* Without the barrier some versions of clang hoist the 1/x2 and - thus division by zero exception can be signaled spuriously. */ - return iy >> 63 ? fp_barrier(1 / x2) : x2; - } - /* Here x and y are non-zero finite. */ - if (ix >> 63) { - /* Finite x < 0. */ - int yint = checkint(iy); - if (yint == 0) - return __math_invalid(x); - if (yint == 1) - sign_bias = SIGN_BIAS; - ix &= 0x7fffffffffffffff; - topx &= 0x7ff; - } - if ((topy & 0x7ff) - 0x3be >= 0x43e - 0x3be) { - /* Note: sign_bias == 0 here because y is not odd. */ - if (ix == asuint64(1.0)) - return 1.0; - if ((topy & 0x7ff) < 0x3be) { - /* |y| < 2^-65, x^y ~= 1 + y*log(x). */ - if (WANT_ROUNDING) - return ix > asuint64(1.0) ? 1.0 + y : 1.0 - y; - else - return 1.0; - } - return (ix > asuint64(1.0)) == (topy < 0x800) ? __math_oflow(0) : __math_uflow(0); - } - if (topx == 0) { - /* Normalize subnormal x so exponent becomes negative. */ - ix = asuint64(x * 0x1p52); - ix &= 0x7fffffffffffffff; - ix -= 52ULL << 52; - } - } - - double_t lo; - double_t hi = log_inline(ix, &lo); - double_t ehi, elo; -#if __FP_FAST_FMA - ehi = y * hi; - elo = y * lo + __builtin_fma(y, hi, -ehi); -#else - double_t yhi = asdouble(iy & -1ULL << 27); - double_t ylo = y - yhi; - double_t lhi = asdouble(asuint64(hi) & -1ULL << 27); - double_t llo = hi - lhi + lo; - ehi = yhi * lhi; - elo = ylo * lhi + y * llo; /* |elo| < |ehi| * 2^-25. */ -#endif - return exp_inline(ehi, elo, sign_bias); -} -#endif diff --git a/arceos/ulib/axlibc/c/printf.c b/arceos/ulib/axlibc/c/printf.c deleted file mode 100644 index 3657376bd..000000000 --- a/arceos/ulib/axlibc/c/printf.c +++ /dev/null @@ -1,1482 +0,0 @@ -/** - * @author (c) Eyal Rozenberg - * 2021-2022, Haifa, Palestine/Israel - * @author (c) Marco Paland (info@paland.com) - * 2014-2019, PALANDesign Hannover, Germany - * - * @note Others have made smaller contributions to this file: see the - * contributors page at https://github.com/eyalroz/printf/graphs/contributors - * or ask one of the authors. The original code for exponential specifiers was - * contributed by Martijn Jasperse . - * - * @brief Small stand-alone implementation of the printf family of functions - * (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with - * a very limited resources. - * - * @note the implementations are thread-safe; re-entrant; use no functions from - * the standard library; and do not dynamically allocate any memory. - * - * @license The MIT License (MIT) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -// Define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H=1 ...) to include the -// printf_config.h header file -#define PRINTF_INCLUDE_CONFIG_H 1 - -#if PRINTF_INCLUDE_CONFIG_H -#include "printf_config.h" -#endif - -#include "printf.h" - -#ifdef __cplusplus -#include -#include -#else -#include -#include -#include -#include -#endif // __cplusplus - -#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES -#define printf_ printf -#define sprintf_ sprintf -#define vsprintf_ vsprintf -#define snprintf_ snprintf -#define vsnprintf_ vsnprintf -#define vprintf_ vprintf -#endif - -// 'ntoa' conversion buffer size, this must be big enough to hold one converted -// numeric number including padded zeros (dynamically created on stack) -#ifndef PRINTF_INTEGER_BUFFER_SIZE -#define PRINTF_INTEGER_BUFFER_SIZE 32 -#endif - -// size of the fixed (on-stack) buffer for printing individual decimal numbers. -// this must be big enough to hold one converted floating-point value including -// padded zeros. -#ifndef PRINTF_DECIMAL_BUFFER_SIZE -#define PRINTF_DECIMAL_BUFFER_SIZE 32 -#endif - -// Support for the decimal notation floating point conversion specifiers (%f, %F) -#ifndef PRINTF_SUPPORT_DECIMAL_SPECIFIERS -#define PRINTF_SUPPORT_DECIMAL_SPECIFIERS 1 -#endif - -// Support for the exponential notation floating point conversion specifiers (%e, %g, %E, %G) -#ifndef PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS -#define PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS 1 -#endif - -// Support for the length write-back specifier (%n) -#ifndef PRINTF_SUPPORT_WRITEBACK_SPECIFIER -#define PRINTF_SUPPORT_WRITEBACK_SPECIFIER 1 -#endif - -// Default precision for the floating point conversion specifiers (the C standard sets this at 6) -#ifndef PRINTF_DEFAULT_FLOAT_PRECISION -#define PRINTF_DEFAULT_FLOAT_PRECISION 6 -#endif - -// According to the C languages standard, printf() and related functions must be able to print any -// integral number in floating-point notation, regardless of length, when using the %f specifier - -// possibly hundreds of characters, potentially overflowing your buffers. In this implementation, -// all values beyond this threshold are switched to exponential notation. -#ifndef PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL -#define PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL 9 -#endif - -// Support for the long long integral types (with the ll, z and t length modifiers for specifiers -// %d,%i,%o,%x,%X,%u, and with the %p specifier). Note: 'L' (long double) is not supported. -#ifndef PRINTF_SUPPORT_LONG_LONG -#define PRINTF_SUPPORT_LONG_LONG 1 -#endif - -// The number of terms in a Taylor series expansion of log_10(x) to -// use for approximation - including the power-zero term (i.e. the -// value at the point of expansion). -#ifndef PRINTF_LOG10_TAYLOR_TERMS -#define PRINTF_LOG10_TAYLOR_TERMS 4 -#endif - -#if PRINTF_LOG10_TAYLOR_TERMS <= 1 -#error "At least one non-constant Taylor expansion is necessary for the log10() calculation" -#endif - -// Be extra-safe, and don't assume format specifiers are completed correctly -// before the format string end. -#ifndef PRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER -#define PRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER 1 -#endif - -#define PRINTF_PREFER_DECIMAL false -#define PRINTF_PREFER_EXPONENTIAL true - -/////////////////////////////////////////////////////////////////////////////// - -// The following will convert the number-of-digits into an exponential-notation literal -#define PRINTF_CONCATENATE(s1, s2) s1##s2 -#define PRINTF_EXPAND_THEN_CONCATENATE(s1, s2) PRINTF_CONCATENATE(s1, s2) -#define PRINTF_FLOAT_NOTATION_THRESHOLD \ - PRINTF_EXPAND_THEN_CONCATENATE(1e, PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL) - -// internal flag definitions -#define FLAGS_ZEROPAD (1U << 0U) -#define FLAGS_LEFT (1U << 1U) -#define FLAGS_PLUS (1U << 2U) -#define FLAGS_SPACE (1U << 3U) -#define FLAGS_HASH (1U << 4U) -#define FLAGS_UPPERCASE (1U << 5U) -#define FLAGS_CHAR (1U << 6U) -#define FLAGS_SHORT (1U << 7U) -#define FLAGS_INT (1U << 8U) -// Only used with PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS -#define FLAGS_LONG (1U << 9U) -#define FLAGS_LONG_LONG (1U << 10U) -#define FLAGS_PRECISION (1U << 11U) -#define FLAGS_ADAPT_EXP (1U << 12U) -#define FLAGS_POINTER (1U << 13U) -// Note: Similar, but not identical, effect as FLAGS_HASH -#define FLAGS_SIGNED (1U << 14U) -// Only used with PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS - -#ifdef PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS - -#define FLAGS_INT8 FLAGS_CHAR - -#if (SHRT_MAX == 32767LL) -#define FLAGS_INT16 FLAGS_SHORT -#elif (INT_MAX == 32767LL) -#define FLAGS_INT16 FLAGS_INT -#elif (LONG_MAX == 32767LL) -#define FLAGS_INT16 FLAGS_LONG -#elif (LLONG_MAX == 32767LL) -#define FLAGS_INT16 FLAGS_LONG_LONG -#else -#error "No basic integer type has a size of 16 bits exactly" -#endif - -#if (SHRT_MAX == 2147483647LL) -#define FLAGS_INT32 FLAGS_SHORT -#elif (INT_MAX == 2147483647LL) -#define FLAGS_INT32 FLAGS_INT -#elif (LONG_MAX == 2147483647LL) -#define FLAGS_INT32 FLAGS_LONG -#elif (LLONG_MAX == 2147483647LL) -#define FLAGS_INT32 FLAGS_LONG_LONG -#else -#error "No basic integer type has a size of 32 bits exactly" -#endif - -#if (SHRT_MAX == 9223372036854775807LL) -#define FLAGS_INT64 FLAGS_SHORT -#elif (INT_MAX == 9223372036854775807LL) -#define FLAGS_INT64 FLAGS_INT -#elif (LONG_MAX == 9223372036854775807LL) -#define FLAGS_INT64 FLAGS_LONG -#elif (LLONG_MAX == 9223372036854775807LL) -#define FLAGS_INT64 FLAGS_LONG_LONG -#else -#error "No basic integer type has a size of 64 bits exactly" -#endif - -#endif // PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS - -typedef unsigned int printf_flags_t; - -#define BASE_BINARY 2 -#define BASE_OCTAL 8 -#define BASE_DECIMAL 10 -#define BASE_HEX 16 - -typedef uint8_t numeric_base_t; - -#if PRINTF_SUPPORT_LONG_LONG -typedef unsigned long long printf_unsigned_value_t; -typedef long long printf_signed_value_t; -#else -typedef unsigned long printf_unsigned_value_t; -typedef long printf_signed_value_t; -#endif - -// The printf()-family functions return an `int`; it is therefore -// unnecessary/inappropriate to use size_t - often larger than int -// in practice - for non-negative related values, such as widths, -// precisions, offsets into buffers used for printing and the sizes -// of these buffers. instead, we use: -typedef unsigned int printf_size_t; -#define PRINTF_MAX_POSSIBLE_BUFFER_SIZE INT_MAX -// If we were to nitpick, this would actually be INT_MAX + 1, -// since INT_MAX is the maximum return value, which excludes the -// trailing '\0'. - -#if (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS) -#include -#if FLT_RADIX != 2 -#error "Non-binary-radix floating-point types are unsupported." -#endif - -#if DBL_MANT_DIG == 24 - -#define DOUBLE_SIZE_IN_BITS 32 -typedef uint32_t double_uint_t; -#define DOUBLE_EXPONENT_MASK 0xFFU -#define DOUBLE_BASE_EXPONENT 127 -#define DOUBLE_MAX_SUBNORMAL_EXPONENT_OF_10 -38 -#define DOUBLE_MAX_SUBNORMAL_POWER_OF_10 1e-38 - -#elif DBL_MANT_DIG == 53 - -#define DOUBLE_SIZE_IN_BITS 64 -typedef uint64_t double_uint_t; -#define DOUBLE_EXPONENT_MASK 0x7FFU -#define DOUBLE_BASE_EXPONENT 1023 -#define DOUBLE_MAX_SUBNORMAL_EXPONENT_OF_10 -308 -#define DOUBLE_MAX_SUBNORMAL_POWER_OF_10 1e-308 - -#else -#error "Unsupported double type configuration" -#endif -#define DOUBLE_STORED_MANTISSA_BITS (DBL_MANT_DIG - 1) - -typedef union { - double_uint_t U; - double F; -} double_with_bit_access; - -// This is unnecessary in C99, since compound initializers can be used, -// but: -// 1. Some compilers are finicky about this; -// 2. Some people may want to convert this to C89; -// 3. If you try to use it as C++, only C++20 supports compound literals -static inline double_with_bit_access get_bit_access(double x) -{ - double_with_bit_access dwba; - dwba.F = x; - return dwba; -} - -static inline int get_sign_bit(double x) -{ - // The sign is stored in the highest bit - return (int)(get_bit_access(x).U >> (DOUBLE_SIZE_IN_BITS - 1)); -} - -static inline int get_exp2(double_with_bit_access x) -{ - // The exponent in an IEEE-754 floating-point number occupies a contiguous - // sequence of bits (e.g. 52..62 for 64-bit doubles), but with a non-trivial representation: An - // unsigned offset from some negative value (with the extremal offset values reserved for - // special use). - return (int)((x.U >> DOUBLE_STORED_MANTISSA_BITS) & DOUBLE_EXPONENT_MASK) - - DOUBLE_BASE_EXPONENT; -} -#define PRINTF_ABS(_x) ((_x) > 0 ? (_x) : -(_x)) - -#endif // (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS) - -// Note in particular the behavior here on LONG_MIN or LLONG_MIN; it is valid -// and well-defined, but if you're not careful you can easily trigger undefined -// behavior with -LONG_MIN or -LLONG_MIN -#define ABS_FOR_PRINTING(_x) \ - ((printf_unsigned_value_t)((_x) > 0 ? (_x) : -((printf_signed_value_t)_x))) - -// wrapper (used as buffer) for output function type -// -// One of the following must hold: -// 1. max_chars is 0 -// 2. buffer is non-null -// 3. function is non-null -// -// ... otherwise bad things will happen. -typedef struct { - void (*function)(char c, void *extra_arg); - void *extra_function_arg; - char *buffer; - printf_size_t pos; - printf_size_t max_chars; -} output_gadget_t; - -// Note: This function currently assumes it is not passed a '\0' c, -// or alternatively, that '\0' can be passed to the function in the output -// gadget. The former assumption holds within the printf library. It also -// assumes that the output gadget has been properly initialized. -static inline void putchar_via_gadget(output_gadget_t *gadget, char c) -{ - printf_size_t write_pos = gadget->pos++; - // We're _always_ increasing pos, so as to count how may characters - // _would_ have been written if not for the max_chars limitation - if (write_pos >= gadget->max_chars) { - return; - } - if (gadget->function != NULL) { - // No check for c == '\0' . - gadget->function(c, gadget->extra_function_arg); - } else { - // it must be the case that gadget->buffer != NULL , due to the constraint - // on output_gadget_t ; and note we're relying on write_pos being non-negative. - gadget->buffer[write_pos] = c; - } -} - -// Possibly-write the string-terminating '\0' character -static inline void append_termination_with_gadget(output_gadget_t *gadget) -{ - if (gadget->function != NULL || gadget->max_chars == 0) { - return; - } - if (gadget->buffer == NULL) { - return; - } - printf_size_t null_char_pos = - gadget->pos < gadget->max_chars ? gadget->pos : gadget->max_chars - 1; - gadget->buffer[null_char_pos] = '\0'; -} - -// We can't use putchar_ as is, since our output gadget -// only takes pointers to functions with an extra argument -// static inline void putchar_wrapper(char c, void *unused) -// { -// (void)unused; -// putchar_(c); -// } - -static inline output_gadget_t discarding_gadget(void) -{ - output_gadget_t gadget; - gadget.function = NULL; - gadget.extra_function_arg = NULL; - gadget.buffer = NULL; - gadget.pos = 0; - gadget.max_chars = 0; - return gadget; -} - -static inline output_gadget_t buffer_gadget(char *buffer, size_t buffer_size) -{ - printf_size_t usable_buffer_size = (buffer_size > PRINTF_MAX_POSSIBLE_BUFFER_SIZE) - ? PRINTF_MAX_POSSIBLE_BUFFER_SIZE - : (printf_size_t)buffer_size; - output_gadget_t result = discarding_gadget(); - if (buffer != NULL) { - result.buffer = buffer; - result.max_chars = usable_buffer_size; - } - return result; -} - -static inline output_gadget_t function_gadget(void (*function)(char, void *), void *extra_arg) -{ - output_gadget_t result = discarding_gadget(); - result.function = function; - result.extra_function_arg = extra_arg; - result.max_chars = PRINTF_MAX_POSSIBLE_BUFFER_SIZE; - return result; -} - -// static inline output_gadget_t extern_putchar_gadget(void) -// { -// return function_gadget(putchar_wrapper, NULL); -// } - -// internal secure strlen -// @return The length of the string (excluding the terminating 0) limited by 'maxsize' -// @note strlen uses size_t, but wes only use this function with printf_size_t -// variables - hence the signature. -static inline printf_size_t strnlen_s_(const char *str, printf_size_t maxsize) -{ - const char *s; - for (s = str; *s && maxsize--; ++s) - ; - return (printf_size_t)(s - str); -} - -// internal test if char is a digit (0-9) -// @return true if char is a digit -static inline bool is_digit_(char ch) -{ - return (ch >= '0') && (ch <= '9'); -} - -// internal ASCII string to printf_size_t conversion -static printf_size_t atou_(const char **str) -{ - printf_size_t i = 0U; - while (is_digit_(**str)) { - i = i * 10U + (printf_size_t)(*((*str)++) - '0'); - } - return i; -} - -// output the specified string in reverse, taking care of any zero-padding -static void out_rev_(output_gadget_t *output, const char *buf, printf_size_t len, - printf_size_t width, printf_flags_t flags) -{ - const printf_size_t start_pos = output->pos; - - // pad spaces up to given width - if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { - for (printf_size_t i = len; i < width; i++) { - putchar_via_gadget(output, ' '); - } - } - - // reverse string - while (len) { - putchar_via_gadget(output, buf[--len]); - } - - // append pad spaces up to given width - if (flags & FLAGS_LEFT) { - while (output->pos - start_pos < width) { - putchar_via_gadget(output, ' '); - } - } -} - -// Invoked by print_integer after the actual number has been printed, performing necessary -// work on the number's prefix (as the number is initially printed in reverse order) -static void print_integer_finalization(output_gadget_t *output, char *buf, printf_size_t len, - bool negative, numeric_base_t base, printf_size_t precision, - printf_size_t width, printf_flags_t flags) -{ - printf_size_t unpadded_len = len; - - // pad with leading zeros - { - if (!(flags & FLAGS_LEFT)) { - if (width && (flags & FLAGS_ZEROPAD) && - (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { - width--; - } - while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_INTEGER_BUFFER_SIZE)) { - buf[len++] = '0'; - } - } - - while ((len < precision) && (len < PRINTF_INTEGER_BUFFER_SIZE)) { - buf[len++] = '0'; - } - - if (base == BASE_OCTAL && (len > unpadded_len)) { - // Since we've written some zeros, we've satisfied the alternative format leading space - // requirement - flags &= ~FLAGS_HASH; - } - } - - // handle hash - if (flags & (FLAGS_HASH | FLAGS_POINTER)) { - if (!(flags & FLAGS_PRECISION) && len && ((len == precision) || (len == width))) { - // Let's take back some padding digits to fit in what will eventually - // be the format-specific prefix - if (unpadded_len < len) { - len--; // This should suffice for BASE_OCTAL - } - if (len && (base == BASE_HEX || base == BASE_BINARY) && (unpadded_len < len)) { - len--; // ... and an extra one for 0x or 0b - } - } - if ((base == BASE_HEX) && !(flags & FLAGS_UPPERCASE) && - (len < PRINTF_INTEGER_BUFFER_SIZE)) { - buf[len++] = 'x'; - } else if ((base == BASE_HEX) && (flags & FLAGS_UPPERCASE) && - (len < PRINTF_INTEGER_BUFFER_SIZE)) { - buf[len++] = 'X'; - } else if ((base == BASE_BINARY) && (len < PRINTF_INTEGER_BUFFER_SIZE)) { - buf[len++] = 'b'; - } - if (len < PRINTF_INTEGER_BUFFER_SIZE) { - buf[len++] = '0'; - } - } - - if (len < PRINTF_INTEGER_BUFFER_SIZE) { - if (negative) { - buf[len++] = '-'; - } else if (flags & FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists - } else if (flags & FLAGS_SPACE) { - buf[len++] = ' '; - } - } - - out_rev_(output, buf, len, width, flags); -} - -// An internal itoa-like function -static void print_integer(output_gadget_t *output, printf_unsigned_value_t value, bool negative, - numeric_base_t base, printf_size_t precision, printf_size_t width, - printf_flags_t flags) -{ - char buf[PRINTF_INTEGER_BUFFER_SIZE]; - printf_size_t len = 0U; - - if (!value) { - if (!(flags & FLAGS_PRECISION)) { - buf[len++] = '0'; - flags &= ~FLAGS_HASH; - // We drop this flag this since either the alternative and regular modes of the - // specifier don't differ on 0 values, or (in the case of octal) we've already provided - // the special handling for this mode. - } else if (base == BASE_HEX) { - flags &= ~FLAGS_HASH; - // We drop this flag this since either the alternative and regular modes of the - // specifier don't differ on 0 values - } - } else { - do { - const char digit = (char)(value % base); - buf[len++] = (char)(digit < 10 ? '0' + digit - : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10); - value /= base; - } while (value && (len < PRINTF_INTEGER_BUFFER_SIZE)); - } - - print_integer_finalization(output, buf, len, negative, base, precision, width, flags); -} - -#if (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS) - -// Stores a fixed-precision representation of a double relative -// to a fixed precision (which cannot be determined by examining this structure) -struct double_components { - int_fast64_t integral; - int_fast64_t fractional; - // ... truncation of the actual fractional part of the double value, scaled - // by the precision value - bool is_negative; -}; - -#define NUM_DECIMAL_DIGITS_IN_INT64_T 18 -#define PRINTF_MAX_PRECOMPUTED_POWER_OF_10 NUM_DECIMAL_DIGITS_IN_INT64_T -static const double powers_of_10[NUM_DECIMAL_DIGITS_IN_INT64_T] = { - 1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, - 1e09, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17}; - -#define PRINTF_MAX_SUPPORTED_PRECISION NUM_DECIMAL_DIGITS_IN_INT64_T - 1 - -// Break up a double number - which is known to be a finite non-negative number - -// into its base-10 parts: integral - before the decimal point, and fractional - after it. -// Taken the precision into account, but does not change it even internally. -static struct double_components get_components(double number, printf_size_t precision) -{ - struct double_components number_; - number_.is_negative = get_sign_bit(number); - double abs_number = (number_.is_negative) ? -number : number; - number_.integral = (int_fast64_t)abs_number; - double remainder = (abs_number - (double)number_.integral) * powers_of_10[precision]; - number_.fractional = (int_fast64_t)remainder; - - remainder -= (double)number_.fractional; - - if (remainder > 0.5) { - ++number_.fractional; - // handle rollover, e.g. case 0.99 with precision 1 is 1.0 - if ((double)number_.fractional >= powers_of_10[precision]) { - number_.fractional = 0; - ++number_.integral; - } - } else if ((remainder == 0.5) && ((number_.fractional == 0U) || (number_.fractional & 1U))) { - // if halfway, round up if odd OR if last digit is 0 - ++number_.fractional; - } - - if (precision == 0U) { - remainder = abs_number - (double)number_.integral; - if ((!(remainder < 0.5) || (remainder > 0.5)) && (number_.integral & 1)) { - // exactly 0.5 and ODD, then round up - // 1.5 -> 2, but 2.5 -> 2 - ++number_.integral; - } - } - return number_; -} - -#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS -struct scaling_factor { - double raw_factor; - bool multiply; // if true, need to multiply by raw_factor; otherwise need to divide by it -}; - -static double apply_scaling(double num, struct scaling_factor normalization) -{ - return normalization.multiply ? num * normalization.raw_factor : num / normalization.raw_factor; -} - -static double unapply_scaling(double normalized, struct scaling_factor normalization) -{ -#ifdef __GNUC__ -// accounting for a static analysis bug in GCC 6.x and earlier -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#endif - return normalization.multiply ? normalized / normalization.raw_factor - : normalized * normalization.raw_factor; -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif -} - -static struct scaling_factor update_normalization(struct scaling_factor sf, - double extra_multiplicative_factor) -{ - struct scaling_factor result; - if (sf.multiply) { - result.multiply = true; - result.raw_factor = sf.raw_factor * extra_multiplicative_factor; - } else { - int factor_exp2 = get_exp2(get_bit_access(sf.raw_factor)); - int extra_factor_exp2 = get_exp2(get_bit_access(extra_multiplicative_factor)); - - // Divide the larger-exponent raw raw_factor by the smaller - if (PRINTF_ABS(factor_exp2) > PRINTF_ABS(extra_factor_exp2)) { - result.multiply = false; - result.raw_factor = sf.raw_factor / extra_multiplicative_factor; - } else { - result.multiply = true; - result.raw_factor = extra_multiplicative_factor / sf.raw_factor; - } - } - return result; -} - -static struct double_components get_normalized_components(bool negative, printf_size_t precision, - double non_normalized, - struct scaling_factor normalization, - int floored_exp10) -{ - struct double_components components; - components.is_negative = negative; - double scaled = apply_scaling(non_normalized, normalization); - - bool close_to_representation_extremum = - ((-floored_exp10 + (int)precision) >= DBL_MAX_10_EXP - 1); - if (close_to_representation_extremum) { - // We can't have a normalization factor which also accounts for the precision, i.e. moves - // some decimal digits into the mantissa, since it's unrepresentable, or nearly - // unrepresentable. So, we'll give up early on getting extra precision... - return get_components(negative ? -scaled : scaled, precision); - } - components.integral = (int_fast64_t)scaled; - double remainder = non_normalized - unapply_scaling((double)components.integral, normalization); - double prec_power_of_10 = powers_of_10[precision]; - struct scaling_factor account_for_precision = - update_normalization(normalization, prec_power_of_10); - double scaled_remainder = apply_scaling(remainder, account_for_precision); - double rounding_threshold = 0.5; - - components.fractional = - (int_fast64_t)scaled_remainder; // when precision == 0, the assigned value should be 0 - scaled_remainder -= - (double)components.fractional; // when precision == 0, this will not change scaled_remainder - - components.fractional += (scaled_remainder >= rounding_threshold); - if (scaled_remainder == rounding_threshold) { - // banker's rounding: Round towards the even number (making the mean error 0) - components.fractional &= ~((int_fast64_t)0x1); - } - // handle rollover, e.g. the case of 0.99 with precision 1 becoming (0,100), - // and must then be corrected into (1, 0). - // Note: for precision = 0, this will "translate" the rounding effect from - // the fractional part to the integral part where it should actually be - // felt (as prec_power_of_10 is 1) - if ((double)components.fractional >= prec_power_of_10) { - components.fractional = 0; - ++components.integral; - } - return components; -} -#endif // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS - -static void print_broken_up_decimal(struct double_components number_, output_gadget_t *output, - printf_size_t precision, printf_size_t width, - printf_flags_t flags, char *buf, printf_size_t len) -{ - if (precision != 0U) { - // do fractional part, as an unsigned number - - printf_size_t count = precision; - - // %g/%G mandates we skip the trailing 0 digits... - if ((flags & FLAGS_ADAPT_EXP) && !(flags & FLAGS_HASH) && (number_.fractional > 0)) { - while (true) { - int_fast64_t digit = number_.fractional % 10U; - if (digit != 0) { - break; - } - --count; - number_.fractional /= 10U; - } - // ... and even the decimal point if there are no - // non-zero fractional part digits (see below) - } - - if (number_.fractional > 0 || !(flags & FLAGS_ADAPT_EXP) || (flags & FLAGS_HASH)) { - while (len < PRINTF_DECIMAL_BUFFER_SIZE) { - --count; - buf[len++] = (char)('0' + number_.fractional % 10U); - if (!(number_.fractional /= 10U)) { - break; - } - } - // add extra 0s - while ((len < PRINTF_DECIMAL_BUFFER_SIZE) && (count > 0U)) { - buf[len++] = '0'; - --count; - } - if (len < PRINTF_DECIMAL_BUFFER_SIZE) { - buf[len++] = '.'; - } - } - } else { - if ((flags & FLAGS_HASH) && (len < PRINTF_DECIMAL_BUFFER_SIZE)) { - buf[len++] = '.'; - } - } - - // Write the integer part of the number (it comes after the fractional - // since the character order is reversed) - while (len < PRINTF_DECIMAL_BUFFER_SIZE) { - buf[len++] = (char)('0' + (number_.integral % 10)); - if (!(number_.integral /= 10)) { - break; - } - } - - // pad leading zeros - if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { - if (width && (number_.is_negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { - width--; - } - while ((len < width) && (len < PRINTF_DECIMAL_BUFFER_SIZE)) { - buf[len++] = '0'; - } - } - - if (len < PRINTF_DECIMAL_BUFFER_SIZE) { - if (number_.is_negative) { - buf[len++] = '-'; - } else if (flags & FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists - } else if (flags & FLAGS_SPACE) { - buf[len++] = ' '; - } - } - - out_rev_(output, buf, len, width, flags); -} - -// internal ftoa for fixed decimal floating point -static void print_decimal_number(output_gadget_t *output, double number, printf_size_t precision, - printf_size_t width, printf_flags_t flags, char *buf, - printf_size_t len) -{ - struct double_components value_ = get_components(number, precision); - print_broken_up_decimal(value_, output, precision, width, flags, buf, len); -} - -#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS - -// A floor function - but one which only works for numbers whose -// floor value is representable by an int. -static int bastardized_floor(double x) -{ - if (x >= 0) { - return (int)x; - } - int n = (int)x; - return (((double)n) == x) ? n : n - 1; -} - -// Computes the base-10 logarithm of the input number - which must be an actual -// positive number (not infinity or NaN, nor a sub-normal) -static double log10_of_positive(double positive_number) -{ - // The implementation follows David Gay (https://www.ampl.com/netlib/fp/dtoa.c). - // - // Since log_10 ( M * 2^x ) = log_10(M) + x , we can separate the components of - // our input number, and need only solve log_10(M) for M between 1 and 2 (as - // the base-2 mantissa is always 1-point-something). In that limited range, a - // Taylor series expansion of log10(x) should serve us well enough; and we'll - // take the mid-point, 1.5, as the point of expansion. - - double_with_bit_access dwba = get_bit_access(positive_number); - // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) - int exp2 = get_exp2(dwba); - // drop the exponent, so dwba.F comes into the range [1,2) - dwba.U = (dwba.U & (((double_uint_t)(1) << DOUBLE_STORED_MANTISSA_BITS) - 1U)) | - ((double_uint_t)DOUBLE_BASE_EXPONENT << DOUBLE_STORED_MANTISSA_BITS); - double z = (dwba.F - 1.5); - return ( - // Taylor expansion around 1.5: - 0.1760912590556812420 // Expansion term 0: ln(1.5) / ln(10) - + z * 0.2895296546021678851 // Expansion term 1: (M - 1.5) * 2/3 / ln(10) -#if PRINTF_LOG10_TAYLOR_TERMS > 2 - - z * z * 0.0965098848673892950 // Expansion term 2: (M - 1.5)^2 * 2/9 / ln(10) -#if PRINTF_LOG10_TAYLOR_TERMS > 3 - + z * z * z * 0.0428932821632841311 // Expansion term 2: (M - 1.5)^3 * 8/81 / ln(10) -#endif -#endif - // exact log_2 of the exponent x, with logarithm base change - + exp2 * 0.30102999566398119521 // = exp2 * log_10(2) = exp2 * ln(2)/ln(10) - ); -} - -static double pow10_of_int(int floored_exp10) -{ - // A crude hack for avoiding undesired behavior with barely-normal or slightly-subnormal values. - if (floored_exp10 == DOUBLE_MAX_SUBNORMAL_EXPONENT_OF_10) { - return DOUBLE_MAX_SUBNORMAL_POWER_OF_10; - } - // Compute 10^(floored_exp10) but (try to) make sure that doesn't overflow - double_with_bit_access dwba; - int exp2 = bastardized_floor(floored_exp10 * 3.321928094887362 + 0.5); - const double z = floored_exp10 * 2.302585092994046 - exp2 * 0.6931471805599453; - const double z2 = z * z; - dwba.U = ((double_uint_t)(exp2) + DOUBLE_BASE_EXPONENT) << DOUBLE_STORED_MANTISSA_BITS; - // compute exp(z) using continued fractions, - // see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex - dwba.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); - return dwba.F; -} - -static void print_exponential_number(output_gadget_t *output, double number, - printf_size_t precision, printf_size_t width, - printf_flags_t flags, char *buf, printf_size_t len) -{ - const bool negative = get_sign_bit(number); - // This number will decrease gradually (by factors of 10) as we "extract" the exponent out of it - double abs_number = negative ? -number : number; - - int floored_exp10; - bool abs_exp10_covered_by_powers_table; - struct scaling_factor normalization; - - // Determine the decimal exponent - if (abs_number == 0.0) { - // TODO: This is a special-case for 0.0 (and -0.0); but proper handling is required for - // denormals more generally. - floored_exp10 = - 0; // ... and no need to set a normalization factor or check the powers table - } else { - double exp10 = log10_of_positive(abs_number); - floored_exp10 = bastardized_floor(exp10); - double p10 = pow10_of_int(floored_exp10); - // correct for rounding errors - if (abs_number < p10) { - floored_exp10--; - p10 /= 10; - } - abs_exp10_covered_by_powers_table = - PRINTF_ABS(floored_exp10) < PRINTF_MAX_PRECOMPUTED_POWER_OF_10; - normalization.raw_factor = - abs_exp10_covered_by_powers_table ? powers_of_10[PRINTF_ABS(floored_exp10)] : p10; - } - - // We now begin accounting for the widths of the two parts of our printed field: - // the decimal part after decimal exponent extraction, and the base-10 exponent part. - // For both of these, the value of 0 has a special meaning, but not the same one: - // a 0 exponent-part width means "don't print the exponent"; a 0 decimal-part width - // means "use as many characters as necessary". - - bool fall_back_to_decimal_only_mode = false; - if (flags & FLAGS_ADAPT_EXP) { - int required_significant_digits = (precision == 0) ? 1 : (int)precision; - // Should we want to fall-back to "%f" mode, and only print the decimal part? - fall_back_to_decimal_only_mode = - (floored_exp10 >= -4 && floored_exp10 < required_significant_digits); - // Now, let's adjust the precision - // This also decided how we adjust the precision value - as in "%g" mode, - // "precision" is the number of _significant digits_, and this is when we "translate" - // the precision value to an actual number of decimal digits. - int precision_ = - fall_back_to_decimal_only_mode - ? (int)precision - 1 - floored_exp10 - : (int)precision - 1; // the presence of the exponent ensures only one significant - // digit comes before the decimal point - precision = (precision_ > 0 ? (unsigned)precision_ : 0U); - flags |= FLAGS_PRECISION; // make sure print_broken_up_decimal respects our choice above - } - - normalization.multiply = (floored_exp10 < 0 && abs_exp10_covered_by_powers_table); - bool should_skip_normalization = (fall_back_to_decimal_only_mode || floored_exp10 == 0); - struct double_components decimal_part_components = - should_skip_normalization ? get_components(negative ? -abs_number : abs_number, precision) - : get_normalized_components(negative, precision, abs_number, - normalization, floored_exp10); - - // Account for roll-over, e.g. rounding from 9.99 to 100.0 - which effects - // the exponent and may require additional tweaking of the parts - if (fall_back_to_decimal_only_mode) { - if ((flags & FLAGS_ADAPT_EXP) && floored_exp10 >= -1 && - decimal_part_components.integral == powers_of_10[floored_exp10 + 1]) { - floored_exp10++; // Not strictly necessary, since floored_exp10 is no longer really used - precision--; - // ... and it should already be the case that decimal_part_components.fractional == 0 - } - // TODO: What about rollover strictly within the fractional part? - } else { - if (decimal_part_components.integral >= 10) { - floored_exp10++; - decimal_part_components.integral = 1; - decimal_part_components.fractional = 0; - } - } - - // the floored_exp10 format is "E%+03d" and largest possible floored_exp10 value for a 64-bit - // double is "307" (for 2^1023), so we set aside 4-5 characters overall - printf_size_t exp10_part_width = fall_back_to_decimal_only_mode ? 0U - : (PRINTF_ABS(floored_exp10) < 100) ? 4U - : 5U; - - printf_size_t decimal_part_width = - ((flags & FLAGS_LEFT) && exp10_part_width) - ? - // We're padding on the right, so the width constraint is the exponent part's - // problem, not the decimal part's, so we'll use as many characters as we need: - 0U - : - // We're padding on the left; so the width constraint is the decimal part's - // problem. Well, can both the decimal part and the exponent part fit within our overall - // width? - ((width > exp10_part_width) - ? - // Yes, so we limit our decimal part's width. - // (Note this is trivially valid even if we've fallen back to "%f" mode) - width - exp10_part_width - : - // No; we just give up on any restriction on the decimal part and use as many - // characters as we need - 0U); - - const printf_size_t printed_exponential_start_pos = output->pos; - print_broken_up_decimal(decimal_part_components, output, precision, decimal_part_width, flags, - buf, len); - - if (!fall_back_to_decimal_only_mode) { - putchar_via_gadget(output, (flags & FLAGS_UPPERCASE) ? 'E' : 'e'); - print_integer(output, ABS_FOR_PRINTING(floored_exp10), floored_exp10 < 0, 10, 0, - exp10_part_width - 1, FLAGS_ZEROPAD | FLAGS_PLUS); - if (flags & FLAGS_LEFT) { - // We need to right-pad with spaces to meet the width requirement - while (output->pos - printed_exponential_start_pos < width) { - putchar_via_gadget(output, ' '); - } - } - } -} -#endif // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS - -static void print_floating_point(output_gadget_t *output, double value, printf_size_t precision, - printf_size_t width, printf_flags_t flags, bool prefer_exponential) -{ - char buf[PRINTF_DECIMAL_BUFFER_SIZE]; - printf_size_t len = 0U; - - // test for special values - if (value != value) { - out_rev_(output, "nan", 3, width, flags); - return; - } - if (value < -DBL_MAX) { - out_rev_(output, "fni-", 4, width, flags); - return; - } - if (value > DBL_MAX) { - out_rev_(output, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, - width, flags); - return; - } - - if (!prefer_exponential && - ((value > PRINTF_FLOAT_NOTATION_THRESHOLD) || (value < -PRINTF_FLOAT_NOTATION_THRESHOLD))) { - // The required behavior of standard printf is to print _every_ integral-part digit -- which - // could mean printing hundreds of characters, overflowing any fixed internal buffer and - // necessitating a more complicated implementation. -#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS - print_exponential_number(output, value, precision, width, flags, buf, len); -#endif - return; - } - - // set default precision, if not set explicitly - if (!(flags & FLAGS_PRECISION)) { - precision = PRINTF_DEFAULT_FLOAT_PRECISION; - } - - // limit precision so that our integer holding the fractional part does not overflow - while ((len < PRINTF_DECIMAL_BUFFER_SIZE) && (precision > PRINTF_MAX_SUPPORTED_PRECISION)) { - buf[len++] = '0'; // This respects the precision in terms of result length only - precision--; - } - -#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS - if (prefer_exponential) - print_exponential_number(output, value, precision, width, flags, buf, len); - else -#endif - print_decimal_number(output, value, precision, width, flags, buf, len); -} - -#endif // (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS) - -// Advances the format pointer past the flags, and returns the parsed flags -// due to the characters passed -static printf_flags_t parse_flags(const char **format) -{ - printf_flags_t flags = 0U; - do { - switch (**format) { - case '0': - flags |= FLAGS_ZEROPAD; - (*format)++; - break; - case '-': - flags |= FLAGS_LEFT; - (*format)++; - break; - case '+': - flags |= FLAGS_PLUS; - (*format)++; - break; - case ' ': - flags |= FLAGS_SPACE; - (*format)++; - break; - case '#': - flags |= FLAGS_HASH; - (*format)++; - break; - default: - return flags; - } - } while (true); -} - -static inline void format_string_loop(output_gadget_t *output, const char *format, va_list args) -{ -#if PRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER -#define ADVANCE_IN_FORMAT_STRING(cptr_) \ - do { \ - (cptr_)++; \ - if (!*(cptr_)) \ - return; \ - } while (0) -#else -#define ADVANCE_IN_FORMAT_STRING(cptr_) (cptr_)++ -#endif - - while (*format) { - if (*format != '%') { - // A regular content character - putchar_via_gadget(output, *format); - format++; - continue; - } - // We're parsing a format specifier: %[flags][width][.precision][length] - ADVANCE_IN_FORMAT_STRING(format); - - printf_flags_t flags = parse_flags(&format); - - // evaluate width field - printf_size_t width = 0U; - if (is_digit_(*format)) { - width = (printf_size_t)atou_(&format); - } else if (*format == '*') { - const int w = va_arg(args, int); - if (w < 0) { - flags |= FLAGS_LEFT; // reverse padding - width = (printf_size_t)-w; - } else { - width = (printf_size_t)w; - } - ADVANCE_IN_FORMAT_STRING(format); - } - - // evaluate precision field - printf_size_t precision = 0U; - if (*format == '.') { - flags |= FLAGS_PRECISION; - ADVANCE_IN_FORMAT_STRING(format); - if (is_digit_(*format)) { - precision = (printf_size_t)atou_(&format); - } else if (*format == '*') { - const int precision_ = va_arg(args, int); - precision = precision_ > 0 ? (printf_size_t)precision_ : 0U; - ADVANCE_IN_FORMAT_STRING(format); - } - } - - // evaluate length field - switch (*format) { -#ifdef PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS - case 'I': { - ADVANCE_IN_FORMAT_STRING(format); - // Greedily parse for size in bits: 8, 16, 32 or 64 - switch (*format) { - case '8': - flags |= FLAGS_INT8; - ADVANCE_IN_FORMAT_STRING(format); - break; - case '1': - ADVANCE_IN_FORMAT_STRING(format); - if (*format == '6') { - format++; - flags |= FLAGS_INT16; - } - break; - case '3': - ADVANCE_IN_FORMAT_STRING(format); - if (*format == '2') { - ADVANCE_IN_FORMAT_STRING(format); - flags |= FLAGS_INT32; - } - break; - case '6': - ADVANCE_IN_FORMAT_STRING(format); - if (*format == '4') { - ADVANCE_IN_FORMAT_STRING(format); - flags |= FLAGS_INT64; - } - break; - default: - break; - } - break; - } -#endif - case 'l': - flags |= FLAGS_LONG; - ADVANCE_IN_FORMAT_STRING(format); - if (*format == 'l') { - flags |= FLAGS_LONG_LONG; - ADVANCE_IN_FORMAT_STRING(format); - } - break; - case 'h': - flags |= FLAGS_SHORT; - ADVANCE_IN_FORMAT_STRING(format); - if (*format == 'h') { - flags |= FLAGS_CHAR; - ADVANCE_IN_FORMAT_STRING(format); - } - break; - case 't': - flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - ADVANCE_IN_FORMAT_STRING(format); - break; - case 'j': - flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - ADVANCE_IN_FORMAT_STRING(format); - break; - case 'z': - flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - ADVANCE_IN_FORMAT_STRING(format); - break; - default: - break; - } - - // evaluate specifier - switch (*format) { - case 'd': - case 'i': - case 'u': - case 'x': - case 'X': - case 'o': - case 'b': { - - if (*format == 'd' || *format == 'i') { - flags |= FLAGS_SIGNED; - } - - numeric_base_t base; - if (*format == 'x' || *format == 'X') { - base = BASE_HEX; - } else if (*format == 'o') { - base = BASE_OCTAL; - } else if (*format == 'b') { - base = BASE_BINARY; - } else { - base = BASE_DECIMAL; - flags &= ~FLAGS_HASH; // decimal integers have no alternative presentation - } - - if (*format == 'X') { - flags |= FLAGS_UPPERCASE; - } - - format++; - // ignore '0' flag when precision is given - if (flags & FLAGS_PRECISION) { - flags &= ~FLAGS_ZEROPAD; - } - - if (flags & FLAGS_SIGNED) { - // A signed specifier: d, i or possibly I + bit size if enabled - - if (flags & FLAGS_LONG_LONG) { -#if PRINTF_SUPPORT_LONG_LONG - const long long value = va_arg(args, long long); - print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, - width, flags); -#endif - } else if (flags & FLAGS_LONG) { - const long value = va_arg(args, long); - print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, - width, flags); - } else { - // We never try to interpret the argument as something potentially-smaller than - // int, due to integer promotion rules: Even if the user passed a short int, - // short unsigned etc. - these will come in after promotion, as int's (or - // unsigned for the case of short unsigned when it has the same size as int) - const int value = (flags & FLAGS_CHAR) ? (signed char)va_arg(args, int) - : (flags & FLAGS_SHORT) ? (short int)va_arg(args, int) - : va_arg(args, int); - print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, - width, flags); - } - } else { - // An unsigned specifier: u, x, X, o, b - - flags &= ~(FLAGS_PLUS | FLAGS_SPACE); - - if (flags & FLAGS_LONG_LONG) { -#if PRINTF_SUPPORT_LONG_LONG - print_integer(output, (printf_unsigned_value_t)va_arg(args, unsigned long long), - false, base, precision, width, flags); -#endif - } else if (flags & FLAGS_LONG) { - print_integer(output, (printf_unsigned_value_t)va_arg(args, unsigned long), - false, base, precision, width, flags); - } else { - const unsigned int value = - (flags & FLAGS_CHAR) ? (unsigned char)va_arg(args, unsigned int) - : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(args, unsigned int) - : va_arg(args, unsigned int); - print_integer(output, (printf_unsigned_value_t)value, false, base, precision, - width, flags); - } - } - break; - } -#if PRINTF_SUPPORT_DECIMAL_SPECIFIERS - case 'f': - case 'F': - if (*format == 'F') - flags |= FLAGS_UPPERCASE; - print_floating_point(output, va_arg(args, double), precision, width, flags, - PRINTF_PREFER_DECIMAL); - format++; - break; -#endif -#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS - case 'e': - case 'E': - case 'g': - case 'G': - if ((*format == 'g') || (*format == 'G')) - flags |= FLAGS_ADAPT_EXP; - if ((*format == 'E') || (*format == 'G')) - flags |= FLAGS_UPPERCASE; - print_floating_point(output, va_arg(args, double), precision, width, flags, - PRINTF_PREFER_EXPONENTIAL); - format++; - break; -#endif // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS - case 'c': { - printf_size_t l = 1U; - // pre padding - if (!(flags & FLAGS_LEFT)) { - while (l++ < width) { - putchar_via_gadget(output, ' '); - } - } - // char output - putchar_via_gadget(output, (char)va_arg(args, int)); - // post padding - if (flags & FLAGS_LEFT) { - while (l++ < width) { - putchar_via_gadget(output, ' '); - } - } - format++; - break; - } - - case 's': { - const char *p = va_arg(args, char *); - if (p == NULL) { - out_rev_(output, ")llun(", 6, width, flags); - } else { - printf_size_t l = - strnlen_s_(p, precision ? precision : PRINTF_MAX_POSSIBLE_BUFFER_SIZE); - // pre padding - if (flags & FLAGS_PRECISION) { - l = (l < precision ? l : precision); - } - if (!(flags & FLAGS_LEFT)) { - while (l++ < width) { - putchar_via_gadget(output, ' '); - } - } - // string output - while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision)) { - putchar_via_gadget(output, *(p++)); - --precision; - } - // post padding - if (flags & FLAGS_LEFT) { - while (l++ < width) { - putchar_via_gadget(output, ' '); - } - } - } - format++; - break; - } - - case 'p': { - width = sizeof(void *) * 2U + 2; // 2 hex chars per byte + the "0x" prefix - flags |= FLAGS_ZEROPAD | FLAGS_POINTER; - uintptr_t value = (uintptr_t)va_arg(args, void *); - (value == (uintptr_t)NULL) ? out_rev_(output, ")lin(", 5, width, flags) - : print_integer(output, (printf_unsigned_value_t)value, - false, BASE_HEX, precision, width, flags); - format++; - break; - } - - case '%': - putchar_via_gadget(output, '%'); - format++; - break; - - // Many people prefer to disable support for %n, as it lets the caller - // engineer a write to an arbitrary location, of a value the caller - // effectively controls - which could be a security concern in some cases. -#if PRINTF_SUPPORT_WRITEBACK_SPECIFIER - case 'n': { - if (flags & FLAGS_CHAR) - *(va_arg(args, char *)) = (char)output->pos; - else if (flags & FLAGS_SHORT) - *(va_arg(args, short *)) = (short)output->pos; - else if (flags & FLAGS_LONG) - *(va_arg(args, long *)) = (long)output->pos; -#if PRINTF_SUPPORT_LONG_LONG - else if (flags & FLAGS_LONG_LONG) - *(va_arg(args, long long *)) = (long long int)output->pos; -#endif // PRINTF_SUPPORT_LONG_LONG - else - *(va_arg(args, int *)) = (int)output->pos; - format++; - break; - } -#endif // PRINTF_SUPPORT_WRITEBACK_SPECIFIER - - default: - putchar_via_gadget(output, *format); - format++; - break; - } - } -} - -// internal vsnprintf - used for implementing _all library functions -static int vsnprintf_impl(output_gadget_t *output, const char *format, va_list args) -{ - // Note: The library only calls vsnprintf_impl() with output->pos being 0. However, it is - // possible to call this function with a non-zero pos value for some "remedial printing". - format_string_loop(output, format, args); - - // termination - append_termination_with_gadget(output); - - // return written chars without terminating \0 - return (int)output->pos; -} - -/////////////////////////////////////////////////////////////////////////////// - -// int vprintf_(const char *format, va_list arg) -// { -// output_gadget_t gadget = extern_putchar_gadget(); -// return vsnprintf_impl(&gadget, format, arg); -// } - -int vsnprintf_(char *s, size_t n, const char *format, va_list arg) -{ - output_gadget_t gadget = buffer_gadget(s, n); - return vsnprintf_impl(&gadget, format, arg); -} - -int vsprintf_(char *s, const char *format, va_list arg) -{ - return vsnprintf_(s, PRINTF_MAX_POSSIBLE_BUFFER_SIZE, format, arg); -} - -int vfctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, - va_list arg) -{ - output_gadget_t gadget = function_gadget(out, extra_arg); - return vsnprintf_impl(&gadget, format, arg); -} - -// int printf_(const char *format, ...) -// { -// va_list args; -// va_start(args, format); -// const int ret = vprintf_(format, args); -// va_end(args); -// return ret; -// } - -int sprintf_(char *s, const char *format, ...) -{ - va_list args; - va_start(args, format); - const int ret = vsprintf_(s, format, args); - va_end(args); - return ret; -} - -int snprintf_(char *s, size_t n, const char *format, ...) -{ - va_list args; - va_start(args, format); - const int ret = vsnprintf_(s, n, format, args); - va_end(args); - return ret; -} - -int fctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, ...) -{ - va_list args; - va_start(args, format); - const int ret = vfctprintf(out, extra_arg, format, args); - va_end(args); - return ret; -} diff --git a/arceos/ulib/axlibc/c/printf.h b/arceos/ulib/axlibc/c/printf.h deleted file mode 100644 index c6484e504..000000000 --- a/arceos/ulib/axlibc/c/printf.h +++ /dev/null @@ -1,215 +0,0 @@ -/** - * @author (c) Eyal Rozenberg - * 2021-2022, Haifa, Palestine/Israel - * @author (c) Marco Paland (info@paland.com) - * 2014-2019, PALANDesign Hannover, Germany - * - * @note Others have made smaller contributions to this file: see the - * contributors page at https://github.com/eyalroz/printf/graphs/contributors - * or ask one of the authors. - * - * @brief Small stand-alone implementation of the printf family of functions - * (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with - * a very limited resources. - * - * @note the implementations are thread-safe; re-entrant; use no functions from - * the standard library; and do not dynamically allocate any memory. - * - * @license The MIT License (MIT) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef PRINTF_H_ -#define PRINTF_H_ - -#ifdef __cplusplus -#include -#include -extern "C" { -#else -#include -#include -#endif - -#ifdef __GNUC__ -#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4) -#define ATTR_PRINTF(one_based_format_index, first_arg) \ - __attribute__((format(gnu_printf, (one_based_format_index), (first_arg)))) -#else -#define ATTR_PRINTF(one_based_format_index, first_arg) \ - __attribute__((format(printf, (one_based_format_index), (first_arg)))) -#endif -#define ATTR_VPRINTF(one_based_format_index) ATTR_PRINTF((one_based_format_index), 0) -#else -#define ATTR_PRINTF(one_based_format_index, first_arg) -#define ATTR_VPRINTF(one_based_format_index) -#endif - -#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES -#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES 0 -#endif - -#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD -#define printf_ printf -#define sprintf_ sprintf -#define vsprintf_ vsprintf -#define snprintf_ snprintf -#define vsnprintf_ vsnprintf -#define vprintf_ vprintf -#endif - -// If you want to include this implementation file directly rather than -// link against, this will let you control the functions' visibility, -// e.g. make them static so as not to clash with other objects also -// using them. -#ifndef PRINTF_VISIBILITY -#define PRINTF_VISIBILITY -#endif - -/** - * Prints/send a single character to some opaque output entity - * - * @note This function is not implemented by the library, only declared; you must provide an - * implementation if you wish to use the @ref printf / @ref vprintf function (and possibly - * for linking against the library, if your toolchain does not support discarding unused functions) - * - * @note The output could be as simple as a wrapper for the `write()` system call on a Unix-like - * system, or even libc's @ref putchar , for replicating actual functionality of libc's @ref printf - * function; but on an embedded system it may involve interaction with a special output device, - * like a UART, etc. - * - * @note in libc's @ref putchar, the parameter type is an int; this was intended to support the - * representation of either a proper character or EOF in a variable - but this is really not - * meaningful to pass into @ref putchar and is discouraged today. See further discussion in: - * @link https://stackoverflow.com/q/17452847/1593077 - * - * @param c the single character to print - */ -// PRINTF_VISIBILITY -// void putchar_(char c); - -/** - * An implementation of the C standard's printf/vprintf - * - * @note you must implement a @ref putchar_ function for using this function - it invokes @ref - * putchar_ rather than directly performing any I/O (which insulates it from any dependence on the - * operating system and external libraries). - * - * @param format A string specifying the format of the output, with %-marked specifiers of how to - * interpret additional arguments. - * @param arg Additional arguments to the function, one for each %-specifier in @p format string - * @return The number of characters written into @p s, not counting the terminating null character - */ -///@{ -// PRINTF_VISIBILITY -// int printf_(const char* format, ...) ATTR_PRINTF(1, 2); -// PRINTF_VISIBILITY -// int vprintf_(const char* format, va_list arg) ATTR_VPRINTF(1); -///@} - -/** - * An implementation of the C standard's sprintf/vsprintf - * - * @note For security considerations (the potential for exceeding the buffer bounds), please - * consider using the size-constrained variant, @ref snprintf / @ref vsnprintf , instead. - * - * @param s An array in which to store the formatted string. It must be large enough to fit the - * formatted output! - * @param format A string specifying the format of the output, with %-marked specifiers of how to - * interpret additional arguments. - * @param arg Additional arguments to the function, one for each specifier in @p format - * @return The number of characters written into @p s, not counting the terminating null character - */ -///@{ -PRINTF_VISIBILITY -int sprintf_(char *s, const char *format, ...) ATTR_PRINTF(2, 3); -PRINTF_VISIBILITY -int vsprintf_(char *s, const char *format, va_list arg) ATTR_VPRINTF(2); -///@} - -/** - * An implementation of the C standard's snprintf/vsnprintf - * - * @param s An array in which to store the formatted string. It must be large enough to fit either - * the entire formatted output, or at least @p n characters. Alternatively, it can be NULL, in which - * case nothing will be printed, and only the number of characters which _could_ have been printed - * is tallied and returned. - * @param n The maximum number of characters to write to the array, including a terminating null - * character - * @param format A string specifying the format of the output, with %-marked specifiers of how to - * interpret additional arguments. - * @param arg Additional arguments to the function, one for each specifier in @p format - * @return The number of characters that COULD have been written into @p s, not counting the - * terminating null character. A value equal or larger than @p n indicates truncation. Only when the - * returned value is non-negative and less than @p n, the null-terminated string has been fully and - * successfully printed. - */ -///@{ -PRINTF_VISIBILITY -int snprintf_(char *s, size_t count, const char *format, ...) ATTR_PRINTF(3, 4); -PRINTF_VISIBILITY -int vsnprintf_(char *s, size_t count, const char *format, va_list arg) ATTR_VPRINTF(3); -///@} - -/** - * printf/vprintf with user-specified output function - * - * An alternative to @ref printf_, in which the output function is specified dynamically - * (rather than @ref putchar_ being used) - * - * @param out An output function which takes one character and a type-erased additional parameters - * @param extra_arg The type-erased argument to pass to the output function @p out with each call - * @param format A string specifying the format of the output, with %-marked specifiers of how to - * interpret additional arguments. - * @param arg Additional arguments to the function, one for each specifier in @p format - * @return The number of characters for which the output f unction was invoked, not counting the - * terminating null character - * - */ -PRINTF_VISIBILITY -int fctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, ...) - ATTR_PRINTF(3, 4); -PRINTF_VISIBILITY -int vfctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, - va_list arg) ATTR_VPRINTF(3); - -#ifdef __cplusplus -} // extern "C" -#endif - -#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD -#undef printf_ -#undef sprintf_ -#undef vsprintf_ -#undef snprintf_ -#undef vsnprintf_ -#undef vprintf_ -#else -#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT -#define printf printf_ -#define sprintf sprintf_ -#define vsprintf vsprintf_ -#define snprintf snprintf_ -#define vsnprintf vsnprintf_ -#define vprintf vprintf_ -#endif -#endif - -#endif // PRINTF_H_ diff --git a/arceos/ulib/axlibc/c/printf_config.h b/arceos/ulib/axlibc/c/printf_config.h deleted file mode 100644 index bd860a754..000000000 --- a/arceos/ulib/axlibc/c/printf_config.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef PRINTF_CONFIG_H -#define PRINTF_CONFIG_H - -#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES 1 - -#ifndef AX_CONFIG_FP_SIMD - -#define PRINTF_SUPPORT_DECIMAL_SPECIFIERS 0 - -#define PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS 0 - -#endif // AX_CONFIG_FP_SIMD - -#endif // PRINTF_CONFIG_H diff --git a/arceos/ulib/axlibc/c/pthread.c b/arceos/ulib/axlibc/c/pthread.c deleted file mode 100644 index 74fb1faf1..000000000 --- a/arceos/ulib/axlibc/c/pthread.c +++ /dev/null @@ -1,110 +0,0 @@ -#ifdef AX_CONFIG_MULTITASK - -#include -#include -#include -#include -#include - -int pthread_setcancelstate(int new, int *old) -{ - unimplemented(); - return 0; -} - -int pthread_setcanceltype(int new, int *old) -{ - unimplemented(); - return 0; -} - -// TODO -void pthread_testcancel(void) -{ - unimplemented(); - return; -} - -// TODO -int pthread_cancel(pthread_t t) -{ - unimplemented(); - return 0; -} - -// TODO -int pthread_mutex_trylock(pthread_mutex_t *m) -{ - unimplemented(); - return 0; -} - -// TODO -int pthread_setname_np(pthread_t thread, const char *name) -{ - unimplemented(); - return 0; -} - -int pthread_cond_init(pthread_cond_t *restrict c, const pthread_condattr_t *restrict a) -{ - *c = (pthread_cond_t){0}; - if (a) { - c->_c_clock = a->__attr & 0x7fffffff; - if (a->__attr >> 31) - c->_c_shared = (void *)-1; - } - return 0; -} - -// TODO -int pthread_cond_signal(pthread_cond_t *__cond) -{ - unimplemented(); - return 0; -} - -// TODO -int pthread_cond_wait(pthread_cond_t *__restrict__ __cond, pthread_mutex_t *__restrict__ __mutex) -{ - unimplemented(); - return 0; -} - -// TODO -int pthread_cond_broadcast(pthread_cond_t *c) -{ - unimplemented(); - return 0; -} - -#define DEFAULT_STACK_SIZE 131072 -#define DEFAULT_GUARD_SIZE 8192 - -// TODO -int pthread_attr_init(pthread_attr_t *a) -{ - *a = (pthread_attr_t){0}; - // __acquire_ptc(); - a->_a_stacksize = DEFAULT_STACK_SIZE; - a->_a_guardsize = DEFAULT_GUARD_SIZE; - // __release_ptc(); - return 0; -} - -int pthread_attr_getstacksize(const pthread_attr_t *restrict a, size_t *restrict size) -{ - *size = a->_a_stacksize; - return 0; -} - -int pthread_attr_setstacksize(pthread_attr_t *a, size_t size) -{ - if (size - PTHREAD_STACK_MIN > SIZE_MAX / 4) - return EINVAL; - a->_a_stackaddr = 0; - a->_a_stacksize = size; - return 0; -} - -#endif // AX_CONFIG_MULTITASK diff --git a/arceos/ulib/axlibc/c/pwd.c b/arceos/ulib/axlibc/c/pwd.c deleted file mode 100644 index 61f32f4ae..000000000 --- a/arceos/ulib/axlibc/c/pwd.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -int getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t size, struct passwd **res) -{ - unimplemented(); - return 0; -} - -int getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t size, struct passwd **res) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/c/resource.c b/arceos/ulib/axlibc/c/resource.c deleted file mode 100644 index 3e34624cb..000000000 --- a/arceos/ulib/axlibc/c/resource.c +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include -#include - -// TODO -int getrusage(int __who, struct rusage *__usage) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/c/sched.c b/arceos/ulib/axlibc/c/sched.c deleted file mode 100644 index 21203c465..000000000 --- a/arceos/ulib/axlibc/c/sched.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -// TODO -int sched_setaffinity(pid_t __pid, size_t __cpusetsize, const cpu_set_t *__cpuset) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/c/select.c b/arceos/ulib/axlibc/c/select.c deleted file mode 100644 index d20d5f680..000000000 --- a/arceos/ulib/axlibc/c/select.c +++ /dev/null @@ -1,17 +0,0 @@ -#ifdef AX_CONFIG_SELECT - -#include -#include -#include -#include -#include - -int pselect(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, - const struct timespec *restrict ts, const sigset_t *restrict mask) -{ - struct timeval tv = {ts->tv_sec, ts->tv_nsec / 1000}; - select(n, rfds, wfds, efds, &tv); - return 0; -} - -#endif // AX_CONFIG_SELECT diff --git a/arceos/ulib/axlibc/c/signal.c b/arceos/ulib/axlibc/c/signal.c deleted file mode 100644 index de2164767..000000000 --- a/arceos/ulib/axlibc/c/signal.c +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include -#include -#include - -int sigaction_helper(int signum, const struct sigaction *act, struct sigaction *oldact, - size_t sigsetsize) -{ - if (signum == SIGKILL || signum == SIGSTOP) - return -EINVAL; - - if (oldact) - *oldact = (struct sigaction){0}; - - return 0; -} - -void (*signal(int signum, void (*handler)(int)))(int) -{ - struct sigaction old; - struct sigaction act = { - .sa_handler = handler, .sa_flags = SA_RESTART, /* BSD signal semantics */ - }; - - if (sigaction_helper(signum, &act, &old, sizeof(sigset_t)) < 0) - return SIG_ERR; - - return (old.sa_flags & SA_SIGINFO) ? NULL : old.sa_handler; -} - -int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact) -{ - return sigaction_helper(sig, act, oact, sizeof(sigset_t)); -} - -// TODO -int kill(pid_t __pid, int __sig) -{ - unimplemented(); - return 0; -} - -int sigemptyset(sigset_t *set) -{ - set->__bits[0] = 0; - if (sizeof(long) == 4 || _NSIG > 65) - set->__bits[1] = 0; - if (sizeof(long) == 4 && _NSIG > 65) { - set->__bits[2] = 0; - set->__bits[3] = 0; - } - return 0; -} - -// TODO -int raise(int __sig) -{ - unimplemented(); - return 0; -} - -int sigaddset(sigset_t *set, int sig) -{ - unsigned s = sig - 1; - if (s >= _NSIG - 1 || sig - 32U < 3) { - errno = EINVAL; - return -1; - } - set->__bits[s / 8 / sizeof *set->__bits] |= 1UL << (s & (8 * sizeof *set->__bits - 1)); - return 0; -} - -// TODO -int pthread_sigmask(int __how, const sigset_t *restrict __newmask, sigset_t *restrict __oldmask) -{ - unimplemented(); - return 0; -} - -#ifdef AX_CONFIG_MULTITASK -// TODO -int pthread_kill(pthread_t t, int sig) -{ - unimplemented(); - return 0; -} -#endif diff --git a/arceos/ulib/axlibc/c/socket.c b/arceos/ulib/axlibc/c/socket.c deleted file mode 100644 index 677e43198..000000000 --- a/arceos/ulib/axlibc/c/socket.c +++ /dev/null @@ -1,47 +0,0 @@ -#ifdef AX_CONFIG_NET - -#include -#include -#include -#include -#include - -int accept4(int fd, struct sockaddr *restrict addr, socklen_t *restrict len, int flg) -{ - if (!flg) - return accept(fd, addr, len); - if (flg & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) { - errno = EINVAL; - return -1; - } - int ret = accept(fd, addr, len); - if (ret < 0) - return ret; - if (flg & SOCK_CLOEXEC) - fcntl(ret, F_SETFD, FD_CLOEXEC); - if (flg & SOCK_NONBLOCK) - fcntl(ret, F_SETFL, O_NONBLOCK); - return ret; -} - -int getsockopt(int fd, int level, int optname, void *restrict optval, socklen_t *restrict optlen) -{ - unimplemented(); - return -1; -} - -int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) -{ - unimplemented("fd: %d, level: %d, optname: %d, optval: %d, optlen: %d", fd, level, optname, - *(int *)optval, optlen); - return 0; -} - -// TODO -ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) -{ - unimplemented(); - return 0; -} - -#endif // AX_CONFIG_NET diff --git a/arceos/ulib/axlibc/c/stat.c b/arceos/ulib/axlibc/c/stat.c deleted file mode 100644 index 27ff3d814..000000000 --- a/arceos/ulib/axlibc/c/stat.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include - -// TODO: -int fchmod(int fd, mode_t mode) -{ - unimplemented(); - return 0; -} - -// TODO: -int mkdir(const char *path, mode_t mode) -{ - unimplemented(); - return 0; -} - -// TODO -int chmod(const char *path, mode_t mode) -{ - unimplemented(); - return 0; -} - -// TODO -mode_t umask(mode_t mask) -{ - unimplemented("mask: %d", mask); - return 0; -} - -// TODO -int fstatat(int fd, const char *restrict path, struct stat *restrict st, int flag) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/c/stdio.c b/arceos/ulib/axlibc/c/stdio.c deleted file mode 100644 index 03ea75cf3..000000000 --- a/arceos/ulib/axlibc/c/stdio.c +++ /dev/null @@ -1,412 +0,0 @@ -#include "printf.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// LOCK used by `puts()` -#ifdef AX_CONFIG_MULTITASK -#include -static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; -#endif - -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -FILE __stdin_FILE = {.fd = 0, .buffer_len = 0}; - -FILE __stdout_FILE = {.fd = 1, .buffer_len = 0}; - -FILE __stderr_FILE = {.fd = 2, .buffer_len = 0}; - -FILE *const stdin = &__stdin_FILE; -FILE *const stdout = &__stdout_FILE; -FILE *const stderr = &__stderr_FILE; - -// Returns: number of chars written, negative for failure -// Warn: buffer_len[f] will not be changed -static int __write_buffer(FILE *f) -{ - int r = 0; - if (f->buffer_len == 0) - return 0; - r = write(f->fd, f->buf, f->buffer_len); - return r; -} - -// Clear buffer_len[f] -static void __clear_buffer(FILE *f) -{ - f->buffer_len = 0; -} - -static int __fflush(FILE *f) -{ - int r = __write_buffer(f); - __clear_buffer(f); - return r >= 0 ? 0 : r; -} - -static int out(FILE *f, const char *s, size_t l) -{ - int ret = 0; - for (size_t i = 0; i < l; i++) { - char c = s[i]; - f->buf[f->buffer_len++] = c; - if (f->buffer_len == FILE_BUF_SIZE || c == '\n') { - int r = __write_buffer(f); - __clear_buffer(f); - if (r < 0) - return r; - if (r < f->buffer_len) - return ret + r; - ret += r; - } - } - return ret; -} - -int getchar(void) -{ - unimplemented(); - return 0; -} - -int fflush(FILE *f) -{ - return __fflush(f); -} - -static inline int do_putc(int c, FILE *f) -{ - char byte = c; - return out(f, &byte, 1); -} - -int fputc(int c, FILE *f) -{ - return do_putc(c, f); -} - -int putc(int c, FILE *f) -{ - return do_putc(c, f); -} - -int putchar(int c) -{ - return do_putc(c, stdout); -} - -int puts(const char *s) -{ -#ifdef AX_CONFIG_MULTITASK - pthread_mutex_lock(&lock); -#endif - - int r = write(1, (const void *)s, strlen(s)); - char brk[1] = {'\n'}; - write(1, (const void *)brk, 1); - -#ifdef AX_CONFIG_MULTITASK - pthread_mutex_unlock(&lock); -#endif - - return r; -} - -void perror(const char *msg) -{ - FILE *f = stderr; - char *errstr = strerror(errno); - - if (msg && *msg) { - out(f, msg, strlen(msg)); - out(f, ": ", 2); - } - out(f, errstr, strlen(errstr)); - out(f, "\n", 1); -} - -static void __out_wrapper(char c, void *arg) -{ - out(arg, &c, 1); -} - -int printf(const char *restrict fmt, ...) -{ - int ret; - va_list ap; - va_start(ap, fmt); - ret = vfprintf(stdout, fmt, ap); - va_end(ap); - return ret; -} - -int fprintf(FILE *restrict f, const char *restrict fmt, ...) -{ - int ret; - va_list ap; - va_start(ap, fmt); - ret = vfprintf(f, fmt, ap); - va_end(ap); - return ret; -} - -int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) -{ - return vfctprintf(__out_wrapper, f, fmt, ap); -} - -// TODO -int sscanf(const char *restrict __s, const char *restrict __format, ...) -{ - unimplemented(); - return 0; -} - -#ifdef AX_CONFIG_FS - -int __fmodeflags(const char *mode) -{ - int flags; - if (strchr(mode, '+')) - flags = O_RDWR; - else if (*mode == 'r') - flags = O_RDONLY; - else - flags = O_WRONLY; - if (strchr(mode, 'x')) - flags |= O_EXCL; - if (strchr(mode, 'e')) - flags |= O_CLOEXEC; - if (*mode != 'r') - flags |= O_CREAT; - if (*mode == 'w') - flags |= O_TRUNC; - if (*mode == 'a') - flags |= O_APPEND; - return flags; -} - -FILE *fopen(const char *filename, const char *mode) -{ - FILE *f; - int flags; - - if (!strchr("rwa", *mode)) { - errno = EINVAL; - return 0; - } - - f = (FILE *)malloc(sizeof(FILE)); - - flags = __fmodeflags(mode); - // TODO: currently mode is unused in ax_open - int fd = open(filename, flags, 0666); - if (fd < 0) - return NULL; - f->fd = fd; - - return f; -} - -char *fgets(char *restrict s, int n, FILE *restrict f) -{ - if (n == 0) - return NULL; - if (n == 1) { - *s = '\0'; - return s; - } - - int cnt = 0; - while (cnt < n - 1) { - char c; - if (read(f->fd, (void *)&c, 1) > 0) { - if (c != '\n') - s[cnt++] = c; - else - break; - } else - break; - } - s[cnt] = '\0'; - return s; -} - -size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f) -{ - size_t total = size * nmemb; - size_t read_len = 0; - size_t len = 0; - do { - len = read(f->fd, destv + read_len, total - read_len); - if (len < 0) - break; - read_len += len; - } while (len > 0); - return read_len == size * nmemb ? nmemb : read_len / size; -} - -size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f) -{ - size_t total = size * nmemb; - size_t write_len = 0; - size_t len = 0; - do { - len = write(f->fd, src + write_len, total - write_len); - if (len < 0) - break; - write_len += len; - } while (len > 0); - return write_len == size * nmemb ? nmemb : write_len / size; -} - -int fputs(const char *restrict s, FILE *restrict f) -{ - size_t l = strlen(s); - return (fwrite(s, 1, l, f) == l) - 1; -} - -int fclose(FILE *f) -{ - return close(f->fd); -} - -int fileno(FILE *f) -{ - return f->fd; -} - -int feof(FILE *f) -{ - unimplemented(); - return 0; -} - -// TODO -int fseek(FILE *__stream, long __off, int __whence) -{ - unimplemented(); - return 0; -} - -// TODO -off_t ftello(FILE *__stream) -{ - unimplemented(); - return 0; -} - -// TODO -char *tmpnam(char *buf) -{ - unimplemented(); - return 0; -} - -// TODO -void clearerr(FILE *f) -{ - unimplemented(); -} - -// TODO -int ferror(FILE *f) -{ - unimplemented(); - return 0; -} - -// TODO -FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict f) -{ - unimplemented(); - return 0; -} - -// TODO -int fscanf(FILE *restrict f, const char *restrict fmt, ...) -{ - unimplemented(); - return 0; -} - -// TODO -long ftell(FILE *f) -{ - unimplemented(); - return 0; -} - -int getc(FILE *f) -{ - unimplemented(); - return 0; -} - -// TODO -int remove(const char *path) -{ - unimplemented(); - return 0; -} - -// TODO -int setvbuf(FILE *restrict f, char *restrict buf, int type, size_t size) -{ - unimplemented(); - return 0; -} - -// TODO -FILE *tmpfile(void) -{ - unimplemented(); - return NULL; -} - -int ungetc(int c, FILE *f) -{ - unimplemented(); - return 0; -} - -ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restrict f) -{ - unimplemented(); - return 0; -} - -ssize_t getline(char **restrict s, size_t *restrict n, FILE *restrict f) -{ - return getdelim(s, n, '\n', f); -} - -int __uflow(FILE *f) -{ - unimplemented(); - return 0; -} - -int getc_unlocked(FILE *f) -{ - unimplemented(); - return 0; -} - -FILE *fdopen(int fd, const char *mode) -{ - unimplemented(); - return NULL; -} - -#endif // AX_CONFIG_FS diff --git a/arceos/ulib/axlibc/c/stdlib.c b/arceos/ulib/axlibc/c/stdlib.c deleted file mode 100644 index ef8a82368..000000000 --- a/arceos/ulib/axlibc/c/stdlib.c +++ /dev/null @@ -1,385 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -char *program_invocation_short_name = "dummy"; -char *program_invocation_name = "dummy"; - -#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) - -void srandom(unsigned int s) -{ - srand(s); -} - -#ifdef AX_CONFIG_ALLOC - -void *calloc(size_t m, size_t n) -{ - void *mem = malloc(m * n); - - return memset(mem, 0, n * m); -} - -void *realloc(void *memblock, size_t size) -{ - if (!memblock) - return malloc(size); - - size_t o_size = *(size_t *)(memblock - 8); - - void *mem = malloc(size); - - for (int i = 0; i < (o_size < size ? o_size : size); i++) - ((char *)mem)[i] = ((char *)memblock)[i]; - - free(memblock); - return mem; -} - -#endif // AX_CONFIG_ALLOC - -long long llabs(long long a) -{ - return a > 0 ? a : -a; -} - -int abs(int a) -{ - return a > 0 ? a : -a; -} - -long long atoll(const char *s) -{ - long long n = 0; - int neg = 0; - while (isspace(*s)) s++; - switch (*s) { - case '-': - neg = 1; - case '+': - s++; - } - /* Compute n as a negative number to avoid overflow on LLONG_MIN */ - while (isdigit(*s)) n = 10 * n - (*s++ - '0'); - return neg ? n : -n; -} - -long strtol(const char *restrict nptr, char **restrict endptr, int base) -{ - const char *s; - unsigned long acc; - unsigned char c; - unsigned long qbase, cutoff; - int neg, any, cutlim; - - s = nptr; - if (base < 0 || base == 1 || base > 36) { - errno = EINVAL; - any = 0; - acc = 0; - goto exit; - } - - do { - c = *s++; - } while (isspace(c)); - if (c == '-') { - neg = 1; - c = *s++; - } else { - neg = 0; - if (c == '+') - c = *s++; - } - if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - base = c == '0' ? 8 : 10; - - qbase = (unsigned int)base; - cutoff = neg ? (unsigned long)LONG_MAX - (unsigned long)(LONG_MIN + LONG_MAX) : LONG_MAX; - cutlim = cutoff % qbase; - cutoff /= qbase; - for (acc = 0, any = 0;; c = *s++) { - if (!isascii(c)) - break; - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - if (c >= base) - break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else { - any = 1; - acc *= qbase; - acc += c; - } - } - - if (any < 0) { - acc = neg ? LONG_MIN : LONG_MAX; - errno = ERANGE; - } else if (neg) - acc = -acc; - -exit: - if (endptr != 0) - *endptr = __DECONST(char *, any ? s - 1 : nptr); - return acc; -} - -unsigned long strtoul(const char *nptr, char **endptr, int base) -{ - const char *s = nptr; - unsigned long acc; - unsigned char c; - unsigned long cutoff; - int neg = 0, any, cutlim; - - if (base < 0 || base == 1 || base > 36) { - errno = EINVAL; - any = 0; - acc = 0; - goto exit; - } - - do { - c = *s++; - } while (isspace(c)); - if (c == '-') { - neg = 1; - c = *s++; - } else if (c == '+') - c = *s++; - if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - base = c == '0' ? 8 : 10; - cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; - cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; - - for (acc = 0, any = 0;; c = *s++) { - if (!isascii(c)) - break; - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - if (c >= base) - break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else { - any = 1; - acc *= base; - acc += c; - } - } - if (any < 0) { - acc = ULONG_MAX; - errno = ERANGE; - } else if (neg) - acc = -acc; -exit: - if (endptr != 0) - *endptr = __DECONST(char *, any ? s - 1 : nptr); - return acc; -} - -long long strtoll(const char *nptr, char **endptr, int base) -{ - const char *s; - unsigned long long acc; - unsigned char c; - unsigned long long qbase, cutoff; - int neg, any, cutlim; - - s = nptr; - if (base < 0 || base == 1 || base > 36) { - errno = EINVAL; - any = 0; - acc = 0; - goto exit; - } - - do { - c = *s++; - } while (isspace(c)); - if (c == '-') { - neg = 1; - c = *s++; - } else { - neg = 0; - if (c == '+') - c = *s++; - } - if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - base = c == '0' ? 8 : 10; - - qbase = (unsigned int)base; - cutoff = neg ? (unsigned long long)LLONG_MAX - (unsigned long long)(LLONG_MIN + LLONG_MAX) - : LLONG_MAX; - cutlim = cutoff % qbase; - cutoff /= qbase; - for (acc = 0, any = 0;; c = *s++) { - if (!isascii(c)) - break; - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - if (c >= base) - break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else { - any = 1; - acc *= qbase; - acc += c; - } - } - - if (any < 0) { - errno = ERANGE; - acc = neg ? LLONG_MIN : LLONG_MAX; - } else if (neg) - acc = -acc; - -exit: - if (endptr != 0) - *endptr = __DECONST(char *, any ? s - 1 : nptr); - return acc; -} - -unsigned long long strtoull(const char *nptr, char **endptr, int base) -{ - const char *s = nptr; - unsigned long long acc; - unsigned char c; - unsigned long long qbase, cutoff; - int neg, any, cutlim; - - if (base < 0 || base == 1 || base > 36) { - errno = EINVAL; - any = 0; - acc = 0; - goto exit; - } - - do { - c = *s++; - } while (isspace(c)); - if (c == '-') { - neg = 1; - c = *s++; - } else { - neg = 0; - if (c == '+') - c = *s++; - } - if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - base = c == '0' ? 8 : 10; - - qbase = (unsigned int)base; - cutoff = (unsigned long long)ULLONG_MAX / qbase; - cutlim = (unsigned long long)ULLONG_MAX % qbase; - for (acc = 0, any = 0;; c = *s++) { - if (!isascii(c)) - break; - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - if (c >= base) - break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else { - any = 1; - acc *= qbase; - acc += c; - } - } - if (any < 0) { - errno = ERANGE; - acc = ULLONG_MAX; - } else if (neg) - acc = -acc; - -exit: - if (endptr != 0) - *endptr = __DECONST(char *, any ? s - 1 : nptr); - return acc; -} - -#ifdef AX_CONFIG_FP_SIMD - -// TODO: precision may not be enough -long double strtold(const char *restrict s, char **restrict p) -{ - return (long double)strtod(s, p); -} - -#endif // AX_CONFIG_FP_SIMD - -typedef int (*cmpfun)(const void *, const void *); - -// TODO -void qsort(void *base, size_t nel, size_t width, cmpfun cmp) -{ - unimplemented(); - return; -} - -// TODO -int mkstemp(char *__template) -{ - unimplemented(); - return 0; -} - -// TODO -int mkostemp(char *__template, int __flags) -{ - unimplemented(); - return 0; -} - -// TODO -int system(const char *cmd) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/c/string.c b/arceos/ulib/axlibc/c/string.c deleted file mode 100644 index 2c56d7e92..000000000 --- a/arceos/ulib/axlibc/c/string.c +++ /dev/null @@ -1,478 +0,0 @@ -#include -#include -#include -#include -#include -#include - -size_t strlen(const char *s) -{ - const char *a = s; - for (; *s; s++) - ; - return s - a; -} - -size_t strnlen(const char *s, size_t n) -{ - const char *p = memchr(s, 0, n); - return p ? p - s : n; -} - -int atoi(const char *s) -{ - int n = 0, neg = 0; - while (isspace(*s)) s++; - switch (*s) { - case '-': - neg = 1; - case '+': - s++; - } - /* Compute n as a negative number to avoid overflow on INT_MIN */ - while (isdigit(*s)) n = 10 * n - (*s++ - '0'); - return neg ? n : -n; -} - -void *memchr(const void *src, int c, size_t n) -{ - const unsigned char *s = src; - c = (unsigned char)c; - for (; n && *s != c; s++, n--) - ; - return n ? (void *)s : 0; -} - -void *memset(void *dest, int c, size_t n) -{ - unsigned char *s = dest; - size_t k; - - /* Fill head and tail with minimal branching. Each - * conditional ensures that all the subsequently used - * offsets are well-defined and in the dest region. */ - - if (!n) - return dest; - s[0] = c; - s[n - 1] = c; - if (n <= 2) - return dest; - s[1] = c; - s[2] = c; - s[n - 2] = c; - s[n - 3] = c; - if (n <= 6) - return dest; - s[3] = c; - s[n - 4] = c; - if (n <= 8) - return dest; - - /* Advance pointer to align it at a 4-byte boundary, - * and truncate n to a multiple of 4. The previous code - * already took care of any head/tail that get cut off - * by the alignment. */ - - k = -(uintptr_t)s & 3; - s += k; - n -= k; - n &= -4; - - /* Pure C fallback with no aliasing violations. */ - for (; n; n--, s++) *s = c; - - return dest; -} - -char *strcpy(char *restrict d, const char *restrict s) -{ - for (; (*d = *s); s++, d++) - ; - return d; -} - -char *strncpy(char *restrict d, const char *restrict s, size_t n) -{ - for (; n && (*d = *s); n--, s++, d++) - ; - return d; -} - -char *strcat(char *restrict d, const char *restrict s) -{ - strcpy(d + strlen(d), s); - return d; -} - -char *strncat(char *restrict d, const char *restrict s, size_t n) -{ - char *a = d; - d += strlen(d); - while (n && *s) n--, *d++ = *s++; - *d++ = 0; - return a; -} - -int strcmp(const char *l, const char *r) -{ - for (; *l == *r && *l; l++, r++) - ; - return *(unsigned char *)l - *(unsigned char *)r; -} - -int strncmp(const char *_l, const char *_r, size_t n) -{ - const unsigned char *l = (void *)_l, *r = (void *)_r; - if (!n--) - return 0; - for (; *l && *r && n && *l == *r; l++, r++, n--) - ; - return *l - *r; -} - -int strcoll(const char *l, const char *r) -{ - return strcmp(l, r); -} - -#define BITOP(a, b, op) \ - ((a)[(size_t)(b) / (8 * sizeof *(a))] op(size_t) 1 << ((size_t)(b) % (8 * sizeof *(a)))) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -size_t strcspn(const char *s1, const char *s2) -{ - const char *a = s1; - size_t byteset[32 / sizeof(size_t)]; - - if (!s2[0] || !s2[1]) { - for (; *s1 != *s2; s1++) return s1 - a; - } - memset(byteset, 0, sizeof byteset); - - for (; *s2 != '\0'; s2++) BITOP(byteset, *(unsigned char *)s2, |=); - for (; *s1 && !(BITOP(byteset, *(unsigned char *)s1, &)); s1++) - ; - - return s1 - a; -} - -size_t strspn(const char *s, const char *c) -{ - const char *a = s; - size_t byteset[32 / sizeof(size_t)] = {0}; - - if (!c[0]) - return 0; - if (!c[1]) { - for (; *s == *c; s++) - ; - return s - a; - } - - for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++) - ; - for (; *s && BITOP(byteset, *(unsigned char *)s, &); s++) - ; - return s - a; -} - -char *strpbrk(const char *s, const char *b) -{ - s += strcspn(s, b); - return *s ? (char *)s : 0; -} - -char *strchrnul(const char *s, int c) -{ - c = (unsigned char)c; - if (!c) - return (char *)s + strlen(s); - - for (; *s && *(unsigned char *)s != c; s++) - ; - return (char *)s; -} - -char *strchr(const char *s, int c) -{ - while (*s != c && *s != '\0') s++; - - if (*s == c) { - return (char *)s; - } else { - return NULL; - } -} - -char *strrchr(const char *s, int c) -{ - char *isCharFind = NULL; - if (s != NULL) { - do { - if (*s == (char)c) { - isCharFind = (char *)s; - } - } while (*s++); - } - return isCharFind; -} - -int strerror_r(int err, char *buf, size_t buflen) -{ - char *msg = strerror(err); - size_t l = strlen(msg); - if (l >= buflen) { - if (buflen) { - memcpy(buf, msg, buflen - 1); - buf[buflen - 1] = 0; - } - return ERANGE; - } - memcpy(buf, msg, l + 1); - return 0; -} - -void *memcpy(void *restrict dest, const void *restrict src, size_t n) -{ - unsigned char *d = dest; - const unsigned char *s = src; - for (; n; n--) *d++ = *s++; - return dest; -} - -void *memmove(void *dest, const void *src, size_t n) -{ - char *d = dest; - const char *s = src; - - if (d == s) - return d; - if ((uintptr_t)s - (uintptr_t)d - n <= -2 * n) - return memcpy(d, s, n); - - if (d < s) { - for (; n; n--) *d++ = *s++; - } else { - while (n) n--, d[n] = s[n]; - } - - return dest; -} - -int memcmp(const void *vl, const void *vr, size_t n) -{ - const unsigned char *l = vl, *r = vr; - for (; n && *l == *r; n--, l++, r++) - ; - return n ? *l - *r : 0; -} - -int strcasecmp(const char *_l, const char *_r) -{ - const unsigned char *l = (void *)_l, *r = (void *)_r; - for (; *l && *r && (*l == *r || tolower(*l) == tolower(*r)); l++, r++) - ; - return tolower(*l) - tolower(*r); -} - -int strncasecmp(const char *_l, const char *_r, size_t n) -{ - const unsigned char *l = (void *)_l, *r = (void *)_r; - if (!n--) - return 0; - for (; *l && *r && n && (*l == *r || tolower(*l) == tolower(*r)); l++, r++, n--) - ; - return tolower(*l) - tolower(*r); -} - -// `strstr` helper function -static char *twobyte_strstr(const unsigned char *h, const unsigned char *n) -{ - uint16_t nw = n[0] << 8 | n[1], hw = h[0] << 8 | h[1]; - for (h++; *h && hw != nw; hw = hw << 8 | *++h) - ; - return *h ? (char *)h - 1 : 0; -} - -// `strstr` helper function -static char *threebyte_strstr(const unsigned char *h, const unsigned char *n) -{ - uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8; - uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8; - for (h += 2; *h && hw != nw; hw = (hw | *++h) << 8) - ; - return *h ? (char *)h - 2 : 0; -} - -// `strstr` helper function -static char *fourbyte_strstr(const unsigned char *h, const unsigned char *n) -{ - uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; - uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]; - for (h += 3; *h && hw != nw; hw = hw << 8 | *++h) - ; - return *h ? (char *)h - 3 : 0; -} - -// `strstr` helper function -static char *twoway_strstr(const unsigned char *h, const unsigned char *n) -{ - const unsigned char *z; - size_t l, ip, jp, k, p, ms, p0, mem, mem0; - size_t byteset[32 / sizeof(size_t)] = {0}; - size_t shift[256]; - - /* Computing length of needle and fill shift table */ - for (l = 0; n[l] && h[l]; l++) BITOP(byteset, n[l], |=), shift[n[l]] = l + 1; - if (n[l]) - return 0; /* hit the end of h */ - - /* Compute maximal suffix */ - ip = -1; - jp = 0; - k = p = 1; - while (jp + k < l) { - if (n[ip + k] == n[jp + k]) { - if (k == p) { - jp += p; - k = 1; - } else - k++; - } else if (n[ip + k] > n[jp + k]) { - jp += k; - k = 1; - p = jp - ip; - } else { - ip = jp++; - k = p = 1; - } - } - ms = ip; - p0 = p; - - /* And with the opposite comparison */ - ip = -1; - jp = 0; - k = p = 1; - while (jp + k < l) { - if (n[ip + k] == n[jp + k]) { - if (k == p) { - jp += p; - k = 1; - } else - k++; - } else if (n[ip + k] < n[jp + k]) { - jp += k; - k = 1; - p = jp - ip; - } else { - ip = jp++; - k = p = 1; - } - } - if (ip + 1 > ms + 1) - ms = ip; - else - p = p0; - - /* Periodic needle? */ - if (memcmp(n, n + p, ms + 1)) { - mem0 = 0; - p = MAX(ms, l - ms - 1) + 1; - } else - mem0 = l - p; - mem = 0; - - /* Initialize incremental end-of-haystack pointer */ - z = h; - - /* Search loop */ - for (;;) { - /* Update incremental end-of-haystack pointer */ - if (z - h < l) { - /* Fast estimate for MAX(l,63) */ - size_t grow = l | 63; - const unsigned char *z2 = memchr(z, 0, grow); - if (z2) { - z = z2; - if (z - h < l) - return 0; - } else - z += grow; - } - - /* Check last byte first; advance by shift on mismatch */ - if (BITOP(byteset, h[l - 1], &)) { - k = l - shift[h[l - 1]]; - if (k) { - if (k < mem) - k = mem; - h += k; - mem = 0; - continue; - } - } else { - h += l; - mem = 0; - continue; - } - - /* Compare right half */ - for (k = MAX(ms + 1, mem); n[k] && n[k] == h[k]; k++) - ; - if (n[k]) { - h += k - ms; - mem = 0; - continue; - } - /* Compare left half */ - for (k = ms + 1; k > mem && n[k - 1] == h[k - 1]; k--) - ; - if (k <= mem) - return (char *)h; - h += p; - mem = mem0; - } -} - -char *strstr(const char *h, const char *n) -{ - /* Return immediately on empty needle */ - if (!n[0]) - return (char *)h; - - /* Use faster algorithms for short needles */ - h = strchr(h, *n); - if (!h || !n[1]) - return (char *)h; - if (!h[1]) - return 0; - if (!n[2]) - return twobyte_strstr((void *)h, (void *)n); - if (!h[2]) - return 0; - if (!n[3]) - return threebyte_strstr((void *)h, (void *)n); - if (!h[3]) - return 0; - if (!n[4]) - return fourbyte_strstr((void *)h, (void *)n); - - return twoway_strstr((void *)h, (void *)n); -} - -#ifdef AX_CONFIG_ALLOC - -#include -char *strdup(const char *s) -{ - size_t l = strlen(s); - char *d = malloc(l + 1); - if (!d) - return NULL; - return memcpy(d, s, l + 1); -} - -#endif // AX_CONFIG_ALLOC diff --git a/arceos/ulib/axlibc/c/syslog.c b/arceos/ulib/axlibc/c/syslog.c deleted file mode 100644 index eb0ea8a1d..000000000 --- a/arceos/ulib/axlibc/c/syslog.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include - -// TODO -void syslog(int __pri, const char *__fmt, ...) -{ - unimplemented(); - return; -} - -// TODO -void openlog(const char *__ident, int __option, int __facility) -{ - unimplemented(); - return; -} diff --git a/arceos/ulib/axlibc/c/time.c b/arceos/ulib/axlibc/c/time.c deleted file mode 100644 index 9a2384ad9..000000000 --- a/arceos/ulib/axlibc/c/time.c +++ /dev/null @@ -1,203 +0,0 @@ -#include -#include -#include -#include -#include -#include - -long timezone = 0; -const char __utc[] = "UTC"; - -const int SEC_PER_MIN = 60; -const int SEC_PER_HOUR = 3600; -const int MIN_PER_HOUR = 60; -const int HOUR_PER_DAY = 24; - -/* 2000-03-01 (mod 400 year, immediately after feb29 */ -#define LEAPOCH (946684800LL + 86400 * (31 + 29)) -#define DAYS_PER_400Y (365 * 400 + 97) -#define DAYS_PER_100Y (365 * 100 + 24) -#define DAYS_PER_4Y (365 * 4 + 1) - -int __secs_to_tm(long long t, struct tm *tm) -{ - long long days, secs, years; - int remdays, remsecs, remyears; - int qc_cycles, c_cycles, q_cycles; - int months; - int wday, yday, leap; - static const char days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29}; - - /* Reject time_t values whose year would overflow int */ - if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL) - return -1; - - secs = t - LEAPOCH; - days = secs / 86400; - remsecs = secs % 86400; - if (remsecs < 0) { - remsecs += 86400; - days--; - } - - wday = (3 + days) % 7; - if (wday < 0) - wday += 7; - - qc_cycles = days / DAYS_PER_400Y; - remdays = days % DAYS_PER_400Y; - if (remdays < 0) { - remdays += DAYS_PER_400Y; - qc_cycles--; - } - - c_cycles = remdays / DAYS_PER_100Y; - if (c_cycles == 4) - c_cycles--; - remdays -= c_cycles * DAYS_PER_100Y; - - q_cycles = remdays / DAYS_PER_4Y; - if (q_cycles == 25) - q_cycles--; - remdays -= q_cycles * DAYS_PER_4Y; - - remyears = remdays / 365; - if (remyears == 4) - remyears--; - remdays -= remyears * 365; - - leap = !remyears && (q_cycles || !c_cycles); - yday = remdays + 31 + 28 + leap; - if (yday >= 365 + leap) - yday -= 365 + leap; - - years = remyears + 4 * q_cycles + 100 * c_cycles + 400LL * qc_cycles; - - for (months = 0; days_in_month[months] <= remdays; months++) remdays -= days_in_month[months]; - - if (months >= 10) { - months -= 12; - years++; - } - - if (years + 100 > INT_MAX || years + 100 < INT_MIN) - return -1; - - tm->tm_year = years + 100; - tm->tm_mon = months + 2; - tm->tm_mday = remdays + 1; - tm->tm_wday = wday; - tm->tm_yday = yday; - - tm->tm_hour = remsecs / 3600; - tm->tm_min = remsecs / 60 % 60; - tm->tm_sec = remsecs % 60; - - return 0; -} - -struct tm *gmtime_r(const time_t *restrict t, struct tm *restrict tm) -{ - if (__secs_to_tm(*t, tm) < 0) { - errno = EOVERFLOW; - return 0; - } - tm->tm_isdst = 0; - tm->__tm_gmtoff = 0; - tm->__tm_zone = __utc; - return tm; -} - -struct tm *gmtime(const time_t *timer) -{ - static struct tm tm; - return gmtime_r(timer, &tm); -} - -struct tm *localtime_r(const time_t *restrict t, struct tm *restrict tm) -{ - if (*t < INT_MIN * 31622400LL || *t > INT_MAX * 31622400LL) { - errno = EOVERFLOW; - return 0; - } - - if (__secs_to_tm(*t, tm) < 0) { - errno = EOVERFLOW; - return 0; - } - - tm->tm_isdst = 0; - tm->__tm_gmtoff = 0; - tm->__tm_zone = __utc; - - return tm; -} - -struct tm *localtime(const time_t *timep) -{ - static struct tm tm; - return localtime_r(timep, &tm); -} - -time_t time(time_t *t) -{ - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - time_t ret = ts.tv_sec; - if (t) - *t = ret; - return ret; -} - -int gettimeofday(struct timeval *tv, struct timezone *tz) -{ - struct timespec ts; - if (!tv) - return 0; - clock_gettime(CLOCK_REALTIME, &ts); - tv->tv_sec = ts.tv_sec; - tv->tv_usec = (int)ts.tv_nsec / 1000; - return 0; -} - -// TODO: -int utimes(const char *filename, const struct timeval times[2]) -{ - unimplemented(); - return 0; -} - -// TODO -void tzset() -{ - unimplemented(); - return; -} - -// TODO -int setitimer(int _which, const struct itimerval *restrict _new, struct itimerval *restrict _old) -{ - unimplemented(); - return 0; -} - -// TODO -char *ctime_r(const time_t *t, char *buf) -{ - unimplemented(); - return NULL; -} - -// TODO -clock_t clock(void) -{ - unimplemented(); - return 0; -} - -#ifdef AX_CONFIG_FP_SIMD -double difftime(time_t t1, time_t t0) -{ - return t1 - t0; -} -#endif diff --git a/arceos/ulib/axlibc/c/unistd.c b/arceos/ulib/axlibc/c/unistd.c deleted file mode 100644 index eec49bf6b..000000000 --- a/arceos/ulib/axlibc/c/unistd.c +++ /dev/null @@ -1,174 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -// TODO: -uid_t geteuid(void) -{ - unimplemented(); - return 0; -} - -// TODO -uid_t getuid(void) -{ - unimplemented(); - return 0; -} - -// TODO -pid_t setsid(void) -{ - unimplemented(); - return 0; -} - -// TODO -int isatty(int fd) -{ - unimplemented(); - return 0; -} - -unsigned int sleep(unsigned int seconds) -{ - struct timespec ts; - - ts.tv_sec = seconds; - ts.tv_nsec = 0; - if (nanosleep(&ts, &ts)) - return ts.tv_sec; - - return 0; -} - -int usleep(unsigned useconds) -{ - struct timespec tv = {.tv_sec = useconds / 1000000, .tv_nsec = (useconds % 1000000) * 1000}; - return nanosleep(&tv, &tv); -} - -#ifdef AX_CONFIG_FS - -// TODO: -int access(const char *pathname, int mode) -{ - unimplemented(); - return 0; -} - -// TODO: -ssize_t readlink(const char *path, char *buf, size_t bufsiz) -{ - unimplemented(); - return 0; -} - -// TODO: -int unlink(const char *pathname) -{ - unimplemented(); - return 0; -} - -// TODO: -int rmdir(const char *pathname) -{ - unimplemented(); - return 0; -} - -// TODO: -int fsync(int fd) -{ - unimplemented(); - return 0; -} - -// TODO -int fdatasync(int __fildes) -{ - unimplemented(); - return 0; -} - -// TODO: -int fchown(int fd, uid_t owner, gid_t group) -{ - unimplemented("owner: %x group: %x", owner, group); - return 0; -} - -// TODO: -int ftruncate(int fd, off_t length) -{ - unimplemented(); - return 0; -} - -// TODO -int chdir(const char *__path) -{ - unimplemented(); - return 0; -} - -// TODO -int truncate(const char *path, off_t length) -{ - unimplemented(); - return 0; -} - -#endif // AX_CONFIG_FS - -#ifdef AX_CONFIG_PIPE - -int pipe2(int fd[2], int flag) -{ - if (!flag) - return pipe(fd); - if (flag & ~(O_CLOEXEC | O_NONBLOCK)) - return -EINVAL; - - int res = pipe(fd); - if (res != 0) - return res; - - if (flag & O_CLOEXEC) { - fcntl(fd[0], F_SETFD, FD_CLOEXEC); - fcntl(fd[1], F_SETFD, FD_CLOEXEC); - } - if (flag & O_NONBLOCK) { - fcntl(fd[0], F_SETFL, O_NONBLOCK); - fcntl(fd[1], F_SETFL, O_NONBLOCK); - } - - return 0; -} - -#endif // AX_CONFIG_PIPE - -// TODO -_Noreturn void _exit(int status) -{ - exit(status); -} - -// TODO -int execve(const char *__path, char *const *__argv, char *const *__envp) -{ - unimplemented(); - return 0; -} - -// TODO -pid_t fork(void) -{ - unimplemented(); - return -1; -} diff --git a/arceos/ulib/axlibc/c/utsname.c b/arceos/ulib/axlibc/c/utsname.c deleted file mode 100644 index 14c35c805..000000000 --- a/arceos/ulib/axlibc/c/utsname.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -// TODO -int uname(struct utsname *a) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/c/wait.c b/arceos/ulib/axlibc/c/wait.c deleted file mode 100644 index a63fa278c..000000000 --- a/arceos/ulib/axlibc/c/wait.c +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include -#include - -// TODO -pid_t waitpid(pid_t pid, int *status, int options) -{ - unimplemented(); - return 0; -} - -// TODO -pid_t wait3(int *status, int _options, struct rusage *usage) -{ - unimplemented(); - return 0; -} diff --git a/arceos/ulib/axlibc/ctypes.h b/arceos/ulib/axlibc/ctypes.h deleted file mode 100644 index 882ec691c..000000000 --- a/arceos/ulib/axlibc/ctypes.h +++ /dev/null @@ -1,2 +0,0 @@ -#include -#include diff --git a/arceos/ulib/axlibc/include/arpa/inet.h b/arceos/ulib/axlibc/include/arpa/inet.h deleted file mode 100644 index 88889f61d..000000000 --- a/arceos/ulib/axlibc/include/arpa/inet.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _ARPA_INET_H -#define _ARPA_INET_H - -#include - -uint32_t htonl(uint32_t); -uint16_t htons(uint16_t); -uint32_t ntohl(uint32_t); -uint16_t ntohs(uint16_t); - -int inet_pton(int, const char *__restrict, void *__restrict); -const char *inet_ntop(int, const void *__restrict, char *__restrict, socklen_t); - -#endif diff --git a/arceos/ulib/axlibc/include/assert.h b/arceos/ulib/axlibc/include/assert.h deleted file mode 100644 index 0385fa3af..000000000 --- a/arceos/ulib/axlibc/include/assert.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __ASSERT_H__ -#define __ASSERT_H__ - -#include - -#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus) -#define static_assert _Static_assert -#endif - -#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__, __func__), 0))) - -_Noreturn void __assert_fail(const char *, const char *, int, const char *); - -#endif // __ASSERT_H__ diff --git a/arceos/ulib/axlibc/include/ctype.h b/arceos/ulib/axlibc/include/ctype.h deleted file mode 100644 index a3ba95b03..000000000 --- a/arceos/ulib/axlibc/include/ctype.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _CTYPE_H -#define _CTYPE_H - -int tolower(int __c); -int toupper(int __c); - -#define isalpha(a) ((((unsigned)(a) | 32) - 'a') < 26) -#define isdigit(a) (((unsigned)(a) - '0') < 10) -#define islower(a) (((unsigned)(a) - 'a') < 26) -#define isupper(a) (((unsigned)(a) - 'A') < 26) -#define isprint(a) (((unsigned)(a)-0x20) < 0x5f) -#define isgraph(a) (((unsigned)(a)-0x21) < 0x5e) -#define isalnum(a) ((isalpha(a) || isdigit(a))) -#define iscntrl(a) (((unsigned)a < 0x20 || a == 0x7f)) -#define ispunct(a) ((isgraph(a) && !isalnum(a))) -#define isxdigit(a) ((isdigit(a) || ((unsigned)a | 32) - 'a' < 6)) -#define isascii(a) ((!(a & ~0x7f))) -#define isspace(a) ((a == ' ' || (unsigned)a - '\t' < 5)) - -#endif diff --git a/arceos/ulib/axlibc/include/dirent.h b/arceos/ulib/axlibc/include/dirent.h deleted file mode 100644 index 41897510b..000000000 --- a/arceos/ulib/axlibc/include/dirent.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _DIRENT_H -#define _DIRENT_H - -#include - -struct __dirstream { - long long tell; - int fd; - int buf_pos; - int buf_end; - int lock[1]; - char buf[2048]; -}; - -typedef struct __dirstream DIR; - -struct dirent { - ino_t d_ino; - off_t d_off; - unsigned short d_reclen; - unsigned char d_type; - char d_name[256]; -}; - -int closedir(DIR *); -DIR *fdopendir(int); -DIR *opendir(const char *); -struct dirent *readdir(DIR *); -int readdir_r(DIR *__restrict, struct dirent *__restrict, struct dirent **__restrict); -void rewinddir(DIR *); -int dirfd(DIR *); - -#define DT_UNKNOWN 0 -#define DT_FIFO 1 -#define DT_CHR 2 -#define DT_DIR 4 -#define DT_BLK 6 -#define DT_REG 8 -#define DT_LNK 10 -#define DT_SOCK 12 -#define DT_WHT 14 -#define IFTODT(x) ((x) >> 12 & 017) -#define DTTOIF(x) ((x) << 12) - -#endif //_DIRENT_H diff --git a/arceos/ulib/axlibc/include/dlfcn.h b/arceos/ulib/axlibc/include/dlfcn.h deleted file mode 100644 index a1caea91e..000000000 --- a/arceos/ulib/axlibc/include/dlfcn.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _DLFCN_H -#define _DLFCN_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#define RTLD_LAZY 1 -#define RTLD_NOW 2 -#define RTLD_NOLOAD 4 -#define RTLD_NODELETE 4096 -#define RTLD_GLOBAL 256 -#define RTLD_LOCAL 0 -#define RTLD_NEXT ((void *)-1) -#define RTLD_DEFAULT ((void *)0) -#define RTLD_DI_LINKMAP 2 - -typedef struct { - const char *dli_fname; - void *dli_fbase; - const char *dli_sname; - void *dli_saddr; -} Dl_info; - -int dladdr(const void *, Dl_info *); -int dlclose(void *); -char *dlerror(void); -void *dlopen(const char *, int); -void *dlsym(void *__restrict, const char *__restrict); - -#if _REDIR_TIME64 -__REDIR(dlsym, __dlsym_time64); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/arceos/ulib/axlibc/include/endian.h b/arceos/ulib/axlibc/include/endian.h deleted file mode 100644 index 819a726a4..000000000 --- a/arceos/ulib/axlibc/include/endian.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef _ENDIAN_H -#define _ENDIAN_H - -#include - -#if defined(__aarch64__) -#if __AARCH64EB__ -#define __BYTE_ORDER 4321 -#else -#define __BYTE_ORDER 1234 -#endif -#else -#define __BYTE_ORDER 1234 -#endif - -#define __LITTLE_ENDIAN 1234 -#define __BIG_ENDIAN 4321 -#define __PDP_ENDIAN 3412 - -#define BIG_ENDIAN __BIG_ENDIAN -#define LITTLE_ENDIAN __LITTLE_ENDIAN -#define PDP_ENDIAN __PDP_ENDIAN -#define BYTE_ORDER __BYTE_ORDER - -static __inline uint16_t __bswap16(uint16_t __x) -{ - return __x << 8 | __x >> 8; -} - -static __inline uint32_t __bswap32(uint32_t __x) -{ - return __x >> 24 | (__x >> 8 & 0xff00) | (__x << 8 & 0xff0000) | __x << 24; -} - -static __inline uint64_t __bswap64(uint64_t __x) -{ - return (__bswap32(__x) + 0ULL) << 32 | __bswap32(__x >> 32); -} - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define htobe16(x) __bswap16(x) -#define be16toh(x) __bswap16(x) -#define htobe32(x) __bswap32(x) -#define be32toh(x) __bswap32(x) -#define htobe64(x) __bswap64(x) -#define be64toh(x) __bswap64(x) -#define htole16(x) (uint16_t)(x) -#define le16toh(x) (uint16_t)(x) -#define htole32(x) (uint32_t)(x) -#define le32toh(x) (uint32_t)(x) -#define htole64(x) (uint64_t)(x) -#define le64toh(x) (uint64_t)(x) -#else -#define htobe16(x) (uint16_t)(x) -#define be16toh(x) (uint16_t)(x) -#define htobe32(x) (uint32_t)(x) -#define be32toh(x) (uint32_t)(x) -#define htobe64(x) (uint64_t)(x) -#define be64toh(x) (uint64_t)(x) -#define htole16(x) __bswap16(x) -#define le16toh(x) __bswap16(x) -#define htole32(x) __bswap32(x) -#define le32toh(x) __bswap32(x) -#define htole64(x) __bswap64(x) -#define le64toh(x) __bswap64(x) -#endif - -#endif diff --git a/arceos/ulib/axlibc/include/errno.h b/arceos/ulib/axlibc/include/errno.h deleted file mode 100644 index 16ed78e31..000000000 --- a/arceos/ulib/axlibc/include/errno.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef __ERRNO_H__ -#define __ERRNO_H__ - -#define EPERM 1 /* Operation not permitted */ -#define ENOENT 2 /* No such file or directory */ -#define ESRCH 3 /* No such process */ -#define EINTR 4 /* Interrupted system call */ -#define EIO 5 /* I/O error */ -#define ENXIO 6 /* No such device or address */ -#define E2BIG 7 /* Argument list too long */ -#define ENOEXEC 8 /* Exec format error */ -#define EBADF 9 /* Bad file number */ -#define ECHILD 10 /* No child processes */ -#define EAGAIN 11 /* Try again */ -#define ENOMEM 12 /* Out of memory */ -#define EACCES 13 /* Permission denied */ -#define EFAULT 14 /* Bad address */ -#define ENOTBLK 15 /* Block device required */ -#define EBUSY 16 /* Device or resource busy */ -#define EEXIST 17 /* File exists */ -#define EXDEV 18 /* Cross-device link */ -#define ENODEV 19 /* No such device */ -#define ENOTDIR 20 /* Not a directory */ -#define EISDIR 21 /* Is a directory */ -#define EINVAL 22 /* Invalid argument */ -#define ENFILE 23 /* File table overflow */ -#define EMFILE 24 /* Too many open files */ -#define ENOTTY 25 /* Not a typewriter */ -#define ETXTBSY 26 /* Text file busy */ -#define EFBIG 27 /* File too large */ -#define ENOSPC 28 /* No space left on device */ -#define ESPIPE 29 /* Illegal seek */ -#define EROFS 30 /* Read-only file system */ -#define EMLINK 31 /* Too many links */ -#define EPIPE 32 /* Broken pipe */ -#define EDOM 33 /* Math argument out of domain of func */ -#define ERANGE 34 /* Math result not representable */ -#define EDEADLK 35 /* Resource deadlock would occur */ -#define ENAMETOOLONG 36 /* File name too long */ -#define ENOLCK 37 /* No record locks available */ -#define ENOSYS 38 /* Invalid system call number */ -#define ENOTEMPTY 39 /* Directory not empty */ -#define ELOOP 40 /* Too many symbolic links encountered */ -#define EWOULDBLOCK EAGAIN /* Operation would block */ -#define ENOMSG 42 /* No message of desired type */ -#define EIDRM 43 /* Identifier removed */ -#define ECHRNG 44 /* Channel number out of range */ -#define EL2NSYNC 45 /* Level 2 not synchronized */ -#define EL3HLT 46 /* Level 3 halted */ -#define EL3RST 47 /* Level 3 reset */ -#define ELNRNG 48 /* Link number out of range */ -#define EUNATCH 49 /* Protocol driver not attached */ -#define ENOCSI 50 /* No CSI structure available */ -#define EL2HLT 51 /* Level 2 halted */ -#define EBADE 52 /* Invalid exchange */ -#define EBADR 53 /* Invalid request descriptor */ -#define EXFULL 54 /* Exchange full */ -#define ENOANO 55 /* No anode */ -#define EBADRQC 56 /* Invalid request code */ -#define EBADSLT 57 /* Invalid slot */ -#define EDEADLOCK EDEADLK -#define EBFONT 59 /* Bad font file format */ -#define ENOSTR 60 /* Device not a stream */ -#define ENODATA 61 /* No data available */ -#define ETIME 62 /* Timer expired */ -#define ENOSR 63 /* Out of streams resources */ -#define ENONET 64 /* Machine is not on the network */ -#define ENOPKG 65 /* Package not installed */ -#define EREMOTE 66 /* Object is remote */ -#define ENOLINK 67 /* Link has been severed */ -#define EADV 68 /* Advertise error */ -#define ESRMNT 69 /* Srmount error */ -#define ECOMM 70 /* Communication error on send */ -#define EPROTO 71 /* Protocol error */ -#define EMULTIHOP 72 /* Multihop attempted */ -#define EDOTDOT 73 /* RFS specific error */ -#define EBADMSG 74 /* Not a data message */ -#define EOVERFLOW 75 /* Value too large for defined data type */ -#define ENOTUNIQ 76 /* Name not unique on network */ -#define EBADFD 77 /* File descriptor in bad state */ -#define EREMCHG 78 /* Remote address changed */ -#define ELIBACC 79 /* Can not access a needed shared library */ -#define ELIBBAD 80 /* Accessing a corrupted shared library */ -#define ELIBSCN 81 /* .lib section in a.out corrupted */ -#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ -#define ELIBEXEC 83 /* Cannot exec a shared library directly */ -#define EILSEQ 84 /* Illegal byte sequence */ -#define ERESTART 85 /* Interrupted system call should be restarted */ -#define ESTRPIPE 86 /* Streams pipe error */ -#define EUSERS 87 /* Too many users */ -#define ENOTSOCK 88 /* Socket operation on non-socket */ -#define EDESTADDRREQ 89 /* Destination address required */ -#define EMSGSIZE 90 /* Message too long */ -#define EPROTOTYPE 91 /* Protocol wrong type for socket */ -#define ENOPROTOOPT 92 /* Protocol not available */ -#define EPROTONOSUPPORT 93 /* Protocol not supported */ -#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ -#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ -#define EPFNOSUPPORT 96 /* Protocol family not supported */ -#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ -#define EADDRINUSE 98 /* Address already in use */ -#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ -#define ENETDOWN 100 /* Network is down */ -#define ENETUNREACH 101 /* Network is unreachable */ -#define ENETRESET 102 /* Network dropped connection because of reset */ -#define ECONNABORTED 103 /* Software caused connection abort */ -#define ECONNRESET 104 /* Connection reset by peer */ -#define ENOBUFS 105 /* No buffer space available */ -#define EISCONN 106 /* Transport endpoint is already connected */ -#define ENOTCONN 107 /* Transport endpoint is not connected */ -#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ -#define ETOOMANYREFS 109 /* Too many references: cannot splice */ -#define ETIMEDOUT 110 /* Connection timed out */ -#define ECONNREFUSED 111 /* Connection refused */ -#define EHOSTDOWN 112 /* Host is down */ -#define EHOSTUNREACH 113 /* No route to host */ -#define EALREADY 114 /* Operation already in progress */ -#define EINPROGRESS 115 /* Operation now in progress */ -#define ESTALE 116 /* Stale file handle */ -#define EUCLEAN 117 /* Structure needs cleaning */ -#define ENOTNAM 118 /* Not a XENIX named type file */ -#define ENAVAIL 119 /* No XENIX semaphores available */ -#define EISNAM 120 /* Is a named type file */ -#define EREMOTEIO 121 /* Remote I/O error */ -#define EDQUOT 122 /* Quota exceeded */ - -#define ENOMEDIUM 123 /* No medium found */ -#define EMEDIUMTYPE 124 /* Wrong medium type */ -#define ECANCELED 125 /* Operation Canceled */ -#define ENOKEY 126 /* Required key not available */ -#define EKEYEXPIRED 127 /* Key has expired */ -#define EKEYREVOKED 128 /* Key has been revoked */ -#define EKEYREJECTED 129 /* Key was rejected by service */ -#define EOWNERDEAD 130 /* Owner died */ -#define ENOTRECOVERABLE 131 /* State not recoverable */ -#define ERFKILL 132 /* Operation not possible due to RF-kill */ -#define EHWPOISON 133 /* Memory page has hardware error */ - -#ifndef ENOTSUP -#define ENOTSUP EOPNOTSUPP -#endif - -int *__errno_location(void); -#define errno (*__errno_location()) - -#ifdef _GNU_SOURCE -extern char *program_invocation_short_name, *program_invocation_name; -#endif - -#endif // __ERRNO_H__ diff --git a/arceos/ulib/axlibc/include/fcntl.h b/arceos/ulib/axlibc/include/fcntl.h deleted file mode 100644 index 48750af66..000000000 --- a/arceos/ulib/axlibc/include/fcntl.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef __FCNTL_H__ -#define __FCNTL_H__ - -#include - -#define O_CREAT 0100 -#define O_EXCL 0200 -#define O_NOCTTY 0400 -#define O_TRUNC 01000 -#define O_APPEND 02000 -#define O_NONBLOCK 04000 -#define O_DSYNC 010000 -#define O_SYNC 04010000 -#define O_RSYNC 04010000 -#define O_DIRECTORY 0200000 -#define O_NOFOLLOW 0400000 -#define O_CLOEXEC 02000000 - -#define O_ASYNC 020000 -#define O_DIRECT 040000 -#define O_LARGEFILE 0100000 -#define O_NOATIME 01000000 -#define O_PATH 010000000 -#define O_TMPFILE 020200000 -#define O_NDELAY O_NONBLOCK - -#define O_SEARCH O_PATH -#define O_EXEC O_PATH -#define O_TTY_INIT 0 - -#define O_ACCMODE (03 | O_SEARCH) -#define O_RDONLY 00 -#define O_WRONLY 01 -#define O_RDWR 02 - -#define F_DUPFD 0 -#define F_GETFD 1 -#define F_SETFD 2 -#define F_GETFL 3 -#define F_SETFL 4 - -#define F_SETOWN 8 -#define F_GETOWN 9 -#define F_SETSIG 10 -#define F_GETSIG 11 - -#if __LONG_MAX == 0x7fffffffL -#define F_GETLK 12 -#define F_SETLK 13 -#define F_SETLKW 14 -#else -#define F_GETLK 5 -#define F_SETLK 6 -#define F_SETLKW 7 -#endif - -#define FD_CLOEXEC 1 -#define F_DUPFD_CLOEXEC 1030 - -#define F_RDLCK 0 -#define F_WRLCK 1 -#define F_UNLCK 2 - -#define F_OK 0 -#define R_OK 4 -#define W_OK 2 -#define X_OK 1 -#define F_ULOCK 0 -#define F_LOCK 1 -#define F_TLOCK 2 -#define F_TEST 3 - -#ifndef S_IRUSR -#define S_ISUID 04000 -#define S_ISGID 02000 -#define S_ISVTX 01000 -#define S_IRUSR 0400 -#define S_IWUSR 0200 -#define S_IXUSR 0100 -#define S_IRWXU 0700 -#define S_IRGRP 0040 -#define S_IWGRP 0020 -#define S_IXGRP 0010 -#define S_IRWXG 0070 -#define S_IROTH 0004 -#define S_IWOTH 0002 -#define S_IXOTH 0001 -#define S_IRWXO 0007 -#endif - -#define POSIX_FADV_NORMAL 0 -#define POSIX_FADV_RANDOM 1 -#define POSIX_FADV_SEQUENTIAL 2 -#define POSIX_FADV_WILLNEED 3 -#ifndef POSIX_FADV_DONTNEED -#define POSIX_FADV_DONTNEED 4 -#define POSIX_FADV_NOREUSE 5 -#endif - -#define AT_FDCWD (-100) -#define AT_EMPTY_PATH 0x1000 - -#define SYNC_FILE_RANGE_WAIT_BEFORE 1 -#define SYNC_FILE_RANGE_WRITE 2 -#define SYNC_FILE_RANGE_WAIT_AFTER 4 - -#define loff_t off_t - -struct flock { - short l_type; - short l_whence; - off_t l_start; - off_t l_len; - pid_t l_pid; -}; - -int fcntl(int fd, int cmd, ... /* arg */); -int posix_fadvise(int __fd, unsigned long __offset, unsigned long __len, int __advise); -int sync_file_range(int, off_t, off_t, unsigned); - -int open(const char *filename, int flags, ...); - -#endif diff --git a/arceos/ulib/axlibc/include/features.h b/arceos/ulib/axlibc/include/features.h deleted file mode 100644 index 2801151cc..000000000 --- a/arceos/ulib/axlibc/include/features.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _FEATURES_H -#define _FEATURES_H - -#if __STDC_VERSION__ >= 201112L -#elif defined(__GNUC__) -#define _Noreturn __attribute__((__noreturn__)) -#else -#define _Noreturn -#endif - -#endif diff --git a/arceos/ulib/axlibc/include/float.h b/arceos/ulib/axlibc/include/float.h deleted file mode 100644 index 32ac40abf..000000000 --- a/arceos/ulib/axlibc/include/float.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef _FLOAT_H -#define _FLOAT_H - -// int __flt_rounds(void); -#define FLT_ROUNDS (__flt_rounds()) - -#define FLT_RADIX 2 - -#define FLT_TRUE_MIN 1.40129846432481707092e-45F -#define FLT_MIN 1.17549435082228750797e-38F -#define FLT_MAX 3.40282346638528859812e+38F -#define FLT_EPSILON 1.1920928955078125e-07F - -#define FLT_MANT_DIG 24 -#define FLT_MIN_EXP (-125) -#define FLT_MAX_EXP 128 -#define FLT_HAS_SUBNORM 1 - -#define FLT_DIG 6 -#define FLT_DECIMAL_DIG 9 -#define FLT_MIN_10_EXP (-37) -#define FLT_MAX_10_EXP 38 - -#define DBL_TRUE_MIN 4.94065645841246544177e-324 -#define DBL_MIN 2.22507385850720138309e-308 -#define DBL_MAX 1.79769313486231570815e+308 -#define DBL_EPSILON 2.22044604925031308085e-16 - -#define DBL_MANT_DIG 53 -#define DBL_MIN_EXP (-1021) -#define DBL_MAX_EXP 1024 -#define DBL_HAS_SUBNORM 1 - -#define DBL_DIG 15 -#define DBL_DECIMAL_DIG 17 -#define DBL_MIN_10_EXP (-307) -#define DBL_MAX_10_EXP 308 - -#define LDBL_HAS_SUBNORM 1 -#define LDBL_DECIMAL_DIG DECIMAL_DIG - -#if defined(__aarch64__) -#define FLT_EVAL_METHOD 0 - -#define LDBL_TRUE_MIN 6.47517511943802511092443895822764655e-4966L -#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L -#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L -#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L - -#define LDBL_MANT_DIG 113 -#define LDBL_MIN_EXP (-16381) -#define LDBL_MAX_EXP 16384 - -#define LDBL_DIG 33 -#define LDBL_MIN_10_EXP (-4931) -#define LDBL_MAX_10_EXP 4932 - -#define DECIMAL_DIG 36 -#elif defined(__riscv__) || defined(__riscv) -#define FLT_EVAL_METHOD 0 - -#define LDBL_TRUE_MIN 6.47517511943802511092443895822764655e-4966L -#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L -#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L -#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L - -#define LDBL_MANT_DIG 113 -#define LDBL_MIN_EXP (-16381) -#define LDBL_MAX_EXP 16384 - -#define LDBL_DIG 33 -#define LDBL_MIN_10_EXP (-4931) -#define LDBL_MAX_10_EXP 4932 - -#define DECIMAL_DIG 36 -#elif defined(__x86_64__) -#ifdef __FLT_EVAL_METHOD__ -#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__ -#else -#define FLT_EVAL_METHOD 0 -#endif - -#define LDBL_TRUE_MIN 3.6451995318824746025e-4951L -#define LDBL_MIN 3.3621031431120935063e-4932L -#define LDBL_MAX 1.1897314953572317650e+4932L -#define LDBL_EPSILON 1.0842021724855044340e-19L - -#define LDBL_MANT_DIG 64 -#define LDBL_MIN_EXP (-16381) -#define LDBL_MAX_EXP 16384 - -#define LDBL_DIG 18 -#define LDBL_MIN_10_EXP (-4931) -#define LDBL_MAX_10_EXP 4932 - -#define DECIMAL_DIG 21 -#endif - -#endif diff --git a/arceos/ulib/axlibc/include/fnmatch.h b/arceos/ulib/axlibc/include/fnmatch.h deleted file mode 100644 index c387c5ce7..000000000 --- a/arceos/ulib/axlibc/include/fnmatch.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _FNMATCH_H -#define _FNMATCH_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define FNM_PATHNAME 0x1 -#define FNM_NOESCAPE 0x2 -#define FNM_PERIOD 0x4 -#define FNM_LEADING_DIR 0x8 -#define FNM_CASEFOLD 0x10 -#define FNM_FILE_NAME FNM_PATHNAME - -#define FNM_NOMATCH 1 -#define FNM_NOSYS (-1) - -int fnmatch(const char *, const char *, int); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/arceos/ulib/axlibc/include/glob.h b/arceos/ulib/axlibc/include/glob.h deleted file mode 100644 index 4dbd34705..000000000 --- a/arceos/ulib/axlibc/include/glob.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _GLOB_H -#define _GLOB_H - -#include - -#define GLOB_ERR 0x01 -#define GLOB_MARK 0x02 -#define GLOB_NOSORT 0x04 -#define GLOB_DOOFFS 0x08 -#define GLOB_NOCHECK 0x10 -#define GLOB_APPEND 0x20 -#define GLOB_NOESCAPE 0x40 -#define GLOB_PERIOD 0x80 - -#define GLOB_TILDE 0x1000 -#define GLOB_TILDE_CHECK 0x4000 - -#define GLOB_NOSPACE 1 -#define GLOB_ABORTED 2 -#define GLOB_NOMATCH 3 -#define GLOB_NOSYS 4 - -typedef struct { - size_t gl_pathc; - char **gl_pathv; - size_t gl_offs; - int __dummy1; - void *__dummy2[5]; -} glob_t; - -int glob(const char *__restrict, int, int (*)(const char *, int), glob_t *__restrict); -void globfree(glob_t *); - -#endif diff --git a/arceos/ulib/axlibc/include/inttypes.h b/arceos/ulib/axlibc/include/inttypes.h deleted file mode 100644 index 536fd3ffa..000000000 --- a/arceos/ulib/axlibc/include/inttypes.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _INTTYPES_H -#define _INTTYPES_H - -#include - -#define __PRI64 "l" - -#define PRIu64 __PRI64 "u" - -#endif diff --git a/arceos/ulib/axlibc/include/langinfo.h b/arceos/ulib/axlibc/include/langinfo.h deleted file mode 100644 index 9114fba47..000000000 --- a/arceos/ulib/axlibc/include/langinfo.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef _LANGINFO_H -#define _LANGINFO_H - -typedef int nl_item; - -#define ABDAY_1 0x20000 -#define ABDAY_2 0x20001 -#define ABDAY_3 0x20002 -#define ABDAY_4 0x20003 -#define ABDAY_5 0x20004 -#define ABDAY_6 0x20005 -#define ABDAY_7 0x20006 - -#define DAY_1 0x20007 -#define DAY_2 0x20008 -#define DAY_3 0x20009 -#define DAY_4 0x2000A -#define DAY_5 0x2000B -#define DAY_6 0x2000C -#define DAY_7 0x2000D - -#define ABMON_1 0x2000E -#define ABMON_2 0x2000F -#define ABMON_3 0x20010 -#define ABMON_4 0x20011 -#define ABMON_5 0x20012 -#define ABMON_6 0x20013 -#define ABMON_7 0x20014 -#define ABMON_8 0x20015 -#define ABMON_9 0x20016 -#define ABMON_10 0x20017 -#define ABMON_11 0x20018 -#define ABMON_12 0x20019 - -#define MON_1 0x2001A -#define MON_2 0x2001B -#define MON_3 0x2001C -#define MON_4 0x2001D -#define MON_5 0x2001E -#define MON_6 0x2001F -#define MON_7 0x20020 -#define MON_8 0x20021 -#define MON_9 0x20022 -#define MON_10 0x20023 -#define MON_11 0x20024 -#define MON_12 0x20025 - -#define AM_STR 0x20026 -#define PM_STR 0x20027 - -#define D_T_FMT 0x20028 -#define D_FMT 0x20029 -#define T_FMT 0x2002A -#define T_FMT_AMPM 0x2002B - -#define ERA 0x2002C -#define ERA_D_FMT 0x2002E -#define ALT_DIGITS 0x2002F -#define ERA_D_T_FMT 0x20030 -#define ERA_T_FMT 0x20031 - -#define CODESET 14 - -#define CRNCYSTR 0x4000F - -#define RADIXCHAR 0x10000 -#define THOUSEP 0x10001 -#define YESEXPR 0x50000 -#define NOEXPR 0x50001 - -#define _NL_LOCALE_NAME(cat) (((cat) << 16) | 0xffff) - -#if defined(_GNU_SOURCE) -#define NL_LOCALE_NAME(cat) _NL_LOCALE_NAME(cat) -#endif - -#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) -#define YESSTR 0x50002 -#define NOSTR 0x50003 -#endif - -#endif diff --git a/arceos/ulib/axlibc/include/libgen.h b/arceos/ulib/axlibc/include/libgen.h deleted file mode 100644 index 7c7fd9c6d..000000000 --- a/arceos/ulib/axlibc/include/libgen.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _LIBGEN_H -#define _LIBGEN_H - -#ifdef __cplusplus -extern "C" { -#endif - -char *dirname(char *); -char *basename(char *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/arceos/ulib/axlibc/include/limits.h b/arceos/ulib/axlibc/include/limits.h deleted file mode 100644 index 26b213a96..000000000 --- a/arceos/ulib/axlibc/include/limits.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __LIMITS__ -#define __LIMITS__ - -#define __LONG_MAX 0x7fffffffffffffffL -#define CHAR_BIT 8 -#define SCHAR_MIN (-128) -#define SCHAR_MAX 127 -#define UCHAR_MAX 255 -#define SHRT_MIN (-1 - 0x7fff) -#define SHRT_MAX 0x7fff -#define USHRT_MAX 0xffff -#define INT_MIN (-1 - 0x7fffffff) -#define INT_MAX 0x7fffffff -#define UINT_MAX 0xffffffffU -#define LONG_MIN (-LONG_MAX - 1) -#define LONG_MAX __LONG_MAX -#define ULONG_MAX (2UL * LONG_MAX + 1) -#define LLONG_MIN (-LLONG_MAX - 1) -#define LLONG_MAX 0x7fffffffffffffffLL -#define ULLONG_MAX (2ULL * LLONG_MAX + 1) -#define IOV_MAX 1024 - -#define PTHREAD_STACK_MIN 2048 - -#define LOGIN_NAME_MAX 256 -#ifndef NAME_MAX -#define NAME_MAX 255 -#endif -#define TZNAME_MAX 6 - -#define PATH_MAX 4096 -#define SSIZE_MAX LONG_MAX -#define CHAR_MAX 127 - -#endif diff --git a/arceos/ulib/axlibc/include/locale.h b/arceos/ulib/axlibc/include/locale.h deleted file mode 100644 index e33b13712..000000000 --- a/arceos/ulib/axlibc/include/locale.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef _LOCALE_H -#define _LOCALE_H - -#define LC_CTYPE 0 -#define LC_NUMERIC 1 -#define LC_TIME 2 -#define LC_COLLATE 3 -#define LC_MONETARY 4 -#define LC_MESSAGES 5 -#define LC_ALL 6 -#define LOCALE_NAME_MAX 23 - -#include - -struct lconv { - char *decimal_point; - char *thousands_sep; - char *grouping; - - char *int_curr_symbol; - char *currency_symbol; - char *mon_decimal_point; - char *mon_thousands_sep; - char *mon_grouping; - char *positive_sign; - char *negative_sign; - char int_frac_digits; - char frac_digits; - char p_cs_precedes; - char p_sep_by_space; - char n_cs_precedes; - char n_sep_by_space; - char p_sign_posn; - char n_sign_posn; - char int_p_cs_precedes; - char int_p_sep_by_space; - char int_n_cs_precedes; - char int_n_sep_by_space; - char int_p_sign_posn; - char int_n_sign_posn; -}; - -struct __locale_map { - const void *map; - size_t map_size; - char name[LOCALE_NAME_MAX + 1]; - const struct __locale_map *next; -}; - -struct __locale_struct { - const struct __locale_map *cat[6]; -}; - -typedef struct __locale_struct *locale_t; - -char *setlocale(int, const char *); -struct lconv *localeconv(void); - -#endif // _LOCALE_H diff --git a/arceos/ulib/axlibc/include/math.h b/arceos/ulib/axlibc/include/math.h deleted file mode 100644 index 649b85126..000000000 --- a/arceos/ulib/axlibc/include/math.h +++ /dev/null @@ -1,321 +0,0 @@ -#ifndef _MATH_H -#define _MATH_H - -#ifdef AX_CONFIG_FP_SIMD - -typedef double double_t; - -#if 100 * __GNUC__ + __GNUC_MINOR__ >= 303 -#define NAN __builtin_nanf("") -#define INFINITY __builtin_inff() -#else -#define NAN (0.0f / 0.0f) -#define INFINITY 1e5000f -#endif - -#define M_PI 3.14159265358979323846 /* pi */ - -#define LOG_TABLE_BITS 7 -#define LOG_POLY_ORDER 6 -#define LOG_POLY1_ORDER 12 - -#define HUGE_VALF INFINITY -#define HUGE_VAL ((double)INFINITY) -#define HUGE_VALL ((long double)INFINITY) - -#define MATH_ERRNO 1 -#define MATH_ERREXCEPT 2 -#define math_errhandling 2 - -#define FP_ILOGBNAN (-1 - 0x7fffffff) -#define FP_ILOGB0 FP_ILOGBNAN - -#define LOG_TABLE_BITS 7 -#define LOG_POLY_ORDER 6 -#define LOG_POLY1_ORDER 12 - -#define FP_NAN 0 -#define FP_INFINITE 1 -#define FP_ZERO 2 -#define FP_SUBNORMAL 3 -#define FP_NORMAL 4 - -int __fpclassify(double); -int __fpclassifyf(float); -int __fpclassifyl(long double); - -static __inline unsigned __FLOAT_BITS(float __f) -{ - union { - float __f; - unsigned __i; - } __u; - __u.__f = __f; - return __u.__i; -} - -static __inline unsigned long long __DOUBLE_BITS(double __f) -{ - union { - double __f; - unsigned long long __i; - } __u; - __u.__f = __f; - return __u.__i; -} - -#define fpclassify(x) \ - (sizeof(x) == sizeof(float) ? __fpclassifyf(x) \ - : sizeof(x) == sizeof(double) ? __fpclassify(x) \ - : __fpclassifyl(x)) - -#define isnan(x) \ - (sizeof(x) == sizeof(float) ? (__FLOAT_BITS(x) & 0x7fffffff) > 0x7f800000 \ - : sizeof(x) == sizeof(double) ? (__DOUBLE_BITS(x) & -1ULL >> 1) > 0x7ffULL << 52 \ - : __fpclassifyl(x) == FP_NAN) - -#define isinf(x) \ - (sizeof(x) == sizeof(float) ? (__FLOAT_BITS(x) & 0x7fffffff) == 0x7f800000 \ - : sizeof(x) == sizeof(double) ? (__DOUBLE_BITS(x) & -1ULL >> 1) == 0x7ffULL << 52 \ - : __fpclassifyl(x) == FP_INFINITE) - -#define isfinite(x) \ - (sizeof(x) == sizeof(float) ? (__FLOAT_BITS(x) & 0x7fffffff) < 0x7f800000 \ - : sizeof(x) == sizeof(double) ? (__DOUBLE_BITS(x) & -1ULL >> 1) < 0x7ffULL << 52 \ - : __fpclassifyl(x) > FP_INFINITE) - -#define isnormal(x) \ - (sizeof(x) == sizeof(float) ? ((__FLOAT_BITS(x) + 0x00800000) & 0x7fffffff) >= 0x01000000 \ - : ((__DOUBLE_BITS(x) + (1ULL << 52)) & -1ULL >> 1) >= 1ULL << 53) - -double acos(double); -float acosf(float); -long double acosl(long double); - -double acosh(double); -float acoshf(float); -long double acoshl(long double); - -double asin(double); -float asinf(float); -long double asinl(long double); - -double asinh(double); -float asinhf(float); -long double asinhl(long double); - -double atan(double); -float atanf(float); -long double atanl(long double); - -double atan2(double, double); -float atan2f(float, float); -long double atan2l(long double, long double); - -double atanh(double); -float atanhf(float); -long double atanhl(long double); - -double cbrt(double); -float cbrtf(float); -long double cbrtl(long double); - -double ceil(double); -float ceilf(float); -long double ceill(long double); - -double copysign(double, double); -float copysignf(float, float); -long double copysignl(long double, long double); - -double cos(double); -float cosf(float); -long double cosl(long double); - -double cosh(double); -float coshf(float); -long double coshl(long double); - -double erf(double); -float erff(float); -long double erfl(long double); - -double erfc(double); -float erfcf(float); -long double erfcl(long double); - -double exp(double); -float expf(float); -long double expl(long double); - -double exp2(double); -float exp2f(float); -long double exp2l(long double); - -double expm1(double); -float expm1f(float); -long double expm1l(long double); - -double fabs(double); -float fabsf(float); -long double fabsl(long double); - -double fdim(double, double); -float fdimf(float, float); -long double fdiml(long double, long double); - -double floor(double); -float floorf(float); -long double floorl(long double); - -double fma(double, double, double); -float fmaf(float, float, float); -long double fmal(long double, long double, long double); - -double fmax(double, double); -float fmaxf(float, float); -long double fmaxl(long double, long double); - -double fmin(double, double); -float fminf(float, float); -long double fminl(long double, long double); - -double fmod(double, double); -float fmodf(float, float); -long double fmodl(long double, long double); - -double frexp(double, int *); -float frexpf(float, int *); -long double frexpl(long double, int *); - -double hypot(double, double); -float hypotf(float, float); -long double hypotl(long double, long double); - -int ilogb(double); -int ilogbf(float); -int ilogbl(long double); - -double ldexp(double, int); -float ldexpf(float, int); -long double ldexpl(long double, int); - -double lgamma(double); -float lgammaf(float); -long double lgammal(long double); - -long long llrint(double); -long long llrintf(float); -long long llrintl(long double); - -long long llround(double); -long long llroundf(float); -long long llroundl(long double); - -double log(double); -float logf(float); -long double logl(long double); - -double log10(double); -float log10f(float); -long double log10l(long double); - -double log1p(double); -float log1pf(float); -long double log1pl(long double); - -double log2(double); -float log2f(float); -long double log2l(long double); - -double logb(double); -float logbf(float); -long double logbl(long double); - -long lrint(double); -long lrintf(float); -long lrintl(long double); - -long lround(double); -long lroundf(float); -long lroundl(long double); - -double modf(double, double *); -float modff(float, float *); -long double modfl(long double, long double *); - -double nan(const char *); -float nanf(const char *); -long double nanl(const char *); - -double nearbyint(double); -float nearbyintf(float); -long double nearbyintl(long double); - -double nextafter(double, double); -float nextafterf(float, float); -long double nextafterl(long double, long double); - -double nexttoward(double, long double); -float nexttowardf(float, long double); -long double nexttowardl(long double, long double); - -double pow(double, double); -float powf(float, float); -long double powl(long double, long double); - -double remainder(double, double); -float remainderf(float, float); -long double remainderl(long double, long double); - -double remquo(double, double, int *); -float remquof(float, float, int *); -long double remquol(long double, long double, int *); - -double rint(double); -float rintf(float); -long double rintl(long double); - -double round(double); -float roundf(float); -long double roundl(long double); - -double scalbln(double, long); -float scalblnf(float, long); -long double scalblnl(long double, long); - -double scalbn(double, int); -float scalbnf(float, int); -long double scalbnl(long double, int); - -double sin(double); -float sinf(float); -long double sinl(long double); - -double sinh(double); -float sinhf(float); -long double sinhl(long double); - -double sqrt(double); -float sqrtf(float); -long double sqrtl(long double); - -double tan(double); -float tanf(float); -long double tanl(long double); - -double tanh(double); -float tanhf(float); -long double tanhl(long double); - -double tgamma(double); -float tgammaf(float); -long double tgammal(long double); - -double trunc(double); -float truncf(float); -long double truncl(long double); - -#endif // AX_CONFIG_FP_SIMD - -#endif // _MATH_H diff --git a/arceos/ulib/axlibc/include/memory.h b/arceos/ulib/axlibc/include/memory.h deleted file mode 100644 index d51b932ee..000000000 --- a/arceos/ulib/axlibc/include/memory.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __MEMORY_H__ -#define __MEMORY_H__ - -#include - -#endif // __MEMORY_H__ diff --git a/arceos/ulib/axlibc/include/netdb.h b/arceos/ulib/axlibc/include/netdb.h deleted file mode 100644 index 6272578b7..000000000 --- a/arceos/ulib/axlibc/include/netdb.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef _NETDB_H -#define _NETDB_H - -#include - -struct addrinfo { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - socklen_t ai_addrlen; - struct sockaddr *ai_addr; - char *ai_canonname; - struct addrinfo *ai_next; -}; - -struct aibuf { - struct addrinfo ai; - union sa { - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - } sa; - volatile int lock[1]; - short slot, ref; -}; - -struct service { - uint16_t port; - unsigned char proto, socktype; -}; - -struct address { - int family; - unsigned scopeid; - uint8_t addr[16]; - int sortkey; -}; - -#define AI_PASSIVE 0x01 -#define AI_CANONNAME 0x02 -#define AI_NUMERICHOST 0x04 -#define AI_V4MAPPED 0x08 -#define AI_ALL 0x10 -#define AI_ADDRCONFIG 0x20 -#define AI_NUMERICSERV 0x400 - -#define NI_NUMERICHOST 0x01 -#define NI_NUMERICSERV 0x02 -#define NI_NOFQDN 0x04 -#define NI_NAMEREQD 0x08 -#define NI_DGRAM 0x10 -#define NI_NUMERICSCOPE 0x100 - -#define EAI_BADFLAGS -1 -#define EAI_NONAME -2 -#define EAI_AGAIN -3 -#define EAI_FAIL -4 -#define EAI_FAMILY -6 -#define EAI_SOCKTYPE -7 -#define EAI_SERVICE -8 -#define EAI_MEMORY -10 -#define EAI_SYSTEM -11 -#define EAI_OVERFLOW -12 - -#define HOST_NOT_FOUND 1 -#define TRY_AGAIN 2 -#define NO_RECOVERY 3 -#define NO_DATA 4 -#define NO_ADDRESS NO_DATA - -extern int h_errno; -const char *hstrerror(int ecode); - -#define MAXSERVS 2 -#define MAXADDRS 48 - -#ifdef AX_CONFIG_NET - -int getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **); -void freeaddrinfo(struct addrinfo *); -const char *gai_strerror(int __ecode); - -#endif // AX_CONFIG_NET - -#endif // _NETDB_H diff --git a/arceos/ulib/axlibc/include/netinet/in.h b/arceos/ulib/axlibc/include/netinet/in.h deleted file mode 100644 index 370f3b17b..000000000 --- a/arceos/ulib/axlibc/include/netinet/in.h +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef _NETINET_IN_H -#define _NETINET_IN_H - -#include - -#define INET_ADDRSTRLEN 16 -#define INET6_ADDRSTRLEN 46 - -uint32_t htonl(uint32_t); -uint16_t htons(uint16_t); -uint32_t ntohl(uint32_t); -uint16_t ntohs(uint16_t); - -#define IPPROTO_IP 0 -#define IPPROTO_HOPOPTS 0 -#define IPPROTO_ICMP 1 -#define IPPROTO_IGMP 2 -#define IPPROTO_IPIP 4 -#define IPPROTO_TCP 6 -#define IPPROTO_EGP 8 -#define IPPROTO_PUP 12 -#define IPPROTO_UDP 17 -#define IPPROTO_IDP 22 -#define IPPROTO_TP 29 -#define IPPROTO_DCCP 33 -#define IPPROTO_IPV6 41 -#define IPPROTO_ROUTING 43 -#define IPPROTO_FRAGMENT 44 -#define IPPROTO_RSVP 46 -#define IPPROTO_GRE 47 -#define IPPROTO_ESP 50 -#define IPPROTO_AH 51 -#define IPPROTO_ICMPV6 58 -#define IPPROTO_NONE 59 -#define IPPROTO_DSTOPTS 60 -#define IPPROTO_MTP 92 -#define IPPROTO_BEETPH 94 -#define IPPROTO_ENCAP 98 -#define IPPROTO_PIM 103 -#define IPPROTO_COMP 108 -#define IPPROTO_SCTP 132 -#define IPPROTO_MH 135 -#define IPPROTO_UDPLITE 136 -#define IPPROTO_MPLS 137 -#define IPPROTO_ETHERNET 143 -#define IPPROTO_RAW 255 -#define IPPROTO_MPTCP 262 -#define IPPROTO_MAX 263 - -#define IPV6_ADDRFORM 1 -#define IPV6_2292PKTINFO 2 -#define IPV6_2292HOPOPTS 3 -#define IPV6_2292DSTOPTS 4 -#define IPV6_2292RTHDR 5 -#define IPV6_2292PKTOPTIONS 6 -#define IPV6_CHECKSUM 7 -#define IPV6_2292HOPLIMIT 8 -#define IPV6_NEXTHOP 9 -#define IPV6_AUTHHDR 10 -#define IPV6_UNICAST_HOPS 16 -#define IPV6_MULTICAST_IF 17 -#define IPV6_MULTICAST_HOPS 18 -#define IPV6_MULTICAST_LOOP 19 -#define IPV6_JOIN_GROUP 20 -#define IPV6_LEAVE_GROUP 21 -#define IPV6_ROUTER_ALERT 22 -#define IPV6_MTU_DISCOVER 23 -#define IPV6_MTU 24 -#define IPV6_RECVERR 25 -#define IPV6_V6ONLY 26 -#define IPV6_JOIN_ANYCAST 27 -#define IPV6_LEAVE_ANYCAST 28 -#define IPV6_MULTICAST_ALL 29 -#define IPV6_ROUTER_ALERT_ISOLATE 30 -#define IPV6_IPSEC_POLICY 34 -#define IPV6_XFRM_POLICY 35 -#define IPV6_HDRINCL 36 - -#define IN6ADDR_ANY_INIT \ - { \ - { \ - { \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ - } \ - } \ - } -#define IN6ADDR_LOOPBACK_INIT \ - { \ - { \ - { \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 \ - } \ - } \ - } - -typedef uint16_t in_port_t; -typedef uint32_t in_addr_t; - -struct in_addr { - in_addr_t s_addr; -}; - -struct sockaddr_in { - sa_family_t sin_family; - in_port_t sin_port; - struct in_addr sin_addr; - uint8_t sin_zero[8]; -}; - -struct in6_addr { - union { - uint8_t __s6_addr[16]; - uint16_t __s6_addr16[8]; - uint32_t __s6_addr32[4]; - } __in6_union; -}; -#define s6_addr __in6_union.__s6_addr -#define s6_addr16 __in6_union.__s6_addr16 -#define s6_addr32 __in6_union.__s6_addr32 - -struct sockaddr_in6 { - sa_family_t sin6_family; - in_port_t sin6_port; - uint32_t sin6_flowinfo; - struct in6_addr sin6_addr; - uint32_t sin6_scope_id; -}; - -#endif // _NETINET_IN_H diff --git a/arceos/ulib/axlibc/include/netinet/tcp.h b/arceos/ulib/axlibc/include/netinet/tcp.h deleted file mode 100644 index dfe65d108..000000000 --- a/arceos/ulib/axlibc/include/netinet/tcp.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _NETINET_TCP_H -#define _NETINET_TCP_H - -#define TCP_NODELAY 1 -#define TCP_MAXSEG 2 -#define TCP_CORK 3 -#define TCP_KEEPIDLE 4 -#define TCP_KEEPINTVL 5 -#define TCP_KEEPCNT 6 -#define TCP_SYNCNT 7 -#define TCP_LINGER2 8 -#define TCP_DEFER_ACCEPT 9 -#define TCP_WINDOW_CLAMP 10 -#define TCP_INFO 11 -#define TCP_QUICKACK 12 -#define TCP_CONGESTION 13 -#define TCP_MD5SIG 14 -#define TCP_THIN_LINEAR_TIMEOUTS 16 -#define TCP_THIN_DUPACK 17 -#define TCP_USER_TIMEOUT 18 -#define TCP_REPAIR 19 -#define TCP_REPAIR_QUEUE 20 -#define TCP_QUEUE_SEQ 21 -#define TCP_REPAIR_OPTIONS 22 -#define TCP_FASTOPEN 23 -#define TCP_TIMESTAMP 24 -#define TCP_NOTSENT_LOWAT 25 -#define TCP_CC_INFO 26 -#define TCP_SAVE_SYN 27 -#define TCP_SAVED_SYN 28 -#define TCP_REPAIR_WINDOW 29 -#define TCP_FASTOPEN_CONNECT 30 -#define TCP_ULP 31 -#define TCP_MD5SIG_EXT 32 -#define TCP_FASTOPEN_KEY 33 -#define TCP_FASTOPEN_NO_COOKIE 34 -#define TCP_ZEROCOPY_RECEIVE 35 -#define TCP_INQ 36 -#define TCP_TX_DELAY 37 - -#define TCP_REPAIR_ON 1 -#define TCP_REPAIR_OFF 0 -#define TCP_REPAIR_OFF_NO_WP -1 - -#endif // _NETINET_TCP_H diff --git a/arceos/ulib/axlibc/include/poll.h b/arceos/ulib/axlibc/include/poll.h deleted file mode 100644 index e5903f249..000000000 --- a/arceos/ulib/axlibc/include/poll.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _POLL_H -#define _POLL_H - -struct pollfd { - int fd; - short events; - short revents; -}; - -#define POLLIN 0x001 -#define POLLPRI 0x002 -#define POLLOUT 0x004 -#define POLLERR 0x008 -#define POLLHUP 0x010 -#define POLLNVAL 0x020 - -typedef unsigned long nfds_t; - -int poll(struct pollfd *__fds, nfds_t __nfds, int __timeout); - -#endif // _POLL_H diff --git a/arceos/ulib/axlibc/include/pthread.h b/arceos/ulib/axlibc/include/pthread.h deleted file mode 100644 index 5f8cd98aa..000000000 --- a/arceos/ulib/axlibc/include/pthread.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef _PTHREAD_H -#define _PTHREAD_H - -#include -#include - -#define PTHREAD_CANCEL_ENABLE 0 -#define PTHREAD_CANCEL_DISABLE 1 -#define PTHREAD_CANCEL_MASKED 2 - -#define PTHREAD_CANCEL_DEFERRED 0 -#define PTHREAD_CANCEL_ASYNCHRONOUS 1 - -typedef struct { - unsigned __attr; -} pthread_condattr_t; - -#include - -typedef struct { - unsigned __attr; -} pthread_mutexattr_t; - -typedef struct { - union { - int __i[sizeof(long) == 8 ? 14 : 9]; - volatile int __vi[sizeof(long) == 8 ? 14 : 9]; - unsigned long __s[sizeof(long) == 8 ? 7 : 9]; - } __u; -} pthread_attr_t; -#define _a_stacksize __u.__s[0] -#define _a_guardsize __u.__s[1] -#define _a_stackaddr __u.__s[2] - -typedef struct { - union { - int __i[12]; - volatile int __vi[12]; - void *__p[12 * sizeof(int) / sizeof(void *)]; - } __u; -} pthread_cond_t; -#define _c_clock __u.__i[4] -#define _c_shared __u.__p[0] - -typedef void *pthread_t; - -#define PTHREAD_CANCELED ((void *)-1) -#define SIGCANCEL 33 - -#ifdef AX_CONFIG_MULTITASK - -_Noreturn void pthread_exit(void *); -pthread_t pthread_self(void); - -int pthread_create(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), - void *__restrict); -int pthread_join(pthread_t t, void **res); - -int pthread_setcancelstate(int, int *); -int pthread_setcanceltype(int, int *); -void pthread_testcancel(void); -int pthread_cancel(pthread_t); - -int pthread_mutex_init(pthread_mutex_t *__restrict, const pthread_mutexattr_t *__restrict); -int pthread_mutex_lock(pthread_mutex_t *); -int pthread_mutex_unlock(pthread_mutex_t *); -int pthread_mutex_trylock(pthread_mutex_t *); - -int pthread_setname_np(pthread_t, const char *); - -int pthread_cond_init(pthread_cond_t *__restrict__ __cond, - const pthread_condattr_t *__restrict__ __cond_attr); -int pthread_cond_signal(pthread_cond_t *__cond); -int pthread_cond_wait(pthread_cond_t *__restrict__ __cond, pthread_mutex_t *__restrict__ __mutex); -int pthread_cond_broadcast(pthread_cond_t *); - -int pthread_attr_init(pthread_attr_t *__attr); -int pthread_attr_getstacksize(const pthread_attr_t *__restrict__ __attr, - size_t *__restrict__ __stacksize); -int pthread_attr_setstacksize(pthread_attr_t *__attr, size_t __stacksize); - -#endif // AX_CONFIG_MULTITASK - -#endif // _PTHREAD_H diff --git a/arceos/ulib/axlibc/include/pwd.h b/arceos/ulib/axlibc/include/pwd.h deleted file mode 100644 index 354854619..000000000 --- a/arceos/ulib/axlibc/include/pwd.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _PWD_H -#define _PWD_H - -#include -#include -#include -#include - -#define NSCDVERSION 2 -#define GETPWBYNAME 0 -#define GETPWBYUID 1 -#define GETGRBYNAME 2 -#define GETGRBYGID 3 -#define GETINITGR 15 - -#define PWVERSION 0 -#define PWFOUND 1 -#define PWNAMELEN 2 -#define PWPASSWDLEN 3 -#define PWUID 4 -#define PWGID 5 -#define PWGECOSLEN 6 -#define PWDIRLEN 7 -#define PWSHELLLEN 8 -#define PW_LEN 9 - -#define REQVERSION 0 -#define REQTYPE 1 -#define REQKEYLEN 2 -#define REQ_LEN 3 - -struct passwd { - char *pw_name; - char *pw_passwd; - uid_t pw_uid; - gid_t pw_gid; - char *pw_gecos; - char *pw_dir; - char *pw_shell; -}; - -int getpwuid_r(uid_t, struct passwd *, char *, size_t, struct passwd **); -int getpwnam_r(const char *, struct passwd *, char *, size_t, struct passwd **); - -#endif // _PWD_H diff --git a/arceos/ulib/axlibc/include/regex.h b/arceos/ulib/axlibc/include/regex.h deleted file mode 100644 index 50b382885..000000000 --- a/arceos/ulib/axlibc/include/regex.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _REGEX_H -#define _REGEX_H - -#endif // _REGEX_H diff --git a/arceos/ulib/axlibc/include/sched.h b/arceos/ulib/axlibc/include/sched.h deleted file mode 100644 index ed201c584..000000000 --- a/arceos/ulib/axlibc/include/sched.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _SCHED_H -#define _SCHED_H - -#include - -typedef struct cpu_set_t { - unsigned long __bits[128 / sizeof(long)]; -} cpu_set_t; - -#define __CPU_op_S(i, size, set, op) \ - ((i) / 8U >= (size) ? 0 \ - : (((unsigned long *)(set))[(i) / 8 / sizeof(long)] op( \ - 1UL << ((i) % (8 * sizeof(long)))))) - -#define CPU_SET_S(i, size, set) __CPU_op_S(i, size, set, |=) -#define CPU_ZERO_S(size, set) memset(set, 0, size) - -#define CPU_SET(i, set) CPU_SET_S(i, sizeof(cpu_set_t), set); -#define CPU_ZERO(set) CPU_ZERO_S(sizeof(cpu_set_t), set) - -int sched_setaffinity(pid_t, size_t, const cpu_set_t *); - -#endif // _SCHED_H diff --git a/arceos/ulib/axlibc/include/setjmp.h b/arceos/ulib/axlibc/include/setjmp.h deleted file mode 100644 index 70981dfb4..000000000 --- a/arceos/ulib/axlibc/include/setjmp.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _SETJMP_H -#define _SETJMP_H - -#include - -#if defined(__aarch64__) -typedef unsigned long __jmp_buf[22]; -#elif defined(__riscv__) || defined(__riscv) -typedef unsigned long __jmp_buf[26]; -#elif defined(__x86_64__) -typedef unsigned long __jmp_buf[8]; -#endif - -typedef struct __jmp_buf_tag { - __jmp_buf __jb; - unsigned long __fl; - unsigned long __ss[128 / sizeof(long)]; -} jmp_buf[1]; - -int setjmp(jmp_buf); -_Noreturn void longjmp(jmp_buf, int); - -#endif diff --git a/arceos/ulib/axlibc/include/signal.h b/arceos/ulib/axlibc/include/signal.h deleted file mode 100644 index 52e21cee7..000000000 --- a/arceos/ulib/axlibc/include/signal.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef _SIGNAL_H -#define _SIGNAL_H - -#include -#include -#include - -typedef int sig_atomic_t; - -union sigval { - int sival_int; - void *sival_ptr; -}; - -typedef union sigval __sigval_t; - -#define SA_NOCLDSTOP 1 -#define SA_NOCLDWAIT 2 -#define SA_SIGINFO 4 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 -#define SA_RESTORER 0x04000000 - -#define SIG_BLOCK 0 -#define SIG_UNBLOCK 1 -#define SIG_SETMASK 2 - -#define SI_ASYNCNL (-60) -#define SI_TKILL (-6) -#define SI_SIGIO (-5) -#define SI_ASYNCIO (-4) -#define SI_MESGQ (-3) -#define SI_TIMER (-2) -#define SI_QUEUE (-1) -#define SI_USER 0 -#define SI_KERNEL 128 - -typedef struct { - int si_signo, si_errno, si_code; - union { - char __pad[128 - 2 * sizeof(int) - sizeof(long)]; - struct { - union { - struct { - int si_pid; - unsigned int si_uid; - } __piduid; - struct { - int si_timerid; - int si_overrun; - } __timer; - } __first; - union { - union sigval si_value; - struct { - int si_status; - long si_utime, si_stime; - } __sigchld; - } __second; - } __si_common; - struct { - void *si_addr; - short si_addr_lsb; - union { - struct { - void *si_lower; - void *si_upper; - } __addr_bnd; - unsigned si_pkey; - } __first; - } __sigfault; - struct { - long si_band; - int si_fd; - } __sigpoll; - struct { - void *si_call_addr; - int si_syscall; - unsigned si_arch; - } __sigsys; - } __si_fields; -} siginfo_t; - -#define si_pid __si_fields.__si_common.__first.__piduid.si_pid -#define si_uid __si_fields.__si_common.__first.__piduid.si_uid -#define si_status __si_fields.__si_common.__second.__sigchld.si_status -#define si_utime __si_fields.__si_common.__second.__sigchld.si_utime -#define si_stime __si_fields.__si_common.__second.__sigchld.si_stime -#define si_value __si_fields.__si_common.__second.si_value -#define si_addr __si_fields.__sigfault.si_addr -#define si_addr_lsb __si_fields.__sigfault.si_addr_lsb -#define si_lower __si_fields.__sigfault.__first.__addr_bnd.si_lower -#define si_upper __si_fields.__sigfault.__first.__addr_bnd.si_upper -#define si_pkey __si_fields.__sigfault.__first.si_pkey -#define si_band __si_fields.__sigpoll.si_band -#define si_fd __si_fields.__sigpoll.si_fd -#define si_timerid __si_fields.__si_common.__first.__timer.si_timerid -#define si_overrun __si_fields.__si_common.__first.__timer.si_overrun -#define si_ptr si_value.sival_ptr -#define si_int si_value.sival_int -#define si_call_addr __si_fields.__sigsys.si_call_addr -#define si_syscall __si_fields.__sigsys.si_syscall -#define si_arch __si_fields.__sigsys.si_arch - -#define SIGHUP 1 -#define SIGINT 2 -#define SIGQUIT 3 -#define SIGILL 4 -#define SIGTRAP 5 -#define SIGABRT 6 -#define SIGIOT SIGABRT -#define SIGBUS 7 -#define SIGFPE 8 -#define SIGKILL 9 -#define SIGUSR1 10 -#define SIGSEGV 11 -#define SIGUSR2 12 -#define SIGPIPE 13 -#define SIGALRM 14 -#define SIGTERM 15 -#define SIGSTKFLT 16 -#define SIGCHLD 17 -#define SIGCONT 18 -#define SIGSTOP 19 -#define SIGTSTP 20 -#define SIGTTIN 21 -#define SIGTTOU 22 -#define SIGURG 23 -#define SIGXCPU 24 -#define SIGXFSZ 25 -#define SIGVTALRM 26 -#define SIGPROF 27 -#define SIGWINCH 28 -#define SIGIO 29 -#define SIGPOLL 29 -#define SIGPWR 30 -#define SIGSYS 31 -#define SIGUNUSED SIGSYS - -#define _NSIG 65 - -typedef void (*sighandler_t)(int); -#define SIG_ERR ((void (*)(int)) - 1) -#define SIG_DFL ((void (*)(int))0) -#define SIG_IGN ((void (*)(int))1) - -typedef struct __sigset_t { - unsigned long __bits[128 / sizeof(long)]; -} sigset_t; - -struct sigaction { - union { - void (*sa_handler)(int); - void (*sa_sigaction)(int, siginfo_t *, void *); - } __sa_handler; - sigset_t sa_mask; - int sa_flags; - void (*sa_restorer)(void); -}; - -#define sa_handler __sa_handler.sa_handler -#define sa_sigaction __sa_handler.sa_sigaction - -void (*signal(int, void (*)(int)))(int); -int sigaction(int, const struct sigaction *__restrict, struct sigaction *__restrict); -int sigemptyset(sigset_t *); -int raise(int); -int sigaddset(sigset_t *, int); -int pthread_sigmask(int, const sigset_t *__restrict, sigset_t *__restrict); - -int kill(pid_t, int); - -#ifdef AX_CONFIG_MULTITASK -int pthread_kill(pthread_t t, int sig); -#endif - -#endif // _SIGNAL_H diff --git a/arceos/ulib/axlibc/include/stdarg.h b/arceos/ulib/axlibc/include/stdarg.h deleted file mode 100644 index 3c23d618c..000000000 --- a/arceos/ulib/axlibc/include/stdarg.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __STDARG_H__ -#define __STDARG_H__ - -#define va_start(v, l) __builtin_va_start(v, l) -#define va_end(v) __builtin_va_end(v) -#define va_arg(v, l) __builtin_va_arg(v, l) -#define va_copy(d, s) __builtin_va_copy(d, s) - -typedef __builtin_va_list va_list; - -#endif // __STDARG_H__ diff --git a/arceos/ulib/axlibc/include/stdbool.h b/arceos/ulib/axlibc/include/stdbool.h deleted file mode 100644 index e3325f24c..000000000 --- a/arceos/ulib/axlibc/include/stdbool.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __STDBOOL_H__ -#define __STDBOOL_H__ - -/* Represents true-or-false values */ -#ifndef __cplusplus -#define true 1 -#define false 0 -#define bool _Bool -#endif - -#endif // __STDBOOL_H__ diff --git a/arceos/ulib/axlibc/include/stddef.h b/arceos/ulib/axlibc/include/stddef.h deleted file mode 100644 index faf08bdd7..000000000 --- a/arceos/ulib/axlibc/include/stddef.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __STDDEF_H__ -#define __STDDEF_H__ - -#include -#include - -/* size_t is used for memory object sizes */ -typedef uintptr_t size_t; -typedef intptr_t ssize_t; -typedef ssize_t ptrdiff_t; - -typedef long clock_t; -typedef int clockid_t; - -#ifdef __cplusplus -#define NULL 0L -#else -#define NULL ((void *)0) -#endif - -#if __GNUC__ > 3 -#define offsetof(type, member) __builtin_offsetof(type, member) -#else -#define offsetof(type, member) ((size_t)((char *)&(((type *)0)->member) - (char *)0)) -#endif - -#endif // __STDDEF_H__ diff --git a/arceos/ulib/axlibc/include/stdint.h b/arceos/ulib/axlibc/include/stdint.h deleted file mode 100644 index 3081bf011..000000000 --- a/arceos/ulib/axlibc/include/stdint.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __STDINT_H__ -#define __STDINT_H__ - -/* Explicitly-sized versions of integer types */ -typedef char int8_t; -typedef unsigned char uint8_t; -typedef short int16_t; -typedef unsigned short uint16_t; -typedef int int32_t; -typedef unsigned int uint32_t; -typedef long long int64_t; -typedef unsigned long long uint64_t; - -typedef int64_t int_fast64_t; -typedef int64_t intmax_t; - -#define INT8_MIN (-1 - 0x7f) -#define INT16_MIN (-1 - 0x7fff) -#define INT32_MIN (-1 - 0x7fffffff) -#define INT64_MIN (-1 - 0x7fffffffffffffff) - -#define INT8_MAX (0x7f) -#define INT16_MAX (0x7fff) -#define INT32_MAX (0x7fffffff) -#define INT64_MAX (0x7fffffffffffffff) - -#define UINT8_MAX (0xff) -#define UINT16_MAX (0xffff) -#define UINT32_MAX (0xffffffffu) -#define UINT64_MAX (0xffffffffffffffffu) - -#define INTPTR_MIN INT64_MIN -#define INTPTR_MAX INT64_MAX -#define UINTPTR_MAX UINT64_MAX - -/* * - * Pointers and addresses are 32 bits long. - * We use pointer types to represent addresses, - * uintptr_t to represent the numerical values of addresses. - * */ -#if __riscv_xlen == 64 || defined(__x86_64__) || defined(__aarch64__) -typedef int64_t intptr_t; -typedef uint64_t uintptr_t; -#elif __riscv_xlen == 32 || defined(__i386__) -typedef int32_t intptr_t; -typedef uint32_t uintptr_t; -#endif - -typedef uint8_t uint_fast8_t; -typedef uint64_t uint_fast64_t; - -#if UINTPTR_MAX == UINT64_MAX -#define INT64_C(c) c##L -#define UINT64_C(c) c##UL -#define INTMAX_C(c) c##L -#define UINTMAX_C(c) c##UL -#else -#define INT64_C(c) c##LL -#define UINT64_C(c) c##ULL -#define INTMAX_C(c) c##LL -#define UINTMAX_C(c) c##ULL -#endif - -#define SIZE_MAX UINT64_MAX - -#endif // __STDINT_H__ diff --git a/arceos/ulib/axlibc/include/stdio.h b/arceos/ulib/axlibc/include/stdio.h deleted file mode 100644 index 12aca2a88..000000000 --- a/arceos/ulib/axlibc/include/stdio.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef __STDIO_H__ -#define __STDIO_H__ - -#include -#include - -#define _IOFBF 0 -#define _IOLBF 1 -#define _IONBF 2 - -#define FILE_BUF_SIZE 1024 -// TODO: complete this struct -struct IO_FILE { - int fd; - uint16_t buffer_len; - char buf[FILE_BUF_SIZE]; -}; - -typedef struct IO_FILE FILE; - -extern FILE *const stdin; -extern FILE *const stdout; -extern FILE *const stderr; - -#define stdin (stdin) -#define stdout (stdout) -#define stderr (stderr) - -#define EOF (-1) - -#if defined(AX_LOG_WARN) || defined(AX_LOG_INFO) || defined(AX_LOG_DEBUG) || defined(AX_LOG_TRACE) - -#define unimplemented(fmt, ...) \ - printf("\x1b[33m%s%s:\x1b[0m " fmt "\n", "WARN: no ax_call implementation for ", __func__, \ - ##__VA_ARGS__) -#else - -#define unimplemented(fmt, ...) \ - do { \ - } while (0) - -#endif - -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 - -#define F_EOF 16 -#define F_ERR 32 -#define F_SVB 64 -#define F_NORD 4 -#define UNGET 8 - -#define FILENAME_MAX 4096 -#define BUFSIZ 1024 -#define L_tmpnam 20 - -FILE *fopen(const char *filename, const char *mode); -FILE *freopen(const char *__restrict, const char *__restrict, FILE *__restrict); -int fclose(FILE *); - -int remove(const char *); -int rename(const char *, const char *); - -int feof(FILE *__stream); -int ferror(FILE *); -int fflush(FILE *); -void clearerr(FILE *); - -int fseek(FILE *__stream, long __off, int __whence); -long ftell(FILE *); - -size_t fread(void *__restrict, size_t, size_t, FILE *__restrict); -size_t fwrite(const void *__restrict, size_t, size_t, FILE *__restrict); - -int getc(FILE *); -int getchar(void); -int ungetc(int, FILE *); - -int fputc(int, FILE *); -int putc(int, FILE *); -int putchar(int); - -char *fgets(char *__restrict, int, FILE *__restrict); - -int fputs(const char *__restrict, FILE *__restrict); -int puts(const char *s); - -int printf(const char *__restrict, ...); -int fprintf(FILE *__restrict, const char *__restrict, ...); -int sprintf(char *__restrict, const char *__restrict, ...); -int snprintf(char *__restrict, size_t, const char *__restrict, ...); - -int vfprintf(FILE *__restrict, const char *__restrict, va_list); -int vsprintf(char *__restrict, const char *__restrict, va_list); -int vsnprintf(char *__restrict, size_t, const char *__restrict, va_list); - -int fscanf(FILE *__restrict, const char *__restrict, ...); -int sscanf(const char *__restrict, const char *__restrict, ...); - -void perror(const char *); - -int setvbuf(FILE *__restrict, char *__restrict, int, size_t); - -char *tmpnam(char *); -FILE *tmpfile(void); - -FILE *fdopen(int, const char *); -int fileno(FILE *); -off_t ftello(FILE *); - -int getc_unlocked(FILE *); -ssize_t getdelim(char **__restrict, size_t *__restrict, int, FILE *__restrict); -ssize_t getline(char **__restrict, size_t *__restrict, FILE *__restrict); - -#endif // __STDIO_H__ diff --git a/arceos/ulib/axlibc/include/stdlib.h b/arceos/ulib/axlibc/include/stdlib.h deleted file mode 100644 index 411ea48b1..000000000 --- a/arceos/ulib/axlibc/include/stdlib.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef __STDLIB_H__ -#define __STDLIB_H__ - -#include -#include - -#define RAND_MAX (0x7fffffff) - -#define WEXITSTATUS(s) (((s)&0xff00) >> 8) -#define WTERMSIG(s) ((s)&0x7f) -#define WIFEXITED(s) (!WTERMSIG(s)) -#define WIFSIGNALED(s) (((s)&0xffff) - 1U < 0xffu) - -#define EXIT_FAILURE 1 -#define EXIT_SUCCESS 0 - -long long atoll(const char *nptr); - -float strtof(const char *__restrict, char **__restrict); -double strtod(const char *__restrict, char **__restrict); - -long strtol(const char *__restrict, char **__restrict, int); -unsigned long strtoul(const char *nptr, char **endptr, int base); -long long strtoll(const char *nptr, char **endptr, int base); -unsigned long long strtoull(const char *nptr, char **endptr, int base); - -int rand(void); -void srand(unsigned); -long random(void); -void srandom(unsigned int); - -#ifdef AX_CONFIG_FP_SIMD -float strtof(const char *__restrict, char **__restrict); -double strtod(const char *__restrict, char **__restrict); -long double strtold(const char *__restrict, char **__restrict); -#endif - -void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); - -void *malloc(size_t); -void *calloc(size_t, size_t); -void *realloc(void *, size_t); -void free(void *); - -_Noreturn void abort(void); -_Noreturn void exit(int); - -char *getenv(const char *); - -int abs(int); -long labs(long); -long long llabs(long long); - -int mkstemp(char *); -int mkostemp(char *, int); -int setenv(const char *, const char *, int); -int unsetenv(const char *); -int system(const char *); - -#endif //__STDLIB_H__ diff --git a/arceos/ulib/axlibc/include/string.h b/arceos/ulib/axlibc/include/string.h deleted file mode 100644 index 3160af4ed..000000000 --- a/arceos/ulib/axlibc/include/string.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef __STRING_H__ -#define __STRING_H__ - -#include - -int atoi(const char *s); - -void *memset(void *dest, int c, size_t n); -void *memchr(const void *src, int c, size_t n); - -size_t strlen(const char *s); -size_t strnlen(const char *s, size_t n); - -char *strcpy(char *restrict d, const char *restrict s); -char *strncpy(char *restrict d, const char *restrict s, size_t n); - -char *strcat(char *restrict d, const char *restrict s); -char *strncat(char *restrict d, const char *restrict s, size_t n); - -int strcmp(const char *l, const char *r); -int strncmp(const char *l, const char *r, size_t n); - -int strcoll(const char *, const char *); - -size_t strcspn(const char *s1, const char *s2); -size_t strspn(const char *s, const char *c); -char *strpbrk(const char *, const char *); - -char *strchrnul(const char *, int); - -char *strrchr(const char *str, int c); -char *strchr(const char *str, int c); - -int strcasecmp(const char *__s1, const char *__s2); -int strncasecmp(const char *__s1, const char *__s2, size_t __n); - -char *strstr(const char *h, const char *n); - -char *strerror(int e); -int strerror_r(int, char *, size_t); - -void *memcpy(void *restrict dest, const void *restrict src, size_t n); - -void *memmove(void *dest, const void *src, size_t n); - -int memcmp(const void *vl, const void *vr, size_t n); - -char *strdup(const char *__s); - -#endif // __STRING_H__ diff --git a/arceos/ulib/axlibc/include/strings.h b/arceos/ulib/axlibc/include/strings.h deleted file mode 100644 index 3616bae19..000000000 --- a/arceos/ulib/axlibc/include/strings.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef __STRINGS_H__ -#define __STRINGS_H__ - -#endif // __STRINGS_H__ diff --git a/arceos/ulib/axlibc/include/sys/epoll.h b/arceos/ulib/axlibc/include/sys/epoll.h deleted file mode 100644 index bd23bcf46..000000000 --- a/arceos/ulib/axlibc/include/sys/epoll.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _SYS_EPOLL_H -#define _SYS_EPOLL_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#define EPOLL_CLOEXEC O_CLOEXEC -#define EPOLL_NONBLOCK O_NONBLOCK - -enum EPOLL_EVENTS { __EPOLL_DUMMY }; -#define EPOLLIN 0x001 -#define EPOLLPRI 0x002 -#define EPOLLOUT 0x004 -#define EPOLLRDNORM 0x040 -#define EPOLLNVAL 0x020 -#define EPOLLRDBAND 0x080 -#define EPOLLWRNORM 0x100 -#define EPOLLWRBAND 0x200 -#define EPOLLMSG 0x400 -#define EPOLLERR 0x008 -#define EPOLLHUP 0x010 -#define EPOLLRDHUP 0x2000 -#define EPOLLEXCLUSIVE (1U << 28) -#define EPOLLWAKEUP (1U << 29) -#define EPOLLONESHOT (1U << 30) -#define EPOLLET (1U << 31) - -#define EPOLL_CTL_ADD 1 -#define EPOLL_CTL_DEL 2 -#define EPOLL_CTL_MOD 3 - -typedef union epoll_data { - void *ptr; - int fd; - uint32_t u32; - uint64_t u64; -} epoll_data_t; - -struct epoll_event { - uint32_t events; - epoll_data_t data; -} -#ifdef __x86_64__ -__attribute__((__packed__)) -#endif -; - -int epoll_create(int __size); -int epoll_ctl(int, int, int, struct epoll_event *); -int epoll_wait(int, struct epoll_event *, int, int); - -#ifdef __cplusplus -} -#endif - -#endif //_SYS_EPOLL_H diff --git a/arceos/ulib/axlibc/include/sys/file.h b/arceos/ulib/axlibc/include/sys/file.h deleted file mode 100644 index d5e15a67f..000000000 --- a/arceos/ulib/axlibc/include/sys/file.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _SYS_FILE_H -#define _SYS_FILE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define LOCK_SH 1 -#define LOCK_EX 2 -#define LOCK_NB 4 -#define LOCK_UN 8 - -#define L_SET 0 -#define L_INCR 1 -#define L_XTND 2 - -int flock(int, int); - -#ifdef __cplusplus -} -#endif - -#endif // _SYS_FILE_H diff --git a/arceos/ulib/axlibc/include/sys/ioctl.h b/arceos/ulib/axlibc/include/sys/ioctl.h deleted file mode 100644 index e43c51013..000000000 --- a/arceos/ulib/axlibc/include/sys/ioctl.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef __SYS_IOCTL_H__ -#define __SYS_IOCTL_H__ - -#define TCGETS 0x5401 -#define TCSETS 0x5402 -#define TCSETSW 0x5403 -#define TCSETSF 0x5404 -#define TCGETA 0x5405 -#define TCSETA 0x5406 -#define TCSETAW 0x5407 -#define TCSETAF 0x5408 -#define TCSBRK 0x5409 -#define TCXONC 0x540A -#define TCFLSH 0x540B -#define TIOCEXCL 0x540C -#define TIOCNXCL 0x540D -#define TIOCSCTTY 0x540E -#define TIOCGPGRP 0x540F -#define TIOCSPGRP 0x5410 -#define TIOCOUTQ 0x5411 -#define TIOCSTI 0x5412 -#define TIOCGWINSZ 0x5413 -#define TIOCSWINSZ 0x5414 -#define TIOCMGET 0x5415 -#define TIOCMBIS 0x5416 -#define TIOCMBIC 0x5417 -#define TIOCMSET 0x5418 -#define TIOCGSOFTCAR 0x5419 -#define TIOCSSOFTCAR 0x541A -#define FIONREAD 0x541B -#define TIOCINQ FIONREAD -#define TIOCLINUX 0x541C -#define TIOCCONS 0x541D -#define TIOCGSERIAL 0x541E -#define TIOCSSERIAL 0x541F -#define TIOCPKT 0x5420 -#define FIONBIO 0x5421 -#define TIOCNOTTY 0x5422 -#define TIOCSETD 0x5423 -#define TIOCGETD 0x5424 -#define TCSBRKP 0x5425 -#define TIOCSBRK 0x5427 -#define TIOCCBRK 0x5428 -#define TIOCGSID 0x5429 -#define TIOCGRS485 0x542E -#define TIOCSRS485 0x542F -#define TIOCGPTN 0x80045430 -#define TIOCSPTLCK 0x40045431 -#define TIOCGDEV 0x80045432 -#define TCGETX 0x5432 -#define TCSETX 0x5433 -#define TCSETXF 0x5434 -#define TCSETXW 0x5435 -#define TIOCSIG 0x40045436 -#define TIOCVHANGUP 0x5437 -#define TIOCGPKT 0x80045438 -#define TIOCGPTLCK 0x80045439 -#define TIOCGEXCL 0x80045440 -#define TIOCGPTPEER 0x5441 -#define TIOCGISO7816 0x80285442 -#define TIOCSISO7816 0xc0285443 - -int ioctl(int, int, ...); - -#endif // __SYS_IOCTL_H__ diff --git a/arceos/ulib/axlibc/include/sys/mman.h b/arceos/ulib/axlibc/include/sys/mman.h deleted file mode 100644 index 3d3502345..000000000 --- a/arceos/ulib/axlibc/include/sys/mman.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef __SYS_MMAN_H__ -#define __SYS_MMAN_H__ - -#include - -#define PROT_READ 0x1 /* Page can be read. */ -#define PROT_WRITE 0x2 /* Page can be written. */ -#define PROT_EXEC 0x4 /* Page can be executed. */ -#define PROT_NONE 0x0 /* Page can not be accessed. */ -#define PROT_GROWSDOWN \ - 0x01000000 /* Extend change to start of \ - growsdown vma (mprotect only). */ -#define PROT_GROWSUP \ - 0x02000000 /* Extend change to start of \ - growsup vma (mprotect only). */ - -/* Sharing types (must choose one and only one of these). */ -#define MAP_SHARED 0x01 /* Share changes. */ -#define MAP_PRIVATE 0x02 /* Changes are private. */ -#define MAP_SHARED_VALIDATE \ - 0x03 /* Share changes and validate \ - extension flags. */ -#define MAP_TYPE 0x0f /* Mask for type of mapping. */ - -/* Other flags. */ -#define MAP_FIXED 0x10 /* Interpret addr exactly. */ -#define MAP_FILE 0 -#ifdef __MAP_ANONYMOUS -#define MAP_ANONYMOUS __MAP_ANONYMOUS /* Don't use a file. */ -#else -#define MAP_ANONYMOUS 0x20 /* Don't use a file. */ -#endif -#define MAP_ANON MAP_ANONYMOUS -/* When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size. */ -#define MAP_HUGE_SHIFT 26 -#define MAP_HUGE_MASK 0x3f - -#define MAP_FAILED ((void *)-1) - -/* Flags for mremap. */ -#define MREMAP_MAYMOVE 1 -#define MREMAP_FIXED 2 -#define MREMAP_DONTUNMAP 4 - -void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off); -int munmap(void *addr, size_t length); -void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, - ... /* void *new_address */); -int mprotect(void *addr, size_t len, int prot); -int madvise(void *addr, size_t length, int advice); - -#endif diff --git a/arceos/ulib/axlibc/include/sys/param.h b/arceos/ulib/axlibc/include/sys/param.h deleted file mode 100644 index bbb762f54..000000000 --- a/arceos/ulib/axlibc/include/sys/param.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _SYS_PARAM_H -#define _SYS_PARAM_H - -#define MAXPATHLEN 4096 - -#endif // _SYS_PARAM_H diff --git a/arceos/ulib/axlibc/include/sys/prctl.h b/arceos/ulib/axlibc/include/sys/prctl.h deleted file mode 100644 index 1ed9cc10e..000000000 --- a/arceos/ulib/axlibc/include/sys/prctl.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _SYS_PRCTL_H -#define _SYS_PRCTL_H - -#endif // _SYS_PRCTL_H diff --git a/arceos/ulib/axlibc/include/sys/resource.h b/arceos/ulib/axlibc/include/sys/resource.h deleted file mode 100644 index 99c8bbc6d..000000000 --- a/arceos/ulib/axlibc/include/sys/resource.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef _SYS_RESOURCE_H -#define _SYS_RESOURCE_H - -#include - -typedef unsigned long long rlim_t; - -struct rlimit { - rlim_t rlim_cur; - rlim_t rlim_max; -}; - -#define RLIMIT_CPU 0 -#define RLIMIT_FSIZE 1 -#define RLIMIT_DATA 2 -#define RLIMIT_STACK 3 -#define RLIMIT_CORE 4 -#ifndef RLIMIT_RSS -#define RLIMIT_RSS 5 -#define RLIMIT_NPROC 6 -#define RLIMIT_NOFILE 7 -#define RLIMIT_MEMLOCK 8 -#define RLIMIT_AS 9 -#endif -#define RLIMIT_LOCKS 10 -#define RLIMIT_SIGPENDING 11 -#define RLIMIT_MSGQUEUE 12 -#define RLIMIT_NICE 13 -#define RLIMIT_RTPRIO 14 -#define RLIMIT_RTTIME 15 -#define RLIMIT_NLIMITS 16 - -#define RUSAGE_SELF 0 -#define RUSAGE_CHILDREN -1 - -struct rusage { - struct timeval ru_utime; - struct timeval ru_stime; - /* linux extentions, but useful */ - long ru_maxrss; - long ru_ixrss; - long ru_idrss; - long ru_isrss; - long ru_minflt; - long ru_majflt; - long ru_nswap; - long ru_inblock; - long ru_oublock; - long ru_msgsnd; - long ru_msgrcv; - long ru_nsignals; - long ru_nvcsw; - long ru_nivcsw; - /* room for more... */ - long __reserved[16]; -}; - -int setrlimit(int __resource, struct rlimit *__rlimits); -int getrlimit(int __resource, struct rlimit *__rlimits); - -int getrusage(int __who, struct rusage *__usage); - -#endif diff --git a/arceos/ulib/axlibc/include/sys/select.h b/arceos/ulib/axlibc/include/sys/select.h deleted file mode 100644 index e8cc2c5ae..000000000 --- a/arceos/ulib/axlibc/include/sys/select.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _SYS_SELECT_H -#define _SYS_SELECT_H - -#include -#include -#include - -#define FD_SETSIZE 1024 - -typedef unsigned long fd_mask; - -typedef struct { - unsigned long fds_bits[FD_SETSIZE / 8 / sizeof(long)]; -} fd_set; - -#define FD_ZERO(s) \ - do { \ - int __i; \ - unsigned long *__b = (s)->fds_bits; \ - for (__i = sizeof(fd_set) / sizeof(long); __i; __i--) *__b++ = 0; \ - } while (0) -#define FD_SET(d, s) \ - ((s)->fds_bits[(d) / (8 * sizeof(long))] |= (1UL << ((d) % (8 * sizeof(long))))) -#define FD_CLR(d, s) \ - ((s)->fds_bits[(d) / (8 * sizeof(long))] &= ~(1UL << ((d) % (8 * sizeof(long))))) -#define FD_ISSET(d, s) \ - !!((s)->fds_bits[(d) / (8 * sizeof(long))] & (1UL << ((d) % (8 * sizeof(long))))) - -int select(int n, fd_set *__restrict rfds, fd_set *__restrict wfds, fd_set *__restrict efds, - struct timeval *__restrict tv); -int pselect(int, fd_set *__restrict, fd_set *__restrict, fd_set *__restrict, - const struct timespec *__restrict, const sigset_t *__restrict); - -#define NFDBITS (8 * (int)sizeof(long)) - -#endif diff --git a/arceos/ulib/axlibc/include/sys/socket.h b/arceos/ulib/axlibc/include/sys/socket.h deleted file mode 100644 index c89c5f1c5..000000000 --- a/arceos/ulib/axlibc/include/sys/socket.h +++ /dev/null @@ -1,310 +0,0 @@ -#ifndef __SOCKET_H__ -#define __SOCKET_H__ - -#include -#include -#include - -typedef unsigned socklen_t; -typedef unsigned short sa_family_t; - -struct msghdr { - void *msg_name; - socklen_t msg_namelen; - struct iovec *msg_iov; -#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __BIG_ENDIAN - int __pad1; -#endif - int msg_iovlen; -#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __LITTLE_ENDIAN - int __pad1; -#endif - void *msg_control; -#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __BIG_ENDIAN - int __pad2; -#endif - socklen_t msg_controllen; -#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __LITTLE_ENDIAN - int __pad2; -#endif - int msg_flags; -}; - -struct cmsghdr { -#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __BIG_ENDIAN - int __pad1; -#endif - socklen_t cmsg_len; -#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __LITTLE_ENDIAN - int __pad1; -#endif - int cmsg_level; - int cmsg_type; -}; - -struct sockaddr { - sa_family_t sa_family; - char sa_data[14]; -}; - -struct sockaddr_storage { - sa_family_t ss_family; - char __ss_padding[128 - sizeof(long) - sizeof(sa_family_t)]; - unsigned long __ss_align; -}; - -int socket(int, int, int); -int shutdown(int, int); - -int bind(int, const struct sockaddr *, socklen_t); -int connect(int, const struct sockaddr *, socklen_t); -int listen(int, int); -int accept(int, struct sockaddr *__restrict, socklen_t *__restrict); -int accept4(int, struct sockaddr *__restrict, socklen_t *__restrict, int); - -ssize_t send(int, const void *, size_t, int); -ssize_t recv(int, void *, size_t, int); -ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t); -ssize_t recvfrom(int, void *__restrict, size_t, int, struct sockaddr *__restrict, - socklen_t *__restrict); -ssize_t sendmsg(int, const struct msghdr *, int); - -int getsockopt(int, int, int, void *__restrict, socklen_t *__restrict); -int setsockopt(int, int, int, const void *, socklen_t); - -int getsockname(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict addrlen); -int getpeername(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict addrlen); - -#define SO_BINDTODEVICE 25 -#define SO_ATTACH_FILTER 26 -#define SO_DETACH_FILTER 27 -#define SO_GET_FILTER SO_ATTACH_FILTER -#define SO_PEERNAME 28 -#define SO_ACCEPTCONN 30 -#define SO_PEERSEC 31 -#define SO_PASSSEC 34 -#define SO_MARK 36 -#define SO_RXQ_OVFL 40 -#define SO_WIFI_STATUS 41 -#define SCM_WIFI_STATUS SO_WIFI_STATUS -#define SO_PEEK_OFF 42 -#define SO_NOFCS 43 -#define SO_LOCK_FILTER 44 -#define SO_SELECT_ERR_QUEUE 45 -#define SO_BUSY_POLL 46 -#define SO_MAX_PACING_RATE 47 -#define SO_BPF_EXTENSIONS 48 -#define SO_INCOMING_CPU 49 -#define SO_ATTACH_BPF 50 -#define SO_DETACH_BPF SO_DETACH_FILTER -#define SO_ATTACH_REUSEPORT_CBPF 51 -#define SO_ATTACH_REUSEPORT_EBPF 52 -#define SO_CNX_ADVICE 53 -#define SCM_TIMESTAMPING_OPT_STATS 54 -#define SO_MEMINFO 55 -#define SO_INCOMING_NAPI_ID 56 -#define SO_COOKIE 57 -#define SCM_TIMESTAMPING_PKTINFO 58 -#define SO_PEERGROUPS 59 -#define SO_ZEROCOPY 60 -#define SO_TXTIME 61 -#define SCM_TXTIME SO_TXTIME -#define SO_BINDTOIFINDEX 62 -#define SO_DETACH_REUSEPORT_BPF 68 -#define SO_PREFER_BUSY_POLL 69 -#define SO_BUSY_POLL_BUDGET 70 - -#define MSG_NOSIGNAL 0x4000 - -#define SHUT_RD 0 -#define SHUT_WR 1 -#define SHUT_RDWR 2 - -#ifndef SOCK_STREAM -#define SOCK_STREAM 1 -#define SOCK_DGRAM 2 -#endif - -#define SOCK_RAW 3 -#define SOCK_RDM 4 -#define SOCK_SEQPACKET 5 -#define SOCK_DCCP 6 -#define SOCK_PACKET 10 - -#ifndef SOCK_CLOEXEC -#define SOCK_CLOEXEC 02000000 -#define SOCK_NONBLOCK 04000 -#endif - -#define PF_UNSPEC 0 -#define PF_LOCAL 1 -#define PF_UNIX PF_LOCAL -#define PF_FILE PF_LOCAL -#define PF_INET 2 -#define PF_AX25 3 -#define PF_IPX 4 -#define PF_APPLETALK 5 -#define PF_NETROM 6 -#define PF_BRIDGE 7 -#define PF_ATMPVC 8 -#define PF_X25 9 -#define PF_INET6 10 -#define PF_ROSE 11 -#define PF_DECnet 12 -#define PF_NETBEUI 13 -#define PF_SECURITY 14 -#define PF_KEY 15 -#define PF_NETLINK 16 -#define PF_ROUTE PF_NETLINK -#define PF_PACKET 17 -#define PF_ASH 18 -#define PF_ECONET 19 -#define PF_ATMSVC 20 -#define PF_RDS 21 -#define PF_SNA 22 -#define PF_IRDA 23 -#define PF_PPPOX 24 -#define PF_WANPIPE 25 -#define PF_LLC 26 -#define PF_IB 27 -#define PF_MPLS 28 -#define PF_CAN 29 -#define PF_TIPC 30 -#define PF_BLUETOOTH 31 -#define PF_IUCV 32 -#define PF_RXRPC 33 -#define PF_ISDN 34 -#define PF_PHONET 35 -#define PF_IEEE802154 36 -#define PF_CAIF 37 -#define PF_ALG 38 -#define PF_NFC 39 -#define PF_VSOCK 40 -#define PF_KCM 41 -#define PF_QIPCRTR 42 -#define PF_SMC 43 -#define PF_XDP 44 -#define PF_MAX 45 - -#define AF_UNSPEC PF_UNSPEC -#define AF_LOCAL PF_LOCAL -#define AF_UNIX AF_LOCAL -#define AF_FILE AF_LOCAL -#define AF_INET PF_INET -#define AF_AX25 PF_AX25 -#define AF_IPX PF_IPX -#define AF_APPLETALK PF_APPLETALK -#define AF_NETROM PF_NETROM -#define AF_BRIDGE PF_BRIDGE -#define AF_ATMPVC PF_ATMPVC -#define AF_X25 PF_X25 -#define AF_INET6 PF_INET6 -#define AF_ROSE PF_ROSE -#define AF_DECnet PF_DECnet -#define AF_NETBEUI PF_NETBEUI -#define AF_SECURITY PF_SECURITY -#define AF_KEY PF_KEY -#define AF_NETLINK PF_NETLINK -#define AF_ROUTE PF_ROUTE -#define AF_PACKET PF_PACKET -#define AF_ASH PF_ASH -#define AF_ECONET PF_ECONET -#define AF_ATMSVC PF_ATMSVC -#define AF_RDS PF_RDS -#define AF_SNA PF_SNA -#define AF_IRDA PF_IRDA -#define AF_PPPOX PF_PPPOX -#define AF_WANPIPE PF_WANPIPE -#define AF_LLC PF_LLC -#define AF_IB PF_IB -#define AF_MPLS PF_MPLS -#define AF_CAN PF_CAN -#define AF_TIPC PF_TIPC -#define AF_BLUETOOTH PF_BLUETOOTH -#define AF_IUCV PF_IUCV -#define AF_RXRPC PF_RXRPC -#define AF_ISDN PF_ISDN -#define AF_PHONET PF_PHONET -#define AF_IEEE802154 PF_IEEE802154 -#define AF_CAIF PF_CAIF -#define AF_ALG PF_ALG -#define AF_NFC PF_NFC -#define AF_VSOCK PF_VSOCK -#define AF_KCM PF_KCM -#define AF_QIPCRTR PF_QIPCRTR -#define AF_SMC PF_SMC -#define AF_XDP PF_XDP -#define AF_MAX PF_MAX - -#define SO_DEBUG 1 -#define SO_REUSEADDR 2 -#define SO_TYPE 3 -#define SO_ERROR 4 -#define SO_DONTROUTE 5 -#define SO_BROADCAST 6 -#define SO_SNDBUF 7 -#define SO_RCVBUF 8 -#define SO_KEEPALIVE 9 -#define SO_OOBINLINE 10 -#define SO_NO_CHECK 11 -#define SO_PRIORITY 12 -#define SO_LINGER 13 -#define SO_BSDCOMPAT 14 -#define SO_REUSEPORT 15 -#define SO_PASSCRED 16 -#define SO_PEERCRED 17 -#define SO_RCVLOWAT 18 -#define SO_SNDLOWAT 19 -#define SO_ACCEPTCONN 30 -#define SO_PEERSEC 31 -#define SO_SNDBUFFORCE 32 -#define SO_RCVBUFFORCE 33 -#define SO_PROTOCOL 38 -#define SO_DOMAIN 39 - -#define SO_SECURITY_AUTHENTICATION 22 -#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 -#define SO_SECURITY_ENCRYPTION_NETWORK 24 - -#define SOL_SOCKET 1 - -#define SOL_IP 0 -#define SOL_IPV6 41 -#define SOL_ICMPV6 58 - -#define SOL_RAW 255 -#define SOL_DECNET 261 -#define SOL_X25 262 -#define SOL_PACKET 263 -#define SOL_ATM 264 -#define SOL_AAL 265 -#define SOL_IRDA 266 -#define SOL_NETBEUI 267 -#define SOL_LLC 268 -#define SOL_DCCP 269 -#define SOL_NETLINK 270 -#define SOL_TIPC 271 -#define SOL_RXRPC 272 -#define SOL_PPPOL2TP 273 -#define SOL_BLUETOOTH 274 -#define SOL_PNPIPE 275 -#define SOL_RDS 276 -#define SOL_IUCV 277 -#define SOL_CAIF 278 -#define SOL_ALG 279 -#define SOL_NFC 280 -#define SOL_KCM 281 -#define SOL_TLS 282 -#define SOL_XDP 283 - -#ifndef SO_RCVTIMEO_OLD -#define SO_RCVTIMEO_OLD 20 -#endif -#ifndef SO_SNDTIMEO_OLD -#define SO_SNDTIMEO_OLD 21 -#endif - -#define SO_RCVTIMEO SO_RCVTIMEO_OLD -#define SO_SNDTIMEO SO_SNDTIMEO_OLD - -#endif // __SOCKET_H__ diff --git a/arceos/ulib/axlibc/include/sys/stat.h b/arceos/ulib/axlibc/include/sys/stat.h deleted file mode 100644 index 24806af7a..000000000 --- a/arceos/ulib/axlibc/include/sys/stat.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef __SYS_STAT_H__ -#define __SYS_STAT_H__ - -#include -#include - -struct stat { - dev_t st_dev; /* ID of device containing file*/ - ino_t st_ino; /* inode number*/ - mode_t st_mode; /* protection*/ - nlink_t st_nlink; /* number of hard links*/ - uid_t st_uid; /* user ID of owner*/ - gid_t st_gid; /* group ID of owner*/ - dev_t st_rdev; /* device ID (if special file)*/ - off_t st_size; /* total size, in bytes*/ - blksize_t st_blksize; /* blocksize for filesystem I/O*/ - blkcnt_t st_blocks; /* number of blocks allocated*/ - struct timespec st_atime; /* time of last access*/ - struct timespec st_mtime; /* time of last modification*/ - struct timespec st_ctime; /* time of last status change*/ -}; - -#define st_atime st_atim.tv_sec -#define st_mtime st_mtim.tv_sec -#define st_ctime st_ctim.tv_sec - -#define S_IFMT 0170000 - -#define S_IFDIR 0040000 -#define S_IFCHR 0020000 -#define S_IFBLK 0060000 -#define S_IFREG 0100000 -#define S_IFIFO 0010000 -#define S_IFLNK 0120000 -#define S_IFSOCK 0140000 - -#define S_TYPEISMQ(buf) 0 -#define S_TYPEISSEM(buf) 0 -#define S_TYPEISSHM(buf) 0 -#define S_TYPEISTMO(buf) 0 - -#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) -#define S_ISCHR(mode) (((mode)&S_IFMT) == S_IFCHR) -#define S_ISBLK(mode) (((mode)&S_IFMT) == S_IFBLK) -#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) -#define S_ISFIFO(mode) (((mode)&S_IFMT) == S_IFIFO) -#define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK) -#define S_ISSOCK(mode) (((mode)&S_IFMT) == S_IFSOCK) - -#ifndef S_IRUSR -#define S_ISUID 04000 -#define S_ISGID 02000 -#define S_ISVTX 01000 -#define S_IRUSR 0400 -#define S_IWUSR 0200 -#define S_IXUSR 0100 -#define S_IRWXU 0700 -#define S_IRGRP 0040 -#define S_IWGRP 0020 -#define S_IXGRP 0010 -#define S_IRWXG 0070 -#define S_IROTH 0004 -#define S_IWOTH 0002 -#define S_IXOTH 0001 -#define S_IRWXO 0007 -#endif - -int stat(const char *path, struct stat *buf); -int fstat(int fd, struct stat *buf); -int lstat(const char *path, struct stat *buf); - -int fchmod(int fd, mode_t mode); -int chmod(const char *file, mode_t mode); -int mkdir(const char *pathname, mode_t mode); -mode_t umask(mode_t mask); -int fstatat(int, const char *__restrict, struct stat *__restrict, int); - -#endif diff --git a/arceos/ulib/axlibc/include/sys/time.h b/arceos/ulib/axlibc/include/sys/time.h deleted file mode 100644 index 5eeaf4c6b..000000000 --- a/arceos/ulib/axlibc/include/sys/time.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __SYS_TIME_H__ -#define __SYS_TIME_H__ - -#include - -#define ITIMER_REAL 0 -#define ITIMER_VIRTUAL 1 -#define ITIMER_PROF 2 - -extern long timezone; -typedef long long time_t; - -struct timeval { - time_t tv_sec; /* seconds */ - long tv_usec; /* microseconds */ -}; - -struct timespec { - time_t tv_sec; /* seconds */ - long tv_nsec; /* nanoseconds */ -}; - -typedef struct timespec timespec; - -struct timezone { - int tz_minuteswest; /* (minutes west of Greenwich) */ - int tz_dsttime; /* (type of DST correction) */ -}; - -struct itimerval { - struct timeval it_interval; - struct timeval it_value; -}; - -int gettimeofday(struct timeval *tv, struct timezone *tz); - -int getitimer(int, struct itimerval *); -int setitimer(int, const struct itimerval *__restrict, struct itimerval *__restrict); -int utimes(const char *filename, const struct timeval times[2]); - -#endif diff --git a/arceos/ulib/axlibc/include/sys/types.h b/arceos/ulib/axlibc/include/sys/types.h deleted file mode 100644 index adb6c3531..000000000 --- a/arceos/ulib/axlibc/include/sys/types.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __SYS_TYPES_H__ -#define __SYS_TYPES_H__ - -#include - -typedef unsigned char u_char; - -typedef unsigned mode_t; -typedef uint32_t nlink_t; -typedef int64_t off_t; -typedef uint64_t ino_t; -typedef uint64_t dev_t; -typedef long blksize_t; -typedef int64_t blkcnt_t; - -typedef int pid_t; -typedef unsigned uid_t; -typedef unsigned gid_t; - -#endif // __SYS_TYPES_H__ diff --git a/arceos/ulib/axlibc/include/sys/uio.h b/arceos/ulib/axlibc/include/sys/uio.h deleted file mode 100644 index d38b197c8..000000000 --- a/arceos/ulib/axlibc/include/sys/uio.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _SYS_UIO_H -#define _SYS_UIO_H - -#include - -struct iovec { - void *iov_base; /* Pointer to data. */ - size_t iov_len; /* Length of data. */ -}; - -ssize_t writev(int, const struct iovec *, int); - -#endif diff --git a/arceos/ulib/axlibc/include/sys/un.h b/arceos/ulib/axlibc/include/sys/un.h deleted file mode 100644 index 85e43ea7b..000000000 --- a/arceos/ulib/axlibc/include/sys/un.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _SYS_UN_H -#define _SYS_UN_H - -#include - -struct sockaddr_un { - sa_family_t sun_family; - char sun_path[108]; -}; - -#endif // _SYS_UN_H diff --git a/arceos/ulib/axlibc/include/sys/utsname.h b/arceos/ulib/axlibc/include/sys/utsname.h deleted file mode 100644 index fa708a129..000000000 --- a/arceos/ulib/axlibc/include/sys/utsname.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _SYS_UTSNAME_H -#define _SYS_UTSNAME_H - -#ifdef __cplusplus -extern "C" { -#endif - -struct utsname { - char sysname[65]; - char nodename[65]; - char release[65]; - char version[65]; - char machine[65]; -#ifdef _GNU_SOURCE - char domainname[65]; -#else - char __domainname[65]; -#endif -}; - -int uname(struct utsname *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/arceos/ulib/axlibc/include/sys/wait.h b/arceos/ulib/axlibc/include/sys/wait.h deleted file mode 100644 index f5e38877e..000000000 --- a/arceos/ulib/axlibc/include/sys/wait.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _SYS_WAIT_H -#define _SYS_WAIT_H - -#include -#include - -#define WNOHANG 1 - -pid_t waitpid(pid_t pid, int *status, int options); -pid_t wait3(int *, int, struct rusage *); - -#endif diff --git a/arceos/ulib/axlibc/include/syslog.h b/arceos/ulib/axlibc/include/syslog.h deleted file mode 100644 index f98d66342..000000000 --- a/arceos/ulib/axlibc/include/syslog.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _SYSLOG_H -#define _SYSLOG_H - -#define LOG_EMERG 0 -#define LOG_ALERT 1 -#define LOG_CRIT 2 -#define LOG_ERR 3 -#define LOG_WARNING 4 -#define LOG_NOTICE 5 -#define LOG_INFO 6 -#define LOG_DEBUG 7 - -#define LOG_PID 0x01 -#define LOG_CONS 0x02 -#define LOG_ODELAY 0x04 -#define LOG_NDELAY 0x08 -#define LOG_NOWAIT 0x10 -#define LOG_PERROR 0x20 - -#define LOG_KERN (0 << 3) -#define LOG_USER (1 << 3) -#define LOG_MAIL (2 << 3) -#define LOG_DAEMON (3 << 3) -#define LOG_AUTH (4 << 3) -#define LOG_SYSLOG (5 << 3) -#define LOG_LPR (6 << 3) -#define LOG_NEWS (7 << 3) -#define LOG_UUCP (8 << 3) -#define LOG_CRON (9 << 3) -#define LOG_AUTHPRIV (10 << 3) -#define LOG_FTP (11 << 3) - -#define LOG_LOCAL0 (16 << 3) -#define LOG_LOCAL1 (17 << 3) -#define LOG_LOCAL2 (18 << 3) -#define LOG_LOCAL3 (19 << 3) -#define LOG_LOCAL4 (20 << 3) -#define LOG_LOCAL5 (21 << 3) -#define LOG_LOCAL6 (22 << 3) -#define LOG_LOCAL7 (23 << 3) - -void syslog(int, const char *, ...); -void openlog(const char *, int, int); - -#endif diff --git a/arceos/ulib/axlibc/include/termios.h b/arceos/ulib/axlibc/include/termios.h deleted file mode 100644 index d319c5b81..000000000 --- a/arceos/ulib/axlibc/include/termios.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _TERMIOS_H -#define _TERMIOS_H - -struct winsize { - unsigned short ws_row, ws_col, ws_xpixel, ws_ypixel; -}; - -#endif // _TERMIOS_H diff --git a/arceos/ulib/axlibc/include/time.h b/arceos/ulib/axlibc/include/time.h deleted file mode 100644 index 356edf920..000000000 --- a/arceos/ulib/axlibc/include/time.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef __TIME_H__ -#define __TIME_H__ - -#include -#include - -#define CLOCK_REALTIME 0 -#define CLOCK_MONOTONIC 1 -#define CLOCKS_PER_SEC 1000000L - -struct tm { - int tm_sec; /* seconds of minute */ - int tm_min; /* minutes of hour */ - int tm_hour; /* hours of day */ - int tm_mday; /* day of month */ - int tm_mon; /* month of year, 0 is first month(January) */ - int tm_year; /* years, whose value equals the actual year minus 1900 */ - int tm_wday; /* day of week, 0 is sunday, 1 is monday, and so on */ - int tm_yday; /* day of year */ - int tm_isdst; /* daylight saving time flag */ - long int __tm_gmtoff; - const char *__tm_zone; -}; - -clock_t clock(void); -time_t time(time_t *); -double difftime(time_t, time_t); -time_t mktime(struct tm *); -size_t strftime(char *__restrict, size_t, const char *__restrict, const struct tm *__restrict); -struct tm *gmtime(const time_t *); -struct tm *localtime(const time_t *); - -struct tm *gmtime_r(const time_t *__restrict, struct tm *__restrict); -struct tm *localtime_r(const time_t *__restrict, struct tm *__restrict); -char *asctime_r(const struct tm *__restrict, char *__restrict); -char *ctime_r(const time_t *, char *); - -void tzset(void); - -int nanosleep(const struct timespec *requested_time, struct timespec *remaining); -int clock_gettime(clockid_t _clk, struct timespec *ts); - -#endif // __TIME_H__ diff --git a/arceos/ulib/axlibc/include/unistd.h b/arceos/ulib/axlibc/include/unistd.h deleted file mode 100644 index 46b580df8..000000000 --- a/arceos/ulib/axlibc/include/unistd.h +++ /dev/null @@ -1,240 +0,0 @@ -#ifndef __UNISTD_H__ -#define __UNISTD_H__ - -#include -#include -#include - -#define STDIN_FILENO 0 -#define STDOUT_FILENO 1 -#define STDERR_FILENO 2 - -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 -#define SEEK_DATA 3 -#define SEEK_HOLE 4 - -int pipe(int[2]); -int pipe2(int[2], int); -int close(int); -int posix_close(int, int); -int dup(int); -int dup2(int, int); -int dup3(int, int, int); -off_t lseek(int, off_t, int); -int fsync(int); -int fdatasync(int); - -ssize_t read(int, void *, size_t); -ssize_t write(int, const void *, size_t); -ssize_t pread(int, void *, size_t, off_t); -ssize_t pwrite(int, const void *, size_t, off_t); - -int chown(const char *, uid_t, gid_t); -int fchown(int, uid_t, gid_t); -int lchown(const char *, uid_t, gid_t); -int fchownat(int, const char *, uid_t, gid_t, int); - -int link(const char *, const char *); -int linkat(int, const char *, int, const char *, int); -int symlink(const char *, const char *); -int symlinkat(const char *, int, const char *); -ssize_t readlink(const char *__restrict, char *__restrict, size_t); -ssize_t readlinkat(int, const char *__restrict, char *__restrict, size_t); -int unlink(const char *); -int unlinkat(int, const char *, int); -int rmdir(const char *); -int truncate(const char *, off_t); -int ftruncate(int, off_t); - -#define F_OK 0 -#define R_OK 4 -#define W_OK 2 -#define X_OK 1 - -int access(const char *, int); -int faccessat(int, const char *, int, int); - -int chdir(const char *); -int fchdir(int); -char *getcwd(char *, size_t); - -unsigned alarm(unsigned); -unsigned sleep(unsigned); -int pause(void); -int usleep(unsigned); - -pid_t fork(void); -int execve(const char *, char *const[], char *const[]); -_Noreturn void _exit(int); - -pid_t getpid(void); -pid_t getppid(void); -pid_t getpgrp(void); -pid_t getpgid(pid_t); -int setpgid(pid_t, pid_t); -pid_t setsid(void); -pid_t getsid(pid_t); -char *ttyname(int); -int ttyname_r(int, char *, size_t); -int isatty(int); -pid_t tcgetpgrp(int); -int tcsetpgrp(int, pid_t); - -uid_t getuid(void); -uid_t geteuid(void); -gid_t getgid(void); -gid_t getegid(void); -int getgroups(int, gid_t[]); -int setuid(uid_t); -int seteuid(uid_t); -int setgid(gid_t); -int setegid(gid_t); - -long sysconf(int); - -#define _SC_ARG_MAX 0 -#define _SC_CHILD_MAX 1 -#define _SC_CLK_TCK 2 -#define _SC_NGROUPS_MAX 3 -#define _SC_OPEN_MAX 4 -#define _SC_STREAM_MAX 5 -#define _SC_TZNAME_MAX 6 -#define _SC_JOB_CONTROL 7 -#define _SC_SAVED_IDS 8 -#define _SC_REALTIME_SIGNALS 9 -#define _SC_PRIORITY_SCHEDULING 10 -#define _SC_TIMERS 11 -#define _SC_ASYNCHRONOUS_IO 12 -#define _SC_PRIORITIZED_IO 13 -#define _SC_SYNCHRONIZED_IO 14 -#define _SC_FSYNC 15 -#define _SC_MAPPED_FILES 16 -#define _SC_MEMLOCK 17 -#define _SC_MEMLOCK_RANGE 18 -#define _SC_MEMORY_PROTECTION 19 -#define _SC_MESSAGE_PASSING 20 -#define _SC_SEMAPHORES 21 -#define _SC_SHARED_MEMORY_OBJECTS 22 -#define _SC_AIO_LISTIO_MAX 23 -#define _SC_AIO_MAX 24 -#define _SC_AIO_PRIO_DELTA_MAX 25 -#define _SC_DELAYTIMER_MAX 26 -#define _SC_MQ_OPEN_MAX 27 -#define _SC_MQ_PRIO_MAX 28 -#define _SC_VERSION 29 -#define _SC_PAGE_SIZE 30 -#define _SC_PAGESIZE 30 /* !! */ -#define _SC_RTSIG_MAX 31 -#define _SC_SEM_NSEMS_MAX 32 -#define _SC_SEM_VALUE_MAX 33 -#define _SC_SIGQUEUE_MAX 34 -#define _SC_TIMER_MAX 35 -#define _SC_BC_BASE_MAX 36 -#define _SC_BC_DIM_MAX 37 -#define _SC_BC_SCALE_MAX 38 -#define _SC_BC_STRING_MAX 39 -#define _SC_COLL_WEIGHTS_MAX 40 -#define _SC_EXPR_NEST_MAX 42 -#define _SC_LINE_MAX 43 -#define _SC_RE_DUP_MAX 44 -#define _SC_2_VERSION 46 -#define _SC_2_C_BIND 47 -#define _SC_2_C_DEV 48 -#define _SC_2_FORT_DEV 49 -#define _SC_2_FORT_RUN 50 -#define _SC_2_SW_DEV 51 -#define _SC_2_LOCALEDEF 52 -#define _SC_UIO_MAXIOV 60 /* !! */ -#define _SC_IOV_MAX 60 -#define _SC_THREADS 67 -#define _SC_THREAD_SAFE_FUNCTIONS 68 -#define _SC_GETGR_R_SIZE_MAX 69 -#define _SC_GETPW_R_SIZE_MAX 70 -#define _SC_LOGIN_NAME_MAX 71 -#define _SC_TTY_NAME_MAX 72 -#define _SC_THREAD_DESTRUCTOR_ITERATIONS 73 -#define _SC_THREAD_KEYS_MAX 74 -#define _SC_THREAD_STACK_MIN 75 -#define _SC_THREAD_THREADS_MAX 76 -#define _SC_THREAD_ATTR_STACKADDR 77 -#define _SC_THREAD_ATTR_STACKSIZE 78 -#define _SC_THREAD_PRIORITY_SCHEDULING 79 -#define _SC_THREAD_PRIO_INHERIT 80 -#define _SC_THREAD_PRIO_PROTECT 81 -#define _SC_THREAD_PROCESS_SHARED 82 -#define _SC_NPROCESSORS_CONF 83 -#define _SC_NPROCESSORS_ONLN 84 -#define _SC_PHYS_PAGES 85 -#define _SC_AVPHYS_PAGES 86 -#define _SC_ATEXIT_MAX 87 -#define _SC_PASS_MAX 88 -#define _SC_XOPEN_VERSION 89 -#define _SC_XOPEN_XCU_VERSION 90 -#define _SC_XOPEN_UNIX 91 -#define _SC_XOPEN_CRYPT 92 -#define _SC_XOPEN_ENH_I18N 93 -#define _SC_XOPEN_SHM 94 -#define _SC_2_CHAR_TERM 95 -#define _SC_2_UPE 97 -#define _SC_XOPEN_XPG2 98 -#define _SC_XOPEN_XPG3 99 -#define _SC_XOPEN_XPG4 100 -#define _SC_NZERO 109 -#define _SC_XBS5_ILP32_OFF32 125 -#define _SC_XBS5_ILP32_OFFBIG 126 -#define _SC_XBS5_LP64_OFF64 127 -#define _SC_XBS5_LPBIG_OFFBIG 128 -#define _SC_XOPEN_LEGACY 129 -#define _SC_XOPEN_REALTIME 130 -#define _SC_XOPEN_REALTIME_THREADS 131 -#define _SC_ADVISORY_INFO 132 -#define _SC_BARRIERS 133 -#define _SC_CLOCK_SELECTION 137 -#define _SC_CPUTIME 138 -#define _SC_THREAD_CPUTIME 139 -#define _SC_MONOTONIC_CLOCK 149 -#define _SC_READER_WRITER_LOCKS 153 -#define _SC_SPIN_LOCKS 154 -#define _SC_REGEXP 155 -#define _SC_SHELL 157 -#define _SC_SPAWN 159 -#define _SC_SPORADIC_SERVER 160 -#define _SC_THREAD_SPORADIC_SERVER 161 -#define _SC_TIMEOUTS 164 -#define _SC_TYPED_MEMORY_OBJECTS 165 -#define _SC_2_PBS 168 -#define _SC_2_PBS_ACCOUNTING 169 -#define _SC_2_PBS_LOCATE 170 -#define _SC_2_PBS_MESSAGE 171 -#define _SC_2_PBS_TRACK 172 -#define _SC_SYMLOOP_MAX 173 -#define _SC_STREAMS 174 -#define _SC_2_PBS_CHECKPOINT 175 -#define _SC_V6_ILP32_OFF32 176 -#define _SC_V6_ILP32_OFFBIG 177 -#define _SC_V6_LP64_OFF64 178 -#define _SC_V6_LPBIG_OFFBIG 179 -#define _SC_HOST_NAME_MAX 180 -#define _SC_TRACE 181 -#define _SC_TRACE_EVENT_FILTER 182 -#define _SC_TRACE_INHERIT 183 -#define _SC_TRACE_LOG 184 - -#define _SC_IPV6 235 -#define _SC_RAW_SOCKETS 236 -#define _SC_V7_ILP32_OFF32 237 -#define _SC_V7_ILP32_OFFBIG 238 -#define _SC_V7_LP64_OFF64 239 -#define _SC_V7_LPBIG_OFFBIG 240 -#define _SC_SS_REPL_MAX 241 -#define _SC_TRACE_EVENT_NAME_MAX 242 -#define _SC_TRACE_NAME_MAX 243 -#define _SC_TRACE_SYS_MAX 244 -#define _SC_TRACE_USER_EVENT_MAX 245 -#define _SC_XOPEN_STREAMS 246 -#define _SC_THREAD_ROBUST_PRIO_INHERIT 247 -#define _SC_THREAD_ROBUST_PRIO_PROTECT 248 - -#endif diff --git a/arceos/ulib/axlibc/src/errno.rs b/arceos/ulib/axlibc/src/errno.rs deleted file mode 100644 index 5f38bee36..000000000 --- a/arceos/ulib/axlibc/src/errno.rs +++ /dev/null @@ -1,39 +0,0 @@ -use axerrno::LinuxError; -use core::ffi::{c_char, c_int}; - -/// The global errno variable. -#[cfg_attr(feature = "tls", thread_local)] -#[no_mangle] -#[allow(non_upper_case_globals)] -pub static mut errno: c_int = 0; - -pub fn set_errno(code: i32) { - unsafe { - errno = code; - } -} - -/// Returns a pointer to the global errno variable. -#[no_mangle] -pub unsafe extern "C" fn __errno_location() -> *mut c_int { - core::ptr::addr_of_mut!(errno) -} - -/// Returns a pointer to the string representation of the given error code. -#[no_mangle] -pub unsafe extern "C" fn strerror(e: c_int) -> *mut c_char { - #[allow(non_upper_case_globals)] - static mut strerror_buf: [u8; 256] = [0; 256]; // TODO: thread safe - - let err_str = if e == 0 { - "Success" - } else { - LinuxError::try_from(e) - .map(|e| e.as_str()) - .unwrap_or("Unknown error") - }; - unsafe { - strerror_buf[..err_str.len()].copy_from_slice(err_str.as_bytes()); - strerror_buf.as_mut_ptr() as *mut c_char - } -} diff --git a/arceos/ulib/axlibc/src/fd_ops.rs b/arceos/ulib/axlibc/src/fd_ops.rs deleted file mode 100644 index 1b1a9d000..000000000 --- a/arceos/ulib/axlibc/src/fd_ops.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::{ctypes, utils::e}; -use arceos_posix_api::{sys_close, sys_dup, sys_dup2, sys_fcntl}; -use axerrno::LinuxError; -use core::ffi::c_int; - -/// Close a file by `fd`. -#[no_mangle] -pub unsafe extern "C" fn close(fd: c_int) -> c_int { - e(sys_close(fd)) -} - -/// Duplicate a file descriptor. -#[no_mangle] -pub unsafe extern "C" fn dup(old_fd: c_int) -> c_int { - e(sys_dup(old_fd)) -} - -/// Duplicate a file descriptor, use file descriptor specified in `new_fd`. -#[no_mangle] -pub unsafe extern "C" fn dup2(old_fd: c_int, new_fd: c_int) -> c_int { - e(sys_dup2(old_fd, new_fd)) -} - -/// Duplicate a file descriptor, the caller can force the close-on-exec flag to -/// be set for the new file descriptor by specifying `O_CLOEXEC` in flags. -/// -/// If oldfd equals newfd, then `dup3()` fails with the error `EINVAL`. -#[no_mangle] -pub unsafe extern "C" fn dup3(old_fd: c_int, new_fd: c_int, flags: c_int) -> c_int { - if old_fd == new_fd { - return e((LinuxError::EINVAL as c_int).wrapping_neg()); - } - let r = e(sys_dup2(old_fd, new_fd)); - if r < 0 { - r - } else { - if flags as u32 & ctypes::O_CLOEXEC != 0 { - e(sys_fcntl( - new_fd, - ctypes::F_SETFD as c_int, - ctypes::FD_CLOEXEC as usize, - )); - } - new_fd - } -} - -/// Manipulate file descriptor. -/// -/// TODO: `SET/GET` command is ignored -#[no_mangle] -pub unsafe extern "C" fn ax_fcntl(fd: c_int, cmd: c_int, arg: usize) -> c_int { - e(sys_fcntl(fd, cmd, arg)) -} diff --git a/arceos/ulib/axlibc/src/fs.rs b/arceos/ulib/axlibc/src/fs.rs deleted file mode 100644 index bd93f8876..000000000 --- a/arceos/ulib/axlibc/src/fs.rs +++ /dev/null @@ -1,67 +0,0 @@ -use core::ffi::{c_char, c_int}; - -use arceos_posix_api::{ - sys_fstat, sys_getcwd, sys_lseek, sys_lstat, sys_open, sys_rename, sys_stat, -}; - -use crate::{ctypes, utils::e}; - -/// Open a file by `filename` and insert it into the file descriptor table. -/// -/// Return its index in the file table (`fd`). Return `EMFILE` if it already -/// has the maximum number of files open. -#[no_mangle] -pub unsafe extern "C" fn ax_open( - filename: *const c_char, - flags: c_int, - mode: ctypes::mode_t, -) -> c_int { - e(sys_open(filename, flags, mode)) -} - -/// Set the position of the file indicated by `fd`. -/// -/// Return its position after seek. -#[no_mangle] -pub unsafe extern "C" fn lseek(fd: c_int, offset: ctypes::off_t, whence: c_int) -> ctypes::off_t { - e(sys_lseek(fd, offset, whence) as _) as _ -} - -/// Get the file metadata by `path` and write into `buf`. -/// -/// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn stat(path: *const c_char, buf: *mut ctypes::stat) -> c_int { - e(sys_stat(path, buf)) -} - -/// Get file metadata by `fd` and write into `buf`. -/// -/// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn fstat(fd: c_int, buf: *mut ctypes::stat) -> c_int { - e(sys_fstat(fd, buf)) -} - -/// Get the metadata of the symbolic link and write into `buf`. -/// -/// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn lstat(path: *const c_char, buf: *mut ctypes::stat) -> c_int { - e(sys_lstat(path, buf) as _) -} - -/// Get the path of the current directory. -#[no_mangle] -pub unsafe extern "C" fn getcwd(buf: *mut c_char, size: usize) -> *mut c_char { - sys_getcwd(buf, size) -} - -/// Rename `old` to `new` -/// If new exists, it is first removed. -/// -/// Return 0 if the operation succeeds, otherwise return -1. -#[no_mangle] -pub unsafe extern "C" fn rename(old: *const c_char, new: *const c_char) -> c_int { - e(sys_rename(old, new)) -} diff --git a/arceos/ulib/axlibc/src/io.rs b/arceos/ulib/axlibc/src/io.rs deleted file mode 100644 index ea6187b71..000000000 --- a/arceos/ulib/axlibc/src/io.rs +++ /dev/null @@ -1,32 +0,0 @@ -use core::ffi::{c_int, c_void}; - -use arceos_posix_api::{sys_read, sys_write, sys_writev}; - -use crate::{ctypes, utils::e}; - -/// Read data from the file indicated by `fd`. -/// -/// Return the read size if success. -#[no_mangle] -pub unsafe extern "C" fn read(fd: c_int, buf: *mut c_void, count: usize) -> ctypes::ssize_t { - e(sys_read(fd, buf, count) as _) as _ -} - -/// Write data to the file indicated by `fd`. -/// -/// Return the written size if success. -#[no_mangle] -#[cfg(not(test))] -pub unsafe extern "C" fn write(fd: c_int, buf: *const c_void, count: usize) -> ctypes::ssize_t { - e(sys_write(fd, buf, count) as _) as _ -} - -/// Write a vector. -#[no_mangle] -pub unsafe extern "C" fn writev( - fd: c_int, - iov: *const ctypes::iovec, - iocnt: c_int, -) -> ctypes::ssize_t { - e(sys_writev(fd, iov, iocnt) as _) as _ -} diff --git a/arceos/ulib/axlibc/src/io_mpx.rs b/arceos/ulib/axlibc/src/io_mpx.rs deleted file mode 100644 index 2bcffc7e0..000000000 --- a/arceos/ulib/axlibc/src/io_mpx.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::{ctypes, utils::e}; - -use core::ffi::c_int; - -#[cfg(feature = "select")] -use arceos_posix_api::sys_select; -#[cfg(feature = "epoll")] -use arceos_posix_api::{sys_epoll_create, sys_epoll_ctl, sys_epoll_wait}; - -/// Creates a new epoll instance. -/// -/// It returns a file descriptor referring to the new epoll instance. -#[cfg(feature = "epoll")] -#[no_mangle] -pub unsafe extern "C" fn epoll_create(size: c_int) -> c_int { - e(sys_epoll_create(size)) -} - -/// Control interface for an epoll file descriptor -#[cfg(feature = "epoll")] -#[no_mangle] -pub unsafe extern "C" fn epoll_ctl( - epfd: c_int, - op: c_int, - fd: c_int, - event: *mut ctypes::epoll_event, -) -> c_int { - e(sys_epoll_ctl(epfd, op, fd, event)) -} - -/// Waits for events on the epoll instance referred to by the file descriptor epfd. -#[cfg(feature = "epoll")] -#[no_mangle] -pub unsafe extern "C" fn epoll_wait( - epfd: c_int, - events: *mut ctypes::epoll_event, - maxevents: c_int, - timeout: c_int, -) -> c_int { - e(sys_epoll_wait(epfd, events, maxevents, timeout)) -} - -/// Monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation -#[cfg(feature = "select")] -#[no_mangle] -pub unsafe extern "C" fn select( - nfds: c_int, - readfds: *mut ctypes::fd_set, - writefds: *mut ctypes::fd_set, - exceptfds: *mut ctypes::fd_set, - timeout: *mut ctypes::timeval, -) -> c_int { - e(sys_select(nfds, readfds, writefds, exceptfds, timeout)) -} diff --git a/arceos/ulib/axlibc/src/lib.rs b/arceos/ulib/axlibc/src/lib.rs deleted file mode 100644 index f1af45f9e..000000000 --- a/arceos/ulib/axlibc/src/lib.rs +++ /dev/null @@ -1,125 +0,0 @@ -//! [ArceOS] user program library for C apps. -//! -//! ## Cargo Features -//! -//! - CPU -//! - `smp`: Enable SMP (symmetric multiprocessing) support. -//! - `fp_simd`: Enable floating point and SIMD support. -//! - Interrupts: -//! - `irq`: Enable interrupt handling support. -//! - Memory -//! - `alloc`: Enable dynamic memory allocation. -//! - `tls`: Enable thread-local storage. -//! - Task management -//! - `multitask`: Enable multi-threading support. -//! - Upperlayer stacks -//! - `fs`: Enable file system support. -//! - `net`: Enable networking support. -//! - Lib C functions -//! - `fd`: Enable file descriptor table. -//! - `pipe`: Enable pipe support. -//! - `select`: Enable synchronous I/O multiplexing ([select]) support. -//! - `epoll`: Enable event polling ([epoll]) support. -//! -//! [ArceOS]: https://github.com/arceos-org/arceos -//! [select]: https://man7.org/linux/man-pages/man2/select.2.html -//! [epoll]: https://man7.org/linux/man-pages/man7/epoll.7.html - -#![cfg_attr(all(not(test), not(doc)), no_std)] -#![feature(doc_cfg)] -#![feature(doc_auto_cfg)] -#![feature(naked_functions)] -#![feature(thread_local)] -#![allow(clippy::missing_safety_doc)] - -#[cfg(feature = "alloc")] -extern crate alloc; - -#[path = "."] -mod ctypes { - #[rustfmt::skip] - #[path = "libctypes_gen.rs"] - #[allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals, clippy::upper_case_acronyms)] - mod libctypes; - - pub use arceos_posix_api::ctypes::*; - pub use libctypes::*; -} - -#[macro_use] -mod utils; - -#[cfg(feature = "fd")] -mod fd_ops; -#[cfg(feature = "fs")] -mod fs; -#[cfg(any(feature = "select", feature = "epoll"))] -mod io_mpx; -#[cfg(feature = "alloc")] -mod malloc; -#[cfg(feature = "net")] -mod net; -#[cfg(feature = "pipe")] -mod pipe; -#[cfg(feature = "multitask")] -mod pthread; -#[cfg(feature = "alloc")] -mod strftime; -#[cfg(feature = "fp_simd")] -mod strtod; - -mod errno; -mod io; -mod mktime; -mod rand; -mod resource; -mod setjmp; -mod sys; -mod time; -mod unistd; - -#[cfg(not(test))] -pub use self::io::write; -pub use self::io::{read, writev}; - -pub use self::errno::strerror; -pub use self::mktime::mktime; -pub use self::rand::{rand, random, srand}; -pub use self::resource::{getrlimit, setrlimit}; -pub use self::setjmp::{longjmp, setjmp}; -pub use self::sys::sysconf; -pub use self::time::{clock_gettime, nanosleep}; -pub use self::unistd::{abort, exit, getpid}; - -#[cfg(feature = "alloc")] -pub use self::malloc::{free, malloc}; -#[cfg(feature = "alloc")] -pub use self::strftime::strftime; - -#[cfg(feature = "fd")] -pub use self::fd_ops::{ax_fcntl, close, dup, dup2, dup3}; - -#[cfg(feature = "fs")] -pub use self::fs::{ax_open, fstat, getcwd, lseek, lstat, rename, stat}; - -#[cfg(feature = "net")] -pub use self::net::{ - accept, bind, connect, freeaddrinfo, getaddrinfo, getpeername, getsockname, listen, recv, - recvfrom, send, sendto, shutdown, socket, -}; - -#[cfg(feature = "multitask")] -pub use self::pthread::{pthread_create, pthread_exit, pthread_join, pthread_self}; -#[cfg(feature = "multitask")] -pub use self::pthread::{pthread_mutex_init, pthread_mutex_lock, pthread_mutex_unlock}; - -#[cfg(feature = "pipe")] -pub use self::pipe::pipe; - -#[cfg(feature = "select")] -pub use self::io_mpx::select; -#[cfg(feature = "epoll")] -pub use self::io_mpx::{epoll_create, epoll_ctl, epoll_wait}; - -#[cfg(feature = "fp_simd")] -pub use self::strtod::{strtod, strtof}; diff --git a/arceos/ulib/axlibc/src/malloc.rs b/arceos/ulib/axlibc/src/malloc.rs deleted file mode 100644 index f635b7ff0..000000000 --- a/arceos/ulib/axlibc/src/malloc.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! Provides the corresponding malloc(size_t) and free(size_t) when using the C user program. -//! -//! The normal malloc(size_t) and free(size_t) are provided by the library malloc.h, and -//! sys_brk is used internally to apply for memory from the kernel. But in a unikernel like -//! `ArceOS`, we noticed that the heap of the Rust user program is shared with the kernel. In -//! order to maintain consistency, C user programs also choose to share the kernel heap, -//! skipping the sys_brk step. - -use alloc::alloc::{alloc, dealloc}; -use core::alloc::Layout; -use core::ffi::c_void; - -use crate::ctypes; - -struct MemoryControlBlock { - size: usize, -} - -const CTRL_BLK_SIZE: usize = core::mem::size_of::(); - -/// Allocate memory and return the memory address. -/// -/// Returns 0 on failure (the current implementation does not trigger an exception) -#[no_mangle] -pub unsafe extern "C" fn malloc(size: ctypes::size_t) -> *mut c_void { - // Allocate `(actual length) + 8`. The lowest 8 Bytes are stored in the actual allocated space size. - // This is because free(uintptr_t) has only one parameter representing the address, - // So we need to save in advance to know the size of the memory space that needs to be released - let layout = Layout::from_size_align(size + CTRL_BLK_SIZE, 8).unwrap(); - unsafe { - let ptr = alloc(layout).cast::(); - assert!(!ptr.is_null(), "malloc failed"); - ptr.write(MemoryControlBlock { size }); - ptr.add(1).cast() - } -} - -/// Deallocate memory. -/// -/// (WARNING) If the address to be released does not match the allocated address, an error should -/// occur, but it will NOT be checked out. This is due to the global allocator `Buddy_system` -/// (currently used) does not check the validity of address to be released. -#[no_mangle] -pub unsafe extern "C" fn free(ptr: *mut c_void) { - if ptr.is_null() { - return; - } - let ptr = ptr.cast::(); - assert!(ptr as usize > CTRL_BLK_SIZE, "free a null pointer"); - unsafe { - let ptr = ptr.sub(1); - let size = ptr.read().size; - let layout = Layout::from_size_align(size + CTRL_BLK_SIZE, 8).unwrap(); - dealloc(ptr.cast(), layout) - } -} diff --git a/arceos/ulib/axlibc/src/mktime.rs b/arceos/ulib/axlibc/src/mktime.rs deleted file mode 100644 index 1caf3325b..000000000 --- a/arceos/ulib/axlibc/src/mktime.rs +++ /dev/null @@ -1,58 +0,0 @@ -use core::ffi::c_int; - -use crate::ctypes; - -const MONTH_DAYS: [[c_int; 12]; 2] = [ - // Non-leap years: - [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], - // Leap years: - [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], -]; - -#[inline(always)] -fn leap_year(year: c_int) -> bool { - year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) -} - -/// Convert broken-down time into time since the Epoch. -#[no_mangle] -pub unsafe extern "C" fn mktime(t: *mut ctypes::tm) -> ctypes::time_t { - let mut year = (*t).tm_year + 1900; - let mut month = (*t).tm_mon; - let mut day = (*t).tm_mday as i64 - 1; - - let leap = if leap_year(year) { 1 } else { 0 }; - - if year < 1970 { - day = MONTH_DAYS[if leap_year(year) { 1 } else { 0 }][(*t).tm_mon as usize] as i64 - day; - - while year < 1969 { - year += 1; - day += if leap_year(year) { 366 } else { 365 }; - } - - while month < 11 { - month += 1; - day += MONTH_DAYS[leap][month as usize] as i64; - } - - (-(day * (60 * 60 * 24) - - (((*t).tm_hour as i64) * (60 * 60) + ((*t).tm_min as i64) * 60 + (*t).tm_sec as i64))) - as ctypes::time_t - } else { - while year > 1970 { - year -= 1; - day += if leap_year(year) { 366 } else { 365 }; - } - - while month > 0 { - month -= 1; - day += MONTH_DAYS[leap][month as usize] as i64; - } - - (day * (60 * 60 * 24) - + ((*t).tm_hour as i64) * (60 * 60) - + ((*t).tm_min as i64) * 60 - + (*t).tm_sec as i64) as ctypes::time_t - } -} diff --git a/arceos/ulib/axlibc/src/net.rs b/arceos/ulib/axlibc/src/net.rs deleted file mode 100644 index e09218157..000000000 --- a/arceos/ulib/axlibc/src/net.rs +++ /dev/null @@ -1,180 +0,0 @@ -use arceos_posix_api::{ - sys_accept, sys_bind, sys_connect, sys_freeaddrinfo, sys_getaddrinfo, sys_getpeername, - sys_getsockname, sys_listen, sys_recv, sys_recvfrom, sys_send, sys_sendto, sys_shutdown, - sys_socket, -}; -use core::ffi::{c_char, c_int, c_void}; - -use crate::{ctypes, utils::e}; - -/// Create an socket for communication. -/// -/// Return the socket file descriptor. -#[no_mangle] -pub unsafe extern "C" fn socket(domain: c_int, socktype: c_int, protocol: c_int) -> c_int { - e(sys_socket(domain, socktype, protocol)) -} - -/// Bind a address to a socket. -/// -/// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn bind( - socket_fd: c_int, - socket_addr: *const ctypes::sockaddr, - addrlen: ctypes::socklen_t, -) -> c_int { - e(sys_bind(socket_fd, socket_addr, addrlen)) -} - -/// Connects the socket to the address specified. -/// -/// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn connect( - socket_fd: c_int, - socket_addr: *const ctypes::sockaddr, - addrlen: ctypes::socklen_t, -) -> c_int { - e(sys_connect(socket_fd, socket_addr, addrlen)) -} - -/// Send a message on a socket to the address specified. -/// -/// Return the number of bytes sent if success. -#[no_mangle] -pub unsafe extern "C" fn sendto( - socket_fd: c_int, - buf_ptr: *const c_void, - len: ctypes::size_t, - flag: c_int, // currently not used - socket_addr: *const ctypes::sockaddr, - addrlen: ctypes::socklen_t, -) -> ctypes::ssize_t { - if socket_addr.is_null() && addrlen == 0 { - return e(sys_send(socket_fd, buf_ptr, len, flag) as _) as _; - } - e(sys_sendto(socket_fd, buf_ptr, len, flag, socket_addr, addrlen) as _) as _ -} - -/// Send a message on a socket to the address connected. -/// -/// Return the number of bytes sent if success. -#[no_mangle] -pub unsafe extern "C" fn send( - socket_fd: c_int, - buf_ptr: *const c_void, - len: ctypes::size_t, - flag: c_int, // currently not used -) -> ctypes::ssize_t { - e(sys_send(socket_fd, buf_ptr, len, flag) as _) as _ -} - -/// Receive a message on a socket and get its source address. -/// -/// Return the number of bytes received if success. -#[no_mangle] -pub unsafe extern "C" fn recvfrom( - socket_fd: c_int, - buf_ptr: *mut c_void, - len: ctypes::size_t, - flag: c_int, // currently not used - socket_addr: *mut ctypes::sockaddr, - addrlen: *mut ctypes::socklen_t, -) -> ctypes::ssize_t { - if socket_addr.is_null() { - return e(sys_recv(socket_fd, buf_ptr, len, flag) as _) as _; - } - e(sys_recvfrom(socket_fd, buf_ptr, len, flag, socket_addr, addrlen) as _) as _ -} - -/// Receive a message on a socket. -/// -/// Return the number of bytes received if success. -#[no_mangle] -pub unsafe extern "C" fn recv( - socket_fd: c_int, - buf_ptr: *mut c_void, - len: ctypes::size_t, - flag: c_int, // currently not used -) -> ctypes::ssize_t { - e(sys_recv(socket_fd, buf_ptr, len, flag) as _) as _ -} - -/// Listen for connections on a socket -/// -/// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn listen( - socket_fd: c_int, - backlog: c_int, // currently not used -) -> c_int { - e(sys_listen(socket_fd, backlog)) -} - -/// Accept for connections on a socket -/// -/// Return file descriptor for the accepted socket if success. -#[no_mangle] -pub unsafe extern "C" fn accept( - socket_fd: c_int, - socket_addr: *mut ctypes::sockaddr, - socket_len: *mut ctypes::socklen_t, -) -> c_int { - e(sys_accept(socket_fd, socket_addr, socket_len)) -} - -/// Shut down a full-duplex connection. -/// -/// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn shutdown( - socket_fd: c_int, - flag: c_int, // currently not used -) -> c_int { - e(sys_shutdown(socket_fd, flag)) -} - -/// Query addresses for a domain name. -/// -/// Return address number if success. -#[no_mangle] -pub unsafe extern "C" fn getaddrinfo( - nodename: *const c_char, - servname: *const c_char, - hints: *const ctypes::addrinfo, - res: *mut *mut ctypes::addrinfo, -) -> c_int { - let ret = e(sys_getaddrinfo(nodename, servname, hints, res)); - match ret { - r if r < 0 => ctypes::EAI_FAIL, - 0 => ctypes::EAI_NONAME, - _ => 0, - } -} - -/// Free queried `addrinfo` struct -#[no_mangle] -pub unsafe extern "C" fn freeaddrinfo(res: *mut ctypes::addrinfo) { - sys_freeaddrinfo(res); -} - -/// Get current address to which the socket sockfd is bound. -#[no_mangle] -pub unsafe extern "C" fn getsockname( - sock_fd: c_int, - addr: *mut ctypes::sockaddr, - addrlen: *mut ctypes::socklen_t, -) -> c_int { - e(sys_getsockname(sock_fd, addr, addrlen)) -} - -/// Get peer address to which the socket sockfd is connected. -#[no_mangle] -pub unsafe extern "C" fn getpeername( - sock_fd: c_int, - addr: *mut ctypes::sockaddr, - addrlen: *mut ctypes::socklen_t, -) -> c_int { - e(sys_getpeername(sock_fd, addr, addrlen)) -} diff --git a/arceos/ulib/axlibc/src/pipe.rs b/arceos/ulib/axlibc/src/pipe.rs deleted file mode 100644 index 2bed253c0..000000000 --- a/arceos/ulib/axlibc/src/pipe.rs +++ /dev/null @@ -1,14 +0,0 @@ -use core::ffi::c_int; - -use arceos_posix_api::sys_pipe; - -use crate::utils::e; - -/// Create a pipe -/// -/// Return 0 if succeed -#[no_mangle] -pub unsafe extern "C" fn pipe(fd: *mut c_int) -> c_int { - let fds = unsafe { core::slice::from_raw_parts_mut(fd, 2) }; - e(sys_pipe(fds)) -} diff --git a/arceos/ulib/axlibc/src/pthread.rs b/arceos/ulib/axlibc/src/pthread.rs deleted file mode 100644 index b170b8b7a..000000000 --- a/arceos/ulib/axlibc/src/pthread.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::{ctypes, utils::e}; -use arceos_posix_api as api; -use core::ffi::{c_int, c_void}; - -/// Returns the `pthread` struct of current thread. -#[no_mangle] -pub unsafe extern "C" fn pthread_self() -> ctypes::pthread_t { - api::sys_pthread_self() -} - -/// Create a new thread with the given entry point and argument. -/// -/// If successful, it stores the pointer to the newly created `struct __pthread` -/// in `res` and returns 0. -#[no_mangle] -pub unsafe extern "C" fn pthread_create( - res: *mut ctypes::pthread_t, - attr: *const ctypes::pthread_attr_t, - start_routine: extern "C" fn(arg: *mut c_void) -> *mut c_void, - arg: *mut c_void, -) -> c_int { - e(api::sys_pthread_create(res, attr, start_routine, arg)) -} - -/// Exits the current thread. The value `retval` will be returned to the joiner. -#[no_mangle] -pub unsafe extern "C" fn pthread_exit(retval: *mut c_void) -> ! { - api::sys_pthread_exit(retval) -} - -/// Waits for the given thread to exit, and stores the return value in `retval`. -#[no_mangle] -pub unsafe extern "C" fn pthread_join( - thread: ctypes::pthread_t, - retval: *mut *mut c_void, -) -> c_int { - e(api::sys_pthread_join(thread, retval)) -} - -/// Initialize a mutex. -#[no_mangle] -pub unsafe extern "C" fn pthread_mutex_init( - mutex: *mut ctypes::pthread_mutex_t, - attr: *const ctypes::pthread_mutexattr_t, -) -> c_int { - e(api::sys_pthread_mutex_init(mutex, attr)) -} - -/// Lock the given mutex. -#[no_mangle] -pub unsafe extern "C" fn pthread_mutex_lock(mutex: *mut ctypes::pthread_mutex_t) -> c_int { - e(api::sys_pthread_mutex_lock(mutex)) -} - -/// Unlock the given mutex. -#[no_mangle] -pub unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut ctypes::pthread_mutex_t) -> c_int { - e(api::sys_pthread_mutex_unlock(mutex)) -} diff --git a/arceos/ulib/axlibc/src/rand.rs b/arceos/ulib/axlibc/src/rand.rs deleted file mode 100644 index 682f4231c..000000000 --- a/arceos/ulib/axlibc/src/rand.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Random number generator. - -use core::{ - ffi::{c_int, c_long, c_uint}, - sync::atomic::{AtomicU64, Ordering::SeqCst}, -}; - -static SEED: AtomicU64 = AtomicU64::new(0xa2ce_a2ce); - -/// Sets the seed for the random number generator. -#[no_mangle] -pub unsafe extern "C" fn srand(seed: c_uint) { - SEED.store(seed.wrapping_sub(1) as u64, SeqCst); -} - -/// Returns a 32-bit unsigned pseudo random interger. -#[no_mangle] -pub unsafe extern "C" fn rand() -> c_int { - let new_seed = SEED.load(SeqCst).wrapping_mul(6364136223846793005) + 1; - SEED.store(new_seed, SeqCst); - (new_seed >> 33) as c_int -} - -/// Returns a 64-bit unsigned pseudo random number. -#[no_mangle] -pub unsafe extern "C" fn random() -> c_long { - let new_seed = SEED.load(SeqCst).wrapping_mul(6364136223846793005) + 1; - SEED.store(new_seed, SeqCst); - new_seed as c_long -} diff --git a/arceos/ulib/axlibc/src/resource.rs b/arceos/ulib/axlibc/src/resource.rs deleted file mode 100644 index 20e013e50..000000000 --- a/arceos/ulib/axlibc/src/resource.rs +++ /dev/null @@ -1,17 +0,0 @@ -use core::ffi::c_int; - -use arceos_posix_api::{sys_getrlimit, sys_setrlimit}; - -use crate::utils::e; - -/// Get resource limitations -#[no_mangle] -pub unsafe extern "C" fn getrlimit(resource: c_int, rlimits: *mut crate::ctypes::rlimit) -> c_int { - e(sys_getrlimit(resource, rlimits)) -} - -/// Set resource limitations -#[no_mangle] -pub unsafe extern "C" fn setrlimit(resource: c_int, rlimits: *mut crate::ctypes::rlimit) -> c_int { - e(sys_setrlimit(resource, rlimits)) -} diff --git a/arceos/ulib/axlibc/src/setjmp.rs b/arceos/ulib/axlibc/src/setjmp.rs deleted file mode 100644 index aed4441ff..000000000 --- a/arceos/ulib/axlibc/src/setjmp.rs +++ /dev/null @@ -1,238 +0,0 @@ -use core::ffi::c_int; - -use crate::ctypes; - -/// `setjmp` implementation -#[naked] -#[no_mangle] -pub unsafe extern "C" fn setjmp(_buf: *mut ctypes::__jmp_buf_tag) { - #[cfg(all(target_arch = "aarch64", feature = "fp_simd"))] - core::arch::asm!( - " - stp x19, x20, [x0,#0] - stp x21, x22, [x0,#16] - stp x23, x24, [x0,#32] - stp x25, x26, [x0,#48] - stp x27, x28, [x0,#64] - stp x29, x30, [x0,#80] - mov x2, sp - str x2, [x0,#104] - stp d8, d9, [x0,#112] - stp d10, d11, [x0,#128] - stp d12, d13, [x0,#144] - stp d14, d15, [x0,#160] - mov x0, #0 - ret", - options(noreturn), - ); - #[cfg(all(target_arch = "aarch64", not(feature = "fp_simd")))] - core::arch::asm!( - " - stp x19, x20, [x0,#0] - stp x21, x22, [x0,#16] - stp x23, x24, [x0,#32] - stp x25, x26, [x0,#48] - stp x27, x28, [x0,#64] - stp x29, x30, [x0,#80] - mov x2, sp - str x2, [x0,#104] - mov x0, #0 - ret", - options(noreturn), - ); - #[cfg(target_arch = "x86_64")] - core::arch::asm!( - "mov [rdi], rbx - mov [rdi + 8], rbp - mov [rdi + 16], r12 - mov [rdi + 24], r13 - mov [rdi + 32], r14 - mov [rdi + 40], r15 - lea rdx, [rsp + 8] - mov [rdi + 48], rdx - mov rdx, [rsp] - mov [rdi + 56], rdx - xor rax, rax - ret", - options(noreturn), - ); - #[cfg(all(target_arch = "riscv64", feature = "fp_simd"))] - core::arch::asm!( - "sd s0, 0(a0) - sd s1, 8(a0) - sd s2, 16(a0) - sd s3, 24(a0) - sd s4, 32(a0) - sd s5, 40(a0) - sd s6, 48(a0) - sd s7, 56(a0) - sd s8, 64(a0) - sd s9, 72(a0) - sd s10, 80(a0) - sd s11, 88(a0) - sd sp, 96(a0) - sd ra, 104(a0) - - fsd fs0, 112(a0) - fsd fs1, 120(a0) - fsd fs2, 128(a0) - fsd fs3, 136(a0) - fsd fs4, 144(a0) - fsd fs5, 152(a0) - fsd fs6, 160(a0) - fsd fs7, 168(a0) - fsd fs8, 176(a0) - fsd fs9, 184(a0) - fsd fs10, 192(a0) - fsd fs11, 200(a0) - - li a0, 0 - ret", - options(noreturn), - ); - #[cfg(all(target_arch = "riscv64", not(feature = "fp_simd")))] - core::arch::asm!( - "sd s0, 0(a0) - sd s1, 8(a0) - sd s2, 16(a0) - sd s3, 24(a0) - sd s4, 32(a0) - sd s5, 40(a0) - sd s6, 48(a0) - sd s7, 56(a0) - sd s8, 64(a0) - sd s9, 72(a0) - sd s10, 80(a0) - sd s11, 88(a0) - sd sp, 96(a0) - sd ra, 104(a0) - - li a0, 0 - ret", - options(noreturn), - ); - #[cfg(not(any( - target_arch = "aarch64", - target_arch = "x86_64", - target_arch = "riscv64" - )))] - core::arch::asm!("ret", options(noreturn)) -} - -/// `longjmp` implementation -#[naked] -#[no_mangle] -pub unsafe extern "C" fn longjmp(_buf: *mut ctypes::__jmp_buf_tag, _val: c_int) -> ! { - #[cfg(all(target_arch = "aarch64", feature = "fp_simd"))] - core::arch::asm!( - "ldp x19, x20, [x0,#0] - ldp x21, x22, [x0,#16] - ldp x23, x24, [x0,#32] - ldp x25, x26, [x0,#48] - ldp x27, x28, [x0,#64] - ldp x29, x30, [x0,#80] - ldr x2, [x0,#104] - mov sp, x2 - ldp d8 , d9, [x0,#112] - ldp d10, d11, [x0,#128] - ldp d12, d13, [x0,#144] - ldp d14, d15, [x0,#160] - - cmp w1, 0 - csinc w0, w1, wzr, ne - br x30", - options(noreturn), - ); - #[cfg(all(target_arch = "aarch64", not(feature = "fp_simd")))] - core::arch::asm!( - "ldp x19, x20, [x0,#0] - ldp x21, x22, [x0,#16] - ldp x23, x24, [x0,#32] - ldp x25, x26, [x0,#48] - ldp x27, x28, [x0,#64] - ldp x29, x30, [x0,#80] - ldr x2, [x0,#104] - mov sp, x2 - - cmp w1, 0 - csinc w0, w1, wzr, ne - br x30", - options(noreturn), - ); - #[cfg(target_arch = "x86_64")] - core::arch::asm!( - "mov rax,rsi - test rax,rax - jnz 1f - inc rax - 1: - mov rbx, [rdi] - mov rbp, [rdi + 8] - mov r12, [rdi + 16] - mov r13, [rdi + 24] - mov r14, [rdi + 32] - mov r15, [rdi + 40] - mov rdx, [rdi + 48] - mov rsp, rdx - mov rdx, [rdi + 56] - jmp rdx", - options(noreturn), - ); - #[cfg(all(target_arch = "riscv64", feature = "fp_simd"))] - core::arch::asm!( - "ld s0, 0(a0) - ld s1, 8(a0) - ld s2, 16(a0) - ld s3, 24(a0) - ld s4, 32(a0) - ld s5, 40(a0) - ld s6, 48(a0) - ld s7, 56(a0) - ld s8, 64(a0) - ld s9, 72(a0) - ld s10, 80(a0) - ld s11, 88(a0) - ld sp, 96(a0) - ld ra, 104(a0) - - fld fs0, 112(a0) - fld fs1, 120(a0) - fld fs2, 128(a0) - fld fs3, 136(a0) - fld fs4, 144(a0) - fld fs5, 152(a0) - fld fs6, 160(a0) - fld fs7, 168(a0) - fld fs8, 176(a0) - fld fs9, 184(a0) - fld fs10, 192(a0) - fld fs11, 200(a0) - - seqz a0, a1 - add a0, a0, a1 - ret", - options(noreturn), - ); - #[cfg(all(target_arch = "riscv64", not(feature = "fp_simd")))] - core::arch::asm!( - "ld s0, 0(a0) - ld s1, 8(a0) - ld s2, 16(a0) - ld s3, 24(a0) - ld s4, 32(a0) - ld s5, 40(a0) - ld s6, 48(a0) - ld s7, 56(a0) - ld s8, 64(a0) - ld s9, 72(a0) - ld s10, 80(a0) - ld s11, 88(a0) - ld sp, 96(a0) - ld ra, 104(a0) - - seqz a0, a1 - add a0, a0, a1 - ret", - options(noreturn), - ); -} diff --git a/arceos/ulib/axlibc/src/strftime.rs b/arceos/ulib/axlibc/src/strftime.rs deleted file mode 100644 index aa3c010a3..000000000 --- a/arceos/ulib/axlibc/src/strftime.rs +++ /dev/null @@ -1,254 +0,0 @@ -use alloc::string::String; -use core::{ffi::c_char, fmt}; - -use axio::Write; - -use crate::ctypes; - -pub trait WriteByte: fmt::Write { - fn write_u8(&mut self, byte: u8) -> fmt::Result; -} - -struct StringWriter(pub *mut u8, pub usize); - -impl Write for StringWriter { - fn write(&mut self, buf: &[u8]) -> axerrno::AxResult { - if self.1 > 1 { - let copy_size = buf.len().min(self.1 - 1); - unsafe { - core::ptr::copy_nonoverlapping(buf.as_ptr(), self.0, copy_size); - self.1 -= copy_size; - - self.0 = self.0.add(copy_size); - *self.0 = 0; - } - } - Ok(buf.len()) - } - fn flush(&mut self) -> axerrno::AxResult { - Ok(()) - } -} - -impl fmt::Write for StringWriter { - fn write_str(&mut self, s: &str) -> fmt::Result { - // can't fail - self.write(s.as_bytes()).unwrap(); - Ok(()) - } -} - -impl WriteByte for StringWriter { - fn write_u8(&mut self, byte: u8) -> fmt::Result { - // can't fail - self.write(&[byte]).unwrap(); - Ok(()) - } -} - -struct CountingWriter { - pub inner: T, - pub written: usize, -} - -impl CountingWriter { - pub fn new(writer: T) -> Self { - Self { - inner: writer, - written: 0, - } - } -} - -impl fmt::Write for CountingWriter { - fn write_str(&mut self, s: &str) -> fmt::Result { - self.written += s.len(); - self.inner.write_str(s) - } -} - -impl WriteByte for CountingWriter { - fn write_u8(&mut self, byte: u8) -> fmt::Result { - self.written += 1; - self.inner.write_u8(byte) - } -} - -impl Write for CountingWriter { - fn write(&mut self, buf: &[u8]) -> axerrno::AxResult { - let res = self.inner.write(buf); - if let Ok(written) = res { - self.written += written; - } - res - } - - fn write_all(&mut self, buf: &[u8]) -> axerrno::AxResult { - match self.inner.write_all(buf) { - Ok(()) => (), - Err(err) => return Err(err), - } - self.written += buf.len(); - Ok(()) - } - - fn flush(&mut self) -> axerrno::AxResult { - self.inner.flush() - } -} - -unsafe fn strftime_inner( - w: W, - format: *const c_char, - t: *const ctypes::tm, -) -> ctypes::size_t { - pub unsafe fn inner_strftime( - w: &mut W, - mut format: *const c_char, - t: *const ctypes::tm, - ) -> bool { - macro_rules! w { - (byte $b:expr) => {{ - if w.write_u8($b).is_err() { - return false; - } - }}; - (char $chr:expr) => {{ - if w.write_char($chr).is_err() { - return false; - } - }}; - (recurse $fmt:expr) => {{ - let mut fmt = String::with_capacity($fmt.len() + 1); - fmt.push_str($fmt); - fmt.push('\0'); - - if !inner_strftime(w, fmt.as_ptr() as *mut c_char, t) { - return false; - } - }}; - ($str:expr) => {{ - if w.write_str($str).is_err() { - return false; - } - }}; - ($fmt:expr, $($args:expr),+) => {{ - // Would use write!() if I could get the length written - if write!(w, $fmt, $($args),+).is_err() { - return false; - } - }}; - } - const WDAYS: [&str; 7] = [ - "Sunday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday", - ]; - const MONTHS: [&str; 12] = [ - "January", - "Febuary", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", - ]; - - while *format != 0 { - if *format as u8 != b'%' { - w!(byte * format as u8); - format = format.offset(1); - continue; - } - - format = format.offset(1); - - if *format as u8 == b'E' || *format as u8 == b'O' { - // Ignore because these do nothing without locale - format = format.offset(1); - } - - match *format as u8 { - b'%' => w!(byte b'%'), - b'n' => w!(byte b'\n'), - b't' => w!(byte b'\t'), - b'a' => w!(&WDAYS[(*t).tm_wday as usize][..3]), - b'A' => w!(WDAYS[(*t).tm_wday as usize]), - b'b' | b'h' => w!(&MONTHS[(*t).tm_mon as usize][..3]), - b'B' => w!(MONTHS[(*t).tm_mon as usize]), - b'C' => { - let mut year = (*t).tm_year / 100; - // Round up - if (*t).tm_year % 100 != 0 { - year += 1; - } - w!("{:02}", year + 19); - } - b'd' => w!("{:02}", (*t).tm_mday), - b'D' => w!(recurse "%m/%d/%y"), - b'e' => w!("{:2}", (*t).tm_mday), - b'F' => w!(recurse "%Y-%m-%d"), - b'H' => w!("{:02}", (*t).tm_hour), - b'I' => w!("{:02}", ((*t).tm_hour + 12 - 1) % 12 + 1), - b'j' => w!("{:03}", (*t).tm_yday), - b'k' => w!("{:2}", (*t).tm_hour), - b'l' => w!("{:2}", ((*t).tm_hour + 12 - 1) % 12 + 1), - b'm' => w!("{:02}", (*t).tm_mon + 1), - b'M' => w!("{:02}", (*t).tm_min), - b'p' => w!(if (*t).tm_hour < 12 { "AM" } else { "PM" }), - b'P' => w!(if (*t).tm_hour < 12 { "am" } else { "pm" }), - b'r' => w!(recurse "%I:%M:%S %p"), - b'R' => w!(recurse "%H:%M"), - // Nothing is modified in mktime, but the C standard of course requires a mutable pointer ._. - b's' => w!("{}", super::mktime(t as *mut ctypes::tm)), - b'S' => w!("{:02}", (*t).tm_sec), - b'T' => w!(recurse "%H:%M:%S"), - b'u' => w!("{}", ((*t).tm_wday + 7 - 1) % 7 + 1), - b'U' => w!("{}", ((*t).tm_yday + 7 - (*t).tm_wday) / 7), - b'w' => w!("{}", (*t).tm_wday), - b'W' => w!("{}", ((*t).tm_yday + 7 - ((*t).tm_wday + 6) % 7) / 7), - b'y' => w!("{:02}", (*t).tm_year % 100), - b'Y' => w!("{}", (*t).tm_year + 1900), - b'z' => w!("+0000"), // TODO - b'Z' => w!("UTC"), // TODO - b'+' => w!(recurse "%a %b %d %T %Z %Y"), - _ => return false, - } - - format = format.offset(1); - } - true - } - - let mut w: CountingWriter = CountingWriter::new(w); - if !inner_strftime(&mut w, format, t) { - return 0; - } - - w.written -} - -/// Convert date and time to a string. -#[no_mangle] -pub unsafe extern "C" fn strftime( - buf: *mut c_char, - size: ctypes::size_t, - format: *const c_char, - timeptr: *const ctypes::tm, -) -> ctypes::size_t { - let ret = strftime_inner(StringWriter(buf as *mut u8, size), format, timeptr); - if ret < size { - ret - } else { - 0 - } -} diff --git a/arceos/ulib/axlibc/src/strtod.rs b/arceos/ulib/axlibc/src/strtod.rs deleted file mode 100644 index d93087892..000000000 --- a/arceos/ulib/axlibc/src/strtod.rs +++ /dev/null @@ -1,131 +0,0 @@ -use core::ffi::{c_char, c_double, c_float, c_int}; - -macro_rules! strto_float_impl { - ($type:ident, $s:expr, $endptr:expr) => {{ - let mut s = $s; - let endptr = $endptr; - - // TODO: Handle named floats: NaN, Inf... - - while isspace(*s as c_int) { - s = s.offset(1); - } - - let mut result: $type = 0.0; - let mut radix = 10; - - let result_sign = match *s as u8 { - b'-' => { - s = s.offset(1); - -1.0 - } - b'+' => { - s = s.offset(1); - 1.0 - } - _ => 1.0, - }; - - if *s as u8 == b'0' && *s.offset(1) as u8 == b'x' { - s = s.offset(2); - radix = 16; - } - - while let Some(digit) = (*s as u8 as char).to_digit(radix) { - result *= radix as $type; - result += digit as $type; - s = s.offset(1); - } - - if *s as u8 == b'.' { - s = s.offset(1); - - let mut i = 1.0; - while let Some(digit) = (*s as u8 as char).to_digit(radix) { - i *= radix as $type; - result += digit as $type / i; - s = s.offset(1); - } - } - - let s_before_exponent = s; - - let exponent = match (*s as u8, radix) { - (b'e' | b'E', 10) | (b'p' | b'P', 16) => { - s = s.offset(1); - - let is_exponent_positive = match *s as u8 { - b'-' => { - s = s.offset(1); - false - } - b'+' => { - s = s.offset(1); - true - } - _ => true, - }; - - // Exponent digits are always in base 10. - if (*s as u8 as char).is_digit(10) { - let mut exponent_value = 0; - - while let Some(digit) = (*s as u8 as char).to_digit(10) { - exponent_value *= 10; - exponent_value += digit; - s = s.offset(1); - } - - let exponent_base = match radix { - 10 => 10u128, - 16 => 2u128, - _ => unreachable!(), - }; - - if is_exponent_positive { - Some(exponent_base.pow(exponent_value) as $type) - } else { - Some(1.0 / (exponent_base.pow(exponent_value) as $type)) - } - } else { - // Exponent had no valid digits after 'e'/'p' and '+'/'-', rollback - s = s_before_exponent; - None - } - } - _ => None, - }; - - // Return pointer should be *mut - if !endptr.is_null() { - *endptr = s as *mut _; - } - - if let Some(exponent) = exponent { - result_sign * result * exponent - } else { - result_sign * result - } - }}; -} - -fn isspace(c: c_int) -> bool { - c == c_int::from(b' ') - || c == c_int::from(b'\t') - || c == c_int::from(b'\n') - || c == c_int::from(b'\r') - || c == 0x0b - || c == 0x0c -} - -/// Convert a string to a double-precision number. -#[no_mangle] -pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double { - strto_float_impl!(c_double, s, endptr) -} - -/// Convert a string to a float number. -#[no_mangle] -pub unsafe extern "C" fn strtof(s: *const c_char, endptr: *mut *mut c_char) -> c_float { - strto_float_impl!(c_float, s, endptr) -} diff --git a/arceos/ulib/axlibc/src/sys.rs b/arceos/ulib/axlibc/src/sys.rs deleted file mode 100644 index 253d76f1a..000000000 --- a/arceos/ulib/axlibc/src/sys.rs +++ /dev/null @@ -1,10 +0,0 @@ -use arceos_posix_api::sys_sysconf; -use core::ffi::{c_int, c_long}; - -/// Return system configuration infomation -/// -/// Notice: currently only support what unikraft covers -#[no_mangle] -pub unsafe extern "C" fn sysconf(name: c_int) -> c_long { - sys_sysconf(name) -} diff --git a/arceos/ulib/axlibc/src/time.rs b/arceos/ulib/axlibc/src/time.rs deleted file mode 100644 index f478cd7f3..000000000 --- a/arceos/ulib/axlibc/src/time.rs +++ /dev/null @@ -1,21 +0,0 @@ -use arceos_posix_api::{sys_clock_gettime, sys_nanosleep}; -use core::ffi::c_int; - -use crate::{ctypes, utils::e}; - -/// Get clock time since booting -#[no_mangle] -pub unsafe extern "C" fn clock_gettime(clk: ctypes::clockid_t, ts: *mut ctypes::timespec) -> c_int { - e(sys_clock_gettime(clk, ts)) -} - -/// Sleep some nanoseconds -/// -/// TODO: should be woken by signals, and set errno -#[no_mangle] -pub unsafe extern "C" fn nanosleep( - req: *const ctypes::timespec, - rem: *mut ctypes::timespec, -) -> c_int { - e(sys_nanosleep(req, rem)) -} diff --git a/arceos/ulib/axlibc/src/unistd.rs b/arceos/ulib/axlibc/src/unistd.rs deleted file mode 100644 index 46c81bdd7..000000000 --- a/arceos/ulib/axlibc/src/unistd.rs +++ /dev/null @@ -1,20 +0,0 @@ -use arceos_posix_api::{sys_exit, sys_getpid}; -use core::ffi::c_int; - -/// Get current thread ID. -#[no_mangle] -pub unsafe extern "C" fn getpid() -> c_int { - sys_getpid() -} - -/// Abort the current process. -#[no_mangle] -pub unsafe extern "C" fn abort() -> ! { - panic!() -} - -/// Exits the current thread. -#[no_mangle] -pub unsafe extern "C" fn exit(exit_code: c_int) -> ! { - sys_exit(exit_code) -} diff --git a/arceos/ulib/axlibc/src/utils.rs b/arceos/ulib/axlibc/src/utils.rs deleted file mode 100644 index 730f8c3de..000000000 --- a/arceos/ulib/axlibc/src/utils.rs +++ /dev/null @@ -1,10 +0,0 @@ -use core::ffi::c_int; - -pub fn e(ret: c_int) -> c_int { - if ret < 0 { - crate::errno::set_errno(ret.abs()); - -1 - } else { - ret as _ - } -} diff --git a/arceos/ulib/axstd/Cargo.toml b/arceos/ulib/axstd/Cargo.toml deleted file mode 100644 index c2322c590..000000000 --- a/arceos/ulib/axstd/Cargo.toml +++ /dev/null @@ -1,82 +0,0 @@ -[package] -name = "axstd" -version.workspace = true -edition = "2021" -authors = [ - "Yuekai Jia ", - "yanjuguang ", - "wudashuai ", - "yfblock <321353225@qq.com>", - "scPointer ", - "Shiping Yuan ", -] -description = "ArceOS user library with an interface similar to rust std" -license.workspace = true -homepage.workspace = true -repository = "https://github.com/arceos-org/arceos/tree/main/ulib/axstd" -documentation = "https://arceos-org.github.io/arceos/axstd/index.html" - -[features] -default = [] - -# Multicore -smp = ["axfeat/smp", "kspin/smp"] - -# Floating point/SIMD -fp_simd = ["axfeat/fp_simd"] - -# Interrupts -irq = ["arceos_api/irq", "axfeat/irq"] - -# Memory -alloc = ["arceos_api/alloc", "axfeat/alloc", "axio/alloc"] -alloc-tlsf = ["axfeat/alloc-tlsf"] -alloc-slab = ["axfeat/alloc-slab"] -alloc-buddy = ["axfeat/alloc-buddy"] -paging = ["axfeat/paging"] -dma = ["arceos_api/dma", "axfeat/dma"] -tls = ["axfeat/tls"] - -alt_alloc = ["arceos_api/alt_alloc", "axfeat/alt_alloc"] - -# Multi-threading and scheduler -multitask = ["arceos_api/multitask", "axfeat/multitask"] -sched_fifo = ["axfeat/sched_fifo"] -sched_rr = ["axfeat/sched_rr"] -sched_cfs = ["axfeat/sched_cfs"] - -# File system -fs = ["arceos_api/fs", "axfeat/fs"] -myfs = ["arceos_api/myfs", "axfeat/myfs"] - -# Networking -net = ["arceos_api/net", "axfeat/net"] -dns = [] - -# Display -display = ["arceos_api/display", "axfeat/display"] - -# Real Time Clock (RTC) Driver. -rtc = ["axfeat/rtc"] - -# Device drivers -bus-mmio = ["axfeat/bus-mmio"] -bus-pci = ["axfeat/bus-pci"] -driver-ramdisk = ["axfeat/driver-ramdisk"] -driver-ixgbe = ["axfeat/driver-ixgbe"] -driver-bcm2835-sdhci = ["axfeat/driver-bcm2835-sdhci"] - -# Logging -log-level-off = ["axfeat/log-level-off"] -log-level-error = ["axfeat/log-level-error"] -log-level-warn = ["axfeat/log-level-warn"] -log-level-info = ["axfeat/log-level-info"] -log-level-debug = ["axfeat/log-level-debug"] -log-level-trace = ["axfeat/log-level-trace"] - -[dependencies] -axfeat = { workspace = true } -arceos_api = { workspace = true } -axio = "0.1" -axerrno = "0.1" -kspin = "0.1" diff --git a/arceos/ulib/axstd/src/env.rs b/arceos/ulib/axstd/src/env.rs deleted file mode 100644 index 13c06e2cb..000000000 --- a/arceos/ulib/axstd/src/env.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Inspection and manipulation of the process’s environment. - -#[cfg(feature = "fs")] -extern crate alloc; - -#[cfg(feature = "fs")] -use {crate::io, alloc::string::String}; - -/// Returns the current working directory as a [`String`]. -#[cfg(feature = "fs")] -pub fn current_dir() -> io::Result { - arceos_api::fs::ax_current_dir() -} - -/// Changes the current working directory to the specified path. -#[cfg(feature = "fs")] -pub fn set_current_dir(path: &str) -> io::Result<()> { - arceos_api::fs::ax_set_current_dir(path) -} diff --git a/arceos/ulib/axstd/src/fs/dir.rs b/arceos/ulib/axstd/src/fs/dir.rs deleted file mode 100644 index bf49cc85a..000000000 --- a/arceos/ulib/axstd/src/fs/dir.rs +++ /dev/null @@ -1,154 +0,0 @@ -extern crate alloc; - -use alloc::string::String; -use core::fmt; - -use super::FileType; -use crate::io::Result; - -use arceos_api::fs as api; - -/// Iterator over the entries in a directory. -pub struct ReadDir<'a> { - path: &'a str, - inner: api::AxDirHandle, - buf_pos: usize, - buf_end: usize, - end_of_stream: bool, - dirent_buf: [api::AxDirEntry; 31], -} - -/// Entries returned by the [`ReadDir`] iterator. -pub struct DirEntry<'a> { - dir_path: &'a str, - entry_name: String, - entry_type: FileType, -} - -/// A builder used to create directories in various manners. -#[derive(Default, Debug)] -pub struct DirBuilder { - recursive: bool, -} - -impl<'a> ReadDir<'a> { - pub(super) fn new(path: &'a str) -> Result { - let mut opts = api::AxOpenOptions::new(); - opts.read(true); - let inner = api::ax_open_dir(path, &opts)?; - - const EMPTY: api::AxDirEntry = api::AxDirEntry::default(); - let dirent_buf = [EMPTY; 31]; - Ok(ReadDir { - path, - inner, - end_of_stream: false, - buf_pos: 0, - buf_end: 0, - dirent_buf, - }) - } -} - -impl<'a> Iterator for ReadDir<'a> { - type Item = Result>; - - fn next(&mut self) -> Option>> { - if self.end_of_stream { - return None; - } - - loop { - if self.buf_pos >= self.buf_end { - match api::ax_read_dir(&mut self.inner, &mut self.dirent_buf) { - Ok(n) => { - if n == 0 { - self.end_of_stream = true; - return None; - } - self.buf_pos = 0; - self.buf_end = n; - } - Err(e) => { - self.end_of_stream = true; - return Some(Err(e)); - } - } - } - let entry = &self.dirent_buf[self.buf_pos]; - self.buf_pos += 1; - let name_bytes = entry.name_as_bytes(); - if name_bytes == b"." || name_bytes == b".." { - continue; - } - let entry_name = unsafe { core::str::from_utf8_unchecked(name_bytes).into() }; - let entry_type = entry.entry_type(); - - return Some(Ok(DirEntry { - dir_path: self.path, - entry_name, - entry_type, - })); - } - } -} - -impl<'a> DirEntry<'a> { - /// Returns the full path to the file that this entry represents. - /// - /// The full path is created by joining the original path to `read_dir` - /// with the filename of this entry. - pub fn path(&self) -> String { - String::from(self.dir_path.trim_end_matches('/')) + "/" + &self.entry_name - } - - /// Returns the bare file name of this directory entry without any other - /// leading path component. - pub fn file_name(&self) -> String { - self.entry_name.clone() - } - - /// Returns the file type for the file that this entry points at. - pub fn file_type(&self) -> FileType { - self.entry_type - } -} - -impl fmt::Debug for DirEntry<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("DirEntry").field(&self.path()).finish() - } -} - -impl DirBuilder { - /// Creates a new set of options with default mode/security settings for all - /// platforms and also non-recursive. - pub fn new() -> Self { - Self { recursive: false } - } - - /// Indicates that directories should be created recursively, creating all - /// parent directories. Parents that do not exist are created with the same - /// security and permissions settings. - pub fn recursive(&mut self, recursive: bool) -> &mut Self { - self.recursive = recursive; - self - } - - /// Creates the specified directory with the options configured in this - /// builder. - pub fn create(&self, path: &str) -> Result<()> { - if self.recursive { - self.create_dir_all(path) - } else { - api::ax_create_dir(path) - } - } - - fn create_dir_all(&self, _path: &str) -> Result<()> { - axerrno::ax_err!( - Unsupported, - "Recursive directory creation is not supported yet" - ) - } -} diff --git a/arceos/ulib/axstd/src/fs/file.rs b/arceos/ulib/axstd/src/fs/file.rs deleted file mode 100644 index 6984057cc..000000000 --- a/arceos/ulib/axstd/src/fs/file.rs +++ /dev/null @@ -1,187 +0,0 @@ -use crate::io::{prelude::*, Result, SeekFrom}; -use core::fmt; - -use arceos_api::fs as api; - -/// A structure representing a type of file with accessors for each file type. -/// It is returned by [`Metadata::file_type`] method. -pub type FileType = api::AxFileType; - -/// Representation of the various permissions on a file. -pub type Permissions = api::AxFilePerm; - -/// An object providing access to an open file on the filesystem. -pub struct File { - inner: api::AxFileHandle, -} - -/// Metadata information about a file. -pub struct Metadata(api::AxFileAttr); - -/// Options and flags which can be used to configure how a file is opened. -#[derive(Clone, Debug)] -pub struct OpenOptions(api::AxOpenOptions); - -impl OpenOptions { - /// Creates a blank new set of options ready for configuration. - pub const fn new() -> Self { - OpenOptions(api::AxOpenOptions::new()) - } - - /// Sets the option for read access. - pub fn read(&mut self, read: bool) -> &mut Self { - self.0.read(read); - self - } - - /// Sets the option for write access. - pub fn write(&mut self, write: bool) -> &mut Self { - self.0.write(write); - self - } - - /// Sets the option for the append mode. - pub fn append(&mut self, append: bool) -> &mut Self { - self.0.append(append); - self - } - - /// Sets the option for truncating a previous file. - pub fn truncate(&mut self, truncate: bool) -> &mut Self { - self.0.truncate(truncate); - self - } - - /// Sets the option to create a new file, or open it if it already exists. - pub fn create(&mut self, create: bool) -> &mut Self { - self.0.create(create); - self - } - - /// Sets the option to create a new file, failing if it already exists. - pub fn create_new(&mut self, create_new: bool) -> &mut Self { - self.0.create_new(create_new); - self - } - - /// Opens a file at `path` with the options specified by `self`. - pub fn open(&self, path: &str) -> Result { - api::ax_open_file(path, &self.0).map(|inner| File { inner }) - } -} - -impl Metadata { - /// Returns the file type for this metadata. - pub const fn file_type(&self) -> FileType { - self.0.file_type() - } - - /// Returns `true` if this metadata is for a directory. The - /// result is mutually exclusive to the result of - /// [`Metadata::is_file`]. - pub const fn is_dir(&self) -> bool { - self.0.is_dir() - } - - /// Returns `true` if this metadata is for a regular file. The - /// result is mutually exclusive to the result of - /// [`Metadata::is_dir`]. - pub const fn is_file(&self) -> bool { - self.0.is_file() - } - - /// Returns the size of the file, in bytes, this metadata is for. - #[allow(clippy::len_without_is_empty)] - pub const fn len(&self) -> u64 { - self.0.size() - } - - /// Returns the permissions of the file this metadata is for. - pub const fn permissions(&self) -> Permissions { - self.0.perm() - } - - /// Returns the total size of this file in bytes. - pub const fn size(&self) -> u64 { - self.0.size() - } - - /// Returns the number of blocks allocated to the file, in 512-byte units. - pub const fn blocks(&self) -> u64 { - self.0.blocks() - } -} - -impl fmt::Debug for Metadata { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Metadata") - .field("file_type", &self.file_type()) - .field("is_dir", &self.is_dir()) - .field("is_file", &self.is_file()) - .field("permissions", &self.permissions()) - .finish_non_exhaustive() - } -} - -impl File { - /// Attempts to open a file in read-only mode. - pub fn open(path: &str) -> Result { - OpenOptions::new().read(true).open(path) - } - - /// Opens a file in write-only mode. - pub fn create(path: &str) -> Result { - OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(path) - } - - /// Creates a new file in read-write mode; error if the file exists. - pub fn create_new(path: &str) -> Result { - OpenOptions::new() - .read(true) - .write(true) - .create_new(true) - .open(path) - } - - /// Returns a new OpenOptions object. - pub fn options() -> OpenOptions { - OpenOptions::new() - } - - /// Truncates or extends the underlying file, updating the size of - /// this file to become `size`. - pub fn set_len(&self, size: u64) -> Result<()> { - api::ax_truncate_file(&self.inner, size) - } - - /// Queries metadata about the underlying file. - pub fn metadata(&self) -> Result { - api::ax_file_attr(&self.inner).map(Metadata) - } -} - -impl Read for File { - fn read(&mut self, buf: &mut [u8]) -> Result { - api::ax_read_file(&mut self.inner, buf) - } -} - -impl Write for File { - fn write(&mut self, buf: &[u8]) -> Result { - api::ax_write_file(&mut self.inner, buf) - } - - fn flush(&mut self) -> Result<()> { - api::ax_flush_file(&self.inner) - } -} - -impl Seek for File { - fn seek(&mut self, pos: SeekFrom) -> Result { - api::ax_seek_file(&mut self.inner, pos) - } -} diff --git a/arceos/ulib/axstd/src/fs/mod.rs b/arceos/ulib/axstd/src/fs/mod.rs deleted file mode 100644 index 5308045b9..000000000 --- a/arceos/ulib/axstd/src/fs/mod.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! Filesystem manipulation operations. - -mod dir; -mod file; - -use crate::io::{self, prelude::*}; - -#[cfg(feature = "alloc")] -use alloc::{string::String, vec::Vec}; - -pub use self::dir::{DirBuilder, DirEntry, ReadDir}; -pub use self::file::{File, FileType, Metadata, OpenOptions, Permissions}; - -/// Read the entire contents of a file into a bytes vector. -#[cfg(feature = "alloc")] -pub fn read(path: &str) -> io::Result> { - let mut file = File::open(path)?; - let size = file.metadata().map(|m| m.len()).unwrap_or(0); - let mut bytes = Vec::with_capacity(size as usize); - file.read_to_end(&mut bytes)?; - Ok(bytes) -} - -/// Read the entire contents of a file into a string. -#[cfg(feature = "alloc")] -pub fn read_to_string(path: &str) -> io::Result { - let mut file = File::open(path)?; - let size = file.metadata().map(|m| m.len()).unwrap_or(0); - let mut string = String::with_capacity(size as usize); - file.read_to_string(&mut string)?; - Ok(string) -} - -/// Write a slice as the entire contents of a file. -pub fn write>(path: &str, contents: C) -> io::Result<()> { - File::create(path)?.write_all(contents.as_ref()) -} - -/// Given a path, query the file system to get information about a file, -/// directory, etc. -pub fn metadata(path: &str) -> io::Result { - File::open(path)?.metadata() -} - -/// Returns an iterator over the entries within a directory. -pub fn read_dir(path: &str) -> io::Result { - ReadDir::new(path) -} - -/// Creates a new, empty directory at the provided path. -pub fn create_dir(path: &str) -> io::Result<()> { - DirBuilder::new().create(path) -} - -/// Recursively create a directory and all of its parent components if they -/// are missing. -pub fn create_dir_all(path: &str) -> io::Result<()> { - DirBuilder::new().recursive(true).create(path) -} - -/// Removes an empty directory. -pub fn remove_dir(path: &str) -> io::Result<()> { - arceos_api::fs::ax_remove_dir(path) -} - -/// Removes a file from the filesystem. -pub fn remove_file(path: &str) -> io::Result<()> { - arceos_api::fs::ax_remove_file(path) -} - -/// Rename a file or directory to a new name. -/// Delete the original file if `old` already exists. -/// -/// This only works then the new path is in the same mounted fs. -pub fn rename(old: &str, new: &str) -> io::Result<()> { - arceos_api::fs::ax_rename(old, new) -} diff --git a/arceos/ulib/axstd/src/io/mod.rs b/arceos/ulib/axstd/src/io/mod.rs deleted file mode 100644 index 7a0cf1fc1..000000000 --- a/arceos/ulib/axstd/src/io/mod.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! Traits, helpers, and type definitions for core I/O functionality. - -mod stdio; - -pub use axio::prelude; -pub use axio::{BufRead, BufReader, Error, Read, Seek, SeekFrom, Write}; - -#[doc(hidden)] -pub use self::stdio::__print_impl; -pub use self::stdio::{stdin, stdout, Stdin, StdinLock, Stdout, StdoutLock}; - -/// A specialized [`Result`] type for I/O operations. -/// -/// This type is broadly used across [`axstd::io`] for any operation which may -/// produce an error. -/// -/// This typedef is generally used to avoid writing out [`io::Error`] directly and -/// is otherwise a direct mapping to [`Result`]. -/// -/// While usual Rust style is to import types directly, aliases of [`Result`] -/// often are not, to make it easier to distinguish between them. [`Result`] is -/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias -/// will generally use `io::Result` instead of shadowing the [prelude]'s import -/// of [`std::result::Result`][`Result`]. -/// -/// [`axstd::io`]: crate::io -/// [`io::Error`]: Error -pub type Result = axio::Result; diff --git a/arceos/ulib/axstd/src/io/stdio.rs b/arceos/ulib/axstd/src/io/stdio.rs deleted file mode 100644 index 0b07f4bb6..000000000 --- a/arceos/ulib/axstd/src/io/stdio.rs +++ /dev/null @@ -1,173 +0,0 @@ -use crate::io::{self, prelude::*, BufReader}; -use crate::sync::{Mutex, MutexGuard}; - -#[cfg(feature = "alloc")] -use alloc::{string::String, vec::Vec}; - -struct StdinRaw; -struct StdoutRaw; - -impl Read for StdinRaw { - // Non-blocking read, returns number of bytes read. - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let mut read_len = 0; - while read_len < buf.len() { - if let Some(c) = arceos_api::stdio::ax_console_read_byte() { - buf[read_len] = c; - read_len += 1; - } else { - break; - } - } - Ok(read_len) - } -} - -impl Write for StdoutRaw { - fn write(&mut self, buf: &[u8]) -> io::Result { - arceos_api::stdio::ax_console_write_bytes(buf) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -/// A handle to the standard input stream of a process. -pub struct Stdin { - inner: &'static Mutex>, -} - -/// A locked reference to the [`Stdin`] handle. -pub struct StdinLock<'a> { - inner: MutexGuard<'a, BufReader>, -} - -impl Stdin { - /// Locks this handle to the standard input stream, returning a readable - /// guard. - /// - /// The lock is released when the returned lock goes out of scope. The - /// returned guard also implements the [`Read`] and [`BufRead`] traits for - /// accessing the underlying data. - pub fn lock(&self) -> StdinLock<'static> { - // Locks this handle with 'static lifetime. This depends on the - // implementation detail that the underlying `Mutex` is static. - StdinLock { - inner: self.inner.lock(), - } - } - - /// Locks this handle and reads a line of input, appending it to the specified buffer. - #[cfg(feature = "alloc")] - pub fn read_line(&self, buf: &mut String) -> io::Result { - self.inner.lock().read_line(buf) - } -} - -impl Read for Stdin { - // Block until at least one byte is read. - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let read_len = self.inner.lock().read(buf)?; - if buf.is_empty() || read_len > 0 { - return Ok(read_len); - } - // try again until we got something - loop { - let read_len = self.inner.lock().read(buf)?; - if read_len > 0 { - return Ok(read_len); - } - crate::thread::yield_now(); - } - } -} - -impl Read for StdinLock<'_> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } -} - -impl BufRead for StdinLock<'_> { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - self.inner.fill_buf() - } - - fn consume(&mut self, n: usize) { - self.inner.consume(n) - } - - #[cfg(feature = "alloc")] - fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { - self.inner.read_until(byte, buf) - } - - #[cfg(feature = "alloc")] - fn read_line(&mut self, buf: &mut String) -> io::Result { - self.inner.read_line(buf) - } -} - -/// A handle to the global standard output stream of the current process. -pub struct Stdout { - inner: &'static Mutex, -} - -/// A locked reference to the [`Stdout`] handle. -pub struct StdoutLock<'a> { - inner: MutexGuard<'a, StdoutRaw>, -} - -impl Stdout { - /// Locks this handle to the standard output stream, returning a writable - /// guard. - /// - /// The lock is released when the returned lock goes out of scope. The - /// returned guard also implements the `Write` trait for writing data. - pub fn lock(&self) -> StdoutLock<'static> { - StdoutLock { - inner: self.inner.lock(), - } - } -} - -impl Write for Stdout { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.lock().write(buf) - } - fn flush(&mut self) -> io::Result<()> { - self.inner.lock().flush() - } -} - -impl Write for StdoutLock<'_> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(buf) - } - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } -} - -/// Constructs a new handle to the standard input of the current process. -pub fn stdin() -> Stdin { - static INSTANCE: Mutex> = Mutex::new(BufReader::new(StdinRaw)); - Stdin { inner: &INSTANCE } -} - -/// Constructs a new handle to the standard output of the current process. -pub fn stdout() -> Stdout { - static INSTANCE: Mutex = Mutex::new(StdoutRaw); - Stdout { inner: &INSTANCE } -} - -#[doc(hidden)] -pub fn __print_impl(args: core::fmt::Arguments) { - if cfg!(feature = "smp") { - // synchronize using the lock in axlog, to avoid interleaving - // with kernel logs - arceos_api::stdio::ax_console_write_fmt(args).unwrap(); - } else { - stdout().lock().write_fmt(args).unwrap(); - } -} diff --git a/arceos/ulib/axstd/src/lib.rs b/arceos/ulib/axstd/src/lib.rs deleted file mode 100644 index 5ab051702..000000000 --- a/arceos/ulib/axstd/src/lib.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! # The ArceOS Standard Library -//! -//! The [ArceOS] Standard Library is a mini-std library, with an interface similar -//! to rust [std], but calling the functions directly in ArceOS modules, instead -//! of using libc and system calls. -//! -//! These features are exactly the same as those in [axfeat], they are used to -//! provide users with the selection of features in axfeat, without import -//! [axfeat] additionally: -//! -//! ## Cargo Features -//! -//! - CPU -//! - `smp`: Enable SMP (symmetric multiprocessing) support. -//! - `fp_simd`: Enable floating point and SIMD support. -//! - Interrupts: -//! - `irq`: Enable interrupt handling support. -//! - Memory -//! - `alloc`: Enable dynamic memory allocation. -//! - `alloc-tlsf`: Use the TLSF allocator. -//! - `alloc-slab`: Use the slab allocator. -//! - `alloc-buddy`: Use the buddy system allocator. -//! - `paging`: Enable page table manipulation. -//! - `tls`: Enable thread-local storage. -//! - Task management -//! - `multitask`: Enable multi-threading support. -//! - `sched_fifo`: Use the FIFO cooperative scheduler. -//! - `sched_rr`: Use the Round-robin preemptive scheduler. -//! - `sched_cfs`: Use the Completely Fair Scheduler (CFS) preemptive scheduler. -//! - Upperlayer stacks -//! - `fs`: Enable file system support. -//! - `myfs`: Allow users to define their custom filesystems to override the default. -//! - `net`: Enable networking support. -//! - `dns`: Enable DNS lookup support. -//! - `display`: Enable graphics support. -//! - Device drivers -//! - `bus-mmio`: Use device tree to probe all MMIO devices. -//! - `bus-pci`: Use PCI bus to probe all PCI devices. -//! - `driver-ramdisk`: Use the RAM disk to emulate the block device. -//! - `driver-ixgbe`: Enable the Intel 82599 10Gbit NIC driver. -//! - `driver-bcm2835-sdhci`: Enable the BCM2835 SDHCI driver (Raspberry Pi SD card). -//! - Logging -//! - `log-level-off`: Disable all logging. -//! - `log-level-error`, `log-level-warn`, `log-level-info`, `log-level-debug`, -//! `log-level-trace`: Keep logging only at the specified level or higher. -//! -//! [ArceOS]: https://github.com/arceos-org/arceos - -#![cfg_attr(all(not(test), not(doc)), no_std)] -#![feature(doc_cfg)] -#![feature(doc_auto_cfg)] - -#[cfg(feature = "alloc")] -extern crate alloc; - -#[cfg(feature = "alloc")] -#[doc(no_inline)] -pub use alloc::{boxed, collections, format, string, vec}; - -#[doc(no_inline)] -pub use core::{arch, cell, cmp, hint, marker, mem, ops, ptr, slice, str}; - -#[macro_use] -mod macros; - -pub mod env; -pub mod io; -pub mod os; -pub mod process; -pub mod sync; -pub mod thread; -pub mod time; - -#[cfg(feature = "fs")] -pub mod fs; -#[cfg(feature = "net")] -pub mod net; diff --git a/arceos/ulib/axstd/src/macros.rs b/arceos/ulib/axstd/src/macros.rs deleted file mode 100644 index c7cd6535e..000000000 --- a/arceos/ulib/axstd/src/macros.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! Standard library macros - -/// Prints to the standard output. -/// -/// Equivalent to the [`println!`] macro except that a newline is not printed at -/// the end of the message. -/// -/// [`println!`]: crate::println -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => { - $crate::io::__print_impl(format_args!($($arg)*)); - } -} - -/// Prints to the standard output, with a newline. -#[macro_export] -macro_rules! println { - () => { $crate::print!("\n") }; - ($($arg:tt)*) => { - $crate::io::__print_impl(format_args!("{}\n", format_args!($($arg)*))); - } -} diff --git a/arceos/ulib/axstd/src/net/mod.rs b/arceos/ulib/axstd/src/net/mod.rs deleted file mode 100644 index 3d789cebb..000000000 --- a/arceos/ulib/axstd/src/net/mod.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! Networking primitives for TCP/UDP communication. -//! -//! This module provides networking functionality for the Transmission Control and User -//! Datagram Protocols, as well as types for IP and socket addresses. -//! -//! # Organization -//! -//! * [`TcpListener`] and [`TcpStream`] provide functionality for communication over TCP -//! * [`UdpSocket`] provides functionality for communication over UDP -//! * [`IpAddr`] represents IP addresses of either IPv4 or IPv6; [`Ipv4Addr`] and -//! [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses -//! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`] -//! and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses -//! * [`ToSocketAddrs`] is a trait that is used for generic address resolution when interacting -//! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`] - -mod socket_addr; -mod tcp; -mod udp; - -pub use self::socket_addr::{IpAddr, Ipv4Addr, Ipv6Addr}; -pub use self::socket_addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; -pub use self::tcp::{TcpListener, TcpStream}; -pub use self::udp::UdpSocket; - -use crate::io; - -fn each_addr(addr: A, mut f: F) -> io::Result -where - F: FnMut(io::Result<&SocketAddr>) -> io::Result, -{ - let addrs = match addr.to_socket_addrs() { - Ok(addrs) => addrs, - Err(e) => return f(Err(e)), - }; - let mut last_err = None; - for addr in addrs { - match f(Ok(&addr)) { - Ok(l) => return Ok(l), - Err(e) => last_err = Some(e), - } - } - Err(last_err.unwrap_or_else(|| { - axerrno::ax_err_type!(InvalidInput, "could not resolve to any addresses") - })) -} diff --git a/arceos/ulib/axstd/src/net/socket_addr.rs b/arceos/ulib/axstd/src/net/socket_addr.rs deleted file mode 100644 index 56f7e0b4a..000000000 --- a/arceos/ulib/axstd/src/net/socket_addr.rs +++ /dev/null @@ -1,190 +0,0 @@ -extern crate alloc; - -use crate::io; -use alloc::string::String; -use core::{iter, option, slice}; - -pub use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; - -/// A trait for objects which can be converted or resolved to one or more -/// [`SocketAddr`] values. -/// -/// This trait is used for generic address resolution when constructing network -/// objects. By default it is implemented for the following types: -/// -/// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function. -/// -/// * [`SocketAddrV4`], ([IpAddr], [u16]), -/// ([Ipv4Addr], [u16]): -/// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. -/// -/// * (&[str], [u16]): &[str] should be either a string representation -/// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host -/// name. [`u16`] is the port number. -/// -/// * &[str]: the string should be either a string representation of a -/// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like -/// `:` pair where `` is a [`u16`] value. -/// -/// [`FromStr`]: core::str::FromStr -/// [`to_socket_addrs`]: ToSocketAddrs::to_socket_addrs -pub trait ToSocketAddrs { - /// Returned iterator over socket addresses which this type may correspond to. - type Iter: Iterator; - - /// Converts this object to an iterator of resolved [`SocketAddr`]s. - fn to_socket_addrs(&self) -> io::Result; -} - -impl ToSocketAddrs for SocketAddr { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - Ok(Some(*self).into_iter()) - } -} - -impl ToSocketAddrs for SocketAddrV4 { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - SocketAddr::V4(*self).to_socket_addrs() - } -} - -impl ToSocketAddrs for (IpAddr, u16) { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - let (ip, port) = *self; - SocketAddr::new(ip, port).to_socket_addrs() - } -} - -impl ToSocketAddrs for (Ipv4Addr, u16) { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - let (ip, port) = *self; - SocketAddrV4::new(ip, port).to_socket_addrs() - } -} - -impl<'a> ToSocketAddrs for &'a [SocketAddr] { - type Iter = iter::Cloned>; - - fn to_socket_addrs(&self) -> io::Result { - Ok(self.iter().cloned()) - } -} - -impl ToSocketAddrs for &T { - type Iter = T::Iter; - fn to_socket_addrs(&self) -> io::Result { - (**self).to_socket_addrs() - } -} - -#[cfg(not(feature = "dns"))] -#[doc(cfg(feature = "net"))] -mod no_dns { - use super::*; - - impl ToSocketAddrs for (&str, u16) { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - let (host, port) = *self; - Ok(host - .parse::() - .ok() - .map(|addr| { - let addr = SocketAddrV4::new(addr, port); - SocketAddr::V4(addr) - }) - .into_iter()) - } - } - - impl ToSocketAddrs for str { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - // parse as a regular SocketAddr first - Ok(self.parse().ok().into_iter()) - } - } - - impl ToSocketAddrs for (String, u16) { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - (&*self.0, self.1).to_socket_addrs() - } - } - - impl ToSocketAddrs for String { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - (**self).to_socket_addrs() - } - } -} - -#[cfg(feature = "dns")] -#[doc(cfg(feature = "net"))] -mod dns { - use super::*; - use alloc::{vec, vec::Vec}; - - impl ToSocketAddrs for (&str, u16) { - type Iter = vec::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - let (host, port) = *self; - - // try to parse the host as a regular IP address first - if let Ok(addr) = host.parse::() { - let addr = SocketAddrV4::new(addr, port); - return Ok(vec![SocketAddr::V4(addr)].into_iter()); - } - - Ok(arceos_api::net::ax_dns_query(host)? - .into_iter() - .map(|ip| SocketAddr::new(ip, port)) - .collect::>() - .into_iter()) - } - } - - impl ToSocketAddrs for str { - type Iter = vec::IntoIter; - - fn to_socket_addrs(&self) -> io::Result> { - // try to parse as a regular SocketAddr first - if let Ok(addr) = self.parse() { - return Ok(vec![addr].into_iter()); - } - - // split the string by ':' and convert the second part to u16 - let (host, port_str) = self - .rsplit_once(':') - .ok_or_else(|| axerrno::ax_err_type!(InvalidInput, "invalid socket address"))?; - let port: u16 = port_str - .parse() - .map_err(|_| axerrno::ax_err_type!(InvalidInput, "invalid port value"))?; - - Ok(arceos_api::net::ax_dns_query(host)? - .into_iter() - .map(|ip| SocketAddr::new(ip, port)) - .collect::>() - .into_iter()) - } - } - - impl ToSocketAddrs for (String, u16) { - type Iter = vec::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - (&*self.0, self.1).to_socket_addrs() - } - } - - impl ToSocketAddrs for String { - type Iter = vec::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - (**self).to_socket_addrs() - } - } -} diff --git a/arceos/ulib/axstd/src/net/tcp.rs b/arceos/ulib/axstd/src/net/tcp.rs deleted file mode 100644 index f527f1467..000000000 --- a/arceos/ulib/axstd/src/net/tcp.rs +++ /dev/null @@ -1,105 +0,0 @@ -use super::{SocketAddr, ToSocketAddrs}; -use crate::io::{self, prelude::*}; - -use arceos_api::net::{self as api, AxTcpSocketHandle}; - -/// A TCP stream between a local and a remote socket. -pub struct TcpStream(AxTcpSocketHandle); - -/// A TCP socket server, listening for connections. -pub struct TcpListener(AxTcpSocketHandle); - -impl TcpStream { - /// Opens a TCP connection to a remote host. - /// - /// `addr` is an address of the remote host. Anything which implements - /// [`ToSocketAddrs`] trait can be supplied for the address; see this trait - /// documentation for concrete examples. - /// - /// If `addr` yields multiple addresses, `connect` will be attempted with - /// each of the addresses until a connection is successful. If none of - /// the addresses result in a successful connection, the error returned from - /// the last connection attempt (the last address) is returned. - pub fn connect(addr: A) -> io::Result { - super::each_addr(addr, |addr: io::Result<&SocketAddr>| { - let addr = addr?; - let socket = api::ax_tcp_socket(); - api::ax_tcp_connect(&socket, *addr)?; - Ok(TcpStream(socket)) - }) - } - - /// Returns the socket address of the local half of this TCP connection. - pub fn local_addr(&self) -> io::Result { - api::ax_tcp_socket_addr(&self.0) - } - - /// Returns the socket address of the remote peer of this TCP connection. - pub fn peer_addr(&self) -> io::Result { - api::ax_tcp_peer_addr(&self.0) - } - - /// Shuts down the connection. - pub fn shutdown(&self) -> io::Result<()> { - api::ax_tcp_shutdown(&self.0) - } -} - -impl Read for TcpStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - api::ax_tcp_recv(&self.0, buf) - } -} - -impl Write for TcpStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - api::ax_tcp_send(&self.0, buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl TcpListener { - /// Creates a new `TcpListener` which will be bound to the specified - /// address. - /// - /// The returned listener is ready for accepting connections. - /// - /// Binding with a port number of 0 will request that the OS assigns a port - /// to this listener. The port allocated can be queried via the - /// [`TcpListener::local_addr`] method. - /// - /// The address type can be any implementor of [`ToSocketAddrs`] trait. See - /// its documentation for concrete examples. - /// - /// If `addr` yields multiple addresses, `bind` will be attempted with - /// each of the addresses until one succeeds and returns the listener. If - /// none of the addresses succeed in creating a listener, the error returned - /// from the last attempt (the last address) is returned. - pub fn bind(addr: A) -> io::Result { - super::each_addr(addr, |addr: io::Result<&SocketAddr>| { - let addr = addr?; - let backlog = 128; - let socket = api::ax_tcp_socket(); - api::ax_tcp_bind(&socket, *addr)?; - api::ax_tcp_listen(&socket, backlog)?; - Ok(TcpListener(socket)) - }) - } - - /// Returns the local socket address of this listener. - pub fn local_addr(&self) -> io::Result { - api::ax_tcp_socket_addr(&self.0) - } - - /// Accept a new incoming connection from this listener. - /// - /// This function will block the calling thread until a new TCP connection - /// is established. When established, the corresponding [`TcpStream`] and the - /// remote peer's address will be returned. - pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - api::ax_tcp_accept(&self.0).map(|(a, b)| (TcpStream(a), b)) - } -} diff --git a/arceos/ulib/axstd/src/net/udp.rs b/arceos/ulib/axstd/src/net/udp.rs deleted file mode 100644 index 65df9e8ff..000000000 --- a/arceos/ulib/axstd/src/net/udp.rs +++ /dev/null @@ -1,96 +0,0 @@ -use super::{SocketAddr, ToSocketAddrs}; -use crate::io; - -use arceos_api::net::{self as api, AxUdpSocketHandle}; - -/// A UDP socket. -pub struct UdpSocket(AxUdpSocketHandle); - -impl UdpSocket { - /// Creates a UDP socket from the given address. - /// - /// The address type can be any implementor of [`ToSocketAddrs`] trait. See - /// its documentation for concrete examples. - /// - /// If `addr` yields multiple addresses, `bind` will be attempted with - /// each of the addresses until one succeeds and returns the socket. If none - /// of the addresses succeed in creating a socket, the error returned from - /// the last attempt (the last address) is returned. - pub fn bind(addr: A) -> io::Result { - super::each_addr(addr, |addr: io::Result<&SocketAddr>| { - let addr = addr?; - let socket = api::ax_udp_socket(); - api::ax_udp_bind(&socket, *addr)?; - Ok(UdpSocket(socket)) - }) - } - - /// Returns the socket address that this socket was created from. - pub fn local_addr(&self) -> io::Result { - api::ax_udp_socket_addr(&self.0) - } - - /// Returns the socket address of the remote peer this socket was connected to. - pub fn peer_addr(&self) -> io::Result { - api::ax_udp_peer_addr(&self.0) - } - - /// Receives a single datagram message on the socket. On success, returns - /// the number of bytes read and the origin. - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - api::ax_udp_recv_from(&self.0, buf) - } - - /// Receives a single datagram message on the socket, without removing it from - /// the queue. On success, returns the number of bytes read and the origin. - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - api::ax_udp_peek_from(&self.0, buf) - } - - /// Sends data on the socket to the given address. On success, returns the - /// number of bytes written. - /// - /// Address type can be any implementor of [`ToSocketAddrs`] trait. See its - /// documentation for concrete examples. - /// - /// It is possible for `addr` to yield multiple addresses, but `send_to` - /// will only send data to the first address yielded by `addr`. - pub fn send_to(&self, buf: &[u8], addr: A) -> io::Result { - match addr.to_socket_addrs()?.next() { - Some(addr) => api::ax_udp_send_to(&self.0, buf, addr), - None => axerrno::ax_err!(InvalidInput, "no addresses to send data to"), - } - } - - /// Connects this UDP socket to a remote address, allowing the `send` and - /// `recv` syscalls to be used to send data and also applies filters to only - /// receive data from the specified address. - /// - /// If `addr` yields multiple addresses, `connect` will be attempted with - /// each of the addresses until the underlying OS function returns no - /// error. Note that usually, a successful `connect` call does not specify - /// that there is a remote server listening on the port, rather, such an - /// error would only be detected after the first send. If the OS returns an - /// error for each of the specified addresses, the error returned from the - /// last connection attempt (the last address) is returned. - pub fn connect(&self, addr: SocketAddr) -> io::Result<()> { - super::each_addr(addr, |addr: io::Result<&SocketAddr>| { - let addr = addr?; - api::ax_udp_connect(&self.0, *addr) - }) - } - - /// Sends data on the socket to the remote address to which it is connected. - /// - /// [`UdpSocket::connect`] will connect this socket to a remote address. This - /// method will fail if the socket is not connected. - pub fn send(&self, buf: &[u8]) -> io::Result { - api::ax_udp_send(&self.0, buf) - } - - /// Receives a single datagram message on the socket from the remote address to - /// which it is connected. On success, returns the number of bytes read. - pub fn recv(&self, buf: &mut [u8]) -> io::Result { - api::ax_udp_recv(&self.0, buf) - } -} diff --git a/arceos/ulib/axstd/src/os.rs b/arceos/ulib/axstd/src/os.rs deleted file mode 100644 index 4ea01aeb0..000000000 --- a/arceos/ulib/axstd/src/os.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! OS-specific functionality. - -/// ArceOS-specific definitions. -pub mod arceos { - pub use arceos_api as api; - #[doc(no_inline)] - pub use arceos_api::modules; -} diff --git a/arceos/ulib/axstd/src/process.rs b/arceos/ulib/axstd/src/process.rs deleted file mode 100644 index 28349d224..000000000 --- a/arceos/ulib/axstd/src/process.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! A module for working with processes. -//! -//! Since ArceOS is a unikernel, there is no concept of processes. The -//! process-related functions will affect the entire system, such as [`exit`] -//! will shutdown the whole system. - -/// Shutdown the whole system. -pub fn exit(_exit_code: i32) -> ! { - arceos_api::sys::ax_terminate(); -} diff --git a/arceos/ulib/axstd/src/sync/mod.rs b/arceos/ulib/axstd/src/sync/mod.rs deleted file mode 100644 index 45546e77c..000000000 --- a/arceos/ulib/axstd/src/sync/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Useful synchronization primitives. - -#[doc(no_inline)] -pub use core::sync::atomic; - -#[cfg(feature = "alloc")] -#[doc(no_inline)] -pub use alloc::sync::{Arc, Weak}; - -#[cfg(feature = "multitask")] -mod mutex; - -#[cfg(feature = "multitask")] -#[doc(cfg(feature = "multitask"))] -pub use self::mutex::{Mutex, MutexGuard}; - -#[cfg(not(feature = "multitask"))] -#[doc(cfg(not(feature = "multitask")))] -pub use kspin::{SpinRaw as Mutex, SpinRawGuard as MutexGuard}; // never used in IRQ context diff --git a/arceos/ulib/axstd/src/sync/mutex.rs b/arceos/ulib/axstd/src/sync/mutex.rs deleted file mode 100644 index 727324b74..000000000 --- a/arceos/ulib/axstd/src/sync/mutex.rs +++ /dev/null @@ -1,198 +0,0 @@ -//! A naïve sleeping mutex. - -use core::cell::UnsafeCell; -use core::fmt; -use core::ops::{Deref, DerefMut}; -use core::sync::atomic::{AtomicU64, Ordering}; - -use arceos_api::task::{self as api, AxWaitQueueHandle}; - -/// A mutual exclusion primitive useful for protecting shared data, similar to -/// [`std::sync::Mutex`](https://doc.rust-lang.org/std/sync/struct.Mutex.html). -/// -/// When the mutex is locked, the current task will block and be put into the -/// wait queue. When the mutex is unlocked, all tasks waiting on the queue -/// will be woken up. -pub struct Mutex { - wq: AxWaitQueueHandle, - owner_id: AtomicU64, - data: UnsafeCell, -} - -/// A guard that provides mutable data access. -/// -/// When the guard falls out of scope it will release the lock. -pub struct MutexGuard<'a, T: ?Sized + 'a> { - lock: &'a Mutex, - data: *mut T, -} - -// Same unsafe impls as `std::sync::Mutex` -unsafe impl Sync for Mutex {} -unsafe impl Send for Mutex {} - -impl Mutex { - /// Creates a new [`Mutex`] wrapping the supplied data. - #[inline(always)] - pub const fn new(data: T) -> Self { - Self { - wq: AxWaitQueueHandle::new(), - owner_id: AtomicU64::new(0), - data: UnsafeCell::new(data), - } - } - - /// Consumes this [`Mutex`] and unwraps the underlying data. - #[inline(always)] - pub fn into_inner(self) -> T { - // We know statically that there are no outstanding references to - // `self` so there's no need to lock. - let Mutex { data, .. } = self; - data.into_inner() - } -} - -impl Mutex { - /// Returns `true` if the lock is currently held. - /// - /// # Safety - /// - /// This function provides no synchronization guarantees and so its result should be considered 'out of date' - /// the instant it is called. Do not use it for synchronization purposes. However, it may be useful as a heuristic. - #[inline(always)] - pub fn is_locked(&self) -> bool { - self.owner_id.load(Ordering::Relaxed) != 0 - } - - /// Locks the [`Mutex`] and returns a guard that permits access to the inner data. - /// - /// The returned value may be dereferenced for data access - /// and the lock will be dropped when the guard falls out of scope. - pub fn lock(&self) -> MutexGuard { - let current_id = api::ax_current_task_id(); - loop { - // Can fail to lock even if the spinlock is not locked. May be more efficient than `try_lock` - // when called in a loop. - match self.owner_id.compare_exchange_weak( - 0, - current_id, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => break, - Err(owner_id) => { - assert_ne!( - owner_id, current_id, - "Thread({}) tried to acquire mutex it already owns.", - current_id, - ); - // Wait until the lock looks unlocked before retrying - api::ax_wait_queue_wait(&self.wq, || !self.is_locked(), None); - } - } - } - MutexGuard { - lock: self, - data: unsafe { &mut *self.data.get() }, - } - } - - /// Try to lock this [`Mutex`], returning a lock guard if successful. - #[inline(always)] - pub fn try_lock(&self) -> Option> { - let current_id = api::ax_current_task_id(); - // The reason for using a strong compare_exchange is explained here: - // https://github.com/Amanieu/parking_lot/pull/207#issuecomment-575869107 - if self - .owner_id - .compare_exchange(0, current_id, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - Some(MutexGuard { - lock: self, - data: unsafe { &mut *self.data.get() }, - }) - } else { - None - } - } - - /// Force unlock the [`Mutex`]. - /// - /// # Safety - /// - /// This is *extremely* unsafe if the lock is not held by the current - /// thread. However, this can be useful in some instances for exposing - /// the lock to FFI that doesn’t know how to deal with RAII. - pub unsafe fn force_unlock(&self) { - let owner_id = self.owner_id.swap(0, Ordering::Release); - let current_id = api::ax_current_task_id(); - assert_eq!( - owner_id, current_id, - "Thread({}) tried to release mutex it doesn't own", - current_id, - ); - // wake up one waiting thread. - api::ax_wait_queue_wake(&self.wq, 1); - } - - /// Returns a mutable reference to the underlying data. - /// - /// Since this call borrows the [`Mutex`] mutably, and a mutable reference is guaranteed to be exclusive in - /// Rust, no actual locking needs to take place -- the mutable borrow statically guarantees no locks exist. As - /// such, this is a 'zero-cost' operation. - #[inline(always)] - pub fn get_mut(&mut self) -> &mut T { - // We know statically that there are no other references to `self`, so - // there's no need to lock the inner mutex. - unsafe { &mut *self.data.get() } - } -} - -impl Default for Mutex { - #[inline(always)] - fn default() -> Self { - Self::new(Default::default()) - } -} - -impl fmt::Debug for Mutex { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.try_lock() { - Some(guard) => write!(f, "Mutex {{ data: ") - .and_then(|()| (*guard).fmt(f)) - .and_then(|()| write!(f, "}}")), - None => write!(f, "Mutex {{ }}"), - } - } -} - -impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> { - type Target = T; - #[inline(always)] - fn deref(&self) -> &T { - // We know statically that only we are referencing data - unsafe { &*self.data } - } -} - -impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> { - #[inline(always)] - fn deref_mut(&mut self) -> &mut T { - // We know statically that only we are referencing data - unsafe { &mut *self.data } - } -} - -impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { - /// The dropping of the [`MutexGuard`] will release the lock it was created from. - fn drop(&mut self) { - unsafe { self.lock.force_unlock() } - } -} diff --git a/arceos/ulib/axstd/src/thread/mod.rs b/arceos/ulib/axstd/src/thread/mod.rs deleted file mode 100644 index 1a291688e..000000000 --- a/arceos/ulib/axstd/src/thread/mod.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! Native threads. - -#[cfg(feature = "multitask")] -mod multi; -#[cfg(feature = "multitask")] -pub use multi::*; - -use arceos_api::task as api; - -/// Current thread gives up the CPU time voluntarily, and switches to another -/// ready thread. -/// -/// For single-threaded configuration (`multitask` feature is disabled), we just -/// relax the CPU and wait for incoming interrupts. -pub fn yield_now() { - api::ax_yield_now(); -} - -/// Exits the current thread. -/// -/// For single-threaded configuration (`multitask` feature is disabled), -/// it directly terminates the main thread and shutdown. -pub fn exit(exit_code: i32) -> ! { - api::ax_exit(exit_code); -} - -/// Current thread is going to sleep for the given duration. -/// -/// If one of `multitask` or `irq` features is not enabled, it uses busy-wait -/// instead. -pub fn sleep(dur: core::time::Duration) { - sleep_until(arceos_api::time::ax_wall_time() + dur); -} - -/// Current thread is going to sleep, it will be woken up at the given deadline. -/// -/// If one of `multitask` or `irq` features is not enabled, it uses busy-wait -/// instead. -pub fn sleep_until(deadline: arceos_api::time::AxTimeValue) { - api::ax_sleep_until(deadline); -} diff --git a/arceos/ulib/axstd/src/thread/multi.rs b/arceos/ulib/axstd/src/thread/multi.rs deleted file mode 100644 index 5ac8c3e5d..000000000 --- a/arceos/ulib/axstd/src/thread/multi.rs +++ /dev/null @@ -1,189 +0,0 @@ -//! Thread APIs for multi-threading configuration. - -extern crate alloc; - -use crate::io; -use alloc::{string::String, sync::Arc}; -use core::{cell::UnsafeCell, num::NonZeroU64}; - -use arceos_api::task::{self as api, AxTaskHandle}; -use axerrno::ax_err_type; - -/// A unique identifier for a running thread. -#[derive(Eq, PartialEq, Clone, Copy, Debug)] -pub struct ThreadId(NonZeroU64); - -/// A handle to a thread. -pub struct Thread { - id: ThreadId, -} - -impl ThreadId { - /// This returns a numeric identifier for the thread identified by this - /// `ThreadId`. - pub fn as_u64(&self) -> NonZeroU64 { - self.0 - } -} - -impl Thread { - fn from_id(id: u64) -> Self { - Self { - id: ThreadId(NonZeroU64::new(id).unwrap()), - } - } - - /// Gets the thread's unique identifier. - pub fn id(&self) -> ThreadId { - self.id - } -} - -/// Thread factory, which can be used in order to configure the properties of -/// a new thread. -/// -/// Methods can be chained on it in order to configure it. -#[derive(Debug)] -pub struct Builder { - // A name for the thread-to-be, for identification in panic messages - name: Option, - // The size of the stack for the spawned thread in bytes - stack_size: Option, -} - -impl Builder { - /// Generates the base configuration for spawning a thread, from which - /// configuration methods can be chained. - pub const fn new() -> Builder { - Builder { - name: None, - stack_size: None, - } - } - - /// Names the thread-to-be. - pub fn name(mut self, name: String) -> Builder { - self.name = Some(name); - self - } - - /// Sets the size of the stack (in bytes) for the new thread. - pub fn stack_size(mut self, size: usize) -> Builder { - self.stack_size = Some(size); - self - } - - /// Spawns a new thread by taking ownership of the `Builder`, and returns an - /// [`io::Result`] to its [`JoinHandle`]. - /// - /// The spawned thread may outlive the caller (unless the caller thread - /// is the main thread; the whole process is terminated when the main - /// thread finishes). The join handle can be used to block on - /// termination of the spawned thread. - pub fn spawn(self, f: F) -> io::Result> - where - F: FnOnce() -> T, - F: Send + 'static, - T: Send + 'static, - { - unsafe { self.spawn_unchecked(f) } - } - - unsafe fn spawn_unchecked(self, f: F) -> io::Result> - where - F: FnOnce() -> T, - F: Send + 'static, - T: Send + 'static, - { - let name = self.name.unwrap_or_default(); - let stack_size = self - .stack_size - .unwrap_or(arceos_api::config::TASK_STACK_SIZE); - - let my_packet = Arc::new(Packet { - result: UnsafeCell::new(None), - }); - let their_packet = my_packet.clone(); - - let main = move || { - let ret = f(); - // SAFETY: `their_packet` as been built just above and moved by the - // closure (it is an Arc<...>) and `my_packet` will be stored in the - // same `JoinHandle` as this closure meaning the mutation will be - // safe (not modify it and affect a value far away). - unsafe { *their_packet.result.get() = Some(ret) }; - drop(their_packet); - }; - - let task = api::ax_spawn(main, name, stack_size); - Ok(JoinHandle { - thread: Thread::from_id(task.id()), - native: task, - packet: my_packet, - }) - } -} - -/// Gets a handle to the thread that invokes it. -pub fn current() -> Thread { - let id = api::ax_current_task_id(); - Thread::from_id(id) -} - -/// Spawns a new thread, returning a [`JoinHandle`] for it. -/// -/// The join handle provides a [`join`] method that can be used to join the -/// spawned thread. -/// -/// The default task name is an empty string. The default thread stack size is -/// [`arceos_api::config::TASK_STACK_SIZE`]. -/// -/// [`join`]: JoinHandle::join -pub fn spawn(f: F) -> JoinHandle -where - F: FnOnce() -> T + Send + 'static, - T: Send + 'static, -{ - Builder::new().spawn(f).expect("failed to spawn thread") -} - -struct Packet { - result: UnsafeCell>, -} - -unsafe impl Sync for Packet {} - -/// An owned permission to join on a thread (block on its termination). -/// -/// A `JoinHandle` *detaches* the associated thread when it is dropped, which -/// means that there is no longer any handle to the thread and no way to `join` -/// on it. -pub struct JoinHandle { - native: AxTaskHandle, - thread: Thread, - packet: Arc>, -} - -unsafe impl Send for JoinHandle {} -unsafe impl Sync for JoinHandle {} - -impl JoinHandle { - /// Extracts a handle to the underlying thread. - pub fn thread(&self) -> &Thread { - &self.thread - } - - /// Waits for the associated thread to finish. - /// - /// This function will return immediately if the associated thread has - /// already finished. - pub fn join(mut self) -> io::Result { - api::ax_wait_for_exit(self.native).ok_or_else(|| ax_err_type!(BadState))?; - Arc::get_mut(&mut self.packet) - .unwrap() - .result - .get_mut() - .take() - .ok_or_else(|| ax_err_type!(BadState)) - } -} diff --git a/arceos/ulib/axstd/src/time.rs b/arceos/ulib/axstd/src/time.rs deleted file mode 100644 index abd041513..000000000 --- a/arceos/ulib/axstd/src/time.rs +++ /dev/null @@ -1,97 +0,0 @@ -//! Temporal quantification. - -use arceos_api::time::AxTimeValue; -use core::ops::{Add, AddAssign, Sub, SubAssign}; - -pub use core::time::Duration; - -/// A measurement of a monotonically nondecreasing clock. -/// Opaque and useful only with [`Duration`]. -#[derive(Clone, Copy)] -pub struct Instant(AxTimeValue); - -impl Instant { - /// Returns an instant corresponding to "now". - pub fn now() -> Instant { - Instant(arceos_api::time::ax_wall_time()) - } - - /// Returns the amount of time elapsed from another instant to this one, - /// or zero duration if that instant is later than this one. - /// - /// # Panics - /// - /// Previous rust versions panicked when `earlier` was later than `self`. Currently this - /// method saturates. Future versions may reintroduce the panic in some circumstances. - pub fn duration_since(&self, earlier: Instant) -> Duration { - self.0.checked_sub(earlier.0).unwrap_or_default() - } - - /// Returns the amount of time elapsed since this instant was created. - /// - /// # Panics - /// - /// Previous rust versions panicked when the current time was earlier than self. Currently this - /// method returns a Duration of zero in that case. Future versions may reintroduce the panic. - pub fn elapsed(&self) -> Duration { - Instant::now() - *self - } - - /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as - /// `Instant` (which means it's inside the bounds of the underlying data structure), `None` - /// otherwise. - pub fn checked_add(&self, duration: Duration) -> Option { - self.0.checked_add(duration).map(Instant) - } - - /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as - /// `Instant` (which means it's inside the bounds of the underlying data structure), `None` - /// otherwise. - pub fn checked_sub(&self, duration: Duration) -> Option { - self.0.checked_sub(duration).map(Instant) - } -} - -impl Add for Instant { - type Output = Instant; - - /// # Panics - /// - /// This function may panic if the resulting point in time cannot be represented by the - /// underlying data structure. - fn add(self, other: Duration) -> Instant { - self.checked_add(other) - .expect("overflow when adding duration to instant") - } -} - -impl AddAssign for Instant { - fn add_assign(&mut self, other: Duration) { - *self = *self + other; - } -} - -impl Sub for Instant { - type Output = Instant; - - fn sub(self, other: Duration) -> Instant { - self.checked_sub(other) - .expect("overflow when subtracting duration from instant") - } -} - -impl SubAssign for Instant { - fn sub_assign(&mut self, other: Duration) { - *self = *self - other; - } -} - -impl Sub for Instant { - type Output = Duration; - - /// Returns the amount of time elapsed from another instant to this one, - /// or zero duration if that instant is later than this one. - fn sub(self, other: Instant) -> Duration { - self.duration_since(other) - } -} diff --git a/arceos/update_disk.sh b/arceos/update_disk.sh deleted file mode 100755 index 28d248b64..000000000 --- a/arceos/update_disk.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -if [ $# -ne 1 ]; then - printf "Usage: ./update.sh [userapp path]\n" - exit -fi - -FILE=$1 - -if [ ! -f $FILE ]; then - printf "File '$FILE' doesn't exist!\n" - exit -fi - -if [ ! -f ./disk.img ]; then - printf "disk.img doesn't exist! Please 'make disk_img'\n" - exit -fi - -printf "Write file '$FILE' into disk.img\n" - -mkdir -p ./mnt -sudo mount ./disk.img ./mnt -sudo mkdir -p ./mnt/sbin -sudo cp $FILE ./mnt/sbin -sudo umount ./mnt -rm -rf mnt