32 Commits
v0.3.0 ... vdso

Author SHA1 Message Date
Justin C. Miller
dd73cf833f Change initrd 'executable' bool to type enum. 2019-10-10 23:09:40 -07:00
Justin C. Miller
71fe3d733b Add the VDSO to the initrd 2019-10-10 00:14:46 -07:00
Justin C. Miller
991b13424e Initial building of the vdso.
Not actually integrating with the kernel yet.
2019-10-09 22:29:45 -07:00
Justin C. Miller
6963304c01 Changing jsix license
jsix is now licensed under the MPL2.
2019-10-06 01:37:46 -07:00
Justin C. Miller
ae651a4fcd Move cpptoml.h to external directory 2019-10-06 00:46:30 -07:00
Justin C. Miller
17c2fe6e4e Add debig-exit device to qemu.sh for future tests 2019-10-06 00:29:10 -07:00
Justin C. Miller
f066ac3ffd Move catch.hpp to external directory 2019-10-06 00:01:27 -07:00
Justin C. Miller
edcf633e84 Remove cargo-culted znocombreloc ld flag 2019-08-10 13:49:57 -07:00
Justin C. Miller
d09a454b8b Normalize bootloader's con_debug line endings 2019-07-21 22:29:19 -07:00
Justin C. Miller
d6329ea9bf Update to bonnibel 2.1 2019-07-21 21:10:43 -07:00
Justin C. Miller
83897048ab Update for bonnibel 2.0 2019-07-20 23:19:21 -07:00
Justin C. Miller
7cc59770b8 Update libc for new sysall values via peru 2019-07-07 10:07:00 -07:00
Justin C. Miller
b056d95920 Organize system calls
* syscalls should all return j6_status_t now
* syscalls are grouped by category in name as well as in files
2019-07-07 09:54:29 -07:00
Justin C. Miller
19cd01ef8d Add initial pass of syscall API kobjects 2019-07-07 09:54:29 -07:00
Justin C. Miller
b3f88bbe02 Further refine sysroot.
* remove need for NASM from sysroot
* have peru sync libc separately
2019-07-07 09:52:06 -07:00
Justin C. Miller
f57f38edbd Remove old ident_page_flags 2019-07-05 20:52:04 -07:00
Justin C. Miller
12377ae730 Ignore .peru 2019-07-05 17:29:56 -07:00
Justin C. Miller
bb93dcef44 Remove sysroot binutils dependency
* Link host-targeted binaries with lld
 * Add peru script for getting prebuilt sysroot
 * Add readme for prebuilt sysroots
 * Remove non-working build_sysroot_gcc.sh, rename clang version to just
   build_sysroot.sh
2019-07-05 17:26:24 -07:00
Justin C. Miller
678a12dc90 Ignore .gdb_history 2019-07-04 17:43:42 -07:00
Justin C. Miller
c3dacb2906 Fix mis-flagged page table entries 2019-07-04 17:43:08 -07:00
Justin C. Miller
3a68ec439d Add CPU feature checking.
Introduces the cpu_features.inc table to enumerate the CPU features that
j6 cares about. Features in this table marked CPU_FEATURE_REQ are
considered required, and the boot process will log an error and halt
when any of these features are not supported. This should save me from
banging my head against the wall like I did last night with the missing
pdpe1gb feature.
2019-07-04 16:41:25 -07:00
Justin C. Miller
7ce418aabc Fix KVM page faults from lack of 1GB page support 2019-07-04 02:51:50 -07:00
Justin C. Miller
8ee5091f41 update gitignore 2019-07-03 21:55:23 -07:00
Justin C. Miller
6285517ef7 Rename Popcorn to jsix.
See README.md for more information.
2019-05-27 14:07:29 -07:00
Justin C. Miller
2b0cd6f2f2 Make qemu.sh work with i3 as well 2019-05-26 10:35:22 -07:00
Justin C. Miller
a653c55941 Use 0 instead of syscall_invalid in syscall jump list 2019-05-18 18:11:08 -07:00
Justin C. Miller
ce035d2a43 Finish address_manager to vm_space transition 2019-05-18 18:06:57 -07:00
Justin C. Miller
2d54eb5143 Add vmem log area 2019-05-11 11:32:22 -07:00
Justin C. Miller
b9c8edb657 Allow clang to colorize output in ninja 2019-04-18 00:28:23 -07:00
Justin C. Miller
88315c25a5 Allow vm_space to merge ranges 2019-04-18 00:22:01 -07:00
Justin C. Miller
806bfd1fbf First pass at vm_space (address_manager replacement) 2019-04-17 19:16:54 -07:00
Justin C. Miller
910b5116f4 Fix stack overruns 2019-04-16 23:39:52 -07:00
87 changed files with 7928 additions and 2408 deletions

4
.gitignore vendored
View File

@@ -2,7 +2,9 @@
/build*
*.bak
tags
popcorn.log
jsix.log
*.o
*.a
sysroot
.gdb_history
.peru

View File

@@ -1,150 +1,354 @@
# Popcorn
# License
Popcorn itself is released under the terms of the MIT license:
jsix is (c) 2017-2019 Justin C Miller, and distributed under the terms of the
Mozilla Public License 2.0.
> Copyright © 2018 Justin C. Miller, https://devjustinian.com
> <justin@devjustinian.com>
>
> 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.
---
# Included works
## Mozilla Public License Version 2.0
Popcorn includes and/or is derived from a number of other works, listed here.
### 1. Definitions
## Catch2
#### 1.1. "Contributor"
Popcorn uses [Catch2](https://github.com/catchorg/Catch2) for testing. Catch2 is
released under the terms of the Boost Software license:
means each individual or legal entity that creates, contributes to the creation
of, or owns Covered Software.
> Boost Software License - Version 1.0 - August 17th, 2003
>
> Permission is hereby granted, free of charge, to any person or organization
> obtaining a copy of the software and accompanying documentation covered by
> this license (the "Software") to use, reproduce, display, distribute,
> execute, and transmit the Software, and to prepare derivative works of the
> Software, and to permit third-parties to whom the Software is furnished to
> do so, all subject to the following:
>
> The copyright notices in the Software and this entire statement, including
> the above license grant, this restriction and the following disclaimer,
> must be included in all copies of the Software, in whole or in part, and
> all derivative works of the Software, unless such copies or derivative
> works are solely in the form of machine-executable object code generated by
> a source language processor.
>
> 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
> SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
> FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
> ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> DEALINGS IN THE SOFTWARE.
#### 1.2. "Contributor Version"
## cpptoml
means the combination of the Contributions of others (if any) used by a
Contributor and that particular Contributor's Contribution.
Popcorn uses the [cpptoml](https://github.com/skystrife/cpptoml) library for
parsing TOML configuration files. cpptoml is released under the terms of the
MIT license:
#### 1.3. "Contribution
> Copyright (c) 2014 Chase Geigle
>
> 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.
means Covered Software of a particular Contributor.
## printf
#### 1.4. "Covered Software"
Popcorn uses 's tiny [printf](https://github.com/mpaland/printf) library for its
`*printf()` functions, which is also released under the terms of the MIT license:
means Source Code Form to which the initial Contributor has attached the notice
in Exhibit A, the Executable Form of such Source Code Form, and Modifications
of such Source Code Form, in each case including portions thereof.
> The MIT License (MIT)
>
> Copyright (c) 2014 Marco Paland
>
> 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.
#### 1.5. "Incompatible With Secondary Licenses"
## GNU-EFI
means
Popcorn's UEFI bootloader initially used
[GNU-EFI](https://gnu-efi.sourceforge.net), and still uses one file (the linker
script for the bootloader) from that project. GNU-EFI claims to be released
under the BSD license. Again, I could not find its specific license file, so I
am reproducing a generic 3-clause BSD license (the most restrictive, so as not
to assume any extra rights that may not actually be granted) for it here:
* **(a)** that the initial Contributor has attached the notice described in
Exhibit B to the Covered Software; or
* **(b)** that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the terms of a
Secondary License.
> Copyright © Nigel Croxon
>
> Redistribution and use in source and binary forms, with or without
> modification, are permitted provided that the following conditions are met:
>
> 1. Redistributions of source code must retain the above copyright notice, this
> list of conditions and the following disclaimer.
>
> 2. Redistributions in binary form must reproduce the above copyright notice,
> this list of conditions and the following disclaimer in the documentation
> and/or other materials provided with the distribution.
>
> 3. Neither the name of the copyright holder nor the names of its contributors
> may be used to endorse or promote products derived from this software
> without specific prior written permission.
>
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
> ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
> WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#### 1.6. "Executable Form"
## Intel EFI Application Toolkit
means any form of the work other than Source Code Form.
#### 1.7. "Larger Work"
means a work that combines Covered Software with other material, in a separate
file or files, that is not Covered Software.
#### 1.8. "License"
means this document.
#### 1.9. "Licensable"
means having the right to grant, to the maximum extent possible, whether at the
time of the initial grant or subsequently, any and all of the rights conveyed
by this License.
#### 1.10. "Modifications"
means any of the following:
* **(a)** any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered Software; or
* **(b)** any new file in Source Code Form that contains any Covered Software.
#### 1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method, process, and
apparatus claims, in any patent Licensable by such Contributor that would be
infringed, but for the grant of the License, by the making, using, selling,
offering for sale, having made, import, or transfer of either its Contributions
or its Contributor Version.
#### 1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU Lesser
General Public License, Version 2.1, the GNU Affero General Public License,
Version 3.0, or any later versions of those licenses.
#### 1.13. "Source Code Form"
means the form of the work preferred for making modifications.
#### 1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this License. For
legal entities, "You" includes any entity that controls, is controlled by, or
is under common control with You. For purposes of this definition, "control"
means **(a)** the power, direct or indirect, to cause the direction or
management of such entity, whether by contract or otherwise, or **(b)**
ownership of more than fifty percent (50%) of the outstanding shares or
beneficial ownership of such entity.
### 2. License Grants and Conditions
#### 2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive
license:
* **(a)** under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available, modify,
display, perform, distribute, and otherwise exploit its Contributions, either
on an unmodified basis, with Modifications, or as part of a Larger Work; and
* **(b)** under Patent Claims of such Contributor to make, use, sell, offer for
sale, have made, import, and otherwise transfer either its Contributions or
its Contributor Version.
#### 2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution become
effective for each Contribution on the date the Contributor first distributes
such Contribution.
#### 2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under this
License. No additional rights or licenses will be implied from the distribution
or licensing of Covered Software under this License. Notwithstanding Section
2.1(b) above, no patent license is granted by a Contributor:
* **(a)** for any code that a Contributor has removed from Covered Software; or
* **(b)** for infringements caused by: **(i)** Your and any other third party's
modifications of Covered Software, or **(ii)** the combination of its
Contributions with other software (except as part of its Contributor
Version); or
* **(c)** under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks, or
logos of any Contributor (except as may be necessary to comply with the notice
requirements in Section 3.4).
#### 2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to distribute
the Covered Software under a subsequent version of this License (see Section
10.2) or under the terms of a Secondary License (if permitted under the terms
of Section 3.3).
#### 2.5. Representation
Each Contributor represents that the Contributor believes its Contributions are
its original creation(s) or it has sufficient rights to grant the rights to its
Contributions conveyed by this License.
#### 2.6. Fair Use
This License is not intended to limit any rights You have under applicable
copyright doctrines of fair use, fair dealing, or other equivalents.
#### 2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
Section 2.1.
### 3. Responsibilities
#### 3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under the
terms of this License. You must inform recipients that the Source Code Form of
the Covered Software is governed by the terms of this License, and how they can
obtain a copy of this License. You may not attempt to alter or restrict the
recipients' rights in the Source Code Form.
#### 3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
* **(a)** such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of the
Executable Form how they can obtain a copy of such Source Code Form by
reasonable means in a timely manner, at a charge no more than the cost of
distribution to the recipient; and
* **(b)** You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the license
for the Executable Form does not attempt to limit or alter the recipients'
rights in the Source Code Form under this License.
#### 3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for the
Covered Software. If the Larger Work is a combination of Covered Software with
a work governed by one or more Secondary Licenses, and the Covered Software is
not Incompatible With Secondary Licenses, this License permits You to
additionally distribute such Covered Software under the terms of such Secondary
License(s), so that the recipient of the Larger Work may, at their option,
further distribute the Covered Software under the terms of either this License
or such Secondary License(s).
#### 3.4. Notices
You may not remove or alter the substance of any license notices (including
copyright notices, patent notices, disclaimers of warranty, or limitations of
liability) contained within the Source Code Form of the Covered Software,
except that You may alter any license notices to the extent required to remedy
known factual inaccuracies.
#### 3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support, indemnity
or liability obligations to one or more recipients of Covered Software.
However, You may do so only on Your own behalf, and not on behalf of any
Contributor. You must make it absolutely clear that any such warranty, support,
indemnity, or liability obligation is offered by You alone, and You hereby
agree to indemnify every Contributor for any liability incurred by such
Contributor as a result of warranty, support, indemnity or liability terms You
offer. You may include additional disclaimers of warranty and limitations of
liability specific to any jurisdiction.
### 4. Inability to Comply Due to Statute or Regulation
If it is impossible for You to comply with any of the terms of this License
with respect to some or all of the Covered Software due to statute, judicial
order, or regulation then You must: **(a)** comply with the terms of this
License to the maximum extent possible; and **(b)** describe the limitations
and the code they affect. Such description must be placed in a text file
included with all distributions of the Covered Software under this License.
Except to the extent prohibited by statute or regulation, such description must
be sufficiently detailed for a recipient of ordinary skill to be able to
understand it.
### 5. Termination
**5.1.** The rights granted under this License will terminate automatically if
You fail to comply with any of its terms. However, if You become compliant,
then the rights granted under this License from a particular Contributor are
reinstated **(a)** provisionally, unless and until such Contributor explicitly
and finally terminates Your grants, and **(b)** on an ongoing basis, if such
Contributor fails to notify You of the non-compliance by some reasonable means
prior to 60 days after You have come back into compliance. Moreover, Your
grants from a particular Contributor are reinstated on an ongoing basis if such
Contributor notifies You of the non-compliance by some reasonable means, this
is the first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after Your
receipt of the notice.
**5.2.** If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions, counter-claims, and
cross-claims) alleging that a Contributor Version directly or indirectly
infringes any patent, then the rights granted to You by any and all
Contributors for the Covered Software under Section 2.1 of this License shall
terminate.
**5.3.** In the event of termination under Sections 5.1 or 5.2 above, all end
user license agreements (excluding distributors and resellers) which have been
validly granted by You or Your distributors under this License prior to
termination shall survive termination.
### 6. Disclaimer of Warranty
> Covered Software is provided under this License on an "as is" basis, without
> warranty of any kind, either expressed, implied, or statutory, including,
> without limitation, warranties that the Covered Software is free of defects,
> merchantable, fit for a particular purpose or non-infringing. The entire risk
> as to the quality and performance of the Covered Software is with You.
> Should any Covered Software prove defective in any respect, You (not any
> Contributor) assume the cost of any necessary servicing, repair, or
> correction. This disclaimer of warranty constitutes an essential part of this
> License. No use of any Covered Software is authorized under this License
> except under this disclaimer.
### 7. Limitation of Liability
> Under no circumstances and under no legal theory, whether tort (including
> negligence), contract, or otherwise, shall any Contributor, or anyone who
> distributes Covered Software as permitted above, be liable to You for any
> direct, indirect, special, incidental, or consequential damages of any
> character including, without limitation, damages for lost profits, loss of
> goodwill, work stoppage, computer failure or malfunction, or any and all
> other commercial damages or losses, even if such party shall have been
> informed of the possibility of such damages. This limitation of liability
> shall not apply to liability for death or personal injury resulting from such
> party's negligence to the extent applicable law prohibits such limitation.
> Some jurisdictions do not allow the exclusion or limitation of incidental or
> consequential damages, so this exclusion and limitation may not apply to You.
### 8. Litigation
Any litigation relating to this License may be brought only in the courts of a
jurisdiction where the defendant maintains its principal place of business and
such litigation shall be governed by laws of that jurisdiction, without
reference to its conflict-of-law provisions. Nothing in this Section shall
prevent a party's ability to bring cross-claims or counter-claims.
### 9. Miscellaneous
This License represents the complete agreement concerning the subject matter
hereof. If any provision of this License is held to be unenforceable, such
provision shall be reformed only to the extent necessary to make it
enforceable. Any law or regulation which provides that the language of a
contract shall be construed against the drafter shall not be used to construe
this License against a Contributor.
### 10. Versions of the License
#### 10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section 10.3,
no one other than the license steward has the right to modify or publish new
versions of this License. Each version will be given a distinguishing version
number.
#### 10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version of the
License under which You originally received the Covered Software, or under the
terms of any subsequent version published by the license steward.
#### 10.3. Modified Versions
If you create software not governed by this License, and you want to create a
new license for such software, you may create and use a modified version of
this License if you rename the license and remove any references to the name of
the license steward (except to note that such modified license differs from
this License).
#### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the notice
described in Exhibit B of this License must be attached.
### Exhibit A - Source Code Form License Notice
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this file,
You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file, then
You may include the notice in a location (such as a LICENSE file in a relevant
directory) where a recipient would be likely to look for such a notice.
You may add additional accurate notices of copyright ownership.
### Exhibit B - "Incompatible With Secondary Licenses" Notice
This Source Code Form is "Incompatible With Secondary Licenses", as defined
by the Mozilla Public License, v. 2.0.
Popcorn's UEFI loader uses code from Intel's EFI Application toolkit. Relevant
code includes license statements at the top of each file.

View File

@@ -1,6 +1,6 @@
# popcorn: A toy OS kernel
# jsix: A toy OS kernel
**popcorn** is the kernel for the hobby OS that I am currently building. It's
**jsix** is the kernel for the hobby OS that I am currently building. It's
far from finished, or even being usable. Instead, it's a sandbox for me to play
with kernel-level code and explore architectures.
@@ -25,47 +25,54 @@ The design goals of the project are:
temporarily) in some places to allow me to play around with the related
hardware.
A note on the name: This kernel was originally named Popcorn, but I have since
discovered that the Popcorn Linux project is also developing a kernel with that
name, started around the same time as this project. So I've renamed this kernel
jsix (Always styled _jsix_ or `j6`, never capitalized) as an homage to L4, xv6,
and my wonderful wife.
## Building
Popcorn uses the [Ninja][] build tool, and generates the build files for it
with a custom tool called [Bonnibel][]. Bonnibel requires [Python 3][] and can
be downloaded with `pip`:
```
pip3 install bonnibel
```
jsix uses the [Ninja][] build tool, and generates the build files for it with a
custom tool called [Bonnibel][]. Bonnibel can be installed with [Cargo][], or
downloaded as a prebuilt binary from its Github repository.
[Ninja]: https://ninja-build.org
[Bonnibel]: https://github.com/justinian/bonnibel
[Python 3]: https://python.org
[Cargo]: https://crates.io/crates/bonnibel
Requrirements:
* python 3 (for installing and running Bonnibel)
* clang
* mtools
* bonnibel
* ninja
* clang
* nasm
* mtools
* curl for downloading the toolchain
### Setting up the cross toolchain
If you have `clang` and `curl` installed, runing the `scripts/build_sysroot_clang.sh`
script will download and build a nasm/binutils/LLVM toolchain configured for building
Popcorn host binaries.
Running `pb sync` will download and unpack the toolchain into `sysroot`.
### Building and running Popcorn
#### Compiling the toolchain yourself
Once the toolchain has been set up, running Bonnibel's `pb` command will set up the
build configuration, and `ninja -C build` will actually run the build. If you
have `qemu-system-x86_64` installed, the `qemu.sh` script will to run Popcorn
If you have `clang` and `curl` installed, runing the `scripts/build_sysroot.sh`
script will download and build a LLVM toolchain configured for building jsix
host binaries.
### Building and running jsix
Once the toolchain has been set up, running Bonnibel's `pb init` command will
set up the build configuration, and `pb build` will actually run the build. If
you have `qemu-system-x86_64` installed, the `qemu.sh` script will to run jsix
in QEMU `-nographic` mode.
I personally run this either from a real debian amd64 testing/buster machine or
a windows WSL debian testing/buster installation. The following should be
enough to set up such a system to build the kernel:
sudo apt install qemu-system-x86 nasm clang-6.0 mtools python3-pip curl
sudo apt install qemu-system-x86 nasm clang-6.0 mtools curl
sudo update-alternatives /usr/bin/clang clang /usr/bin/clang-6.0 1000
sudo update-alternatives /usr/bin/clang++ clang++ /usr/bin/clang++-6.0 1000
sudo pip3 install bonnibel
curl -L -o pb https://github.com/justinian/bonnibel/releases/download/2.0.0/pb_linux_amd64 && chmod a+x pb

View File

@@ -8,6 +8,11 @@
# # initial application for the kernel to execute
# # on startup
[[files]]
dest = "vdso.so"
source = "host/libvdso.so"
type = "vdso"
[[files]]
dest = "screenfont.psf"
source = "../assets/fonts/tamsyn8x16r.psf"
@@ -15,9 +20,9 @@ source = "../assets/fonts/tamsyn8x16r.psf"
[[files]]
dest = "nulldrv1"
source = "user/nulldrv"
executable = true
type = "executable"
[[files]]
dest = "nulldrv2"
source = "user/nulldrv"
executable = true
type = "executable"

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,15 @@
name: Popcorn
name: jsix
templates: scripts/templates
modules:
kernel:
output: popcorn.elf
kind: exe
output: jsix.elf
target: host
deps:
- elf
- initrd
- kutil
- vdso
includes:
- src/kernel
source:
@@ -34,6 +36,8 @@ modules:
- src/kernel/main.cpp
- src/kernel/memory_bootstrap.cpp
- src/kernel/msr.cpp
- src/kernel/objects/handle.cpp
- src/kernel/objects/kobject.cpp
- src/kernel/page_manager.cpp
- src/kernel/pci.cpp
- src/kernel/process.cpp
@@ -42,13 +46,8 @@ modules:
- src/kernel/serial.cpp
- src/kernel/syscall.cpp
- src/kernel/syscall.s
- src/kernel/syscalls/exit.cpp
- src/kernel/syscalls/fork.cpp
- src/kernel/syscalls/getpid.cpp
- src/kernel/syscalls/message.cpp
- src/kernel/syscalls/noop.cpp
- src/kernel/syscalls/pause.cpp
- src/kernel/syscalls/sleep.cpp
- src/kernel/syscalls/object.cpp
- src/kernel/syscalls/process.cpp
- src/kernel/task.s
- src/kernel/crtn.s
@@ -66,6 +65,16 @@ modules:
- src/boot/reloc.cpp
- src/boot/utility.cpp
vdso:
kind: exe
target: host
output: libvdso.so
extra:
- src/arch/x86_64/vdso.ld
source:
- src/vdso/syscalls.cpp
- src/vdso/overrides.cpp
nulldrv:
kind: exe
target: user
@@ -106,6 +115,7 @@ modules:
- src/libraries/kutil/logger.cpp
- src/libraries/kutil/memory.cpp
- src/libraries/kutil/printf.c
- src/libraries/kutil/vm_space.cpp
makerd:
kind: exe
@@ -130,3 +140,8 @@ modules:
- src/tests/logger.cpp
- src/tests/heap_allocator.cpp
- src/tests/main.cpp
overlays:
- url: https://f000.backblazeb2.com/file/jsix-os/sysroot-llvm8-20190706.tar.bz2
path: sysroot
- url: https://f000.backblazeb2.com/file/jsix-os/sysroot-j6libc-8cb8ce7.tar.bz2
path: sysroot

132
other_software.md Normal file
View File

@@ -0,0 +1,132 @@
# Included works
jsix includes and/or is derived from a number of other works, listed here.
## Catch2
jsix uses [Catch2][] for testing. Catch2 is released under the terms of the
Boost Software license:
[Catch2]: https://github.com/catchorg/Catch2
> Boost Software License - Version 1.0 - August 17th, 2003
>
> Permission is hereby granted, free of charge, to any person or organization
> obtaining a copy of the software and accompanying documentation covered by
> this license (the "Software") to use, reproduce, display, distribute,
> execute, and transmit the Software, and to prepare derivative works of the
> Software, and to permit third-parties to whom the Software is furnished to
> do so, all subject to the following:
>
> The copyright notices in the Software and this entire statement, including
> the above license grant, this restriction and the following disclaimer,
> must be included in all copies of the Software, in whole or in part, and
> all derivative works of the Software, unless such copies or derivative
> works are solely in the form of machine-executable object code generated by
> a source language processor.
>
> 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
> SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
> FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
> ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> DEALINGS IN THE SOFTWARE.
## cpptoml
jsix uses the [cpptoml][] library for parsing TOML configuration files. cpptoml
is released under the terms of the MIT license:
[cpptoml]: https://github.com/skystrife/cpptoml
> Copyright (c) 2014 Chase Geigle
>
> 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.
## printf
jsix uses Marco Paland's tiny [printf][] library for its `*printf()` functions,
which is also released under the terms of the MIT license:
[printf]: https://github.com/mpaland/printf
> The MIT License (MIT)
>
> Copyright (c) 2014 Marco Paland
>
> 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.
## GNU-EFI
jsix's UEFI bootloader initially used [GNU-EFI][], and still uses one file (the
linker script for the bootloader) from that project. GNU-EFI claims to be
released under the BSD license. Again, I could not find its specific license
file, so I am reproducing a generic 3-clause BSD license (the most restrictive,
so as not to assume any extra rights that may not actually be granted) for it
here:
[GNU-EFI]: https://gnu-efi.sourceforge.net
> Copyright (c) Nigel Croxon
>
> Redistribution and use in source and binary forms, with or without
> modification, are permitted provided that the following conditions are met:
>
> 1. Redistributions of source code must retain the above copyright notice, this
> list of conditions and the following disclaimer.
>
> 2. Redistributions in binary form must reproduce the above copyright notice,
> this list of conditions and the following disclaimer in the documentation
> and/or other materials provided with the distribution.
>
> 3. Neither the name of the copyright holder nor the names of its contributors
> may be used to endorse or promote products derived from this software
> without specific prior written permission.
>
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
> ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
> WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## Intel EFI Application Toolkit
jsix's UEFI loader uses code from Intel's EFI Application toolkit. Relevant
code includes license statements at the top of each file.

17
qemu.sh
View File

@@ -6,6 +6,7 @@ debug=""
flash_name="ovmf_vars"
gfx="-nographic"
kvm=""
cpu="Broadwell,+pdpe1gb"
for arg in $@; do
case "${arg}" in
@@ -18,6 +19,7 @@ for arg in $@; do
;;
--kvm)
kvm="-enable-kvm"
cpu="host"
;;
*)
build="${arg}"
@@ -35,22 +37,29 @@ fi
if [[ -n $TMUX ]]; then
if [[ -n $debug ]]; then
tmux split-window "gdb ${build}/popcorn.elf" &
tmux split-window "gdb ${build}/jsix.elf" &
else
tmux split-window -l 10 "sleep 1; telnet localhost 45454" &
fi
elif [[ $DESKTOP_SESSION = "i3" ]]; then
if [[ -n $debug ]]; then
i3-msg exec i3-sensible-terminal -- -e "gdb ${PWD}/${build}/jsix.elf" &
else
i3-msg exec i3-sensible-terminal -- -e 'telnet localhost 45454' &
fi
fi
exec qemu-system-x86_64 \
-drive "if=pflash,format=raw,readonly,file=${assets}/ovmf/x64/ovmf_code.fd" \
-drive "if=pflash,format=raw,file=${build}/${flash_name}.fd" \
-drive "format=raw,file=${build}/popcorn.img" \
-drive "format=raw,file=${build}/jsix.img" \
-device "isa-debug-exit,iobase=0xf4,iosize=0x04" \
-monitor telnet:localhost:45454,server,nowait \
-smp 4 \
-m 512 \
-d mmu,int,guest_errors \
-D popcorn.log \
-cpu Broadwell \
-D jsix.log \
-cpu "${cpu}" \
-M q35 \
-no-reboot \
$gfx $kvm $debug

131
scripts/build_sysroot.sh Executable file
View File

@@ -0,0 +1,131 @@
#!/usr/bin/env bash
TARGET="x86_64-elf"
LLVM_BRANCH="release_80"
TOOLS="clang lld" # lld libunwind libcxxabi libcxx"
PROJECTS="compiler-rt libcxxabi libcxx libunwind"
#RUNTIMES="compiler-rt libcxxabi libcxx libunwind"
set -e
README=$(realpath "$(dirname $0)/readme_for_prebuilt_sysroots.md")
SYSROOT=$(realpath "$(dirname $0)/../sysroot")
WORK=$(realpath "$(dirname $0)/sysroot")
mkdir -p "${SYSROOT}"
mkdir -p "${WORK}"
export CC=clang
export CXX=clang++
if [[ ! -d "${WORK}/llvm" ]]; then
echo "Downloading LLVM..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/llvm.git" "${WORK}/llvm"
fi
for tool in ${TOOLS}; do
if [[ ! -d "${WORK}/llvm/tools/${tool}" ]]; then
echo "Downloading ${tool}..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/${tool}.git" "${WORK}/llvm/tools/${tool}"
fi
done
if [[ ! -d "${WORK}/llvm/tools/clang/tools/extra" ]]; then
echo "Downloading clang-tools-extra..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/clang-tools-extra.git" "${WORK}/llvm/tools/clang/tools/extra"
fi
for proj in ${PROJECTS}; do
if [[ ! -d "${WORK}/llvm/projects/${proj}" ]]; then
echo "Downloading ${proj}..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/${proj}.git" "${WORK}/llvm/projects/${proj}"
fi
done
for proj in ${RUNTIMES}; do
if [[ ! -d "${WORK}/llvm/runtimes/${proj}" ]]; then
echo "Downloading ${proj}..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/${proj}.git" "${WORK}/llvm/runtime/${proj}"
fi
done
mkdir -p "${WORK}/build/llvm"
pushd "${WORK}/build/llvm"
echo "Configuring LLVM..."
cmake -G Ninja \
-DCLANG_DEFAULT_RTLIB=compiler-rt \
-DCLANG_DEFAULT_STD_C=c11 \
-DCLANG_DEFAULT_STD_CXX=cxx14 \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER="clang" \
-DCMAKE_CXX_COMPILER="clang++" \
-DCMAKE_CXX_FLAGS="-Wno-unused-parameter -D_LIBCPP_HAS_NO_ALIGNED_ALLOCATION -D_LIBUNWIND_IS_BAREMETAL=1 -U_LIBUNWIND_SUPPORT_DWARF_UNWIND" \
-DCMAKE_INSTALL_PREFIX="${SYSROOT}" \
-DCMAKE_MAKE_PROGRAM=`which ninja` \
-DDEFAULT_SYSROOT="${SYSROOT}" \
-DLIBCXX_CXX_ABI=libcxxabi \
-DLIBCXX_CXX_ABI_INCLUDE_PATHS="${WORK}/llvm/projects/libcxxabi/include" \
-DLIBCXX_CXX_ABI_LIBRARY_PATH=lib \
-DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=OFF \
-DLIBCXX_ENABLE_NEW_DELETE_DEFINITIONS=ON \
-DLIBCXX_ENABLE_SHARED=OFF \
-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON \
-DLIBCXX_ENABLE_THREADS=OFF \
-DLIBCXX_INCLUDE_BENCHMARKS=OFF \
-DLIBCXX_USE_COMPILER_RT=ON \
-DLIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS=OFF \
-DLIBCXXABI_ENABLE_SHARED=OFF \
-DLIBCXXABI_ENABLE_STATIC_UNWINDER=ON \
-DLIBCXXABI_ENABLE_THREADS=OFF \
-DLIBCXXABI_LIBCXX_PATH="${WORK}/llvm/projects/libcxx" \
-DLIBCXXABI_USE_COMPILER_RT=ON \
-DLIBCXXABI_USE_LLVM_UNWINDER=ON \
-DLIBUNWIND_ENABLE_SHARED=OFF \
-DLIBUNWIND_ENABLE_THREADS=OFF \
-DLIBUNWIND_USE_COMPILER_RT=ON \
-DLLVM_CONFIG_PATH="${SYSROOT}/bin/llvm-config" \
-DLLVM_DEFAULT_TARGET_TRIPLE="x86_64-unknown-elf" \
-DLLVM_ENABLE_LIBCXX=ON \
-DLLVM_ENABLE_LLD=ON \
-DLLVM_ENABLE_PIC=OFF \
-DLLVM_ENABLE_THREADS=OFF \
-DLLVM_INSTALL_BINUTILS_SYMLINKS=ON \
-DLLVM_TARGETS_TO_BUILD="X86" \
${WORK}/llvm > cmake_configure.log
# -DCMAKE_ASM_COMPILER=nasm \
# -DCMAKE_LINKER="${SYSROOT}/bin/ld.lld" \
# -DCOMPILER_RT_ENABLE_LLD=ON \
# -DLIBCXX_ENABLE_LLD=ON \
# -DLIBCXX_ENABLE_STATIC_UNWINDER=ON \
# -DLIBCXXABI_ENABLE_LLD=ON \
# -DLIBUNWIND_ENABLE_LLD=ON \
# -DLLVM_ENABLE_PROJECTS="libcxx;libcxxabi;libunwind;compiler-rt" \
# -DCOMPILER_RT_BAREMETAL_BUILD=ON \
# -DLIBCXXABI_BAREMETAL=ON \
echo "Building LLVM..."
ninja && ninja install
ninja cxx cxxabi compiler-rt
ninja install-compiler-rt install-cxx install-cxxabi
popd
cp "${README}" "${SYSROOT}/README.md"

View File

@@ -1,221 +0,0 @@
#!/usr/bin/env bash
TARGET="x86_64-elf"
NASM_VERSION="2.13.03"
BINUTILS_VERSION="2.31.1"
LLVM_BRANCH="release_80"
TOOLS="clang" # lld libunwind libcxxabi libcxx"
PROJECTS="compiler-rt libcxxabi libcxx libunwind"
#RUNTIMES="compiler-rt libcxxabi libcxx libunwind"
set -e
SYSROOT=$(realpath "$(dirname $0)/../sysroot")
WORK=$(realpath "$(dirname $0)/sysroot")
mkdir -p "${SYSROOT}"
mkdir -p "${WORK}"
export CC=clang
export CXX=clang++
function build_nasm() {
if [[ ! -d "${WORK}/nasm-${NASM_VERSION}" ]]; then
echo "Downloading NASM..."
tarball="nasm-${NASM_VERSION}.tar.gz"
curl -sSOL "https://www.nasm.us/pub/nasm/releasebuilds/${NASM_VERSION}/${tarball}"
tar xzf "${tarball}" -C "${WORK}" && rm "${tarball}"
fi
mkdir -p "${WORK}/build/nasm"
pushd "${WORK}/build/nasm"
if [[ ! -f "${WORK}/build/nasm/config.cache" ]]; then
echo "Configuring NASM..."
"${WORK}/nasm-${NASM_VERSION}/configure" \
--quiet \
--config-cache \
--disable-werror \
--prefix="${SYSROOT}" \
--srcdir="${WORK}/nasm-${NASM_VERSION}"
fi
echo "Building NASM..."
(make -j && make install) > "${WORK}/build/nasm_build.log"
popd
}
function build_binutils() {
if [[ ! -d "${WORK}/binutils-${BINUTILS_VERSION}" ]]; then
echo "Downloading binutils..."
tarball="binutils-${BINUTILS_VERSION}.tar.gz"
curl -sSOL "https://ftp.gnu.org/gnu/binutils/${tarball}"
tar xzf "${tarball}" -C "${WORK}" && rm "${tarball}"
fi
mkdir -p "${WORK}/build/binutils"
pushd "${WORK}/build/binutils"
if [[ ! -f "${WORK}/build/binutils/config.cache" ]]; then
echo "Configuring binutils..."
"${WORK}/binutils-${BINUTILS_VERSION}/configure" \
--quiet \
--config-cache \
--target="${TARGET}" \
--prefix="${SYSROOT}" \
--with-sysroot="${SYSROOT}" \
--with-lib-path="${SYSROOT}/lib" \
--disable-nls \
--disable-werror
fi
echo "Building binutils..."
(make -j && make install) > "${WORK}/build/binutils_build.log"
popd
}
function build_llvm() {
if [[ ! -d "${WORK}/llvm" ]]; then
echo "Downloading LLVM..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/llvm.git" "${WORK}/llvm"
fi
for tool in ${TOOLS}; do
if [[ ! -d "${WORK}/llvm/tools/${tool}" ]]; then
echo "Downloading ${tool}..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/${tool}.git" "${WORK}/llvm/tools/${tool}"
fi
done
if [[ ! -d "${WORK}/llvm/tools/clang/tools/extra" ]]; then
echo "Downloading clang-tools-extra..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/clang-tools-extra.git" "${WORK}/llvm/tools/clang/tools/extra"
fi
for proj in ${PROJECTS}; do
if [[ ! -d "${WORK}/llvm/projects/${proj}" ]]; then
echo "Downloading ${proj}..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/${proj}.git" "${WORK}/llvm/projects/${proj}"
fi
done
for proj in ${RUNTIMES}; do
if [[ ! -d "${WORK}/llvm/runtimes/${proj}" ]]; then
echo "Downloading ${proj}..."
git clone -q \
--branch "${LLVM_BRANCH}" \
--depth 1 \
"https://git.llvm.org/git/${proj}.git" "${WORK}/llvm/runtime/${proj}"
fi
done
mkdir -p "${WORK}/build/llvm"
pushd "${WORK}/build/llvm"
echo "Configuring LLVM..."
cmake -G Ninja \
-DCLANG_DEFAULT_RTLIB=compiler-rt \
-DCLANG_DEFAULT_STD_C=c11 \
-DCLANG_DEFAULT_STD_CXX=cxx14 \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER="clang" \
-DCMAKE_CXX_COMPILER="clang++" \
-DCMAKE_CXX_FLAGS="-Wno-unused-parameter -D_LIBCPP_HAS_NO_ALIGNED_ALLOCATION -D_LIBUNWIND_IS_BAREMETAL=1 -U_LIBUNWIND_SUPPORT_DWARF_UNWIND" \
-DCMAKE_INSTALL_PREFIX="${SYSROOT}" \
-DCMAKE_MAKE_PROGRAM=`which ninja` \
-DDEFAULT_SYSROOT="${SYSROOT}" \
-DLIBCXX_CXX_ABI=libcxxabi \
-DLIBCXX_CXX_ABI_INCLUDE_PATHS="${WORK}/llvm/projects/libcxxabi/include" \
-DLIBCXX_CXX_ABI_LIBRARY_PATH=lib \
-DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=OFF \
-DLIBCXX_ENABLE_NEW_DELETE_DEFINITIONS=ON \
-DLIBCXX_ENABLE_SHARED=OFF \
-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON \
-DLIBCXX_ENABLE_THREADS=OFF \
-DLIBCXX_INCLUDE_BENCHMARKS=OFF \
-DLIBCXX_USE_COMPILER_RT=ON \
-DLIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS=OFF \
-DLIBCXXABI_ENABLE_SHARED=OFF \
-DLIBCXXABI_ENABLE_STATIC_UNWINDER=ON \
-DLIBCXXABI_ENABLE_THREADS=OFF \
-DLIBCXXABI_LIBCXX_PATH="${WORK}/llvm/projects/libcxx" \
-DLIBCXXABI_USE_COMPILER_RT=ON \
-DLIBCXXABI_USE_LLVM_UNWINDER=ON \
-DLIBUNWIND_ENABLE_SHARED=OFF \
-DLIBUNWIND_ENABLE_THREADS=OFF \
-DLIBUNWIND_USE_COMPILER_RT=ON \
-DLLVM_CONFIG_PATH="${SYSROOT}/bin/llvm-config" \
-DLLVM_DEFAULT_TARGET_TRIPLE="x86_64-unknown-elf" \
-DLLVM_ENABLE_LIBCXX=ON \
-DLLVM_ENABLE_PIC=OFF \
-DLLVM_ENABLE_THREADS=OFF \
-DLLVM_INSTALL_BINUTILS_SYMLINKS=ON \
-DLLVM_TARGETS_TO_BUILD="X86" \
${WORK}/llvm > cmake_configure.log
# -DCMAKE_ASM_COMPILER=nasm \
# -DCMAKE_LINKER="${SYSROOT}/bin/ld.lld" \
# -DCOMPILER_RT_ENABLE_LLD=ON \
# -DLIBCXX_ENABLE_LLD=ON \
# -DLIBCXX_ENABLE_STATIC_UNWINDER=ON \
# -DLIBCXXABI_ENABLE_LLD=ON \
# -DLIBUNWIND_ENABLE_LLD=ON \
# -DLLVM_ENABLE_LLD=ON \
# -DLLVM_ENABLE_PROJECTS="libcxx;libcxxabi;libunwind;compiler-rt" \
# -DCOMPILER_RT_BAREMETAL_BUILD=ON \
# -DLIBCXXABI_BAREMETAL=ON \
echo "Building LLVM..."
ninja && ninja install
ninja cxx cxxabi compiler-rt
ninja install-compiler-rt install-cxx install-cxxabi
popd
}
function build_libc() {
if [[ ! -d "${WORK}/poplibc" ]]; then
echo "Downloading poplibc..."
git clone \
"https://github.com/justinian/poplibc.git" \
"${WORK}/poplibc"
else
echo "Updating poplibc..."
git -C "${WORK}/poplibc" pull
fi
pushd "${WORK}/poplibc"
echo "Building poplibc..."
make install PREFIX="${SYSROOT}"
popd
}
function update_links() {
for exe in `ls "${SYSROOT}/bin/${TARGET}-"*`; do
base=$(echo "$exe" | sed -e "s/${TARGET}-//")
ln -fs "${exe}" "${base}"
done
}
build_nasm
build_binutils
build_libc
build_llvm
update_links
export CC="${SYSROOT}/bin/clang"
export CXX="${SYSROOT}/bin/clang++"
export LD="${SYSROOT}/bin/ld"
build_libc

View File

@@ -1,186 +0,0 @@
#!/usr/bin/env bash
TARGET="x86_64-elf"
NASM_VERSION="2.14.02"
GCC_VERSION="7.4.0"
BINUTILS_VERSION="2.31.1"
SYSROOT=$(realpath "$(dirname $0)/../sysroot")
WORK=$(realpath "$(dirname $0)/sysroot")
echo "Not currently supported"
exit 1
set -e
mkdir -p "${SYSROOT}"
mkdir -p "${WORK}"
function build_nasm() {
if [[ ! -d "${WORK}/nasm-${NASM_VERSION}" ]]; then
echo "Downloading NASM..."
tarball="nasm-${NASM_VERSION}.tar.gz"
curl -sSOL "https://www.nasm.us/pub/nasm/releasebuilds/${NASM_VERSION}/${tarball}"
tar xzf "${tarball}" -C "${WORK}" && rm "${tarball}"
fi
mkdir -p "${WORK}/build/nasm"
pushd "${WORK}/build/nasm"
if [[ ! -f "${WORK}/build/nasm/config.cache" ]]; then
echo "Configuring NASM..."
"${WORK}/nasm-${NASM_VERSION}/configure" \
--quiet \
--config-cache \
--disable-werror \
--prefix="${SYSROOT}" \
--srcdir="${WORK}/nasm-${NASM_VERSION}"
fi
echo "Building NASM..."
(make -j && make install) > "${WORK}/build/nasm_build.log"
popd
}
function build_binutils() {
if [[ ! -d "${WORK}/binutils-${BINUTILS_VERSION}" ]]; then
echo "Downloading binutils..."
tarball="binutils-${BINUTILS_VERSION}.tar.gz"
curl -sSOL "https://ftp.gnu.org/gnu/binutils/${tarball}"
tar xzf "${tarball}" -C "${WORK}" && rm "${tarball}"
fi
mkdir -p "${WORK}/build/binutils"
pushd "${WORK}/build/binutils"
if [[ ! -f "${WORK}/build/binutils/config.cache" ]]; then
echo "Configuring binutils..."
"${WORK}/binutils-${BINUTILS_VERSION}/configure" \
--quiet \
--config-cache \
--target="${TARGET}" \
--prefix="${SYSROOT}" \
--with-sysroot="${SYSROOT}" \
--with-lib-path="${SYSROOT}/lib" \
--disable-nls \
--disable-werror
fi
echo "Building binutils..."
(make -j && make install) > "${WORK}/build/binutils_build.log"
popd
}
function build_gcc() {
if [[ ! -d "${WORK}/gcc-${GCC_VERSION}" ]]; then
echo "Downloading GCC..."
tarball="gcc-${GCC_VERSION}.tar.gz"
curl -sSOL "https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VERSION}/${tarball}"
tar xzf "${tarball}" -C "${WORK}" && rm "${tarball}"
# no-red-zone support version of libgcc
echo "MULTILIB_OPTIONS += mno-red-zone" > "${WORK}/gcc-${GCC_VERSION}/gcc/config/i386/t-${TARGET}"
echo "MULTILIB_DIRNAMES += no-red-zone" >> "${WORK}/gcc-${GCC_VERSION}/gcc/config/i386/t-${TARGET}"
cat <<EOF >> "${WORK}/gcc-${GCC_VERSION}/gcc/config.gcc"
case \${target} in
${TARGET})
tmake_file="\${tmake_file} i386/t-${TARGET}"
;;
esac
EOF
fi
mkdir -p "${WORK}/build/gcc"
pushd "${WORK}/build/gcc"
if [[ ! -f "${WORK}/build/gcc/config.cache" ]]; then
echo "Configuring GCC..."
"${WORK}/gcc-${GCC_VERSION}/configure" \
--quiet \
--config-cache \
--target="${TARGET}" \
--prefix="${SYSROOT}" \
--with-sysroot="${SYSROOT}" \
--with-native-system-header-dir="${SYSROOT}/include" \
--with-newlib \
--without-headers \
--disable-nls \
--enable-languages=c,c++ \
--disable-shared \
--disable-multilib \
--disable-decimal-float \
--disable-threads \
--disable-libatomic \
--disable-libgomp \
--disable-libmpx \
--disable-libquadmath \
--disable-libssp \
--disable-libvtv \
--disable-libstdcxx
fi
echo "Building GCC..."
(make -j all-gcc && make -j all-target-libgcc && \
make install-gcc && make install-target-libgcc) > "${WORK}/build/gcc_build.log"
popd
}
function build_libstdcxx() {
mkdir -p "${WORK}/build/libstdcxx"
pushd "${WORK}/build/libstdcxx"
if [[ ! -f "${WORK}/build/libstdcxx/config.cache" ]]; then
echo "Configuring libstdc++..."
CFLAGS="-I${SYSROOT}/include" \
CXXFLAGS="-I${SYSROOT}/include" \
"${WORK}/gcc-${GCC_VERSION}/libstdc++-v3/configure" \
--config-cache \
--host="${TARGET}" \
--target="${TARGET}" \
--prefix="${SYSROOT}" \
--disable-nls \
--disable-multilib \
--with-newlib \
--disable-libstdcxx-threads \
--disable-libstdcxx-pch \
--with-gxx-include-dir="${SYSROOT}/include/c++"
fi
echo "Building libstdc++..."
(make -j && make install) > "${WORK}/build/libstdcxx_build.log"
popd
}
function build_libc() {
if [[ ! -d "${WORK}/poplibc" ]]; then
echo "Downloading poplibc..."
git clone \
"https://github.com/justinian/poplibc.git" \
"${WORK}/poplibc"
else
echo "Updating poplibc..."
git -C "${WORK}/poplibc" pull
fi
pushd "${WORK}/poplibc"
echo "Building poplibc..."
make install PREFIX="${SYSROOT}"
popd
}
function update_links() {
for exe in `ls "${SYSROOT}/bin/${TARGET}-"*`; do
base=$(echo "$exe" | sed -e "s/${TARGET}-//")
ln -fs "${exe}" "${base}"
done
}
build_nasm
build_binutils
build_gcc
update_links
export PATH="${SYSROOT}/bin:${PATH}"
build_libc
build_libstdcxx

10
scripts/parse_syms.py Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env python3
def parse_elf(filename):
import struct
with open(filename, 'rb') as elf:
if __name__ == "__main__":
import sys
for arg in sys.argv[1:]:
parse_elf(arg)

View File

@@ -0,0 +1,14 @@
# jsix OS sysroot
This is a pre-built sysroot for building the jsix operating system kernel,
bootloader, and utilities. This package is provided as a convenience, and
contains software from the following repositories.
## The LLVM toolchain
The LLVM sources as downloaded via git from [llvm.org][llvm] under the terms of
the [Apache License v2.0][apache2], modified [as described here][llvmlic].
[llvm]: https://llvm.org
[apache2]: https://www.apache.org/licenses/LICENSE-2.0
[llvmlic]: https://llvm.org/docs/DeveloperPolicy.html#new-llvm-project-license-framework

View File

@@ -1,14 +1,123 @@
{% extends "build.base.j2" %}
ninja_required_version = 1.3
builddir = {{ buildroot }}
srcroot = {{ srcroot }}
modulefile = {{ modulefile }}
{% block variables %}
{{ super() }}
ccflags = $ccflags $
{%- for var, value in vars %}
{{ var }} = {{ value }}
{%- endfor %}
warnflags = $
-Wformat=2 $
-Winit-self $
-Wfloat-equal $
-Winline $
-Wmissing-format-attribute $
-Wmissing-include-dirs $
-Wswitch $
-Wundef $
-Wdisabled-optimization $
-Wpointer-arith $
-Wno-attributes $
-Wno-sign-compare $
-Wno-multichar $
-Wno-div-by-zero $
-Wno-endif-labels $
-Wno-pragmas $
-Wno-format-extra-args $
-Wno-unused-result $
-Wno-deprecated-declarations $
-Wno-unused-function $
-Werror
ccflags = $
-I${srcroot}/src/include $
-I${srcroot}/src/include/x86_64
{% endblock %}
-I${srcroot}/src/include/x86_64 $
-fcolor-diagnostics $
-DVERSION_MAJOR={{ version_major }} $
-DVERSION_MINOR={{ version_minor }} $
-DVERSION_PATCH={{ version_patch }} $
-DVERSION_GITSHA=0x0{{ version_sha }} $
-DGIT_VERSION=\"{{ version }}\" $
-DGIT_VERSION_WIDE=L\"{{ version }}\" $
$warnflags
asflags = $
-I${srcroot}/src/include $
-DVERSION_MAJOR={{ version_major }} $
-DVERSION_MINOR={{ version_minor }} $
-DVERSION_PATCH={{ version_patch }} $
-DVERSION_GITSHA=0x{{ version_sha }}
cflags = -std=c11
cxxflags = -std=c++14
libs =
rule c
deps = gcc
depfile = $out.d
description = Compiling $name
command = $cc -MMD -MF $out.d $ccflags $cflags -o $out -c $in
rule dump_c_defs
description = Dumping C defines for $target
command = echo "" | $cc $ccflags $cflags -dM -E - > $out
rule dump_c_run
description = Dumping C arguments for $target
command = $
echo "#!/bin/bash" > $out; $
echo '$cc $ccflags $cflags $$*' > $out; $
chmod a+x $out
rule cpp
deps = gcc
depfile = $out.d
description = Compiling $name
command = $cxx -MMD -MF $out.d $cxxflags $ccflags -o $out -c $in
rule dump_cpp_defs
description = Dumping C++ defines for $target
command = echo "" | $cxx -x c++ $cxxflags $ccflags -dM -E - > $out
rule dump_cpp_run
description = Dumping C++ arguments for $target
command = $
echo "#!/bin/bash" > $out; $
echo '$cc $cxxflags $ccflags $$*' > $out; $
chmod a+x $out
rule s
deps = gcc
depfile = $out.d
description = Assembling $name
command = $nasm -o $out -felf64 -MD $out.d $asflags $in
rule exe
description = Linking $name
command = $ld $ldflags -o $out $in $libs
rule lib
description = Archiving $name
command = $ar qcs $out $in
rule regen
generator = true
description = Regenrating build files
command = $
{{ generator }} $
--file $modulefile $
--dir $builddir $
generate
rule cp
description = Copying $name
command = cp $in $out
rule dump
description = Dumping decompiled $name
command = objdump -DSC -M intel $in > $out
{% block baserules %}
{{ super() }}
rule makerd
description = Making init ramdisk
command = $builddir/native/makerd $in $out
@@ -40,47 +149,60 @@ rule strip
objcopy --only-keep-debug $out $out.debug; $
strip -g $out; $
objcopy --add-gnu-debuglink=$out.debug $out
{% endblock %}
{% block extra %}
{% for target in targets %}
subninja {{ target }}/target.ninja
{% endfor %}
build $
{%- for buildfile in buildfiles %}
{{ buildfile }} $
{%- endfor %}
: regen | $
{%- for template in templates %}
{{ template }} $
{%- endfor %}
$modulefile $
{{ generator }}
build $builddir/ovmf_vars.fd : cp $srcroot/assets/ovmf/x64/ovmf_vars.fd
name = ovmf_vars.fd
build $builddir/ovmf_vars_d.fd : cp $srcroot/assets/ovmf/x64/ovmf_vars_d.fd
name = ovmf_vars_d.fd
build $builddir/popcorn.elf | $builddir/popcorn.elf.debug : strip $builddir/host/popcorn.elf
build $builddir/jsix.elf | $builddir/jsix.elf.debug : strip $builddir/host/jsix.elf
name = kernel
build $builddir/popcorn.dump : dump $builddir/host/popcorn.elf
build $builddir/jsix.dump : dump $builddir/host/jsix.elf
name = kernel
build $builddir/popcorn.elf-gdb.py : cp ${srcroot}/assets/debugging/popcorn.elf-gdb.py
build $builddir/jsix.elf-gdb.py : cp ${srcroot}/assets/debugging/jsix.elf-gdb.py
name = kernel debug python scripts
build $builddir/fatroot/popcorn.elf : cp $builddir/popcorn.elf
build $builddir/fatroot/jsix.elf : cp $builddir/jsix.elf
name = kernel to FAT image
build $builddir/fatroot/efi/boot/bootx64.efi : cp $builddir/boot/boot.efi
name = bootloader to FAT image
build $builddir/fatroot/initrd.img : makerd ${srcroot}/assets/initrd.toml | $
${builddir}/host/libvdso.so $
${builddir}/native/makerd $
${builddir}/user/nulldrv
build $builddir/popcorn.img : makefat | $
build $builddir/jsix.img : makefat | $
$builddir/fatroot/initrd.img $
$builddir/fatroot/popcorn.elf $
$builddir/fatroot/jsix.elf $
$builddir/fatroot/efi/boot/bootx64.efi
name = popcorn.img
name = jsix.img
default $
$builddir/ovmf_vars.fd $
$builddir/ovmf_vars_d.fd $
$builddir/popcorn.dump $
$builddir/popcorn.elf-gdb.py $
$builddir/popcorn.img
{% endblock %}
$builddir/jsix.dump $
$builddir/jsix.elf-gdb.py $
$builddir/jsix.img
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -3,7 +3,7 @@
{{ super() }}
ccflags = $ccflags $
-DKERNEL_FILENAME=L\"popcorn.elf\" $
-DKERNEL_FILENAME=L\"jsix.elf\" $
-DGNU_EFI_USE_MS_ABI $
-DHAVE_USE_MS_ABI $
-DEFI_DEBUG=0 $

View File

@@ -0,0 +1,8 @@
{% extends "module.base.j2" %}
{% block variables %}
{{ super() }}
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,10 @@
{% extends "exe.default.j2" %}
{% block variables %}
{{ super() }}
ccflags = $ccflags -I${srcroot}/external/cpptoml
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -2,7 +2,7 @@
{% block variables %}
{{ super() }}
ccflags = $ccflags -ggdb
ccflags = $ccflags -ggdb -I${srcroot}/external/catch
{% endblock %}

View File

@@ -0,0 +1,9 @@
{% extends "exe.default.j2" %}
{% block variables %}
{{ super() }}
ccflags = $ccflags -fPIC -mcmodel=large
ldflags = $ldflags -shared -znotext -T ${srcroot}/src/arch/x86_64/vdso.ld
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,4 @@
{% extends "module.base.j2" %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -0,0 +1,45 @@
moddir = ${builddir}/{{ name }}.dir
{% block variables %}
ccflags = $ccflags $
{%- for dep in depmods %}
{%- for inc in dep.includes %}
-I${srcroot}/{{ inc }} $
{%- endfor %}
{%- endfor %}
{%- for inc in module.includes %}
-I${srcroot}/{{ inc }} $
{%- endfor %}
{%- for define in module.defines %}
-D{{ define }} $
{%- endfor %}
{% endblock %}
{% for source in module.source %}
build ${moddir}/{{ source.output }} : {{ source.action }} ${srcroot}/{{ source.input }} || {{ buildfile }}
name = {{ source.name }}
{% endfor %}
build ${builddir}/{{ module.output }} : {{ module.kind }} $
{%- for source in module.source %}
${moddir}/{{ source.output }} $
{%- endfor -%}
{%- for dep in deplibs %}
${builddir}/{{ dep.output }} $
{%- endfor %}
| $
{%- for dep in depexes %}
${builddir}/{{ dep.output }} $
{%- endfor %}
{{ buildfile }}
name = {{ name }}
{% if module.default %}
default ${builddir}/{{ module.output }}
{% endif %}
{% block extra %}
{% endblock %}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -31,7 +31,6 @@ cxxflags = $cxxflags $
ldflags = $ldflags $
-g $
-nostdlib $
-znocombreloc $
-Bsymbolic $
-nostartfiles

View File

@@ -0,0 +1,26 @@
builddir = $builddir/{{ target }}
target = {{ target }}
{% block variables %}
{% endblock %}
{% block binaries %}
cc = clang
cxx = clang++
ld = ld
ar = ar
nasm = nasm
objcopy = objcopy
{% endblock %}
{% for module in modules %}
subninja {{ module }}.ninja
{% endfor %}
build ${builddir}/c.defs : dump_c_defs | {{ buildfile }}
build ${builddir}/cpp.defs : dump_cpp_defs | {{ buildfile }}
build ${builddir}/c.run : dump_c_run | {{ buildfile }}
build ${builddir}/cpp.run : dump_cpp_run | {{ buildfile }}
# vim: ft=ninja et ts=4 sts=4 sw=4

View File

@@ -3,10 +3,10 @@
{% block binaries %}
cc = ${srcroot}/sysroot/bin/clang
cxx = ${srcroot}/sysroot/bin/clang++
ld = ${srcroot}/sysroot/bin/x86_64-elf-ld
ar = ${srcroot}/sysroot/bin/x86_64-elf-ar
nasm = ${srcroot}/sysroot/bin/nasm
objcopy = ${srcroot}/sysroot/bin/x86_64-elf-objcopy
ld = ${srcroot}/sysroot/bin/ld.lld
ar = ${srcroot}/sysroot/bin/ar
nasm = nasm
objcopy = ${srcroot}/sysroot/bin/objcopy
{% endblock %}
{% block variables %}
@@ -22,7 +22,7 @@ ccflags = $ccflags $
-g $
-mcmodel=large $
-D__ELF__ $
-D__POPCORN__ $
-D__JSIX__ $
-isystem${srcroot}/sysroot/include $
--sysroot="${srcroot}/sysroot"
@@ -34,9 +34,7 @@ cxxflags = $cxxflags $
ldflags = $ldflags $
-g $
-nostdlib $
-znocombreloc $
-Bsymbolic $
-nostartfiles $
-Bstatic
{% endblock %}

View File

@@ -3,10 +3,10 @@
{% block binaries %}
cc = ${srcroot}/sysroot/bin/clang
cxx = ${srcroot}/sysroot/bin/clang++
ld = ${srcroot}/sysroot/bin/x86_64-elf-ld
ar = ${srcroot}/sysroot/bin/x86_64-elf-ar
nasm = ${srcroot}/sysroot/bin/nasm
objcopy = ${srcroot}/sysroot/bin/x86_64-elf-objcopy
ld = ${srcroot}/sysroot/bin/ld.lld
ar = ${srcroot}/sysroot/bin/ar
nasm = nasm
objcopy = ${srcroot}/sysroot/bin/objcopy
{% endblock %}
{% block variables %}
@@ -21,7 +21,7 @@ ccflags = $ccflags $
-g $
-mcmodel=large $
-D__ELF__ $
-D__POPCORN__ $
-D__JSIX__ $
-isystem${srcroot}/sysroot/include $
--sysroot="${srcroot}/sysroot"
@@ -33,9 +33,7 @@ cxxflags = $cxxflags $
ldflags = $ldflags $
-g $
-nostdlib $
-znocombreloc $
-Bsymbolic $
-nostartfiles $
-Bstatic $
--sysroot="${srcroot}/sysroot" $
-L "${srcroot}/sysroot/lib" $

View File

@@ -10,29 +10,26 @@ SECTIONS
__header_end = .;
}
.text : {
.text ALIGN(4096) : {
*(.text)
*(.isrs)
}
.data : {
.data ALIGN(4096) : {
*(.data)
*(.rodata)
}
.isrs : {
*(.isrs)
.bss ALIGN(4096) : {
__bss_start = .;
*(.bss)
__bss_end = .;
}
.note : {
*(.note.*)
}
.bss ALIGN(16) : {
__bss_start = .;
*(.bss)
__bss_end = .;
}
.eh_frame : {
__eh_frame_start = .;
KEEP(*(.eh_frame))

73
src/arch/x86_64/vdso.ld Normal file
View File

@@ -0,0 +1,73 @@
PHDRS {
headers PT_PHDR FLAGS(4) FILEHDR PHDRS ;
rodata PT_LOAD FLAGS(4) ;
text PT_LOAD FLAGS(5) ;
dynamic PT_DYNAMIC FLAGS(4) ;
note PT_NOTE ;
eh_frame PT_GNU_EH_FRAME ;
}
SECTIONS {
. = SIZEOF_HEADERS;
/DISCARD/ : {
*(.got*)
*(.plt*)
*(.note.*)
*(.hash*)
*(.debug*)
}
.illegal.relocations : {
*(.rel*)
}
.illegal.writeable : {
*(.data*)
*(.bss*)
}
.rodata : {
*(.rodata*)
} :rodata
.dynamic : {
*(.dynamic)
} :dynamic
.dynsym : {
*(.dynsym*)
} :rodata :dynamic
.dynstr : {
*(.dynstr*)
} :rodata :dynamic
.gnu.hash : {
*(.gnu.hash*)
} :rodata
.eh_frame_hdr : {
__eh_frame_start = .;
KEEP(*(.eh_frame))
__eh_frame_end = .;
KEEP(*(.eh_frame_hdr))
} :eh_frame
.shstrtab : {
*(.shstrtab)
}
.text ALIGN(0x1000) : {
*(.text*)
*(.init*)
*(.fini*)
. = ALIGN(0x1000);
} :text
ASSERT(SIZEOF(.illegal.relocations) == 0,
"Code has introduced relocations into the VDSO")
ASSERT(SIZEOF(.illegal.writeable) == 0,
"Code has introduced writeable data into the VDSO")
}

View File

@@ -40,7 +40,7 @@ console::initialize(const wchar_t *version)
CHECK_EFI_STATUS_OR_RETURN(status, "ClearScreen");
m_out->SetAttribute(m_out, EFI_LIGHTCYAN);
m_out->OutputString(m_out, (wchar_t *)L"Popcorn loader ");
m_out->OutputString(m_out, (wchar_t *)L"jsix loader ");
m_out->SetAttribute(m_out, EFI_LIGHTMAGENTA);
m_out->OutputString(m_out, (wchar_t *)version);

View File

@@ -6,6 +6,6 @@ GUID(0x964e5b22,0x6459,0x11d2,0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b, guid_simp
GUID(0x09576e91,0x6d3f,0x11d2,0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b, guid_device_path);
GUID(0x8b843e20,0x8132,0x4852,0x90,0xcc,0x55,0x1a,0x4e,0x4a,0x7f,0x1c, guid_device_path_to_text);
GUID(0x10d0669c,0x9ec6,0x4268,0xbc,0x48,0xff,0x74,0x75,0x21,0xfe,0x07, guid_popcorn_vendor);
GUID(0x10d0669c,0x9ec6,0x4268,0xbc,0x48,0xff,0x74,0x75,0x21,0xfe,0x07, guid_jsix_vendor);
// vim: ft=c

View File

@@ -26,15 +26,15 @@ loader_alloc_aligned(
size_t page_count = alignment / PAGE_SIZE;
*length = alignment;
con_debug(L"Trying to find %d aligned pages for %x\n", page_count, mem_type);
con_debug(L"Trying to find %d aligned pages for %x", page_count, mem_type);
status = bootsvc->AllocatePages(AllocateAnyPages, mem_type, page_count * 2, &addr);
CHECK_EFI_STATUS_OR_RETURN(status, L"Allocating %d pages for alignment", page_count * 2);
con_debug(L" Found %d pages at %lx\n", page_count * 2, addr);
con_debug(L" Found %d pages at %lx", page_count * 2, addr);
EFI_PHYSICAL_ADDRESS aligned = addr;
aligned = ((aligned - 1) & ~(alignment - 1)) + alignment;
con_debug(L" Aligning %lx to %lx\n", addr, aligned);
con_debug(L" Aligning %lx to %lx", addr, aligned);
size_t before =
(reinterpret_cast<uint64_t>(aligned) -
@@ -42,7 +42,7 @@ loader_alloc_aligned(
PAGE_SIZE;
if (before) {
con_debug(L" Freeing %d initial pages\n", before);
con_debug(L" Freeing %d initial pages", before);
bootsvc->FreePages(addr, before);
}
@@ -52,7 +52,7 @@ loader_alloc_aligned(
reinterpret_cast<EFI_PHYSICAL_ADDRESS>(
reinterpret_cast<uint64_t>(aligned) +
page_count * PAGE_SIZE);
con_debug(L" Freeing %d remaining pages\n", after);
con_debug(L" Freeing %d remaining pages", after);
bootsvc->FreePages(end, after);
}
@@ -72,7 +72,7 @@ loader_alloc_pages(
size_t page_count = ((*length - 1) / PAGE_SIZE) + 1;
EFI_PHYSICAL_ADDRESS addr = (EFI_PHYSICAL_ADDRESS)*pages;
con_debug(L"Trying to find %d non-aligned pages for %x at %lx\n",
con_debug(L"Trying to find %d non-aligned pages for %x at %lx",
page_count, mem_type, addr);
status = bootsvc->AllocatePages(AllocateAddress, mem_type, page_count, &addr);
@@ -136,7 +136,7 @@ loader_load_elf(
{
EFI_STATUS status;
con_debug(L"Opening kernel file %s\r\n", (wchar_t *)kernel_name);
con_debug(L"Opening kernel file %s", (wchar_t *)kernel_name);
EFI_FILE_PROTOCOL *file = NULL;
status = root->Open(root, &file, (wchar_t *)kernel_name, EFI_FILE_MODE_READ,
@@ -158,7 +158,7 @@ loader_load_elf(
status = file->Read(file, &length, &header);
CHECK_EFI_STATUS_OR_RETURN(status, L"Reading ELF header");
con_debug(L"Read %u bytes of ELF header\r\n", length);
con_debug(L"Read %u bytes of ELF header", length);
if (length < sizeof(struct elf_header))
CHECK_EFI_STATUS_OR_RETURN(EFI_LOAD_ERROR, L"Incomplete read of ELF header");
@@ -184,7 +184,7 @@ loader_load_elf(
header.machine != 0x3e)
CHECK_EFI_STATUS_OR_RETURN(EFI_LOAD_ERROR, L"ELF load error: wrong machine architecture");
con_debug(L"ELF is valid, entrypoint %lx\r\n", header.entrypoint);
con_debug(L"ELF is valid, entrypoint %lx", header.entrypoint);
data->kernel_entry = (void *)header.entrypoint;
@@ -209,7 +209,7 @@ loader_load_elf(
data->kernel = addr;
data->kernel_length = (uint64_t)addr + length - (uint64_t)data->kernel;
}
con_debug(L"Read %d ELF program headers\r\n", header.ph_num);
con_debug(L"Read %d ELF program headers", header.ph_num);
struct elf_section_header sec_header;
for (int i = 0; i < header.sh_num; ++i) {
@@ -237,7 +237,7 @@ loader_load_elf(
bootsvc->SetMem(addr, sec_header.size, 0);
}
}
con_debug(L"Read %d ELF section headers\r\n", header.ph_num);
con_debug(L"Read %d ELF section headers", header.ph_num);
status = file->Close(file);
CHECK_EFI_STATUS_OR_RETURN(status, L"Closing file handle");

View File

@@ -51,15 +51,15 @@ detect_debug_mode(EFI_RUNTIME_SERVICES *run, kernel_args *header) {
uint8_t debug = 0;
UINTN var_size = sizeof(debug);
#ifdef __POPCORN_SET_DEBUG_UEFI_VAR__
debug = __POPCORN_SET_DEBUG_UEFI_VAR__;
#ifdef __JSIX_SET_DEBUG_UEFI_VAR__
debug = __JSIX_SET_DEBUG_UEFI_VAR__;
uint32_t attrs =
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS;
status = run->SetVariable(
var_name,
&guid_popcorn_vendor,
&guid_jsix_vendor,
attrs,
var_size,
&debug);
@@ -68,14 +68,14 @@ detect_debug_mode(EFI_RUNTIME_SERVICES *run, kernel_args *header) {
status = run->GetVariable(
var_name,
&guid_popcorn_vendor,
&guid_jsix_vendor,
nullptr,
&var_size,
&debug);
CHECK_EFI_STATUS_OR_RETURN(status, "detect_debug_mode::GetVariable");
if (debug)
header->flags |= POPCORN_FLAG_DEBUG;
header->flags |= JSIX_FLAG_DEBUG;
return EFI_SUCCESS;
}

View File

@@ -34,7 +34,7 @@ const wchar_t *util_error_message(EFI_STATUS status);
}
#ifdef BOOTLOADER_DEBUG
#define con_debug(...) console::print(L"DEBUG: " __VA_ARGS__)
#define con_debug(msg, ...) console::print(L"DEBUG: " msg L"\r\n", __VA_ARGS__)
#else
#define con_debug(...)
#define con_debug(msg, ...)
#endif

View File

@@ -1,12 +1,15 @@
#include <stdint.h>
#include <stdlib.h>
#include "j6/types.h"
#include "j6/errors.h"
extern "C" {
int32_t getpid();
int32_t fork();
void sleep(uint64_t til);
void debug();
void message(const char *msg);
j6_status_t getpid(uint64_t *);
j6_status_t fork(uint64_t *);
j6_status_t sleep(uint64_t til);
j6_status_t debug();
j6_status_t message(const char *msg);
int main(int, const char **);
}
@@ -15,10 +18,21 @@ extern "C" {
int
main(int argc, const char **argv)
{
int32_t pid = getpid();
int32_t child = fork();
uint64_t pid = 0;
uint64_t child = 0;
j6_status_t result = fork(&child);
if (result != j6_status_ok)
return result;
message("hello from nulldrv!");
result = getpid(&pid);
if (result != j6_status_ok)
return result;
for (int i = 1; i < 5; ++i)
sleep(i*10);
return 0;
return pid;
}

View File

@@ -11,8 +11,9 @@ getpid:
push rbp
mov rbp, rsp
mov rax, 0x02 ; getpid syscall
syscall ; pid is now already in rax, so just return
; address of out var should already be in rdi
mov rax, 0x13 ; getpid syscall
syscall ; result is now already in rax, so just return
pop rbp
ret
@@ -33,7 +34,7 @@ sleep:
push rbp
mov rbp, rsp
mov rax, 0x21 ; sleep syscall
mov rax, 0x16 ; sleep syscall
syscall
pop rbp
@@ -44,8 +45,9 @@ fork:
push rbp
mov rbp, rsp
mov rax, 0x03
syscall ; pid left in rax
; address of out var should already be in rdi
mov rax, 0x12
syscall ; result left in rax
pop rbp
ret
@@ -57,7 +59,7 @@ message:
mov rbp, rsp
; message should already be in rdi
mov rax, 0x10
mov rax, 0x14
syscall
pop rbp

16
src/include/j6/errors.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
/// \file errors.h
/// Collection of constants for the j6_status_t type
#define j6_status_error 0x8000000000000000
#define j6_err(x) ((x) | j6_status_error)
#define j6_is_err(x) (((x) & j6_status_error) == j6_status_error)
#define j6_status_ok 0x0000
#define j6_status_destroyed 0x1001
#define j6_err_nyi j6_err(0x0001)
#define j6_err_unexpected j6_err(0x0002)
#define j6_err_invalid_arg j6_err(0x0003)

18
src/include/j6/signals.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
/// \file signals.h
/// Collection of constants for the j6_signal_t type
// Signals 0-7 are common to all types
#define j6_signal_no_handles (1 << 0)
// Signals 8-15 are user-defined signals
#define j6_signal_user0 (1 << 8)
#define j6_signal_user1 (1 << 9)
#define j6_signal_user2 (1 << 10)
#define j6_signal_user3 (1 << 11)
#define j6_signal_user4 (1 << 12)
#define j6_signal_user5 (1 << 13)
#define j6_signal_user6 (1 << 14)
#define j6_signal_user7 (1 << 15)
// All other signals are type-specific

20
src/include/j6/types.h Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
/// \file types.h
/// Basic kernel types exposed to userspace
#include <stdint.h>
/// All interactable kernel objects have a uniqe kernel object id
typedef uint64_t j6_koid_t;
/// Syscalls return status as this type
typedef uint64_t j6_status_t;
/// Handles are references and capabilities to other objects
typedef uint32_t j6_handle_t;
/// Some objects have signals, which are a bitmap of 64 possible signals
typedef uint64_t j6_signal_t;
/// The rights of a handle/capability are a bitmap of 64 possible rights
typedef uint64_t j6_rights_t;

View File

@@ -7,7 +7,7 @@
#define DATA_HEADER_MAGIC 0x600dda7a
#define DATA_HEADER_VERSION 1
#define POPCORN_FLAG_DEBUG 0x00000001
#define JSIX_FLAG_DEBUG 0x00000001
#pragma pack(push, 1)
struct kernel_args {

View File

@@ -25,6 +25,9 @@ namespace memory {
/// Max size of the kernel heap
static const size_t kernel_max_heap = 0x800000000; // 32GiB
/// Start of the kernel heap
static const uintptr_t heap_start = page_offset - kernel_max_heap;
/// Helper to determine if a physical address can be accessed
/// through the page_offset area.
inline bool page_mappable(uintptr_t a) { return (a & page_offset) == 0; }

View File

@@ -5,5 +5,7 @@ LOG(driver, info);
LOG(memory, info);
LOG(fs, info);
LOG(task, info);
LOG(boot, info);
LOG(syscall,info);
LOG(boot, debug);
LOG(syscall,debug);
LOG(vmem, debug);
LOG(objs, debug);

9
src/include/syscalls.inc Normal file
View File

@@ -0,0 +1,9 @@
SYSCALL(0x00, object_noop, void)
SYSCALL(0x01, object_wait, j6_handle_t, j6_signal_t, j6_signal_t *)
SYSCALL(0x11, process_exit, int64_t)
//SYSCALL(0x12, process_fork, j6_koid_t*)
//SYSCALL(0x13, process_getpid, j6_koid_t*)
SYSCALL(0x14, process_log, const char *)
SYSCALL(0x15, process_pause, void)
SYSCALL(0x16, process_sleep, uint64_t)

View File

@@ -46,7 +46,6 @@ apic::apic(uint32_t *base) :
lapic::lapic(uint32_t *base, isr spurious) :
apic(base)
{
// TODO: This causes a "reserved" page fault under KVM
apic_write(m_base, 0xf0, static_cast<uint32_t>(spurious));
log::info(logs::apic, "LAPIC created, base %lx", m_base);
}

View File

@@ -1,4 +1,4 @@
MAGIC equ 0x600db007 ; Popcorn OS header magic number
MAGIC equ 0x600db007 ; jsix OS header magic number
section .header
align 4
@@ -48,7 +48,7 @@ interrupts_disable:
section .bss
align 0x100
idle_stack_begin:
resb 0x1000 ; 4KiB stack space
resb 0x4000 ; 16KiB stack space
global idle_stack_end
idle_stack_end:

View File

@@ -5,6 +5,9 @@
cpu_data bsp_cpu_data;
static constexpr uint32_t cpuid_extended = 0x80000000;
inline static void
__cpuid(
uint32_t leaf,
@@ -25,42 +28,89 @@ __cpuid(
if (edx) *edx = d;
}
cpu_id::cpu_id()
cpu_id::cpu_id() :
m_features(0)
{
__cpuid(0, 0,
&m_high_leaf,
&m_high_basic,
reinterpret_cast<uint32_t *>(&m_vendor_id[0]),
reinterpret_cast<uint32_t *>(&m_vendor_id[8]),
reinterpret_cast<uint32_t *>(&m_vendor_id[4]));
uint32_t eax = 0;
__cpuid(0, 1, &eax);
m_stepping = eax & 0xf;
m_model = (eax >> 4) & 0xf;
m_family = (eax >> 8) & 0xf;
m_cpu_type = (eax >> 12) & 0x3;
uint32_t ext_model = (eax >> 16) & 0xf;
uint32_t ext_family = (eax >> 20) & 0xff;
if (m_family == 0x6 || m_family == 0xf)
m_model = (ext_model << 4) + m_model;
if (m_family == 0xf)
m_family += ext_family;
__cpuid(cpuid_extended, 0, &m_high_ext);
if (m_high_ext >= cpuid_extended + 4) {
__cpuid(cpuid_extended + 2, 0,
reinterpret_cast<uint32_t *>(&m_brand_name[0]),
reinterpret_cast<uint32_t *>(&m_brand_name[4]),
reinterpret_cast<uint32_t *>(&m_brand_name[8]),
reinterpret_cast<uint32_t *>(&m_brand_name[12]));
__cpuid(cpuid_extended + 3, 0,
reinterpret_cast<uint32_t *>(&m_brand_name[16]),
reinterpret_cast<uint32_t *>(&m_brand_name[20]),
reinterpret_cast<uint32_t *>(&m_brand_name[24]),
reinterpret_cast<uint32_t *>(&m_brand_name[28]));
__cpuid(cpuid_extended + 4, 0,
reinterpret_cast<uint32_t *>(&m_brand_name[32]),
reinterpret_cast<uint32_t *>(&m_brand_name[36]),
reinterpret_cast<uint32_t *>(&m_brand_name[40]),
reinterpret_cast<uint32_t *>(&m_brand_name[44]));
} else {
m_brand_name[0] = 0;
}
}
cpu_id::regs
cpu_id::get(uint32_t leaf, uint32_t sub) const
{
if (leaf > m_high_leaf) return {};
regs ret {0, 0, 0, 0};
if ((leaf & cpuid_extended) == 0 && leaf > m_high_basic) return ret;
if ((leaf & cpuid_extended) != 0 && leaf > m_high_ext) return ret;
regs ret;
__cpuid(leaf, sub, &ret.eax, &ret.ebx, &ret.ecx, &ret.edx);
return ret;
}
void
cpu_id::validate()
{
bool fail = false;
uint32_t leaf = 0;
uint32_t sub = 0;
regs r;
log::info(logs::boot, "CPU: %s", brand_name());
log::debug(logs::boot, " Vendor is %s", vendor_id());
log::debug(logs::boot, " Higest basic CPUID: 0x%02x", highest_basic());
log::debug(logs::boot, " Higest ext CPUID: 0x%02x", highest_ext() & ~cpuid_extended);
#define CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit) \
if (leaf != feat_leaf || sub != feat_sub) { \
leaf = feat_leaf; sub = feat_sub; r = get(leaf, sub); \
} \
if (r.regname & (1 << bit)) \
m_features |= (1 << static_cast<uint64_t>(cpu_feature::name)); \
log::debug(logs::boot, " Supports %9s: %s", #name, (r.regname & (1<<bit)) ? "yes" : "no");
#define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \
CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \
if ((r.regname & (1 << bit)) == 0) { \
log::error(logs::boot, "CPU missing required feature " #name); \
fail = true; \
}
#include "cpu_features.inc"
#undef CPU_FEATURE_OPT
#undef CPU_FEATURE_REQ
if (fail)
log::fatal(logs::boot, "CPU not supported.");
}
bool
cpu_id::has_feature(cpu_feature feat)
{
return (m_features & (1 << static_cast<uint64_t>(feat))) != 0;
}

View File

@@ -23,40 +23,69 @@ struct cpu_data
extern cpu_data bsp_cpu_data;
/// Enum of the cpu features jsix cares about
enum class cpu_feature {
#define CPU_FEATURE_REQ(name, ...) name,
#define CPU_FEATURE_OPT(name, ...) name,
#include "cpu_features.inc"
#undef CPU_FEATURE_OPT
#undef CPU_FEATURE_REQ
max
};
class cpu_id
{
public:
/// CPUID result register values
struct regs {
union {
uint32_t reg[4];
uint32_t eax, ebx, ecx, edx;
};
regs() : eax(0), ebx(0), ecx(0), edx(0) {}
regs(uint32_t a, uint32_t b, uint32_t c, uint32_t d) : eax(a), ebx(b), ecx(c), edx(d) {}
regs(const regs &r) : eax(r.eax), ebx(r.ebx), ecx(r.ecx), edx(r.edx) {}
/// Return true if bit |bit| of EAX is set
bool eax_bit(unsigned bit) { return (eax >> bit) & 0x1; }
/// Return true if bit |bit| of EBX is set
bool ebx_bit(unsigned bit) { return (ebx >> bit) & 0x1; }
/// Return true if bit |bit| of ECX is set
bool ecx_bit(unsigned bit) { return (ecx >> bit) & 0x1; }
/// Return true if bit |bit| of EDX is set
bool edx_bit(unsigned bit) { return (edx >> bit) & 0x1; }
};
cpu_id();
/// The the result of a given CPUID leaf/subleaf
/// \arg leaf The leaf selector (initial EAX)
/// \arg subleaf The subleaf selector (initial ECX)
/// \returns A |regs| struct of the values retuned
regs get(uint32_t leaf, uint32_t sub = 0) const;
/// Get the name of the cpu vendor (eg, "GenuineIntel")
inline const char * vendor_id() const { return m_vendor_id; }
inline uint8_t cpu_type() const { return m_cpu_type; }
inline uint8_t stepping() const { return m_stepping; }
inline uint16_t family() const { return m_family; }
inline uint16_t model() const { return m_model; }
/// Get the brand name of this processor model
inline const char * brand_name() const { return m_brand_name; }
/// Get the highest basic CPUID leaf supported
inline uint32_t highest_basic() const { return m_high_basic; }
/// Get the highest extended CPUID leaf supported
inline uint32_t highest_ext() const { return m_high_ext; }
/// Validate the CPU supports the necessary options for jsix
void validate();
/// Return true if the CPU claims to support the given feature
bool has_feature(cpu_feature feat);
private:
void read();
uint32_t m_high_leaf;
uint32_t m_high_basic;
uint32_t m_high_ext;
char m_vendor_id[13];
uint8_t m_cpu_type;
uint8_t m_stepping;
uint16_t m_family;
uint16_t m_model;
char m_brand_name[48];
uint64_t m_features;
};

View File

@@ -0,0 +1,16 @@
CPU_FEATURE_OPT(pcid, 0x00000001, 0, ecx, 17)
CPU_FEATURE_OPT(x2apic, 0x00000001, 0, ecx, 21)
CPU_FEATURE_REQ(fpu, 0x00000001, 0, edx, 0)
CPU_FEATURE_REQ(pse, 0x00000001, 0, edx, 3)
CPU_FEATURE_OPT(tsc, 0x00000001, 0, edx, 4)
CPU_FEATURE_REQ(msr, 0x00000001, 0, edx, 5)
CPU_FEATURE_REQ(apic, 0x00000001, 0, edx, 9)
CPU_FEATURE_REQ(pge, 0x00000001, 0, edx, 13)
CPU_FEATURE_OPT(pat, 0x00000001, 0, edx, 16)
CPU_FEATURE_REQ(fxsr, 0x00000001, 0, edx, 24)
CPU_FEATURE_OPT(fsgsbase, 0x00000007, 0, ebx, 0)
CPU_FEATURE_OPT(invpcid, 0x00000007, 0, ebx, 10)
CPU_FEATURE_OPT(pku, 0x00000007, 0, ecx, 3)
CPU_FEATURE_REQ(syscall, 0x80000001, 0, edx, 11)
CPU_FEATURE_REQ(pdpe1gb, 0x80000001, 0, edx, 26)
CPU_FEATURE_OPT(extapic, 0x80000001, 0, ecx, 3)

View File

@@ -184,7 +184,10 @@ isr_handler(cpu_state *regs)
uintptr_t cr2 = 0;
__asm__ __volatile__ ("mov %%cr2, %0" : "=r"(cr2));
if (!page_manager::get()->fault_handler(cr2)) {
if ((regs->errorcode & 0x9) == 0 &&
page_manager::get()->fault_handler(cr2))
break;
cons->set_color(11);
cons->puts("\nPage Fault:\n");
cons->set_color();
@@ -200,7 +203,6 @@ isr_handler(cpu_state *regs)
print_stacktrace(2);
_halt();
}
}
break;
case isr::isrTimer:

View File

@@ -1,8 +1,12 @@
#include <stddef.h>
#include <stdint.h>
#include "j6/signals.h"
#include "initrd/initrd.h"
#include "kutil/assert.h"
#include "kutil/heap_allocator.h"
#include "kutil/vm_space.h"
#include "apic.h"
#include "block_device.h"
#include "console.h"
@@ -12,7 +16,10 @@
#include "interrupts.h"
#include "io.h"
#include "kernel_args.h"
#include "kernel_memory.h"
#include "log.h"
#include "objects/event.h"
#include "objects/handle.h"
#include "page_manager.h"
#include "scheduler.h"
#include "serial.h"
@@ -25,6 +32,28 @@ extern "C" {
extern void __kernel_assert(const char *, unsigned, const char *);
extern kutil::heap_allocator g_kernel_heap;
class test_observer :
public kobject::observer
{
public:
test_observer(const char *name) : m_name(name) {}
virtual bool on_signals_changed(
kobject *obj,
j6_signal_t s,
j6_signal_t ds,
j6_status_t result)
{
log::info(logs::objs, " %s: Signals %016lx changed, object %p, result %016lx",
m_name, ds, obj, result);
return false;
}
const char *m_name;
};
void
init_console()
{
@@ -32,7 +61,7 @@ init_console()
console *cons = new (&g_console) console(com1);
cons->set_color(0x21, 0x00);
cons->puts("Popcorn OS ");
cons->puts("jsix OS ");
cons->set_color(0x08, 0x00);
cons->puts(GIT_VERSION " booting...\n");
@@ -42,7 +71,7 @@ init_console()
void
kernel_main(kernel_args *header)
{
bool waiting = header && (header->flags && POPCORN_FLAG_DEBUG);
bool waiting = header && (header->flags && JSIX_FLAG_DEBUG);
while (waiting);
kutil::assert_set_callback(__kernel_assert);
@@ -50,12 +79,14 @@ kernel_main(kernel_args *header)
gdt_init();
interrupts_init();
kutil::allocator &heap = memory_initialize(
memory_initialize(
header->scratch_pages,
header->memory_map,
header->memory_map_length,
header->memory_map_desc_size);
kutil::allocator &heap = g_kernel_heap;
if (header->frame_buffer && header->frame_buffer_length) {
page_manager::get()->map_offset_pointer(
&header->frame_buffer,
@@ -64,17 +95,24 @@ kernel_main(kernel_args *header)
init_console();
log::debug(logs::boot, " Popcorn header is at: %016lx", header);
log::debug(logs::boot, " jsix header is at: %016lx", header);
log::debug(logs::boot, " Framebuffer is at: %016lx", header->frame_buffer);
log::debug(logs::boot, " Kernel data is at: %016lx", header->data);
log::debug(logs::boot, " Memory map is at: %016lx", header->memory_map);
log::debug(logs::boot, "ACPI root table is at: %016lx", header->acpi_table);
log::debug(logs::boot, "Runtime service is at: %016lx", header->runtime);
cpu_id cpu;
cpu.validate();
initrd::disk ird(header->initrd, heap);
log::info(logs::boot, "initrd loaded with %d files.", ird.files().count());
for (auto &f : ird.files())
log::info(logs::boot, " %s%s (%d bytes).", f.executable() ? "*" : "", f.name(), f.size());
log::info(logs::boot, " %s%s (%d bytes).",
f.type() == initrd::file_type::executable ? "*" :
f.type() == initrd::file_type::vdso ? "^" : "",
f.name(),
f.size());
/*
page_manager::get()->dump_pml4(nullptr, 0);
@@ -87,11 +125,6 @@ kernel_main(kernel_args *header)
interrupts_enable();
/*
cpu_id cpu;
log::info(logs::boot, "CPU Vendor: %s", cpu.vendor_id());
log::info(logs::boot, "CPU Family %x Model %x Stepping %x",
cpu.family(), cpu.model(), cpu.stepping());
auto r = cpu.get(0x15);
log::info(logs::boot, "CPU Crystal: %dHz", r.ecx);
@@ -134,9 +167,24 @@ kernel_main(kernel_args *header)
sched->create_kernel_task(-1, logger_task);
for (auto &f : ird.files()) {
if (f.executable())
if (f.type() == initrd::file_type::executable)
sched->load_process(f.name(), f.data(), f.size());
}
log::info(logs::objs, "Testing object system:");
test_observer obs1("event");
test_observer obs2("no handles");
{
event e;
e.register_signal_observer(&obs1, j6_signal_user0);
e.register_signal_observer(&obs2, j6_signal_no_handles);
e.assert_signal(j6_signal_user0);
handle h(1, 0, &e);
}
sched->start();
}

View File

@@ -1,22 +1,24 @@
#include <algorithm>
#include <utility>
#include "kutil/address_manager.h"
#include "kutil/assert.h"
#include "kutil/heap_allocator.h"
#include "kutil/vm_space.h"
#include "frame_allocator.h"
#include "io.h"
#include "log.h"
#include "page_manager.h"
using memory::frame_size;
using memory::heap_start;
using memory::kernel_max_heap;
using memory::kernel_offset;
using memory::page_offset;
static const unsigned ident_page_flags = 0xb;
kutil::address_manager g_kernel_address_manager;
kutil::vm_space g_kspace;
kutil::heap_allocator g_kernel_heap;
bool g_memory_initialized = false;
void * operator new(size_t size) { return g_kernel_heap.allocate(size); }
void * operator new [] (size_t size) { return g_kernel_heap.allocate(size); }
@@ -43,12 +45,12 @@ enum class efi_memory_type : uint32_t
efi_max,
popcorn_kernel = 0x80000000,
popcorn_data,
popcorn_initrd,
popcorn_scratch,
jsix_kernel = 0x80000000,
jsix_data,
jsix_initrd,
jsix_scratch,
popcorn_max
jsix_max
};
struct efi_memory_descriptor
@@ -117,27 +119,23 @@ public:
}
}
void add_used_frames(kutil::address_manager &am) {
void add_used_frames(kutil::vm_space &vm) {
for (auto *desc : map) {
if (desc->type == efi_memory_type::popcorn_data ||
desc->type == efi_memory_type::popcorn_initrd)
if (desc->type == efi_memory_type::jsix_data ||
desc->type == efi_memory_type::jsix_initrd ||
desc->type == efi_memory_type::jsix_kernel)
{
uintptr_t virt_addr = desc->physical_start + kernel_offset;
am.mark(virt_addr, desc->pages * frame_size);
}
else if (desc->type == efi_memory_type::popcorn_kernel)
{
uintptr_t virt_addr = desc->physical_start + kernel_offset;
am.mark_permanent(virt_addr, desc->pages * frame_size);
vm.commit(virt_addr, desc->pages * frame_size);
}
}
}
void page_in_kernel(page_manager &pm, page_table *pml4) {
for (auto *desc : map) {
if (desc->type == efi_memory_type::popcorn_kernel ||
desc->type == efi_memory_type::popcorn_data ||
desc->type == efi_memory_type::popcorn_initrd)
if (desc->type == efi_memory_type::jsix_kernel ||
desc->type == efi_memory_type::jsix_data ||
desc->type == efi_memory_type::jsix_initrd)
{
uintptr_t virt_addr = desc->physical_start + kernel_offset;
pm.page_in(pml4, desc->physical_start, virt_addr, desc->pages);
@@ -157,9 +155,11 @@ private:
const memory_map map;
};
kutil::allocator &
void
memory_initialize(uint16_t scratch_pages, const void *memory_map, size_t map_length, size_t desc_length)
{
g_memory_initialized = false;
// make sure the options we want in CR4 are set
uint64_t cr4;
__asm__ __volatile__ ( "mov %%cr4, %0" : "=r" (cr4) );
@@ -184,9 +184,31 @@ memory_initialize(uint16_t scratch_pages, const void *memory_map, size_t map_len
page_table *id_pml4 = &tables[0];
page_table *id_pdp = &tables[1];
// Flags: 0 0 0 0 1 1 0 0 0 0 0 1 1 = 0x0183
// | IGN | | | | | | | | +- Present
// | | | | | | | | +--- Writeable
// | | | | | | | +----- Supervisor only
// | | | | | | +------- PWT (determining memory type for page)
// | | | | | +---------- PCD (determining memory type for page)
// | | | | +------------ Accessed flag (not accessed yet)
// | | | +-------------- Dirty (not dirtied yet)
// | | +---------------- Page size (1GiB page)
// | +------------------- Global
// +---------------------------- PAT (determining memory type for page)
for (int i=0; i<512; ++i)
id_pdp->entries[i] = (static_cast<uintptr_t>(i) << 30) | 0x18b;
id_pml4->entries[511] = reinterpret_cast<uintptr_t>(id_pdp) | 0x10b;
id_pdp->entries[i] = (static_cast<uintptr_t>(i) << 30) | 0x0183;
// Flags: 0 0 0 0 0 0 0 0 0 0 1 1 = 0x0003
// IGNORED | | | | | | | +- Present
// | | | | | | +--- Writeable
// | | | | | +----- Supervisor only
// | | | | +------- PWT (determining memory type for pdpt)
// | | | +---------- PCD (determining memory type for pdpt)
// | | +------------ Accessed flag (not accessed yet)
// | +-------------- Ignored
// +---------------- Reserved 0
id_pml4->entries[511] = reinterpret_cast<uintptr_t>(id_pdp) | 0x003;
// Make sure the page table is finished updating before we write to memory
__sync_synchronize();
@@ -199,27 +221,12 @@ memory_initialize(uint16_t scratch_pages, const void *memory_map, size_t map_len
frame_allocator *fa = new (&g_frame_allocator) frame_allocator;
bootstrap.add_free_frames(*fa);
// Build an initial address manager that we'll copy into the real
// address manager later (so that we can use a raw allocator now)
kutil::allocator &alloc = fa->raw_allocator();
kutil::address_manager init_am(alloc);
init_am.add_regions(kernel_offset, page_offset - kernel_offset);
bootstrap.add_used_frames(init_am);
// Add the heap into the address manager
uintptr_t heap_start = page_offset - kernel_max_heap;
init_am.mark(heap_start, kernel_max_heap);
kutil::allocator *heap_alloc =
new (&g_kernel_heap) kutil::heap_allocator(heap_start, kernel_max_heap);
// Copy everything into the real address manager
kutil::address_manager *am =
new (&g_kernel_address_manager) kutil::address_manager(
std::move(init_am), *heap_alloc);
new (&g_kspace) kutil::vm_space(kernel_offset, (page_offset-kernel_offset), g_kernel_heap);
bootstrap.add_used_frames(g_kspace);
// Create the page manager
page_manager *pm = new (&g_page_manager) page_manager(*fa, *am);
page_manager *pm = new (&g_page_manager) page_manager(*fa);
// Give the frame_allocator back the rest of the scratch pages
fa->free(scratch_phys + (3 * frame_size), scratch_pages - 3);
@@ -231,12 +238,10 @@ memory_initialize(uint16_t scratch_pages, const void *memory_map, size_t map_len
pml4 = kutil::offset_pointer(pml4, page_offset);
kutil::memset(pml4, 0, sizeof(page_table));
pml4->entries[511] = reinterpret_cast<uintptr_t>(id_pdp) | 0x10b;
pml4->entries[511] = reinterpret_cast<uintptr_t>(id_pdp) | 0x003;
bootstrap.page_in_kernel(*pm, pml4);
// Reclaim the old PML4
fa->free(scratch_phys, 1);
return *heap_alloc;
}

View File

@@ -0,0 +1,13 @@
#pragma once
/// \file event.h
/// Definition of event kobject types
#include "objects/kobject.h"
class event :
public kobject
{
public:
event() :
kobject(type::event) {}
};

View File

@@ -0,0 +1,26 @@
#include "objects/handle.h"
handle::handle(handle&& other) :
m_owner(other.m_owner),
m_object(other.m_object),
m_rights(other.m_rights)
{
other.m_owner = 0;
other.m_object = nullptr;
other.m_rights = 0;
}
handle::handle(j6_koid_t owner, j6_rights_t rights, kobject *obj) :
m_owner(owner),
m_object(obj),
m_rights(rights)
{
if (m_object)
m_object->handle_retain();
}
handle::~handle()
{
if (m_object)
m_object->handle_release();
}

View File

@@ -0,0 +1,30 @@
#pragma once
/// \file handle.h
/// Defines types for user handles to kernel objects
#include "j6/types.h"
#include "objects/kobject.h"
class handle
{
public:
/// Move constructor. Takes ownership of the object from other.
handle(handle&& other);
/// Constructor.
/// \arg owner koid of the process that has this handle
/// \arg rights access rights this handle has over the object
/// \arg obj the object held
handle(j6_koid_t owner, j6_rights_t rights, kobject *obj);
~handle();
handle() = delete;
handle(const handle &other) = delete;
handle & operator=(const handle& other) = delete;
private:
j6_koid_t m_owner;
kobject *m_object;
j6_rights_t m_rights;
};

View File

@@ -0,0 +1,98 @@
#include "j6/errors.h"
#include "j6/signals.h"
#include "j6/types.h"
#include "kutil/heap_allocator.h"
#include "objects/kobject.h"
extern kutil::heap_allocator g_kernel_heap;
// TODO: per-cpu this?
static j6_koid_t next_koid;
kobject::kobject(type t, j6_signal_t signals) :
m_koid(koid_generate(t)),
m_signals(signals),
m_observers(g_kernel_heap),
m_handle_count(0)
{}
kobject::~kobject()
{
notify_signal_observers(0, j6_status_destroyed);
}
j6_koid_t
kobject::koid_generate(type t)
{
return (static_cast<uint64_t>(t) << 48) | next_koid++;
}
kobject::type
kobject::koid_type(j6_koid_t koid)
{
return static_cast<type>((koid >> 48) & 0xffffull);
}
void
kobject::assert_signal(j6_signal_t s)
{
m_signals |= s;
notify_signal_observers(s);
}
void
kobject::deassert_signal(j6_signal_t s)
{
m_signals &= ~s;
notify_signal_observers(s);
}
void
kobject::register_signal_observer(observer *object, j6_signal_t s)
{
m_observers.emplace(object, s);
}
void
kobject::deregister_signal_observer(observer *object)
{
for (size_t i = 0; i < m_observers.count(); ++i) {
auto &reg = m_observers[i];
if (reg.object != object) continue;
reg = m_observers[m_observers.count() - 1];
m_observers.remove();
break;
}
}
void
kobject::notify_signal_observers(j6_signal_t mask, j6_status_t result)
{
for (auto &reg : m_observers) {
if (mask == 0 || (reg.signals & mask) != 0) {
if (!reg.object->on_signals_changed(this, m_signals, mask, result))
reg.object = nullptr;
}
}
// Compact the observer list
long last = m_observers.count() - 1;
while (m_observers[last].object == nullptr && last >= 0) last--;
for (long i = 0; i < long(m_observers.count()) && i < last; ++i) {
auto &reg = m_observers[i];
if (reg.object != nullptr) continue;
reg = m_observers[last--];
while (m_observers[last].object == nullptr && last >= i) last--;
}
m_observers.set_size(last + 1);
}
void
kobject::on_no_handles()
{
assert_signal(j6_signal_no_handles);
}

View File

@@ -0,0 +1,110 @@
#pragma once
/// \file kobject.h
/// Definition of base type for user-interactable kernel objects
#include "j6/errors.h"
#include "j6/types.h"
#include "kutil/vector.h"
/// Base type for all user-interactable kernel objects
class kobject
{
public:
/// Types of kernel objects.
enum class type : uint16_t
{
none,
event,
eventpair,
vms,
vmo,
job,
process,
thread,
};
kobject(type t, j6_signal_t signals = 0ull);
virtual ~kobject();
/// Generate a new koid for a given type
/// \arg t The object type
/// \returns A new unique koid
static j6_koid_t koid_generate(type t);
/// Get the kobject type from a given koid
/// \arg koid An existing koid
/// \returns The object type for the koid
static type koid_type(j6_koid_t koid);
/// Set the given signals active on this object
/// \arg s The set of signals to assert
void assert_signal(j6_signal_t s);
/// Clear the given signals on this object
/// \arg s The set of signals to deassert
void deassert_signal(j6_signal_t s);
class observer
{
public:
/// Callback for when signals change.
/// \arg obj The object triggering the callback
/// \arg s The current state of obj's signals
/// \arg ds Which signals caused the callback
/// \arg result Status code for this notification
/// \returns True if this object wants to keep watching signals
virtual bool on_signals_changed(
kobject *obj,
j6_signal_t s,
j6_signal_t ds,
j6_status_t result) = 0;
};
/// Register a signal observer
/// \arg object The observer
/// \arg s The signals the object wants notifiations for
void register_signal_observer(observer *object, j6_signal_t s);
/// Deegister a signal observer
/// \arg object The observer
void deregister_signal_observer(observer *object);
/// Increment the handle refcount
inline void handle_retain() { ++m_handle_count; }
/// Decrement the handle refcount
inline void handle_release() {
if (--m_handle_count == 0) on_no_handles();
}
protected:
kobject() = delete;
kobject(const kobject &other) = delete;
kobject(const kobject &&other) = delete;
/// Notifiy observers of this object
/// \arg mask The signals that triggered this call. If 0, notify all observers.
/// \arg result The result to pass to the observers
void notify_signal_observers(j6_signal_t mask, j6_status_t result = j6_status_ok);
/// Interface for subclasses to handle when all handles are closed. Subclasses
/// should either call the base version, or assert j6_signal_no_handles.
virtual void on_no_handles();
j6_koid_t m_koid;
j6_signal_t m_signals;
uint16_t m_handle_count;
struct observer_registration
{
observer_registration(observer* o = nullptr, j6_signal_t s = 0) :
object(o), signals(s) {}
observer *object;
j6_signal_t signals;
};
kutil::vector<observer_registration> m_observers;
};

View File

@@ -1,21 +1,28 @@
#include <algorithm>
#include "kutil/assert.h"
#include "kutil/vm_space.h"
#include "console.h"
#include "io.h"
#include "log.h"
#include "page_manager.h"
using memory::frame_size;
using memory::heap_start;
using memory::kernel_max_heap;
using memory::kernel_offset;
using memory::page_offset;
using memory::page_mappable;
extern kutil::address_manager g_kernel_address_manager;
page_manager g_page_manager(
g_frame_allocator,
g_kernel_address_manager);
page_manager g_page_manager(g_frame_allocator);
extern kutil::vm_space g_kspace;
// NB: in 4KiB page table entries, bit 7 isn't pagesize but PAT. Currently this
// doesn't matter, becasue in the default PAT table, both 000 and 100 are WB.
constexpr uint64_t sys_page_flags = 0x183; // global, pagesize, write, present
constexpr uint64_t sys_table_flags = 0x003; // write, present
constexpr uint64_t user_page_flags = 0x087; // pagesize, user, write, present
constexpr uint64_t user_table_flags = 0x007; // user, write, present
static uintptr_t
pt_to_phys(page_table *pt)
@@ -38,12 +45,10 @@ struct free_page_header
};
page_manager::page_manager(
frame_allocator &frames,
kutil::address_manager &addrs) :
page_manager::page_manager(frame_allocator &frames) :
m_page_cache(nullptr),
m_frames(frames),
m_addrs(addrs)
m_memory_initialized(false)
{
}
@@ -72,52 +77,18 @@ page_manager::copy_page(uintptr_t orig)
bool paged_orig = false;
bool paged_copy = false;
uintptr_t orig_virt;
if (page_mappable(orig)) {
orig_virt = orig + page_offset;
} else {
orig_virt = m_addrs.allocate(frame_size);
page_in(get_pml4(), orig, orig_virt, 1);
paged_orig = true;
}
uintptr_t copy = 0;
uintptr_t copy_virt;
size_t n = m_frames.allocate(1, &copy);
kassert(n, "copy_page could not allocate page");
if (page_mappable(copy)) {
copy_virt = copy + page_offset;
} else {
copy_virt = m_addrs.allocate(frame_size);
page_in(get_pml4(), copy, copy_virt, 1);
paged_copy = true;
}
// TODO: multiple page copies at a time, so that we don't have to keep
// paying this mapping penalty
if (paged_orig || paged_copy) {
set_pml4(get_pml4());
__sync_synchronize();
io_wait();
}
uintptr_t orig_virt = orig + page_offset;
uintptr_t copy_virt = copy + page_offset;
kutil::memcpy(
reinterpret_cast<void *>(copy_virt),
reinterpret_cast<void *>(orig_virt),
frame_size);
if (paged_orig) {
page_out(get_pml4(), orig_virt, 1);
m_addrs.free(orig_virt);
}
if (paged_copy) {
page_out(get_pml4(), copy_virt, 1);
m_addrs.free(copy_virt);
}
return copy;
}
@@ -246,10 +217,7 @@ page_manager::free_table_pages(void *pages, size_t count)
void *
page_manager::map_pages(uintptr_t address, size_t count, bool user, page_table *pml4)
{
if (!address) {
kassert(!user, "Cannot call map_pages with 0 address for user mapping");
address = m_addrs.allocate(count * frame_size);
}
kassert(address, "Cannot call map_pages with 0 address");
void *ret = reinterpret_cast<void *>(address);
if (!pml4) pml4 = get_pml4();
@@ -346,19 +314,21 @@ page_manager::unmap_pages(void* address, size_t count, page_table *pml4)
uintptr_t iaddr = reinterpret_cast<uintptr_t>(address);
page_out(pml4, iaddr, count, true);
if (iaddr >= kernel_offset) {
// TODO
// m_addrs.free(address, count);
}
}
bool
page_manager::fault_handler(uintptr_t addr)
{
if (!m_addrs.contains(addr))
if (!addr)
return false;
if (m_memory_initialized &&
g_kspace.get(addr) != kutil::vm_state::committed)
return false;
uintptr_t page = addr & ~0xfffull;
log::debug(logs::memory, "PF: attempting to page in %016lx for %016lx", page, addr);
bool user = addr < kernel_offset;
map_pages(page, 1, user);
@@ -372,7 +342,7 @@ page_manager::check_needs_page(page_table *table, unsigned index, bool user)
page_table *new_table = get_table_page();
for (int i=0; i<512; ++i) new_table->entries[i] = 0;
table->entries[index] = pt_to_phys(new_table) | (user ? 0xf : 0xb);
table->entries[index] = pt_to_phys(new_table) | (user ? user_table_flags : sys_table_flags);
}
void
@@ -386,9 +356,7 @@ page_manager::page_in(page_table *pml4, uintptr_t phys_addr, uintptr_t virt_addr
page_table_indices idx{virt_addr};
page_table *tables[4] = {pml4, nullptr, nullptr, nullptr};
uint64_t flags = user ?
0x00f: // writethru, user, write, present
0x10b; // global, writethru, write, present
uint64_t flags = user ? user_table_flags : sys_table_flags;
for (; idx[0] < 512; idx[0] += 1) {
check_needs_page(tables[0], idx[0], user);

View File

@@ -5,10 +5,9 @@
#include <stddef.h>
#include <stdint.h>
#include "kutil/address_manager.h"
#include "kutil/enum_bitfields.h"
#include "kutil/linked_list.h"
#include "kutil/slab_allocator.h"
#include "kutil/memory.h"
#include "frame_allocator.h"
#include "kernel_memory.h"
#include "page_table.h"
@@ -19,9 +18,9 @@ struct free_page_header;
class page_manager
{
public:
page_manager(
frame_allocator &frames,
kutil::address_manager &addrs);
/// Constructor.
/// \arg frames The frame allocator to get physical frames from
page_manager(frame_allocator &frames);
/// Helper to get the number of pages needed for a given number of bytes.
/// \arg bytes The number of bytes desired
@@ -67,8 +66,7 @@ public:
page_table_indices index = {});
/// Allocate and map pages into virtual memory.
/// \arg address The virtual address at which to map the pages, or zero
/// for any free kernel space.
/// \arg address The virtual address at which to map the pages
/// \arg count The number of pages to map
/// \arg user True is this memory is user-accessible
/// \arg pml4 The pml4 to map into - null for the current one
@@ -176,7 +174,8 @@ private:
free_page_header *m_page_cache; ///< Cache of free pages to use for tables
frame_allocator &m_frames;
kutil::address_manager &m_addrs;
bool m_memory_initialized;
friend class memory_bootstrap;
page_manager(const page_manager &) = delete;
@@ -211,7 +210,7 @@ page_table_align(T p)
/// Bootstrap the memory managers.
kutil::allocator & memory_initialize(
void memory_initialize(
uint16_t scratch_pages,
const void *memory_map,
size_t map_length,

View File

@@ -14,10 +14,6 @@ extern "C" {
namespace syscalls {
void send() {}
void receive() {}
} // namespace syscalls
uintptr_t syscall_registry[static_cast<unsigned>(syscall::MAX)];
@@ -145,15 +141,14 @@ syscall_enable()
static constexpr unsigned num_calls =
static_cast<unsigned>(syscall::MAX);
for (unsigned i = 0; i < num_calls; ++i) {
syscall_registry[i] = reinterpret_cast<uintptr_t>(syscall_invalid);
syscall_names[i] = nullptr;
}
kutil::memset(&syscall_registry, 0, sizeof(syscall_registry));
kutil::memset(&syscall_names, 0, sizeof(syscall_names));
#define SYSCALL(id, name, result, ...) \
syscall_registry[id] = reinterpret_cast<uintptr_t>(syscalls::name); \
syscall_names[id] = #name; \
static_assert( id <= num_calls, "Syscall " #name " has id > syscall::MAX" );
static_assert( id <= num_calls, "Syscall " #name " has id > syscall::MAX" ); \
log::debug(logs::syscall, "Enabling syscall 0x%02x as " #name , id);
#include "syscalls.inc"
#undef SYSCALL
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include <stdint.h>
#include "j6/types.h"
struct cpu_state;
@@ -19,7 +20,7 @@ void syscall_enable();
namespace syscalls
{
#define SYSCALL(id, name, result, ...) result name (__VA_ARGS__);
#define SYSCALL(id, name, ...) j6_status_t name (__VA_ARGS__);
#include "syscalls.inc"
#undef SYSCALL
}

View File

@@ -34,12 +34,16 @@ syscall_handler_prelude:
cmp rax, MAX_SYSCALLS
jle .ok_syscall
.bad_syscall:
mov rdi, rax
call syscall_invalid
.ok_syscall:
lea r11, [rel syscall_registry]
mov r11, [r11 + rax * 8]
cmp r11, 0
je .bad_syscall
call r11
inc qword [rel __counter_syscall_sysret]

View File

@@ -1,12 +0,0 @@
SYSCALL(0x00, noop, void)
SYSCALL(0x01, exit, void, int64_t)
SYSCALL(0x02, getpid, pid_t)
SYSCALL(0x03, fork, pid_t)
SYSCALL(0x10, message, void, const char *)
SYSCALL(0x20, pause, void)
SYSCALL(0x21, sleep, void, uint64_t)
SYSCALL(0x30, send, void)
SYSCALL(0x31, receive, void)

View File

@@ -1,17 +0,0 @@
#include "log.h"
#include "scheduler.h"
namespace syscalls {
void
exit(int64_t status)
{
auto &s = scheduler::get();
auto *p = s.current();
log::debug(logs::syscall, "Process %d exiting with code %d", p->pid, status);
p->exit(status);
s.schedule();
}
} // namespace syscalls

View File

@@ -1,24 +0,0 @@
#include "log.h"
#include "scheduler.h"
namespace syscalls {
pid_t
fork()
{
auto &s = scheduler::get();
auto *p = s.current();
pid_t ppid = p->pid;
log::debug(logs::syscall, "Process %d calling fork()", ppid);
pid_t pid = p->fork();
p = s.current();
log::debug(logs::syscall, "Process %d's fork: returning %d from process %d", ppid, pid, p->pid);
return pid;
}
} // namespace syscalls

View File

@@ -1,14 +0,0 @@
#include "log.h"
#include "scheduler.h"
namespace syscalls {
pid_t
getpid()
{
auto &s = scheduler::get();
auto *p = s.current();
return p->pid;
}
} // namespace syscalls

View File

@@ -1,14 +0,0 @@
#include "log.h"
#include "scheduler.h"
namespace syscalls {
void
message(const char *message)
{
auto &s = scheduler::get();
auto *p = s.current();
log::info(logs::syscall, "Message[%d]: %s", p->pid, message);
}
} // namespace syscalls

View File

@@ -1,14 +1,24 @@
#include "j6/errors.h"
#include "j6/types.h"
#include "log.h"
#include "scheduler.h"
namespace syscalls {
void
noop()
j6_status_t
object_noop()
{
auto &s = scheduler::get();
auto *p = s.current();
log::debug(logs::syscall, "Process %d called noop syscall.", p->pid);
return j6_status_ok;
}
j6_status_t
object_wait(j6_handle_t, j6_signal_t, j6_signal_t*)
{
return j6_err_nyi;
}
} // namespace syscalls

View File

@@ -1,15 +0,0 @@
#include "log.h"
#include "scheduler.h"
namespace syscalls {
void
pause()
{
auto &s = scheduler::get();
auto *p = s.current();
p->wait_on_signal(-1ull);
s.schedule();
}
} // namespace syscalls

View File

@@ -0,0 +1,93 @@
#include "j6/errors.h"
#include "j6/types.h"
#include "log.h"
#include "scheduler.h"
namespace syscalls {
j6_status_t
process_exit(int64_t status)
{
auto &s = scheduler::get();
auto *p = s.current();
log::debug(logs::syscall, "Process %d exiting with code %d", p->pid, status);
p->exit(status);
s.schedule();
log::error(logs::syscall, "returned to exit syscall");
return j6_err_unexpected;
}
j6_status_t
process_fork(pid_t *pid)
{
if (pid == nullptr) {
return j6_err_invalid_arg;
}
auto &s = scheduler::get();
auto *p = s.current();
pid_t ppid = p->pid;
log::debug(logs::syscall, "Process %d calling fork(%016llx)", ppid, pid);
*pid = p->fork();
p = s.current();
log::debug(logs::syscall, "Process %d's fork: returning %d from process %d", ppid, *pid, p->pid);
return j6_status_ok;
}
j6_status_t
process_getpid(pid_t *pid)
{
if (pid == nullptr) {
return j6_err_invalid_arg;
}
auto &s = scheduler::get();
auto *p = s.current();
*pid = p->pid;
return j6_status_ok;
}
j6_status_t
process_log(const char *message)
{
if (message == nullptr) {
return j6_err_invalid_arg;
}
auto &s = scheduler::get();
auto *p = s.current();
log::info(logs::syscall, "Message[%d]: %s", p->pid, message);
return j6_status_ok;
}
j6_status_t
process_pause()
{
auto &s = scheduler::get();
auto *p = s.current();
p->wait_on_signal(-1ull);
s.schedule();
return j6_status_ok;
}
j6_status_t
process_sleep(uint64_t til)
{
auto &s = scheduler::get();
auto *p = s.current();
log::debug(logs::syscall, "Process %d sleeping until %d", p->pid, til);
p->wait_on_time(til);
s.schedule();
return j6_status_ok;
}
} // namespace syscalls

View File

@@ -1,17 +0,0 @@
#include "log.h"
#include "scheduler.h"
namespace syscalls {
void
sleep(uint64_t til)
{
auto &s = scheduler::get();
auto *p = s.current();
log::debug(logs::syscall, "Process %d sleeping until %d", p->pid, til);
p->wait_on_time(til);
s.schedule();
}
} // namespace syscalls

View File

@@ -0,0 +1,13 @@
#pragma once
#include <stdint.h>
namespace initrd {
enum class file_type : uint8_t
{
unknown,
executable,
vdso
};
} // namespace initrd

View File

@@ -1,6 +1,7 @@
#pragma once
#include <stdint.h>
#include "kutil/enum_bitfields.h"
#include "initrd/file_type.h"
namespace initrd {
@@ -18,10 +19,8 @@ struct disk_header
uint8_t reserved[3];
} __attribute__ ((packed));
enum class file_flags : uint16_t
enum class file_flags : uint8_t
{
executable = 0x01
};
struct file_header
@@ -29,10 +28,10 @@ struct file_header
uint32_t offset;
uint32_t length;
uint16_t name_offset;
file_type type;
file_flags flags;
} __attribute__ ((packed));
} // namepsace initrd
IS_BITFIELD(initrd::disk_flags);
IS_BITFIELD(initrd::file_flags);

View File

@@ -1,10 +1,11 @@
#pragma once
/// \file initrd.h
/// Definitions defining the simple inital ramdisk file format used by the
/// popcorn kernel.
/// jsix kernel.
#include <stdint.h>
#include "kutil/vector.h"
#include "initrd/file_type.h"
// File format:
// 1x disk_header
@@ -33,8 +34,8 @@ public:
/// Get a pointer to the file data
const void * data() const;
/// Whether this file is an executable
bool executable() const;
/// Type of file
file_type type() const;
private:
const file_header *m_header;

View File

@@ -16,11 +16,7 @@ file::file(const file_header *header, const void *start) :
const char * file::name() const { return m_name; }
const size_t file::size() const { return m_header->length; }
const void * file::data() const { return m_data; }
bool
file::executable() const {
return bitfield_has(m_header->flags, file_flags::executable);
}
file_type file::type() const { return m_header->type; }
disk::disk(const void *start, kutil::allocator &alloc) :

View File

@@ -0,0 +1,250 @@
#pragma once
/// \file avl_tree.h
/// Templated container class for an AVL tree
#include <algorithm>
#include <stdint.h>
#include "kutil/assert.h"
namespace kutil {
template <typename T> class avl_tree;
/// A node in a `avl_tree<T>`
template <typename T>
class avl_node :
public T
{
public:
using item_type = T;
using node_type = avl_node<T>;
/// Dereference operator. Helper to cast this node to the contained type.
/// \returns A pointer to the node, cast to T*.
inline item_type & operator*() { return *this; }
/// Dereference operator. Helper to cast this node to the contained type.
/// \returns A pointer to the node, cast to T*.
inline const item_type & operator*() const { return *this; }
/// Cast operator. Helper to cast this node to the contained type.
/// \returns A reference to the node, cast to T&.
inline operator item_type& () { return *this; }
/// Cast operator. Helper to cast this node to the contained type.
/// \returns A reference to the node, cast to const T&.
inline operator const item_type& () { return *this; }
/// Helper to cast this node to the contained type.
/// \returns A reference to the node, cast to const T&.
inline const item_type& item() const { return *this; }
/// Helper to cast this node to the contained type.
/// \returns A reference to the node, cast to T&.
inline item_type& item() { return *this; }
/// Accessor for the left child.
/// \returns A pointer to the left child, or nullptr.
inline node_type * left() { return m_left; }
/// Accessor for the left child.
/// \returns A pointer to the left child, or nullptr.
inline const node_type * left() const { return m_left; }
/// Accessor for the right child.
/// \returns A pointer to the right child, or nullptr.
inline node_type * right() { return m_right; }
/// Accessor for the right child.
/// \returns A pointer to the right child, or nullptr.
inline const node_type * right() const { return m_right; }
private:
friend class avl_tree<T>;
inline static int height(node_type *l) { return (l ? l->m_height : 0); }
// Update this node's height and return its new balance factor
inline int update_height()
{
int left = height(m_left);
int right = height(m_right);
m_height = std::max(left, right) + 1;
return left - right;
}
int bias(node_type *addend)
{
const item_type &this_item = *this;
const item_type &that_item = *addend;
if (that_item < this_item)
return -1;
else if (that_item > this_item)
return 1;
kassert(false, "Equal items not allowed in AVL tree");
return 0;
}
static node_type * rotate_right(node_type *existing)
{
node_type *root = existing->m_left;
node_type *left = root->m_right;
root->m_right = existing;
existing->m_left = left;
existing->update_height();
root->update_height();
return root;
}
static node_type * rotate_left(node_type *existing)
{
node_type *root = existing->m_right;
node_type *right = root->m_left;
root->m_left = existing;
existing->m_right = right;
existing->update_height();
root->update_height();
return root;
}
static node_type * insert(node_type *existing, node_type *addend)
{
if (existing == nullptr)
return addend;
if (existing->compare(addend) < 0)
existing->m_left = insert(existing->m_left, addend);
else
existing->m_right = insert(existing->m_right, addend);
int balance = existing->update_height();
if (balance > 1) {
// Left-heavy
if (existing->m_left->compare(addend) < 0) {
// Left Left
return rotate_right(existing);
} else {
// Left Right
existing->m_left = rotate_left(existing->m_left);
return rotate_right(existing);
}
} else if (balance < -1) {
// Right-heavy
if (existing->m_right->compare(addend) > 0) {
// Right Right
return rotate_left(existing);
} else {
// Right Left
existing->m_right = rotate_right(existing->m_right);
return rotate_left(existing);
}
}
return existing;
}
static node_type * remove(node_type *existing, node_type *subtrahend, allocator &alloc)
{
if (existing == nullptr)
return existing;
if (existing == subtrahend) {
if (!existing->m_left || !existing->m_right) {
// At least one child is null
node_type *temp = existing->m_left ?
existing->m_left : existing->m_right;
if (temp == nullptr) {
// Both were null
temp = existing;
existing = nullptr;
} else {
*existing = *temp;
}
alloc.free(temp);
} else {
// Both children exist, find next node
node_type *temp = existing->m_right;
while (temp->m_left)
temp = temp->m_left;
*existing = *temp;
existing->m_right = remove(existing->m_right, temp, alloc);
}
} else if (existing->compare(subtrahend) < 0) {
existing->m_left = remove(existing->m_left, subtrahend, alloc);
} else {
existing->m_right = remove(existing->m_right, subtrahend, alloc);
}
if (!existing)
return nullptr;
int balance = existing->update_height();
if (balance > 1) {
int left_balance = existing->m_left->update_height();
if (left_balance < 0)
existing->m_left = rotate_left(existing->m_left);
return rotate_right(existing);
} else if (balance < -1) {
int right_balance = existing->m_right->update_height();
if (right_balance > 0)
existing->m_right = rotate_right(existing->m_right);
return rotate_left(existing);
}
return existing;
}
int m_height;
node_type *m_left;
node_type *m_right;
};
template <typename T>
class avl_tree
{
public:
using item_type = T;
using node_type = avl_node<T>;
avl_tree() = default;
avl_tree(avl_tree &&other) :
m_count(other.m_count), m_root(other.m_root)
{
other.m_root = nullptr;
other.m_count = 0;
}
inline node_type * root() { return m_root; }
inline unsigned count() const { return m_count; }
inline void remove(node_type *subtrahend, allocator &alloc) {
m_root = node_type::remove(m_root, subtrahend, alloc);
m_count--;
}
inline void insert(node_type *addend) {
m_root = node_type::insert(m_root, addend);
m_count++;
}
private:
unsigned m_count {0};
node_type *m_root {nullptr};
};
} // namespace kutil

View File

@@ -110,7 +110,7 @@ void fatal(area_t area, const char *fmt, ...);
} // namespace log
namespace logs {
#define LOG(name, lvl) extern log::area_t name;
#define LOG(name, lvl) extern const log::area_t name;
#include "log_areas.inc"
#undef LOG
} // namespace logs

View File

@@ -12,24 +12,36 @@ namespace kutil {
/// A slab allocator for small structures kept in a linked list
template <typename T, size_t N = memory::frame_size>
class slab_allocator :
public linked_list<T>
public linked_list<T>,
public allocator
{
public:
using item_type = list_node<T>;
/// Default constructor.
/// \arg chunk_size The size of chunk to allocate, in bytes. 0 means default.
/// \arg alloc The allocator to use to allocate chunks. Defaults to malloc().
slab_allocator(allocator &alloc) :
m_alloc(alloc)
m_alloc(alloc) {}
/// Allocator interface implementation
virtual void * allocate(size_t size) override
{
kassert(size == sizeof(T), "Asked slab allocator for wrong size");
if (size != sizeof(T)) return 0;
return pop();
}
/// Allocator interface implementation
virtual void free(void *p) override
{
push(static_cast<item_type*>(p));
}
/// Get an item from the cache. May allocate a new chunk if the cache is empty.
/// \returns An allocated element
inline item_type * pop()
{
if (this->empty()) allocate();
if (this->empty()) this->allocate_chunk();
kassert(!this->empty(), "Slab allocator is empty after allocate()");
item_type *item = this->pop_front();
kutil::memset(item, 0, sizeof(item_type));
@@ -43,7 +55,8 @@ public:
this->push_front(item);
}
void allocate()
private:
void allocate_chunk()
{
constexpr unsigned count = N / sizeof(item_type);
@@ -53,7 +66,6 @@ public:
this->push_back(&items[i]);
}
private:
allocator& m_alloc;
};

View File

@@ -117,12 +117,14 @@ public:
m_elements[m_size].~T();
}
/// Set the size of the array. Any new items are default
/// constructed. The array is realloced if needed.
/// Set the size of the array. Any new items are default constructed.
/// Any items past the end are deleted. The array is realloced if needed.
/// \arg size The new size
void set_size(size_t size)
{
ensure_capacity(size);
for (size_t i = size; i < m_size; ++i)
m_elements[i].~T();
for (size_t i = m_size; i < size; ++i)
new (&m_elements[i]) T;
m_size = size;

View File

@@ -0,0 +1,84 @@
#pragma once
/// \file vm_range.h
/// Structure for tracking a range of virtual memory addresses
#include <stdint.h>
#include "kutil/allocator.h"
#include "kutil/avl_tree.h"
#include "kutil/slab_allocator.h"
namespace kutil {
enum class vm_state : uint8_t {
unknown,
none,
reserved,
committed,
mapped
};
struct vm_range
{
uintptr_t address;
size_t size;
vm_state state;
inline uintptr_t end() const { return address + size; }
inline int compare(const vm_range *other) const {
return other->address - address;
}
};
/// Tracks a region of virtual memory address space
class vm_space
{
public:
/// Default constructor. Define an empty range.
vm_space();
/// Constructor. Define a range of managed VM space.
/// \arg start Starting address of the managed space
/// \arg size Size of the managed space, in bytes
/// \arg alloc Allocator to use for tracking objects
vm_space(uintptr_t start, size_t size, kutil::allocator &alloc);
/// Reserve a section of address space.
/// \arg start Starting address of reservaion, or 0 for any address
/// \arg size Size of reservation in bytes
/// \returns The address of the reservation, or 0 on failure
uintptr_t reserve(uintptr_t start, size_t size);
/// Unreserve (and uncommit, if committed) a section of address space.
/// \arg start Starting address of reservaion
/// \arg size Size of reservation in bytes
void unreserve(uintptr_t start, size_t size);
/// Mark a section of address space as committed.
/// \arg start Starting address of reservaion
/// \arg size Size of reservation in bytes
/// \returns The address of the reservation, or 0 on failure
uintptr_t commit(uintptr_t start, size_t size);
/// Mark a section of address space as uncommitted, but still reserved.
/// \arg start Starting address of reservaion
/// \arg size Size of reservation in bytes
void uncommit(uintptr_t start, size_t size);
/// Check the state of the given address.
/// \arg addr The address to check
/// \returns The state of the memory if known, or 'unknown'
vm_state get(uintptr_t addr);
private:
using node_type = kutil::avl_node<vm_range>;
using tree_type = kutil::avl_tree<vm_range>;
node_type * split_out(node_type* node, uintptr_t start, size_t size, vm_state state);
node_type * consolidate(node_type* needle);
slab_allocator<node_type> m_slab;
allocator &m_alloc;
tree_type m_ranges;
};
} // namespace kutil

View File

@@ -7,7 +7,7 @@
namespace kutil {
namespace logs {
#define LOG(name, lvl) \
log::area_t name = #name ## _h; \
const log::area_t name = #name ## _h; \
const char * name ## _name = #name;
#include "log_areas.inc"
#undef LOG
@@ -19,7 +19,7 @@ using kutil::memset;
using kutil::memcpy;
logger *logger::s_log = nullptr;
const char *logger::s_level_names[] = {"", "debug", " info", " warn", "error", "fatal"};
const char *logger::s_level_names[] = {"", "debug", "info", "warn", "error", "fatal"};
logger::logger() :
m_buffer(nullptr, 0),

View File

@@ -0,0 +1,205 @@
#include <algorithm>
#include "kutil/logger.h"
#include "kutil/vector.h"
#include "kutil/vm_space.h"
namespace kutil {
using node_type = kutil::avl_node<vm_range>;
using node_vec = kutil::vector<node_type*>;
vm_space::vm_space(uintptr_t start, size_t size, allocator &alloc) :
m_slab(alloc),
m_alloc(alloc)
{
node_type *node = m_slab.pop();
node->address = start;
node->size = size;
node->state = vm_state::none;
m_ranges.insert(node);
log::info(logs::vmem, "Creating address space from %016llx-%016llx",
start, start+size);
}
vm_space::vm_space() :
m_slab(allocator::invalid),
m_alloc(allocator::invalid)
{
}
inline static bool
overlaps(node_type *node, uintptr_t start, size_t size)
{
return start < node->end() &&
(start + size) > node->address;
}
static node_type *
find_overlapping(node_type *from, uintptr_t start, size_t size)
{
while (from) {
if (overlaps(from, start, size))
return from;
from = start < from->address ?
from->left() :
from->right();
}
return nullptr;
}
node_type *
vm_space::split_out(node_type *node, uintptr_t start, size_t size, vm_state state)
{
// No cross-boundary splits allowed for now
bool contained =
start >= node->address &&
start+size <= node->end();
kassert(contained,
"Tried to split an address range across existing boundaries");
if (!contained)
return nullptr;
vm_state old_state = node->state;
if (state == old_state)
return node;
node->state = state;
log::debug(logs::vmem, "Splitting out region %016llx-%016llx[%d] from %016llx-%016llx[%d]",
start, start+size, state, node->address, node->end(), old_state);
bool do_consolidate = false;
if (node->address < start) {
// Split off rest into new node
size_t leading = start - node->address;
node_type *next = m_slab.pop();
next->state = state;
next->address = start;
next->size = node->size - leading;
node->size = leading;
node->state = old_state;
log::debug(logs::vmem,
" leading region %016llx-%016llx[%d]",
node->address, node->address + node->size, node->state);
m_ranges.insert(next);
node = next;
} else {
do_consolidate = true;
}
if (node->end() > start + size) {
// Split off remaining into new node
size_t trailing = node->size - size;
node->size -= trailing;
node_type *next = m_slab.pop();
next->state = old_state;
next->address = node->end();
next->size = trailing;
log::debug(logs::vmem,
" tailing region %016llx-%016llx[%d]",
next->address, next->address + next->size, next->state);
m_ranges.insert(next);
} else {
do_consolidate = true;
}
if (do_consolidate)
node = consolidate(node);
return node;
}
inline void gather(node_type *node, node_vec &vec)
{
if (node) {
gather(node->left(), vec);
vec.append(node);
gather(node->right(), vec);
}
}
node_type *
vm_space::consolidate(node_type *needle)
{
node_vec nodes(m_ranges.count(), m_alloc);
gather(m_ranges.root(), nodes);
node_type *prev = nullptr;
for (auto *node : nodes) {
log::debug(logs::vmem,
"* Existing region %016llx-%016llx[%d]",
node->address, node->address + node->size, node->state);
if (prev && node->address == prev->end() && node->state == prev->state) {
log::debug(logs::vmem,
"Joining regions %016llx-%016llx[%d] %016llx-%016llx[%d]",
prev->address, prev->address + prev->size, prev->state,
node->address, node->address + node->size, node->state);
prev->size += node->size;
if (needle == node)
needle = prev;
m_ranges.remove(node, m_slab);
} else {
prev = node;
}
}
return needle;
}
uintptr_t
vm_space::reserve(uintptr_t start, size_t size)
{
log::debug(logs::vmem, "Reserving region %016llx-%016llx", start, start+size);
node_type *node = find_overlapping(m_ranges.root(), start, size);
if (!node) {
log::debug(logs::vmem, " found no match");
return 0;
} else if (node->state != vm_state::none) {
log::debug(logs::vmem, " found wrong state %016llx-%016llx[%d]",
node->address, node->address + node->size, node->state);
return 0;
}
node = split_out(node, start, size, vm_state::reserved);
return node ? start : 0;
}
void
vm_space::unreserve(uintptr_t start, size_t size)
{
}
uintptr_t
vm_space::commit(uintptr_t start, size_t size)
{
return 0;
}
void
vm_space::uncommit(uintptr_t start, size_t size)
{
}
vm_state
vm_space::get(uintptr_t addr)
{
node_type *node = find_overlapping(m_ranges.root(), addr, 0);
return node ? node->state : vm_state::unknown;
}
} // namespace kutil

View File

@@ -1,10 +1,10 @@
#include "entry.h"
entry::entry(const std::string &in, const std::string &out, bool executable) :
entry::entry(const std::string &in, const std::string &out, initrd::file_type type) :
m_in(in),
m_out(out),
m_file(in, std::ios_base::binary),
m_exec(executable)
m_type(type)
{
m_file.seekg(0, std::ios_base::end);
m_size = m_file.tellg();

View File

@@ -1,17 +1,18 @@
#pragma once
#include <string>
#include <fstream>
#include "initrd/headers.h"
class entry
{
public:
entry(const std::string &in, const std::string &out, bool executable = false);
entry(const std::string &in, const std::string &out, initrd::file_type type);
inline const std::string & in() const { return m_in; }
inline const std::string & out() const { return m_out; }
inline const std::ifstream & file() const { return m_file; }
inline bool executable() const { return m_exec; }
inline initrd::file_type type() const { return m_type; }
inline size_t size() const { return m_size; }
inline bool good() const { return m_file.good(); }
@@ -20,6 +21,6 @@ private:
std::string m_out;
std::ifstream m_file;
size_t m_size;
bool m_exec;
initrd::file_type m_type;
};

View File

@@ -43,9 +43,15 @@ int main(int argc, char **argv)
return 1;
}
auto exec = file->get_as<bool>("executable").value_or(false);
auto type_name = file->get_as<std::string>("type").value_or("unknown");
initrd::file_type type = initrd::file_type::unknown;
if (type_name == "executable") {
type = initrd::file_type::executable;
} else if (type_name == "vdso") {
type = initrd::file_type::vdso;
}
entries.emplace_back(*source, *dest, exec);
entries.emplace_back(*source, *dest, type);
const entry &e = entries.back();
if (!e.good()) {
@@ -92,9 +98,7 @@ int main(int argc, char **argv)
fheader.offset = file_offset;
fheader.length = e.size();
fheader.name_offset = name_offset;
if (e.executable())
fheader.flags |= initrd::file_flags::executable;
fheader.type = e.type();
out.write(
reinterpret_cast<const char *>(&fheader),

17
src/vdso/overrides.cpp Normal file
View File

@@ -0,0 +1,17 @@
#include <j6/errors.h>
#include <j6/types.h>
#include "vdso_internal.h"
extern "C" {
j6_status_t j6_object_noop() {
// Skip the kernel
return j6_status_ok;
}
// An example of overriding a weak default symbol with a custom function
j6_status_t j6_object_wait(j6_handle_t target, j6_signal_t signals, j6_signal_t *triggered) {
return __sys_j6_object_wait(target, signals, triggered);
}
}

17
src/vdso/syscalls.cpp Normal file
View File

@@ -0,0 +1,17 @@
#include <j6/errors.h>
#include <j6/types.h>
#include "vdso_internal.h"
#define SYSCALL(num, name, ...) \
j6_status_t __sys_j6_##name (__VA_ARGS__) { \
j6_status_t result = 0; \
__asm__ __volatile__ ( "syscall" : "=a"(result) : "a"(num) ); \
return result; \
} \
j6_status_t j6_ ## name(__VA_ARGS__) __weak_alias("__sys_j6_" #name);
extern "C" {
#include "syscalls.inc"
}
#undef SYSCALL

16
src/vdso/vdso_internal.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
/// \file vdso_internal.h
/// VDSO syscall forward-declares and linker utils
#define __weak_alias(name) __attribute__((weak, alias(name)));
#define __local __attribute__((__visibility__("hidden")))
#define SYSCALL(num, name, ...) \
j6_status_t __sys_j6_ ## name (__VA_ARGS__) __local; \
extern "C" {
#include "syscalls.inc"
}
#undef SYSCALL