mirror of
https://github.com/Tom-on64/kern.git
synced 2026-11-03 18:22:22 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c74ea060e5 | ||
|
|
a2cd3aa1b1 | ||
|
|
92268b70fc | ||
|
|
6dd0823c93 | ||
|
|
ffa23b1dba | ||
|
|
6c609e9840 | ||
|
|
318fe96319 | ||
|
|
b0ab02c634 | ||
|
|
a95839c7c6 | ||
|
|
3fe3d05b1b | ||
|
|
700b1ec4b4 | ||
|
|
07bd738566 | ||
|
|
16fde28a8b | ||
|
|
7c0ac01110 | ||
|
|
b917ebe973 | ||
|
|
675ff8519a | ||
|
|
8ab7e5a33d | ||
|
|
eba8b5ad4f | ||
|
|
ce75e8c195 | ||
|
|
9bdc3c8fc9 | ||
|
|
8909e3c4ca | ||
|
|
70114f6326 | ||
|
|
9c386bf447 | ||
|
|
041f1f886b | ||
|
|
4bc3382abb | ||
|
|
22852599df | ||
|
|
12ec371196 | ||
|
|
f10f065e91 | ||
|
|
ad45de562a | ||
|
|
f316916ff1 | ||
|
|
5d67cbd958 | ||
|
|
63a238d2c4 | ||
|
|
2f05396651 | ||
|
|
7a57999d05 | ||
|
|
e43bc126b5 | ||
|
|
004399c122 | ||
|
|
eca7c957e2 | ||
|
|
8cbe050f35 | ||
|
|
74d1edbf9f | ||
|
|
e8d5a8be35 | ||
|
|
421a83d202 | ||
|
|
9c66d7228a | ||
|
|
93ef197e58 | ||
|
|
0214b4da31 | ||
|
|
1542cf0ada | ||
|
|
50a1d6198e | ||
|
|
d9471572b8 | ||
|
|
2b4beae3c5 | ||
|
|
2cd84b5e89 | ||
|
|
024dcfffcc | ||
|
|
d6035dff80 | ||
|
|
c646404cf0 | ||
|
|
a48fa362d0 | ||
|
|
f4b10746d6 | ||
|
|
1a58cfee97 | ||
|
|
5522218767 | ||
|
|
9181f3afd3 | ||
|
|
b8fba03773 | ||
|
|
bbb3c131b3 | ||
|
|
1bc758f3c1 | ||
|
|
7b5efc1837 | ||
|
|
c5193dd188 | ||
|
|
0c2bba8c33 | ||
|
|
30445e9d25 | ||
|
|
a73eb77418 | ||
|
|
354339e831 | ||
|
|
f1bdfc9c9f | ||
|
|
ba28eafb20 | ||
|
|
7c2fcd8e9f | ||
|
|
ced6cb250f | ||
|
|
c2b0f0baa2 | ||
|
|
b104755904 | ||
|
|
25771de53e | ||
|
|
5d7a4d790f | ||
|
|
dd7e621640 | ||
|
|
9d931f9e9d | ||
|
|
5cee647ff0 | ||
|
|
f73a6f9ccb | ||
|
|
4f543f3fd0 | ||
|
|
c3f8d7d8f2 | ||
|
|
05c8ee8f67 | ||
|
|
5076d1c56b | ||
|
|
05561cd857 | ||
|
|
883cd5c1d4 | ||
|
|
244b83d370 | ||
|
|
8674d32f77 | ||
|
|
609e10e13c | ||
|
|
f9dece59ce | ||
|
|
983174a081 | ||
|
|
7d41cf45ed |
+297
@@ -0,0 +1,297 @@
|
||||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionDeclarations: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionDeclarations: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionDeclarations: true
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionDeclarations: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveShortCaseStatements:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCaseArrows: false
|
||||
AlignCaseColons: false
|
||||
AlignConsecutiveTableGenBreakingDAGArgColons:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionDeclarations: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveTableGenCondOperatorColons:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionDeclarations: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveTableGenDefinitionColons:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionDeclarations: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments:
|
||||
Kind: Always
|
||||
OverEmptyLines: 0
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowBreakBeforeNoexceptSpecifier: Never
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseExpressionOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortCompoundRequirementOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortNamespacesOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: true
|
||||
BinPackLongBracedList: true
|
||||
BinPackParameters: BinPack
|
||||
BitFieldColonSpacing: Both
|
||||
BracedInitializerIndentWidth: -1
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterExternBlock: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakAdjacentStringLiterals: true
|
||||
BreakAfterAttributes: Leave
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakAfterReturnType: None
|
||||
BreakArrays: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInlineASMColon: OnlyMultiline
|
||||
BreakBeforeTemplateCloser: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakBinaryOperations: Never
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakFunctionDefinitionParameters: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakStringLiterals: true
|
||||
BreakTemplateDeclarations: MultiLine
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
EnumTrailingComma: Leave
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseBlocks: false
|
||||
IndentCaseLabels: false
|
||||
IndentExportBlock: true
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentRequiresClause: true
|
||||
IndentWidth: 8
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertBraces: false
|
||||
InsertNewlineAtEOF: false
|
||||
InsertTrailingCommas: None
|
||||
IntegerLiteralSeparator:
|
||||
Binary: 0
|
||||
BinaryMinDigits: 0
|
||||
Decimal: 0
|
||||
DecimalMinDigits: 0
|
||||
Hex: 0
|
||||
HexMinDigits: 0
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLines:
|
||||
AtEndOfFile: false
|
||||
AtStartOfBlock: true
|
||||
AtStartOfFile: true
|
||||
KeepFormFeed: false
|
||||
LambdaBodyIndentation: Signature
|
||||
LineEnding: DeriveLF
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MainIncludeChar: Quote
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
OneLineFormatOffRegex: ''
|
||||
PackConstructorInitializers: BinPack
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakBeforeMemberAccess: 150
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakScopeResolution: 500
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Left
|
||||
PPIndentWidth: -1
|
||||
QualifierAlignment: Leave
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: Always
|
||||
RemoveBracesLLVM: false
|
||||
RemoveEmptyLinesInUnwrappedLines: false
|
||||
RemoveParentheses: Leave
|
||||
RemoveSemicolon: false
|
||||
RequiresClausePosition: OwnLine
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SkipMacroDefinitionBody: false
|
||||
SortIncludes:
|
||||
Enabled: true
|
||||
IgnoreCase: false
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: LexicographicNumeric
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterOperatorKeyword: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeJsonColon: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: true
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: true
|
||||
AfterNot: false
|
||||
AfterOverloadedOperator: false
|
||||
AfterPlacementOperator: true
|
||||
AfterRequiresInClause: false
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParens: Never
|
||||
SpacesInParensOptions:
|
||||
ExceptDoubleParentheses: false
|
||||
InCStyleCasts: false
|
||||
InConditionalStatements: false
|
||||
InEmptyParentheses: false
|
||||
Other: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TableGenBreakInsideDAGArg: DontBreak
|
||||
TabWidth: 8
|
||||
UseTab: Always
|
||||
VerilogBreakBetweenInstancePorts: true
|
||||
WhitespaceSensitiveMacros:
|
||||
- BOOST_PP_STRINGIZE
|
||||
- CF_SWIFT_NAME
|
||||
- NS_SWIFT_NAME
|
||||
- PP_STRINGIZE
|
||||
- STRINGIZE
|
||||
WrapNamespaceBodyWithEmptyLines: Leave
|
||||
...
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*.sys
|
||||
*.dtb
|
||||
*~
|
||||
sysroot
|
||||
|
||||
# Local
|
||||
DS_Store
|
||||
@@ -27,4 +28,10 @@ DS_Store
|
||||
*.swo
|
||||
/.clangd
|
||||
/.cache
|
||||
/compile_commands.json
|
||||
.ssp
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
/log
|
||||
|
||||
|
||||
@@ -1,13 +1,674 @@
|
||||
Copyright 2023-2024 Tomáš Kubeček.
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
A custom x86_64 OS written from scratch
|
||||
Copyright (C) 2023-2025 Tom-on
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
kern. Copyright (C) 2023-2025 Tom-on
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
|
||||
@@ -4,25 +4,36 @@ kern.
|
||||
Idk why i called it that it was 3am and i needed sleep.
|
||||
|
||||
!! WARNING !!
|
||||
Kern is broken at the moment. The last working commit is: '11feab5'
|
||||
(https://github.com/Tom-on64/kern/tree/11feab5)
|
||||
Kern is being rewritten at the moment. To see the last version before the
|
||||
rewrite, see commit 11feab5 on master. (https://github.com/Tom-on64/kern/tree/11feab5)
|
||||
|
||||
About
|
||||
-----
|
||||
Kern is a 32-bit OS based on the x86 architecture written in NASM Assembly and C.
|
||||
I'm working on a basic command line as well as a custom unix-esque filesystem.
|
||||
It has a simple shell with some commands (use 'help' for a list of available ones).
|
||||
Kern is a 64-bit OS based on the x86_64 architecture written in C & NASM
|
||||
Assembly. It attempts to be a µ-kernel, although i have no clue what i'm doing.
|
||||
|
||||
Features
|
||||
Dependencies
|
||||
------------
|
||||
* binutils that can target x86_64-elf
|
||||
* GCC that can target x86_64-elf
|
||||
* Limine
|
||||
* make
|
||||
* Mtools
|
||||
* NASM
|
||||
* OpenSSL
|
||||
* sfdisk
|
||||
* QEMU (for emulation)
|
||||
|
||||
Building
|
||||
--------
|
||||
* Shell
|
||||
* Filesystem
|
||||
* Userspace
|
||||
* Font support
|
||||
* Graphics mode
|
||||
* Physical memory manager
|
||||
* Virtual memory manager
|
||||
* System calls
|
||||
Building should be as easy as running:
|
||||
$ make
|
||||
If it says that a command was not found, check that the utilities are correctly
|
||||
defined in config.mk.
|
||||
|
||||
If you want to emulate it with QEMU, you can run:
|
||||
$ make qemu
|
||||
|
||||
|
||||
Old Version: https://github.com/Tom-on64/old-kern
|
||||
|
||||
|
||||
@@ -1,189 +1,67 @@
|
||||
=== Todo ===
|
||||
TODO
|
||||
====
|
||||
|
||||
Legend:
|
||||
- [ ] Not done
|
||||
- [x] Done
|
||||
- [_] Was done at some point, but isn't now
|
||||
- [!] Important todo
|
||||
- [?] Optional
|
||||
Architectural Milestones
|
||||
[-] 64-bit rewrite
|
||||
[x] Limine (Bootloader)
|
||||
[ ] Decent build system (feat. cross-compiler)
|
||||
[x] kernel.h rewrite & header cleanup
|
||||
[x] debugf() cleanup, kprintf() & pr_*() (Standardized logging levels)
|
||||
[x] errno.h errors and "errno-in-pointer" macros
|
||||
|
||||
- [ ] Refactoring
|
||||
- [ ] Use UEFI
|
||||
- [ ] Use an existing bootloader
|
||||
- [x] libc - User space
|
||||
- [x] libk - Kernel libc
|
||||
- [x] Kernel rewrite
|
||||
- [ ] Better filesystem
|
||||
- [x] Makefile refactorin' (finally done!!!)
|
||||
Low-Level Hardware & Interrupts
|
||||
[x] GDT
|
||||
[x] IDT
|
||||
[x] Basic IRQs (Internal/Legacy)
|
||||
[x] Proper fault handling (Exceptions, Page Faults, #GP)
|
||||
[-] Check for features with CPUID (NX-bit, SSE, AVX)
|
||||
[ ] APIC driver (Local APIC & I/O APIC)
|
||||
[ ] ACPI driver (Parsing RSDP/MADT for multi-core/APIC)
|
||||
[ ] HPET driver (High precision timing)
|
||||
|
||||
- [ ] LIBC
|
||||
- [ ] assert.h
|
||||
- [ ] complex.h (idk why we would need this)
|
||||
- [x] ctype.h
|
||||
- [x] errno.h
|
||||
- [x] fcntl.h
|
||||
- [x] float.h
|
||||
- [x] limits.h
|
||||
- [x] math.h (maybe a separate libm?) TODO: add errno errors in there
|
||||
- [x] setjmp.h (this plagues my mind)
|
||||
- [ ] signal.h (we would need signals first)
|
||||
- [x] stdarg.h
|
||||
- [x] stdbool.h
|
||||
- [x] stddef.h
|
||||
- [x] stdint.h
|
||||
- [x] stdio.h
|
||||
- [x] stdlib.h
|
||||
- [x] string.h
|
||||
- [x] syscall.h
|
||||
- [x] time.h
|
||||
- [ ] unistd.h (do we do POSIX?)
|
||||
- [ ] wchar.h (we would need text support for wide chars ig?)
|
||||
- [ ] wctype.h (same as above)
|
||||
- [ ] sys/
|
||||
- [ ] types.h (syscall types)
|
||||
- [ ] gfx.h (basic graphics lib)
|
||||
Memory Management
|
||||
[x] Physical memory manager (Bitmap or Buddy)
|
||||
[x] Paging (Recursive or Offset mapping)
|
||||
[-] Kernel heap (kmalloc/kfree - Linked list or Slab)
|
||||
[ ] Memory mapped I/O (MMIO) API for drivers
|
||||
[ ] VMM: Shared memory regions (For IPC/Framebuffers)
|
||||
[ ] VMM: Copy-on-Write (COW) support (Optional but good)
|
||||
|
||||
- [x] LIBK
|
||||
- [x] drivers - everything that works with hardware
|
||||
- [x] error - error handling (bigerr is not enough :( )
|
||||
- [x] fs - filesystem
|
||||
- [x] interrupt - handling and registering interupts
|
||||
- [x] memory - memory managing (physical and virtual)
|
||||
- [x] screen - everything that displays on the screen
|
||||
- [x] syscall - system calls
|
||||
Multitasking & User Space
|
||||
[ ] System calls (SYSCALL/SYSRET implementation)
|
||||
[ ] Context switching (Saving/Restoring CPU state)
|
||||
[ ] Tasking (Thread/Process control blocks)
|
||||
[ ] Scheduler (Round Robin or Priority-based)
|
||||
[ ] User-space stacks & privilege isolation (Ring 3)
|
||||
[x] Stack Smash Protector
|
||||
|
||||
- [x] Multistage Bootloader
|
||||
- [x] Bootloader reads filesystem to find files
|
||||
- [x] The almighty 'printf()'
|
||||
- [x] Write down where stuff is in memory (in notes.txt)
|
||||
Interprocess Communication
|
||||
[ ] Interprocess Communication (Sync/Async messaging)
|
||||
[ ] Capability-based security (Optional: basic handle system)
|
||||
[ ] Signal/Event system (Interrupt forwarding to user space)
|
||||
|
||||
- [ ] "Text" mode (not actually)
|
||||
- [x] Scrolling
|
||||
- [ ] Scroll-back
|
||||
- [x] Color codes (and just multicolor text in general)
|
||||
- [x] Controll sequences!
|
||||
- [x] VESA BIOS Extensions
|
||||
- [x] Better resolution
|
||||
- [x] Graphics mode
|
||||
- [x] Custom font
|
||||
- [_] Larger text size
|
||||
- [ ] Variable text size :)
|
||||
- [x] Make output overflow go to next line
|
||||
- [x] More fonts
|
||||
- [x] Generic screen.h stuff (don't assume 1920x1080 32bpp)
|
||||
- [x] Multi vbe mode support
|
||||
- [x] Setup on boot
|
||||
- [ ] Different font size support
|
||||
Bootstrapping & Filesystem
|
||||
[ ] USTAR parser (Read initrd.tar)
|
||||
[ ] Initrd integration (Loading modules via Limine)
|
||||
[ ] ELF parser (Loading PT_LOAD segments)
|
||||
[ ] /init (The first user-space process)
|
||||
[ ] VFS Server (Abstracting file requests via IPC)
|
||||
|
||||
- [x] Math
|
||||
- [x] Trigonometry
|
||||
- [x] Sine
|
||||
- [x] Cosine
|
||||
- [x] Tangent
|
||||
- [x] Cotangent
|
||||
- [x] Arc (inverse) versions
|
||||
- [x] Hyperbolic versions
|
||||
- [x] Absolute value
|
||||
- [?] isOdd() 🗿
|
||||
- [x] Exponential fn (e^x)
|
||||
- [x] Logarithm
|
||||
- [x] Power
|
||||
- [x] Square Root
|
||||
- [x] Floor
|
||||
- [x] Round
|
||||
- [x] Ceiling
|
||||
- [x] Sign
|
||||
- [x] INFINITY
|
||||
- [x] NAN
|
||||
- [x] E (eulers number)
|
||||
- [x] PI
|
||||
Drivers & IO
|
||||
[x] Serial driver (For kernel debugging)
|
||||
[-] Framebuffer driver (Basic LFB/GOP)
|
||||
[ ] PS/2 Keyboard driver (As a user-space server)
|
||||
[ ] PCI Bus Enumerator (The "parent" of hardware drivers)
|
||||
[ ] Storage driver (SATA/AHCI or VirtIO)
|
||||
|
||||
- [ ] Filesystem
|
||||
- [x] Utility for filesystem building (not just an assembly file)
|
||||
- [x] Better header for file i/o (disk/filesys.h)
|
||||
- [x] Filetable
|
||||
- [x] A better filesystem using INodes etc.
|
||||
- [x] Files
|
||||
- [x] Larger than one sector (512B)
|
||||
- [x] Any file size (Not multiples of 512B)
|
||||
- [x] Filetypes
|
||||
- [ ] Directories
|
||||
- [x] File tree
|
||||
- [x] Dir Entries
|
||||
- [ ] cd command
|
||||
- [ ] Links??
|
||||
- [ ] Symbolic
|
||||
- [ ] Hard
|
||||
The Final TODOs
|
||||
[ ] Gaming???!!??
|
||||
[ ] Run DOOM
|
||||
[-] Finish all the TODOs
|
||||
|
||||
- [ ] System Calls
|
||||
- [x] Sleep()
|
||||
- [x] Write()
|
||||
- [x] Read()
|
||||
- [x] Open()
|
||||
- [x] Close()
|
||||
- [x] Malloc()
|
||||
- [x] Free()
|
||||
- [x] Seek()
|
||||
- [ ] Tell()
|
||||
- [ ] Exit()
|
||||
|
||||
- [ ] Shell
|
||||
- [ ] Separate file/program
|
||||
- [ ] ';' separated commands
|
||||
- [ ] I/O Redirection with '<' '>'
|
||||
- [x] Display directory in prompt
|
||||
- [ ] Custom prompts
|
||||
- [ ] Variables
|
||||
- [ ] Enviromental/Global
|
||||
- [ ] Normal
|
||||
- [ ] Commands
|
||||
- [x] echo
|
||||
- [x] clear
|
||||
- [x] help
|
||||
- [x] ls
|
||||
- [x] exit
|
||||
- [ ] touch (make file)
|
||||
- [ ] rm
|
||||
- [ ] mkdir (add dirs first)
|
||||
- [x] reboot
|
||||
- [ ] cd
|
||||
|
||||
- [ ] Standard I/O stuff
|
||||
- [ ] stdin
|
||||
- [x] stdout
|
||||
- [ ] stderr
|
||||
|
||||
- [ ] User (or system) programs
|
||||
- [x] Loading them
|
||||
- [_] Running them
|
||||
- [x] Exit back to kernel/shell
|
||||
- [x] Let them use libs
|
||||
- [x] Proper include files (LibC?)
|
||||
- [x] argc, argv[]
|
||||
|
||||
- [ ] Userspace programs
|
||||
- [ ] Shell
|
||||
- [x] Calculator
|
||||
- [ ] Calendar
|
||||
|
||||
- [ ] Code Editor
|
||||
- [ ] Text editor
|
||||
- [ ] Syntax highlighting
|
||||
- [ ] Saving/Loading
|
||||
- [ ] Hex editor
|
||||
|
||||
- [ ] Assembler/Compiler
|
||||
- [ ] Assembler
|
||||
- [ ] Compiler (probably C)
|
||||
- [ ] Standard lib
|
||||
|
||||
- [ ] Finish all todos
|
||||
- [ ] Refactoring!!!
|
||||
- [ ] Can it run DOOM?
|
||||
- [ ] Games
|
||||
- [ ] Minesweeper
|
||||
- [ ] Solitaire
|
||||
- [ ] Tetris
|
||||
|
||||
- [ ] Write an OS in kern (The FINAL Todo)
|
||||
Legend
|
||||
------
|
||||
[ ] Not finished
|
||||
[-] In progress
|
||||
[x] Finished
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
include ../defaults.mk
|
||||
|
||||
BIN = ./bin
|
||||
STAGE1_SRC = ./stage1
|
||||
STAGE2_SRC = ./stage2
|
||||
|
||||
STAGE1_SRCS = $(wildcard $(STAGE1_SRC)/*.s)
|
||||
STAGE2_SRCS = $(wildcard $(STAGE2_SRC)/*.c)
|
||||
STAGE2_OBJS = $(patsubst $(STAGE2_SRC)/%.c, $(BIN)/%.o, $(STAGE2_SRCS))
|
||||
|
||||
LINKER = $(STAGE2_SRC)/linker.ld
|
||||
STAGE1 = stage1.bin
|
||||
STAGE2 = stage2.bin
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(STAGE1) $(STAGE2)
|
||||
|
||||
$(STAGE1): $(STAGE1_SRCS)
|
||||
$(AS) $(ASFLAGS) -fbin -o $@ $(STAGE1_SRC)/bootsect.s
|
||||
|
||||
$(STAGE2): $(STAGE2_OBJS)
|
||||
$(LD) $(LDFLAGS) -T$(LINKER) -o $@ $^
|
||||
|
||||
$(BIN)/%.o: $(STAGE2_SRC)/%.c
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -fr $(BIN) $(STAGE1) $(STAGE2)
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
; KBOOT - Kern Bootloader
|
||||
; Most of the code is taken from Limine (https://github.com/limine-bootloader/limine)
|
||||
; I tried to add more documentation than the Limine code had, but it's not everything
|
||||
; Any of my code is pretty bad, so i recommend using an existing bootloader
|
||||
|
||||
[org 0x7c00]
|
||||
[bits 16]
|
||||
|
||||
; BPB Requires these
|
||||
jmp short .bpb_end
|
||||
nop
|
||||
|
||||
; FAT32 Bios Parameter Block
|
||||
; Some BIOSes mess with it so we just leave it blank
|
||||
.bpb:
|
||||
.bpb_oem_id: db "KERN "
|
||||
.bpb_sector_size: dw 0
|
||||
.bpb_sects_per_clust: db 0
|
||||
.bpb_reserved_sects: dw 0
|
||||
.bpb_fat_count: db 0
|
||||
.bpb_root_dir_entries: dw 0
|
||||
.bpb_sector_count: dw 0
|
||||
.bpb_media_type: db 0
|
||||
.bpb_sects_per_fat: dw 0
|
||||
.bpb_sects_per_track: dw 18
|
||||
.bpb_heads_count: dw 2
|
||||
.bpb_hidden_sects: dd 0
|
||||
.bpb_sect_count_big: dd 0
|
||||
; Extended BPB
|
||||
.bpb_drive_num: db 0
|
||||
.bpb_reserved: db 0
|
||||
.bpb_signature: db 0
|
||||
.bpb_volume_id: dd 0
|
||||
.bpb_volume_label: dd "KERN "
|
||||
.bpb_fs_type: times 8 db 0
|
||||
.bpb_end:
|
||||
cli
|
||||
cld
|
||||
jmp 0x0000:.init_codeseg ; Long jump to set CS = 0
|
||||
|
||||
; Zero out segment regs (Because segmentation is shit)
|
||||
.init_codeseg:
|
||||
xor si, si ; We cannot change segment regs directly
|
||||
mov ds, si ; Data Segment
|
||||
mov es, si ; Extra Segment
|
||||
mov ss, si ; Stack Segment
|
||||
mov sp, 0x7c00 ; Set Stack Pointer
|
||||
sti
|
||||
|
||||
; We probably won't be booting from a floppy, so
|
||||
; ignore if boot drive is < 0x80 and assume an error
|
||||
cmp dl, 0x80
|
||||
jl err.0
|
||||
; Also anything above 0x8f is "dubious" so we also
|
||||
; just assume an error
|
||||
cmp dl, 0x8f
|
||||
jg err.1
|
||||
|
||||
; Check that int 13h extensions are supported
|
||||
.int13chk:
|
||||
mov ah, 0x41
|
||||
mov bx, 0x55aa ; Expects bx to be this magic value
|
||||
int 0x13 ; Will se CF if unsupported
|
||||
jc err.2
|
||||
cmp bx, 0xaa55 ; Also sets bx to this magic
|
||||
jne err.3
|
||||
|
||||
; Load the stage 2 bootloader code to 0x70000
|
||||
.load_stage2:
|
||||
mov eax, 1 ; LBA
|
||||
mov cx, 20 ; Read 20 sectors (we have space for 2048)
|
||||
|
||||
; Destination - 0x70000
|
||||
push 0x7000
|
||||
pop es
|
||||
xor bx, bx
|
||||
|
||||
call read_sectors
|
||||
jc err.4 ; Failed to read stage 2
|
||||
|
||||
.enable_protected:
|
||||
; Load GDT Pointer
|
||||
lgdt [gdtp]
|
||||
|
||||
; Set PE (Protected mode Enable) flag
|
||||
cli
|
||||
mov eax, cr0
|
||||
or eax, 1 ; Bit 1 - PE
|
||||
mov cr0, eax
|
||||
|
||||
; Far jump to protected mode
|
||||
jmp code_seg:vector
|
||||
|
||||
%include "stage1/disk.s" ; Disk I/O helper functions
|
||||
%include "stage1/gdt.s" ; Global Descriptor Table
|
||||
|
||||
; Handles an error
|
||||
err:
|
||||
; Error codes
|
||||
.4: inc si ; Failed to read stage2 from disk
|
||||
.3: inc si ; Int 13h extensions unsupported (BX wasn't magic)
|
||||
.2: inc si ; Int 13h extensions unsupported (CF was set)
|
||||
.1: inc si ; Invalid boot drive number (> 0x8f)
|
||||
.0: ; Invalid boot drive number (< 0x80)
|
||||
; Common error handler
|
||||
add si, '0' | (0x4f << 8) ; Store error code number char in SI, white on red
|
||||
push 0xb800 ; VGA Text mode video memory
|
||||
pop es ; ES = 0xb800
|
||||
mov word [es:0], si ; Write character
|
||||
|
||||
; Hang
|
||||
sti
|
||||
.h: hlt
|
||||
jmp .h
|
||||
|
||||
[bits 32]
|
||||
; Protected mode entry vector
|
||||
vector:
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
|
||||
and edx, 0xff ; Still should be boot drive number
|
||||
|
||||
; Call stage 2 bootloader
|
||||
call code_seg:0x70000
|
||||
|
||||
; Padding and boot signature
|
||||
times 510-($-$$) db 0
|
||||
dw 0xaa55
|
||||
@@ -1,26 +0,0 @@
|
||||
; Reads sectors from disk
|
||||
; eax - LBA
|
||||
; cx - Sector count
|
||||
; dl - Drive number
|
||||
; es:dx - Destination
|
||||
read_sectors:
|
||||
pusha
|
||||
|
||||
; Fill out Disk Address Packet
|
||||
mov si, .da_packet
|
||||
mov word [si], 0x10 ; Packet Size and Unused
|
||||
mov word [si+2], cx ; Sector count
|
||||
mov word [si+4], bx ; Dest. offset
|
||||
mov word [si+6], es ; Dest. segment
|
||||
mov dword [si+8], eax ; LBA
|
||||
|
||||
mov ah, 0x42 ; Extended read
|
||||
clc ; Clear CF
|
||||
int 0x13
|
||||
.done:
|
||||
popa
|
||||
ret
|
||||
|
||||
; Disk Address Packet
|
||||
.da_packet: equ 0x8000
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
; Global Descriptor Table
|
||||
gdt:
|
||||
.null_desc: ; Just zeros, no clue why it even exists
|
||||
dq 0
|
||||
.code_desc: ; 32-bit code
|
||||
dw 0xffff ; Limit (low 16-bits)
|
||||
dw 0x0000 ; Base (low 16 bits)
|
||||
db 0x00 ; Base (mid 8 bits)
|
||||
db 0b10011011 ; Access flags
|
||||
db 0b11001111 ; Low 4 bits - Granularity, High 4 bits - Limit (high 4 bits)
|
||||
db 0x00 ; Base (high 8 bits)
|
||||
.data_desc: ; 32-bit data
|
||||
dw 0xffff ; Limit (low 16-bits)
|
||||
dw 0x0000 ; Base (low 16 bits)
|
||||
db 0x00 ; Base (mid 8 bits)
|
||||
db 0b10010011 ; Access flags
|
||||
db 0b11001111 ; Low 4 bits - Granularity, High 4 bits - Limit (high 4 bits)
|
||||
db 0x00 ; Base (high 8 bits)
|
||||
.end:
|
||||
|
||||
; GDT Pointer
|
||||
gdtp:
|
||||
dw gdt.end - gdt - 1 ; Size
|
||||
dd gdt ; Pointer
|
||||
|
||||
; Segments
|
||||
code_seg: equ gdt.code_desc - gdt
|
||||
data_seg: equ gdt.data_desc - gdt
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef _DEFS_H
|
||||
#define _DEFS_H
|
||||
|
||||
#define __packed __attribute__((packed))
|
||||
#define __naked __attribute__((naked))
|
||||
#define __section(_sect) __attribute__((section(_sect)))
|
||||
#define noreturn __attribute__((noreturn))
|
||||
#define sizeof_array(_a) (sizeof(_a) / sizeof(_a[0]))
|
||||
|
||||
#endif
|
||||
@@ -1,38 +0,0 @@
|
||||
#include "stdint.h"
|
||||
#include "port.h"
|
||||
#include "disk.h"
|
||||
|
||||
void readSectors(uint32_t lba, size_t count, void* dst) {
|
||||
outb(PIO_PORT + 6, ((lba >> 24) & 0x0f) | 0xe0);
|
||||
outb(PIO_PORT + 2, count);
|
||||
outb(PIO_PORT + 3, lba & 0xff);
|
||||
outb(PIO_PORT + 4, (lba >> 8) & 0xff);
|
||||
outb(PIO_PORT + 5, (lba >> 16) & 0xff);
|
||||
outb(PIO_PORT + 7, PIO_CMD_READ);
|
||||
|
||||
uint16_t* buf = (uint16_t*)dst;
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
while (inb(PIO_PORT + 7) & (1 << 7)); // Wait until BSY is cleared
|
||||
for (size_t j = 0; j < SECTOR_SIZE / 2; j++) *buf++ = inw(PIO_PORT);
|
||||
for (uint8_t wait = 0; wait < 4; wait++) inb(PIO_ALT_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
void writeSectors(uint32_t lba, size_t count, void* src) {
|
||||
outb(PIO_PORT + 6, ((lba >> 24) & 0x0f) | 0xe0);
|
||||
outb(PIO_PORT + 2, count);
|
||||
outb(PIO_PORT + 3, lba & 0xff);
|
||||
outb(PIO_PORT + 4, (lba >> 8) & 0xff);
|
||||
outb(PIO_PORT + 5, (lba >> 16) & 0xff);
|
||||
outb(PIO_PORT + 7, PIO_CMD_WRITE);
|
||||
|
||||
uint16_t* buf = (uint16_t*)src;
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
while (inb(PIO_PORT + 7) & (1 << 7)); // Wait until BSY is cleared
|
||||
for (size_t j = 0; j < SECTOR_SIZE / 2; j++) outw(PIO_PORT, *buf++);
|
||||
for (uint8_t wait = 0; wait < 4; wait++) inb(PIO_ALT_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#ifndef DISK_H
|
||||
#define DISK_H
|
||||
|
||||
#include "stdint.h"
|
||||
#include "defs.h"
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
#define PIO_PORT 0x1f0
|
||||
#define PIO_ALT_STATUS 0x3f6
|
||||
#define PIO_MASTER 0xa0
|
||||
#define PIO_CMD_READ 0x20
|
||||
#define PIO_CMD_WRITE 0x30
|
||||
#define PIO_CMD_FLUSH 0 // TODO
|
||||
|
||||
#define BOOTABLE 0x80
|
||||
|
||||
#define LBA_TO_OFFSET(_a) ((_a) * SECTOR_SIZE)
|
||||
|
||||
struct partition {
|
||||
uint8_t bootable;
|
||||
uint8_t startCHS[3];
|
||||
uint8_t type;
|
||||
uint8_t endCHS[3];
|
||||
uint32_t startLBA;
|
||||
uint32_t size;
|
||||
} __packed;
|
||||
|
||||
struct MBR {
|
||||
uint8_t bootstrap[446];
|
||||
struct partition partitions[4];
|
||||
uint16_t signature;
|
||||
} __packed;
|
||||
|
||||
void readSectors(uint32_t lba, size_t count, void* buffer);
|
||||
void writeSectors(uint32_t lba, size_t count, void* buffer);
|
||||
|
||||
#endif
|
||||
@@ -1,115 +0,0 @@
|
||||
#include "stdint.h"
|
||||
#include "fat32.h"
|
||||
#include "stdio.h"
|
||||
#include "defs.h"
|
||||
#include "disk.h"
|
||||
#include "menu.h"
|
||||
#include "kbd.h"
|
||||
|
||||
noreturn void panic() {
|
||||
setAttr(0x04);
|
||||
text(COLS/2, ROWS/2, "[ PANIC ]");
|
||||
while (1) __asm__ volatile ("cli; hlt");
|
||||
}
|
||||
|
||||
void drawPartitions(struct MBR* mbr, uint8_t sel);
|
||||
void partitonInfo(struct partition* part);
|
||||
struct partition* menu(struct MBR* mbr);
|
||||
|
||||
__section("entry")
|
||||
noreturn void main() {
|
||||
keyboardInit();
|
||||
struct MBR mbr;
|
||||
readSectors(0, 1, &mbr);
|
||||
struct partition* bootpart = menu(&mbr);
|
||||
|
||||
setAttr(0x0f);
|
||||
cls();
|
||||
showCursor();
|
||||
|
||||
if (fat32_init(bootpart) != 0) {
|
||||
setAttr(0x0c);
|
||||
printf("Failed to initialize FAT32.");
|
||||
panic();
|
||||
}
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
struct partition* menu(struct MBR* mbr) {
|
||||
// Select bootable partition by default
|
||||
uint8_t selected = 0;
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
if (mbr->partitions[i].bootable != BOOTABLE) continue;
|
||||
selected = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// Initial draw
|
||||
setAttr(0x0f);
|
||||
cls();
|
||||
hideCursor();
|
||||
rect(0, 0, COLS, ROWS);
|
||||
hline(0, 2, COLS);
|
||||
setAttr(0x02);
|
||||
text(COLS / 2, 1, "KBOOT");
|
||||
drawPartitions(mbr, selected);
|
||||
partitonInfo(&mbr->partitions[selected]);
|
||||
|
||||
while (1) {
|
||||
// Check for up/down arrow keys or enter
|
||||
uint8_t scancode = getScancode();
|
||||
if (scancode == SC_ENTER) { // Boot selected
|
||||
if (mbr->partitions[selected].type != 0) break;
|
||||
|
||||
// Don't allow booting an unused partition
|
||||
setAttr(0x4f);
|
||||
text(COLS / 2, ROWS / 2 + 6, "Unused Partition");
|
||||
} else if (scancode != SC_EXTENDED) continue; // Not an arrow key
|
||||
|
||||
scancode = getScancode();
|
||||
if (scancode == SCE_ARROW_UP) selected--;
|
||||
else if (scancode == SCE_ARROW_DOWN) selected++;
|
||||
else continue;
|
||||
|
||||
if (selected == 0xff) selected = 3;
|
||||
else if (selected == 4) selected = 0;
|
||||
|
||||
// Redraw
|
||||
drawPartitions(mbr, selected);
|
||||
partitonInfo(&mbr->partitions[selected]);
|
||||
}
|
||||
|
||||
return &mbr->partitions[selected];
|
||||
}
|
||||
|
||||
void drawPartitions(struct MBR* mbr, uint8_t sel) {
|
||||
uint32_t basey = ROWS / 2 - 2;
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
if (i == sel) setAttr(0xf0);
|
||||
else if (mbr->partitions[i].type == 0) setAttr(0x04);
|
||||
else setAttr(0x0f);
|
||||
|
||||
text(COLS / 2, basey + i, " [ Partition %d ] ", i+1);
|
||||
}
|
||||
}
|
||||
|
||||
void partitonInfo(struct partition* part) {
|
||||
uint32_t basey = ROWS / 2 + 6;
|
||||
setAttr(0x02);
|
||||
|
||||
// Clear previous text
|
||||
fill(1, basey, COLS - 2, 3, '\0');
|
||||
|
||||
if (part->type == 0) {
|
||||
text(COLS / 2, basey, "Unused Partition");
|
||||
return;
|
||||
}
|
||||
|
||||
text(COLS / 2, basey, "Type: %02x%s", part->type,
|
||||
(part->bootable == BOOTABLE) ? " Bootable" : "");
|
||||
text(COLS / 2, basey + 1, "Start LBA: %d; End LBA: %d",
|
||||
part->startLBA, part->startLBA + part->size);
|
||||
text(COLS / 2, basey + 2, "Length: 0x%x", part->size);
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
#include "disk.h"
|
||||
#include "fat32.h"
|
||||
|
||||
// Local context
|
||||
struct fat32_ctx ctx;
|
||||
|
||||
int fat32_init(struct partition* p) {
|
||||
readSectors(p->startLBA, 1, &ctx.bpb);
|
||||
ctx.offsetBase = p->startLBA;
|
||||
|
||||
if (ctx.bpb.bytesPerSect != SECTOR_SIZE) return 1;
|
||||
|
||||
ctx.offsetFats = ctx.offsetBase + ctx.bpb.reservedSects;
|
||||
ctx.offsetClusts = ctx.offsetFats + ctx.bpb.fatCount * ctx.bpb.sectsPerFat_32;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fat32_open(char* filename, int flags, ...) {
|
||||
// TODO: flags
|
||||
|
||||
//struct fat32_traversed res = fat32_traverse(ctx, filename);
|
||||
//if (!res.dir) return -1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void fat32_close(void* file) {}
|
||||
|
||||
int fat32_read(const void* buf, size_t size, size_t count, void* file) {}
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
#ifndef _FAT32_H
|
||||
#define _FAT32_H
|
||||
|
||||
#include "stdint.h"
|
||||
#include "defs.h"
|
||||
#include "disk.h"
|
||||
|
||||
// Macros
|
||||
#define FAT32_PTR(_p) ((struct fat32_ctx*)(_p))
|
||||
#define FAT32_DIR_PTR(_p) ((struct fat32_fd*)(_p))
|
||||
#define FAT32_FULL_CLUST(_hi, _lo) (((uint32_t)(_hi) << 16) | (_lo))
|
||||
#define FAT32_INODE_GEN(_dir, _i) ((_dir) * 100 + (_i))
|
||||
|
||||
// Long File Name (LFN)
|
||||
#define LFN_MAX 20
|
||||
#define LFN_MAX_CHARS 256
|
||||
|
||||
// Attributes
|
||||
#define FAT32_ATTR_READ_ONLY (1 << 0)
|
||||
#define FAT32_ATTR_HIDDEN (1 << 1)
|
||||
#define FAT32_ATTR_SYSTEM (1 << 2)
|
||||
#define FAT32_ATTR_VOLUME_ID (1 << 3)
|
||||
#define FAT32_ATTR_DIRECTORY (1 << 4)
|
||||
#define FAT32_ATTR_ARCHIVE (1 << 5)
|
||||
#define FAT32_ATTR_LFN \
|
||||
(FAT32_ATTR_READ_ONLY | FAT32_ATTR_HIDDEN \
|
||||
FAT32_ATTR_SYSTEM | FAT32_ATTR_VOLUME_ID)
|
||||
|
||||
/* On-disk structures */
|
||||
|
||||
// FAT32 Bios Parameter Block & Extended BPB
|
||||
struct fat32_bpb {
|
||||
uint8_t bootjmp[3];
|
||||
char oemName[8];
|
||||
uint16_t bytesPerSect;
|
||||
uint8_t sectsPerClust;
|
||||
uint16_t reservedSects;
|
||||
uint8_t fatCount;
|
||||
uint16_t rootEntryCount;
|
||||
uint16_t totalSects_16;
|
||||
uint8_t mediaType;
|
||||
uint16_t sectsPerFat_16;
|
||||
uint16_t sectsPerTrack;
|
||||
uint16_t headCount;
|
||||
uint32_t hiddenSects;
|
||||
uint32_t sectCount_32;
|
||||
// Extended
|
||||
uint32_t sectsPerFat_32;
|
||||
uint16_t flags;
|
||||
uint16_t fatVersion;
|
||||
uint32_t rootClust;
|
||||
uint16_t fsinfoSect;
|
||||
uint16_t backupBootsect;
|
||||
uint8_t _reserved[12];
|
||||
uint8_t driveNum;
|
||||
uint8_t winNTFlags;
|
||||
uint8_t signature;
|
||||
uint32_t volumeID;
|
||||
char volumeLabel[11];
|
||||
char systemID[8];
|
||||
uint8_t bootcode[420];
|
||||
uint16_t bootsig;
|
||||
} __packed;
|
||||
|
||||
// FAT32 Directory Entry
|
||||
struct fat32_dentry {
|
||||
char name[8];
|
||||
char ext[3];
|
||||
uint8_t attr;
|
||||
uint8_t userattr;
|
||||
char undelete;
|
||||
uint16_t createTime;
|
||||
uint16_t createDate;
|
||||
uint16_t accessDate;
|
||||
uint16_t clustHigh;
|
||||
uint16_t modifyTime;
|
||||
uint16_t modifyDate;
|
||||
uint16_t clustLow;
|
||||
uint32_t size;
|
||||
} __packed;
|
||||
|
||||
// FAT32 Long File Name entry
|
||||
struct fat32_lfn {
|
||||
uint8_t order;
|
||||
uint8_t name1[10];
|
||||
uint8_t attr;
|
||||
uint8_t type;
|
||||
uint8_t checksum;
|
||||
uint8_t name2[12];
|
||||
uint16_t zero;
|
||||
uint8_t name3[4];
|
||||
} __packed;
|
||||
|
||||
/* In memory structures */
|
||||
struct fat32_ctx {
|
||||
size_t offsetBase;
|
||||
size_t offsetFats;
|
||||
size_t offsetClusts;
|
||||
|
||||
struct fat32_bpb bpb;
|
||||
};
|
||||
|
||||
struct fat32_fd {
|
||||
uint32_t ptr;
|
||||
uint8_t index;
|
||||
uint32_t dirStart;
|
||||
uint32_t dirCurrent;
|
||||
struct fat32_dentry dentry;
|
||||
};
|
||||
|
||||
// Handlers
|
||||
int fat32_init(struct partition* p);
|
||||
int fat32_open(char* filename, int flags, ...); /* We won't use the va_args */
|
||||
|
||||
|
||||
void* fat32_fopen(const char* path, const char* mode);
|
||||
void fat32_fclose(void* file);
|
||||
int fat32_fgetc(void* file);
|
||||
char* fat32_fgets(char* s, size_t n, void* file);
|
||||
int fat32_fread(const void* buf, size_t size, size_t count, void* file);
|
||||
int fat32_fseek(void* file, size_t offset, int whence);
|
||||
long fat32_ftell(void* file);
|
||||
|
||||
#endif
|
||||
@@ -1,12 +0,0 @@
|
||||
#include "stdint.h"
|
||||
#include "port.h"
|
||||
#include "kbd.h"
|
||||
|
||||
// TODO: Maybe do some setup?
|
||||
int keyboardInit() { return 0; }
|
||||
|
||||
uint8_t getScancode() {
|
||||
while ((inb(PS2_STAT_PORT) & 0x01) == 0);
|
||||
return inb(PS2_DATA_PORT);
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef _KBD_H
|
||||
#define _KBD_H
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
#define PS2_DATA_PORT 0x60
|
||||
#define PS2_STAT_PORT 0x64
|
||||
|
||||
// Scancodes
|
||||
#define SC_ENTER 0x1C
|
||||
#define SC_EXTENDED 0xE0
|
||||
// Extended scancodes
|
||||
#define SCE_ARROW_UP 0x48
|
||||
#define SCE_ARROW_DOWN 0x50
|
||||
|
||||
int keyboardInit();
|
||||
uint8_t getScancode();
|
||||
|
||||
#endif
|
||||
@@ -1,24 +0,0 @@
|
||||
OUTPUT_FORMAT(binary)
|
||||
OUTPUT_ARCH(i386)
|
||||
|
||||
SECTIONS {
|
||||
. = 0x70000;
|
||||
|
||||
.text : {
|
||||
*(entry)
|
||||
*(.text)
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
.data : {
|
||||
*(.data)
|
||||
}
|
||||
|
||||
.bss : {
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
#include "stdarg.h"
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
#include "menu.h"
|
||||
|
||||
/*
|
||||
* The reason we subtract one from the width and height (or length) is because
|
||||
* we use the (in this example) width to offset from the (in this example) x
|
||||
* position. If something has a width of 1 character, the end of it should be
|
||||
* at 'x + w', so if 'w' were 1, it would be off by one. Therefore we subtract
|
||||
* one from the given dimensions.
|
||||
*/
|
||||
|
||||
void rect(uint32_t x, uint32_t y, uint32_t _w, uint32_t _h) {
|
||||
if (_w < 2 || _h < 2) return;
|
||||
uint32_t w = _w - 1;
|
||||
uint32_t h = _h - 1;
|
||||
|
||||
// Top
|
||||
putat(y, x, CORNER_TL);
|
||||
for (size_t dx = 1; dx < w; dx++) putat(y, x + dx, LINE_H);
|
||||
putat(y, x + w, CORNER_TR);
|
||||
|
||||
// Sides
|
||||
for (size_t dy = 1; dy < h; dy++) {
|
||||
putat(y + dy, x, LINE_V);
|
||||
putat(y + dy, x + w, LINE_V);
|
||||
}
|
||||
|
||||
// Bottom
|
||||
putat(y + h, x, CORNER_BL);
|
||||
for (size_t dx = 1; dx < w; dx++) putat(y + h, x + dx, LINE_H);
|
||||
putat(y + h, x + w, CORNER_BR);
|
||||
}
|
||||
|
||||
void fill(uint32_t x, uint32_t y, uint32_t w, uint32_t h, char c) {
|
||||
// We don't add one to the dimensions here
|
||||
for (size_t dy = 0; dy < h; dy++) {
|
||||
for (size_t dx = 0; dx < w; dx++) {
|
||||
putat(y + dy, x + dx, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hline(uint32_t x, uint32_t y, uint32_t _len) {
|
||||
uint32_t len = _len - 1;
|
||||
putat(y, x, LINE_T_RIGHT);
|
||||
for (size_t dx = 1; dx < len; dx++) putat(y, x + dx, LINE_H);
|
||||
putat(y, x + len, LINE_T_LEFT);
|
||||
}
|
||||
|
||||
void vline(uint32_t x, uint32_t y, uint32_t _len) {
|
||||
uint32_t len = _len - 1;
|
||||
putat(y, x, LINE_T_DOWN);
|
||||
for (size_t dy = 1; dy < len; dy++) putat(y + dy, x, LINE_V);
|
||||
putat(y + len, x, LINE_T_UP);
|
||||
}
|
||||
|
||||
void text(uint32_t x, uint32_t y, char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char buf[256];
|
||||
vsnprintf(buf, 256, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
uint32_t len = strlen(buf);
|
||||
uint32_t basex = x - len / 2;
|
||||
|
||||
size_t i = 0;
|
||||
while (buf[i] != '\0') putat(y, basex + i, buf[i++]);
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef _MENU_H
|
||||
#define _MENU_H
|
||||
|
||||
// Box drawing characters
|
||||
#define SHADE_LIGHT 0xB0
|
||||
#define SHADE_MEDIUM 0xB1
|
||||
#define SHADE_DARK 0xB2
|
||||
#define LINE_V 0xB3
|
||||
#define LINE_T_LEFT 0xB4
|
||||
#define CORNER_TR 0xBF
|
||||
#define CORNER_BL 0xC0
|
||||
#define LINE_T_UP 0xC1
|
||||
#define LINE_T_DOWN 0xC2
|
||||
#define LINE_T_RIGHT 0xC3
|
||||
#define LINE_H 0xC4
|
||||
#define LINE_CROSS 0xC5
|
||||
#define CORNER_BR 0xD9
|
||||
#define CORNER_TL 0xDA
|
||||
#define BLOCK 0xDB
|
||||
#define BLOCK_UPPER 0xDC
|
||||
#define BLOCK_LEFT 0xDD
|
||||
#define BLOCK_RIGHT 0xDE
|
||||
#define BLOCK_LOWER 0xDF
|
||||
#define INT_UPPER 0xF4
|
||||
#define INT_LOWER 0xF5
|
||||
|
||||
void rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h);
|
||||
void fill(uint32_t x, uint32_t y, uint32_t w, uint32_t h, char c);
|
||||
void hline(uint32_t x, uint32_t y, uint32_t len);
|
||||
void vline(uint32_t x, uint32_t y, uint32_t len);
|
||||
void text(uint32_t x, uint32_t y, char* fmt, ...);
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef PORT_H
|
||||
#define PORT_H
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
inline uint8_t inb(uint16_t port) {
|
||||
uint8_t result;
|
||||
__asm__ volatile("inb %1, %0" : "=a"(result) : "Nd"(port));
|
||||
return result;
|
||||
}
|
||||
inline void outb(uint16_t port, uint8_t data) {
|
||||
__asm__ volatile("outb %0, %1" :: "a"(data), "Nd"(port));
|
||||
}
|
||||
|
||||
inline uint16_t inw(uint16_t port) {
|
||||
uint16_t result;
|
||||
__asm__ volatile("inw %1, %0" : "=a"(result) : "Nd"(port));
|
||||
return result;
|
||||
}
|
||||
inline void outw(uint16_t port, uint16_t data) {
|
||||
__asm__ volatile("outw %0, %1" :: "a"(data), "Nd"(port));
|
||||
}
|
||||
|
||||
inline uint32_t inl(uint16_t port) {
|
||||
uint32_t result;
|
||||
__asm__ volatile("inl %1, %0" : "=a"(result) : "Nd"(port));
|
||||
return result;
|
||||
}
|
||||
inline void outl(uint16_t port, uint32_t data) {
|
||||
__asm__ volatile("outl %0, %1" :: "a"(data), "Nd"(port));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef _STDARG_H
|
||||
#define _STDARG_H
|
||||
|
||||
typedef char* va_list;
|
||||
#define va_start(ap, paramn) (void)((ap) = (char*)(&(paramn) + 1))
|
||||
#define va_end(ap) (void)((ap) = 0)
|
||||
#define va_arg(ap, type) (((type*)((ap) = ((ap) + sizeof(type))))[-1])
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef _STDINT_H
|
||||
#define _STDINT_H
|
||||
|
||||
#define NULL ((void*)0)
|
||||
|
||||
// Naitive size
|
||||
typedef unsigned int size_t;
|
||||
typedef signed int ssize_t;
|
||||
|
||||
// Signed ints
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed long long int64_t;
|
||||
|
||||
// Unsigned ints
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
#endif
|
||||
@@ -1,143 +0,0 @@
|
||||
#include "stdarg.h"
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
#include "port.h"
|
||||
|
||||
static uint32_t xpos;
|
||||
static uint32_t ypos;
|
||||
static uint8_t attr;
|
||||
|
||||
void setAttr(uint8_t newattr) { attr = newattr; }
|
||||
|
||||
void setCursor(uint32_t row, uint32_t col) {
|
||||
xpos = col;
|
||||
ypos = row;
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
void updateCursor() {
|
||||
uint16_t pos = xpos + ypos * COLS;
|
||||
|
||||
outb(0x3d4, 0x0f);
|
||||
outb(0x3d5, pos & 0xff);
|
||||
outb(0x3d4, 0x0e);
|
||||
outb(0x3d5, (pos >> 8) & 0xff);
|
||||
}
|
||||
|
||||
void hideCursor() {
|
||||
outb(0x3d4, 0x0a);
|
||||
outb(0x3d5, 0x20);
|
||||
}
|
||||
|
||||
void showCursor() {
|
||||
uint8_t start = 0;
|
||||
uint8_t end = 15;
|
||||
|
||||
outb(0x3d4, 0x0a);
|
||||
outb(0x3d5, (inb(0x3d5) & 0xc0) | start);
|
||||
outb(0x3d4, 0x0b);
|
||||
outb(0x3d5, (inb(0x3d5) & 0xe0) | end);
|
||||
}
|
||||
|
||||
void cls() {
|
||||
uint8_t* vidmem = (uint8_t*)VIDMEM;
|
||||
|
||||
for (size_t i = 0; i < ROWS * COLS; i++) {
|
||||
vidmem[i * 2] = 0;
|
||||
vidmem[i * 2 + 1] = attr;
|
||||
}
|
||||
|
||||
xpos = 0;
|
||||
ypos = 0;
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
void putat(uint32_t row, uint32_t col, int c) {
|
||||
uint8_t* vidmem = (uint8_t*)VIDMEM;
|
||||
vidmem[(col + row * COLS) * 2] = c & 0xFF;
|
||||
vidmem[(col + row * COLS) * 2 + 1] = attr;
|
||||
}
|
||||
|
||||
void newline() {
|
||||
xpos = 0;
|
||||
ypos++;
|
||||
if (ypos >= ROWS) ypos = 0;
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
void putc(int c) {
|
||||
putat(ypos, xpos, c);
|
||||
xpos++;
|
||||
if (xpos >= COLS) newline();
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
void puts(char* s) {
|
||||
while (*s != '\0') {
|
||||
if (*s == '\n' || *s == '\r') {
|
||||
newline();
|
||||
s++;
|
||||
} else putc(*s++);
|
||||
}
|
||||
}
|
||||
|
||||
int vsnprintf(void* buf, size_t len, char* fmt, va_list args) {
|
||||
char* str = (char*)buf;
|
||||
size_t pos = 0;
|
||||
|
||||
while (*fmt != '\0') {
|
||||
if (*fmt != '%') {
|
||||
if (pos < len - 1) str[pos++] = *fmt++;
|
||||
continue;
|
||||
}
|
||||
|
||||
fmt++;
|
||||
char pad = ' ';
|
||||
int width = 0;
|
||||
|
||||
if (*fmt == '0') pad = '0';
|
||||
while (*fmt >= '0' && *fmt <= '9') {
|
||||
width *= 10;
|
||||
width += *fmt++ - '0';
|
||||
}
|
||||
|
||||
// DO NOT TALK ABOUT THIS ABOMINATION
|
||||
char* s;
|
||||
switch (*fmt++) {
|
||||
case 'd': s = itoa(va_arg(args, int), 10); goto string;
|
||||
case 'x': s = itoa(va_arg(args, int), 16); goto string;
|
||||
case 's': s = va_arg(args, char*); goto string;
|
||||
case 'c': if (pos < len - 1) str[pos++] = va_arg(args, char); break;
|
||||
case '%': if (pos < len - 1) str[pos++] = '%'; break;
|
||||
default:
|
||||
if (pos < len - 1) str[pos++] = '%';
|
||||
if (pos < len - 1) str[pos++] = *(fmt - 1);
|
||||
break;
|
||||
string:
|
||||
width -= strlen(s) - 1;
|
||||
if (width < 0) width = 0;
|
||||
while (width-- && pos < len - 1) str[pos++] = pad;
|
||||
while (*s && pos < len - 1) str[pos++] = *s++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
if (pos < len) str[pos++] = '\0';
|
||||
else str[len - 1] = '\0'; // Shouldn't be able to be reached, but who knows
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
int printf(char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char buf[256];
|
||||
int ret = vsnprintf(buf, 256, fmt, args);
|
||||
va_end(args);
|
||||
puts(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef _STDIO_H
|
||||
#define _STDIO_H
|
||||
|
||||
#include "stdarg.h"
|
||||
#include "stdint.h"
|
||||
|
||||
#define VIDMEM 0xb8000
|
||||
#define COLS 80
|
||||
#define ROWS 25
|
||||
|
||||
void setAttr(uint8_t attr);
|
||||
void setCursor(uint32_t row, uint32_t col);
|
||||
void updateCursor();
|
||||
void hideCursor();
|
||||
void showCursor();
|
||||
|
||||
void cls();
|
||||
void newline();
|
||||
void putc(int c);
|
||||
void puts(char* s);
|
||||
int printf(char* fmt, ...);
|
||||
int vsnprintf(void* buf, size_t len, char* fmt, va_list args);
|
||||
void putat(uint32_t row, uint32_t col, int c);
|
||||
|
||||
#endif
|
||||
@@ -1,74 +0,0 @@
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
|
||||
char* itoa(size_t val, int base) {
|
||||
static char buf[32] = { 0 };
|
||||
|
||||
if (base == 0 || base > 16) return NULL;
|
||||
|
||||
if (val == 0) {
|
||||
buf[0] = '0';
|
||||
buf[1] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
int i;
|
||||
buf[31] = '\0';
|
||||
for (i = 30; val && i; i--, val /= base) {
|
||||
buf[i] = "0123456789abcdef"[val % base];
|
||||
}
|
||||
|
||||
return &buf[i + 1];
|
||||
}
|
||||
|
||||
void* memcpy(void* src, void* dst, size_t length) {
|
||||
uint8_t* p = dst;
|
||||
size_t i = 0;
|
||||
while (i < length) p[i] = *(uint8_t*)(src + i);
|
||||
return dst;
|
||||
}
|
||||
|
||||
void* memset(void* dst, uint8_t val, size_t length) {
|
||||
uint8_t* p = dst;
|
||||
size_t i = 0;
|
||||
while (i < length) p[i++] = val;
|
||||
return dst;
|
||||
}
|
||||
|
||||
char* strcpy(char* str1, const char* str2) {
|
||||
char* p = str1;
|
||||
while (*str2 != '\0') *p++ = *str2++;
|
||||
return str1;
|
||||
}
|
||||
|
||||
char* strcat(char* str1, const char* str2) {
|
||||
char* p = str1;
|
||||
while (*str2++ != '\0');
|
||||
while (*str2 != '\0') *p++ = *str2++;
|
||||
return str1;
|
||||
}
|
||||
|
||||
char* strchr(const char* str, char c) {
|
||||
char* p = (char*)str;
|
||||
while (*p != '\0' && *p != c) p++;
|
||||
return (*p == c) ? p : NULL;
|
||||
}
|
||||
|
||||
int strcmp(const char* str1, const char* str2) {
|
||||
while (*str1 != '\0' && *str1 == *str2) {
|
||||
str1++;
|
||||
str2++;
|
||||
}
|
||||
|
||||
uint8_t c1 = (*(uint8_t*)str1);
|
||||
uint8_t c2 = (*(uint8_t*)str2);
|
||||
|
||||
return ((c1 < c2) ? -1 : (c1 > c2));
|
||||
}
|
||||
|
||||
size_t strlen(const char* str) {
|
||||
size_t len = 0;
|
||||
while (str[len++] != '\0');
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#ifndef _STRING_H
|
||||
#define _STRING_H
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
char* itoa(size_t val, int base);
|
||||
void* memcpy(void* src, void* dst, size_t length);
|
||||
void* memset(void* dst, uint8_t value, size_t length);
|
||||
char* strcpy(char* str1, const char* str2);
|
||||
char* strcat(char* str1, const char* str2);
|
||||
char* strchr(const char* str, char c);
|
||||
int strcmp(const char* str1, const char* str2);
|
||||
size_t strlen(const char* str);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
# Tools
|
||||
HOSTCC = cc
|
||||
CC = cc
|
||||
LD = ld
|
||||
AS = nasm
|
||||
AR = ar
|
||||
OBJCOPY = objcopy
|
||||
MAKE = make
|
||||
|
||||
# Flags
|
||||
HOSTCCFLAGS = -Wall -Wextra -O2
|
||||
CCFLAGS = -Wall -Wextra -m64 -ffreestanding -fcommon -Iinclude \
|
||||
-mcmodel=kernel \
|
||||
-fno-pie \
|
||||
-fno-omit-frame-pointer \
|
||||
-mno-mmx \
|
||||
-mno-80387 \
|
||||
-fno-stack-protector \
|
||||
-mno-red-zone \
|
||||
-nostartfiles \
|
||||
-nostdlib \
|
||||
-nostdinc \
|
||||
-fno-lto
|
||||
ASFLAGS = -felf64
|
||||
LDFLAGS = -melf_x86_64 -nostdlib -static \
|
||||
--no-dynamic-linker \
|
||||
-z text -z max-page-size=0x1000
|
||||
ARFLAGS =
|
||||
|
||||
# Kernel config
|
||||
CONSOLE_LOGLEVEL = 7
|
||||
|
||||
# Sysroot
|
||||
LIMINE_CFG = ./limine.conf
|
||||
|
||||
# Disk image
|
||||
IMG_NAME = disk.img
|
||||
IMG_SIZE = 256
|
||||
|
||||
# Qemu
|
||||
Q_MEMORY = 256M
|
||||
Q_AUDIODEV = pipewire
|
||||
Q_LOGGING = int,cpu_reset
|
||||
Q_LOGFILE = qemu.log
|
||||
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
# Tools
|
||||
HOSTCC = cc
|
||||
CC = i686-elf-gcc
|
||||
LD = i686-elf-ld
|
||||
AS = nasm
|
||||
AR = i686-elf-ar
|
||||
OBJCOPY = i686-elf-objcopy
|
||||
MAKE = make
|
||||
|
||||
# Flags
|
||||
HOSTCFLAGS = -Wall -Wextra -Wpedantic -Os -std=c17 -g
|
||||
CFLAGS = -Wall -Wextra -Wpedantic -Wno-pointer-arith\
|
||||
-ffreestanding -fno-stack-protector -fno-builtin -fno-pie -fcommon\
|
||||
-O2 -std=c17 -nostdinc -nostdlib -z notext -march=i386 -g
|
||||
LDFLAGS = -melf_i386
|
||||
ASFLAGS =
|
||||
ARFLAGS =
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
Bootloader
|
||||
============
|
||||
|
||||
Kern uses a two stage bootloader. The first stage is the 512 byte bootsector.
|
||||
This code loads the 2nd stage, which is in the next seven sectors.
|
||||
Together this whole bootloader takes up the first filesystem block (4kiB).
|
||||
|
||||
Bootframe
|
||||
---------
|
||||
When the bootloader runs the kernel, it pushes a 32-bit address that points
|
||||
to the bootframe It follows the following structure:
|
||||
* Memory map
|
||||
* Video memory
|
||||
* ...todo
|
||||
|
||||
It is defined in the libk header 'boot.h'
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
Bootup Sequence
|
||||
===============
|
||||
|
||||
When the system boots, the bootloader will look for a kernel image and init ram
|
||||
disk. It will do some basic setup, load these into memory and hand over control.
|
||||
Since kern uses a µ-kernel, it only contains the minimal number of device
|
||||
drives that it must. One of these is a ramfs/tmpfs driver. It uses this driver
|
||||
to load and execute a program at '/init' inside the initrd as process 1. This
|
||||
process is then responsable for running things like a disk & filesystem server
|
||||
that loads the actual OSes root filesystem. Usually it would also replace
|
||||
iself with '/sbin/init' from the root filesystem that would finish initialization
|
||||
and do things like launching a login shell, etc.
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
Building & Running
|
||||
==================
|
||||
_If you want to try kern for some reason, you can._
|
||||
|
||||
Tools
|
||||
-----
|
||||
* [NASM](https://www.nasm.us/)
|
||||
* [QEMU](https://www.qemu.org/) (for emulation)
|
||||
|
||||
Unix-Like Systems
|
||||
*****************
|
||||
* [GCC](https://gcc.gnu.org/)
|
||||
|
||||
On MacOS
|
||||
********
|
||||
* A cross compiler: `$ brew tap nativeos/i386-elf-toolchain && brew install i386-elf-binutils i386-elf-gcc`
|
||||
|
||||
Commands
|
||||
--------
|
||||
```sh
|
||||
$ make # Or 'make os'
|
||||
$ make run # Run QEMU
|
||||
```
|
||||
|
||||
_I personally wouldn't recommend running this on real hardware, because it's untested and will just probably break you pc, but if you really want to, you can try it, but don't blame me if something goes wrong._
|
||||
+17
-16
@@ -57,9 +57,8 @@ should not be placed after/before unary operators or member access operators.
|
||||
Naming
|
||||
------
|
||||
_The hardest thing in programming_
|
||||
Identifiers should use camelCase (starting with lowercase). In special
|
||||
cases (e.g. syscall handlers) a short prefix separated with an underscore
|
||||
may be used (e.g. 'sys_malloc').
|
||||
Identifiers should use snake_case (starting with lowercase). And should have a
|
||||
short prefix to indicate what system they're from (e.g. 'vmm_alloc' & 'pmm_alloc').
|
||||
|
||||
Global variables (that should be sparse) and global functions need good,
|
||||
descriptive names. A disk reading function shouldn't be called 'dskrd()'.
|
||||
@@ -70,18 +69,14 @@ should be named 'i' and not loopCounter.
|
||||
Some good naming examples:
|
||||
```c
|
||||
// Random good function names
|
||||
int32_t findFreeBlock(uint32_t count);
|
||||
int32_t ttyWrite(const void* buf, size_t len);
|
||||
uint8_t getRtcRegister(uint8_t reg);
|
||||
int32_t disk_find_free_block(uint32_t count);
|
||||
int32_t tty_write(const void* buf, size_t len);
|
||||
uint8_t get_rtc_register(uint8_t reg);
|
||||
|
||||
// Serial functions all start with 'serial'
|
||||
int serialSetup();
|
||||
void serialWrite(uint8_t byte);
|
||||
uint8_t serialRead();
|
||||
|
||||
// Syscall handlers are prefixed with 'sys_'
|
||||
int sys_malloc(struct intFrame iframe);
|
||||
int sys_free(struct intFrame iframe);
|
||||
// Serial functions all start with 'serial_'
|
||||
int serial_init();
|
||||
void serial_write(uint8_t byte);
|
||||
uint8_t serial_read();
|
||||
```
|
||||
|
||||
Labels, for 'goto' statements or assembly, should be snake_case.
|
||||
@@ -149,7 +144,7 @@ lowercase names. Generally, inline functions are prefered over macros.
|
||||
If a macro uses more than one statement, enclose them in their own scope.
|
||||
```c
|
||||
#define MAGIC(_x)\
|
||||
if (_x > 0) doSomething(_x);
|
||||
if ((_x) > 0) doSomething(_x);
|
||||
```
|
||||
|
||||
Things to look out for:
|
||||
@@ -177,7 +172,8 @@ These functions can be called uncoditionally. Empty inline functions work too.
|
||||
|
||||
Using Bool
|
||||
**********
|
||||
You may use bool, but are not required to. It does improve readability
|
||||
You may use bool, but are not required to. It does improve readability, but i
|
||||
personally prefer int.
|
||||
|
||||
Allocating Memory
|
||||
*****************
|
||||
@@ -212,3 +208,8 @@ For example `drivers/fat32.h would have this guard:
|
||||
#endif
|
||||
```
|
||||
|
||||
Hex literals
|
||||
************
|
||||
Hexadecimal literals are preffered over binary and should be written in uppercase.
|
||||
Example: 0xA1B2C0DE
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
Documentation Syntax
|
||||
====================
|
||||
|
||||
Headers
|
||||
-------
|
||||
You may utilize three levels of headers. The highest headers are underlined with
|
||||
equal signs (see the top of this document). The second header level is
|
||||
underlined with dashes (see the header of this section). The lowest level of
|
||||
headings are underlined with asterisks. The number of underline characters shall
|
||||
be the same length as the header.
|
||||
|
||||
Lists
|
||||
-----
|
||||
There are two types of lists: ordered and unordered lists. Ordered lists are
|
||||
written with hashes separated by a space at the start of lines like this:
|
||||
# First entry
|
||||
# Another entry
|
||||
# The last entry
|
||||
|
||||
Unordered lists are written with a asterisk separated by a space instead:
|
||||
* No numbers here
|
||||
* Not even here
|
||||
|
||||
Lists may also be indented with a tab.
|
||||
|
||||
Ephasizing
|
||||
----------
|
||||
If you want to emphasize some text you have these options:
|
||||
* **Bold**
|
||||
* __Italics__
|
||||
* ~~Strikethrough~~
|
||||
|
||||
If you don't want some text to be formatted, you can escape it with a backslash.
|
||||
|
||||
Code blocks
|
||||
-----------
|
||||
One can write code blocks either as inline by wrapping the code in backticks
|
||||
like this: `malloc()`. Multiline code blocks can be written by indenting the
|
||||
code as so:
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
printf("Args for %s:\n", argv[0]);
|
||||
for (size_t i = 1; i < argc; i++) {
|
||||
printf("\t%s\n", argv[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Code blocks ignore all documentation formatting.
|
||||
|
||||
References
|
||||
----------
|
||||
References to other pieces of documentation may be inserted using this syntax:
|
||||
* `[[doc-syntax]]` displays as [[doc-syntax]] and links to `doc-syntax.txt`
|
||||
* `[[Documentation syntax|doc-syntax]]` displays as [[Documentation syntax|doc-syntax]] and links to `doc-syntax.txt`
|
||||
* `[[doc-syntax]]-document` displays as [[doc-syntax]]-document and links to `doc-syntax.txt`
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
Error handling
|
||||
==============
|
||||
|
||||
Functions that can fail must have a way of telling the caller that something
|
||||
went wrong and preferably what went wrong. The simplest and cleanest way of
|
||||
indicating an error is a return code. Error codes are defined in the <errno.h>
|
||||
header alongside some helpfull macros.
|
||||
|
||||
Error codes have identifiers like these: ENOMEM, ENOENT, EALIGN, ...
|
||||
They are defined as positive values, however all functions should return a
|
||||
negative integer on error, so it would look something like 'return -EFAULT;'.
|
||||
Also theres SUCCESS which is just 0. You can use it, but don't need to.
|
||||
|
||||
If you are returning a pointer/address, the highest address is almost certainly
|
||||
unused, so returning '(void*)-EINVAL', should work just fine. This is quite an
|
||||
eyesore, so there are three macros for working with these "errno-in-pointer"s.
|
||||
IS_ERR(ptr) just returns 1 if the pointer is an errno. Otherwise 0.
|
||||
ERR_PTR(err) does that void* cast mentioned above so it would be ERR_PTR(-EINVAL).
|
||||
PTR_ERR(ptr) is the inverse of ERR_PTR(), as it converts a errno-in-pointer to
|
||||
an errno value. PTR_ERR(ERR_PTR(-EIO)) == -EIO
|
||||
|
||||
|
||||
Here are some usage examples:
|
||||
int pag_init(void) {
|
||||
if (...) return -ENOMEM; // Not enough memory
|
||||
|
||||
void* paddr = pmm_alloc();
|
||||
if (IS_ERR(paddr)) return PTR_ERR(paddr); // Pass the error down
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
+44
-39
@@ -1,46 +1,51 @@
|
||||
--- Terminal Escape Sequences ---
|
||||
Terminal Escape Sequences
|
||||
=========================
|
||||
|
||||
Escape character:
|
||||
char: '\e'
|
||||
hex: 0x1b
|
||||
oct: 0o33
|
||||
dec: 27
|
||||
Escape character
|
||||
----------------
|
||||
* hex: 0x1b
|
||||
* oct: 0o33
|
||||
* dec: 27
|
||||
|
||||
Note: the escape character will be denoted by ESC here
|
||||
|
||||
Syntax:
|
||||
All escape sequenced start with the escape character followed by an opening square bracket '['
|
||||
The sequence can take any number of arguments in a semicolon separated list
|
||||
If a argument is skipped, it will be implicitly set to 0 unless stated otherwise
|
||||
The escape sequence must end with a uppercase or lowercase letter
|
||||
Syntax
|
||||
------
|
||||
All escape sequenced start with the escape character followed by an opening
|
||||
square bracket '['. The sequence can take any number of arguments in a semicolon
|
||||
separated list. If a argument is skipped, it will be implicitly set to 0 unless
|
||||
stated otherwise. The escape sequence must end with a uppercase or lowercase
|
||||
letter.
|
||||
|
||||
Available escape sequences:
|
||||
- Cursor Controls -
|
||||
`ESC[#A` - Moves cursor # rows up (default: 1)
|
||||
`ESC[#B` - Moves cursor # rows down (default: 1)
|
||||
`ESC[#C` - Moves cursor # columns left (default: 1)
|
||||
`ESC[#D` - Moves cursor # columns right (default: 1)
|
||||
`ESC[#E` - Moves cursor to #th row
|
||||
`ESC[#F` - Moves cursor to #th column
|
||||
`ESC[#G` - Show (# = 1) or hide (# = 0) cursor
|
||||
`ESC[{row};{col}H` - Moves cursor to specified position (if not arguments given, moves to [0,0])
|
||||
- Erase functions -
|
||||
`ESC[I` - Reserved (Falls though to erase screen)
|
||||
`ESC[J` - Erase screen
|
||||
`ESC[K` - Erase line (not implemented)
|
||||
`ESC[L` - Erase column (not implemented)
|
||||
- Text Style -
|
||||
`ESC[#M` - Sets foreground color to # (default 8)
|
||||
`ESC[#N` - Sets backgorund color to # (default 8)
|
||||
Available escape sequences
|
||||
--------------------------
|
||||
Cursor Controls
|
||||
* `ESC[#A` - Moves cursor # rows up (default: 1)
|
||||
* `ESC[#B` - Moves cursor # rows down (default: 1)
|
||||
* `ESC[#C` - Moves cursor # columns left (default: 1)
|
||||
* `ESC[#D` - Moves cursor # columns right (default: 1)
|
||||
* `ESC[#E` - Moves cursor to #th row
|
||||
* `ESC[#F` - Moves cursor to #th column
|
||||
* `ESC[#G` - Show (# = 1) or hide (# = 0) cursor
|
||||
* `ESC[{row};{col}H` - Moves cursor to specified position (if not arguments given, moves to [0,0])
|
||||
Erase functions
|
||||
* `ESC[I` - Reserved (Falls though to erase screen)
|
||||
* `ESC[J` - Erase screen
|
||||
* `ESC[K` - Erase line (not implemented)
|
||||
* `ESC[L` - Erase column (not implemented)
|
||||
Text Style
|
||||
* `ESC[#M` - Sets foreground color to # (default 8)
|
||||
* `ESC[#N` - Sets backgorund color to # (default 8)
|
||||
|
||||
Color codes:
|
||||
0 - Black
|
||||
1 - Red
|
||||
2 - Green
|
||||
3 - Yellow
|
||||
4 - Blue
|
||||
5 - Magenta
|
||||
6 - Cyan
|
||||
7 - White
|
||||
8 - Default
|
||||
Color codes
|
||||
-----------
|
||||
* 0 - Black (000)
|
||||
* 1 - Red (100)
|
||||
* 2 - Green (010)
|
||||
* 3 - Yellow (110)
|
||||
* 4 - Blue (001)
|
||||
* 5 - Magenta (101)
|
||||
* 6 - Cyan (011)
|
||||
* 7 - White (111)
|
||||
* 8 - Default
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
=== Project Structure ===
|
||||
|
||||
Root contains the Makefile that is used to build kern and some documents.
|
||||
It also contains these directories:
|
||||
src/ - Kernel source code
|
||||
boot/ - Bootloader code
|
||||
libc/ - C Standard library
|
||||
libk/ - Kernel library
|
||||
docs/ - Some documentation (mainly for me)
|
||||
other/ - Things like screenshot, etc.
|
||||
usr/ - Userspace files like fonts and programs
|
||||
bin/ - Intermediary binaries
|
||||
|
||||
After running the Makefile and succesfully building the OS
|
||||
a 'kern.iso' file will be created in the root directory
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
Filesystem
|
||||
============
|
||||
|
||||
Sector = 512 Bytes
|
||||
Block = 4096 Bytes
|
||||
|
||||
Reserved sectors
|
||||
----------------
|
||||
* Sector 0..7 - Bootblock, constains bootloader code that gets ran by the BIOS (4KiB)
|
||||
* Sector 8..F - Superblock, contains metadata about the filesystem itself (4KiB)
|
||||
|
||||
Superblock structure (4096B)
|
||||
--------------------
|
||||
* Device ID
|
||||
* Max File Size
|
||||
* INode Count
|
||||
* INode Bitmap Block
|
||||
* INodes Start
|
||||
* INode Block Count
|
||||
* INodes per sector
|
||||
* Data Bitmap Block
|
||||
* Data Start
|
||||
* Data Block Count
|
||||
* Root INode Pointer
|
||||
* First Unreserved INode
|
||||
|
||||
INode structure (64B)
|
||||
---------------
|
||||
* Type
|
||||
* Size (bytes)
|
||||
* Sector Count (size in sectors)
|
||||
* Mode
|
||||
* Extent[4]
|
||||
* Single Indirect
|
||||
* Double Indirect?
|
||||
|
||||
Extent (8B)
|
||||
------
|
||||
* Block
|
||||
* Length
|
||||
|
||||
Directory Entry (64B)
|
||||
---------------
|
||||
* INode Number
|
||||
* Name (max length 60 Bytes)
|
||||
|
||||
Filetypes
|
||||
---------
|
||||
* File
|
||||
* Directory
|
||||
# TODO
|
||||
* Link
|
||||
* Device
|
||||
* Stream?
|
||||
|
||||
These structs are defined in the libk header 'fs/fs.h'
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 51 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 8.9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,66 @@
|
||||
Memory Management
|
||||
=================
|
||||
|
||||
Memory management is split into three layers: physical, virtual & the heap.
|
||||
|
||||
pmm.h
|
||||
-----
|
||||
The **physical memory manager** (PMM) is responsible for allocating physical
|
||||
memory. It gives `pmm_*` functions. The `pmm_allocPage()` function allocates a
|
||||
4kB page frame and retuns its **physical address**.
|
||||
|
||||
vmm.h
|
||||
-----
|
||||
The **virtual memory manager** (VMM) is responsible for allocating virtual
|
||||
memory. It provides `vmm_*` functions. The `vmm_alloc()` function takes in a
|
||||
number of 4kB pages to allocate and returns the **virtual address** of the
|
||||
first page. Userspace can interface with the VMM using the `mmap()` and
|
||||
`munmap()` syscalls.
|
||||
|
||||
kmalloc.h
|
||||
---------
|
||||
The `kmalloc.h` header provides memory management functions for kernel memory.
|
||||
|
||||
`void* kmalloc(size_t size)`
|
||||
****************************
|
||||
**Parameters**
|
||||
* `size_t size` - Number of bytes to allocate
|
||||
|
||||
**Descriptions**
|
||||
This function allocates `size` bytes of contiguous memory.
|
||||
|
||||
**Returns**
|
||||
A pointer to allocated memory or NULL.
|
||||
|
||||
`void* kzalloc(size_t size)`
|
||||
****************************
|
||||
**Parameters**
|
||||
* `size_t size` - Number of bytes to allocate
|
||||
|
||||
**Description**
|
||||
This function allocates `size` bytes of contiguous, zeroed-out memory.
|
||||
|
||||
**Returns**
|
||||
A pointer to allocated memory or NULL.
|
||||
|
||||
`void* kcalloc(size_t count, size_t size)`
|
||||
******************************************
|
||||
**Parameters**
|
||||
* `size_t count` -
|
||||
|
||||
**Description**
|
||||
This function allocates memory for `count` elements each of `size` bytes, zeroed-out memory.
|
||||
|
||||
**Returns**
|
||||
A pointer to allocated memory or NULL.
|
||||
|
||||
`void* kfree(void* p)`
|
||||
******************************************
|
||||
**Parameters**
|
||||
* `void* p` -
|
||||
|
||||
**Description**
|
||||
This function frees memory previously allocated using `k[m,z,c]alloc()`
|
||||
|
||||
**Returns**
|
||||
Nothing
|
||||
@@ -0,0 +1,16 @@
|
||||
Memory Map
|
||||
==========
|
||||
__This document specifies the **virtual** memory map. The **physical** memory
|
||||
map is not OS defined and should be provided by the bootloader.__
|
||||
|
||||
| 00000000 | Null Page |
|
||||
| 00001000 | TODO: userspace |
|
||||
| C0000000 | Kernel Base |
|
||||
| C0100000 | Kernel Binary Base |
|
||||
| C6000000 | VMM Bitmap |
|
||||
| C8000000 | Kernel Framebuffer |
|
||||
| CFFE0000 | PMM Bitmap |
|
||||
| D0000000 | Kernel Heap |
|
||||
| F0000000 | Kernel Shared |
|
||||
| FFFFF000 | Recursive pagedir |
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
Kern Dev Struct
|
||||
===============
|
||||
|
||||
Independant Modules
|
||||
-------------------
|
||||
* Each MUST have their own directory (eg. 'kernel/', 'boot/')
|
||||
* Each MAY have their own internal independant submodules (eg. userspace programs in 'usr/')
|
||||
* A module MAY be dependant on it's own submodules, but it's submodules MUST be independant of each other
|
||||
* Each MUST have a makefile in their directory (eg. 'libc/makefile')
|
||||
* Each module makefile MUST implement the 'all' and 'clean' targets
|
||||
* Each module MUST be listed in the 'make.defaults' directory
|
||||
* Each module MUST be self-contained and independentally compilable
|
||||
* A module SHOULD output binaries into the 'bin/' directory
|
||||
|
||||
kern (Root "module", is dependant on all of it's submodules)
|
||||
|- boot
|
||||
| |- bootsect (stage1)
|
||||
| '- bootload (stage2)
|
||||
|- kernel
|
||||
| '- libk
|
||||
|- libc (C Standard Library)
|
||||
'- user !EXCEPTION: Userspace programs are dependant upon libc!
|
||||
|- coreutils
|
||||
|- fdisk
|
||||
|- init
|
||||
|- mkfs
|
||||
|- sh
|
||||
..
|
||||
|
||||
TODO
|
||||
====
|
||||
[ ] boot
|
||||
[ ] kernel
|
||||
[x] libc
|
||||
[ ] user
|
||||
[ ] makefile
|
||||
[ ] make.defaults
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
OS Filesystem
|
||||
=============
|
||||
|
||||
Here's how the filesystem is layed out:
|
||||
/
|
||||
|- bin/ Administrator binaries
|
||||
|- boot/ Files required to boot, like the kernel
|
||||
|- dev/ Device nodes
|
||||
|- etc/ Configuration files
|
||||
|- lib/ Shared libraties
|
||||
|- sbin/ System binaries
|
||||
|- usr/ Regular user stuff
|
||||
| |- bin/ User binaries
|
||||
| |- include/ Headers
|
||||
| '- share/ "Constant" stuff, same across systems
|
||||
'- tmp/ Temporary filesystem, cleared on reboot
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
How paging works
|
||||
================
|
||||
NOTE: This is mainly so I can wrap my head around paging.
|
||||
|
||||
Table levels
|
||||
------------
|
||||
Since 2^64 is quite a large number, paging uses a bunch of tables to organize
|
||||
& navigate pages. These are also called layers & 4-layer paging is most common.
|
||||
* Level 1 - Page Table (PT)
|
||||
* Level 2 - Page Directory (PD)
|
||||
* Level 3 - Page Directory Pointer Table (PDPT)
|
||||
* Level 4 - Page Map Layer 4 (PML4)
|
||||
* Level 5 - Page Map Layer 5 (PML5) (optional)
|
||||
|
||||
Virtual address
|
||||
---------------
|
||||
A 64-bit virtual address has four parts:
|
||||
* 47-39 - PML4 index
|
||||
* 38-30 - PDPT index
|
||||
* 29-21 - PD index
|
||||
* 20-12 - PT index
|
||||
* 11-0 - 4 kiB page offset
|
||||
|
||||
Note that the top 16 bits are unused. These must always be all 0s or all 1s.
|
||||
|
||||
Walking the tables
|
||||
------------------
|
||||
Here are the steps that the MMU will take to translate an address:
|
||||
1. Find the physical address of the PML4 in the CR3 register
|
||||
2. Index the PML4 with bits 47-39 to find the paddr of the PDPT
|
||||
3. Index the PDPT with bits 38-30 to find the paddr of the PD
|
||||
4. Index the PD with bits 29-21 to find the paddr of the PT
|
||||
5. Index the PT with bits 20-12 to find the paddr of the Page
|
||||
6. Offset the Page address by bits 11-0 to find the actual byte
|
||||
|
||||
The flags
|
||||
---------
|
||||
Since all physical addresses in these tables MUST be page (4 kiB) aligned, the
|
||||
bottom 12 bits will always be zero. These bits are used to store Page Table
|
||||
Entry (PTE) flags. Since the 64-bit address space is SO large, bits 52-63 are
|
||||
also used for flags. Here's how a PTE entry looks:
|
||||
* 0 - Present, 0 - page fault, 1 - page is in RAM
|
||||
* 1 - Writable, 0 - read-only, 1 - read & write
|
||||
* 2 - Userspace, 0 - kernel only, 1 - user & kernel
|
||||
* 3 - Page-level write-through caching
|
||||
* 4 - Page-level cache disable
|
||||
* 5 - Accesed, set by CPU when page is read or written to
|
||||
* 6 - Dirty, set by CPU when page is written to (level 1 only)
|
||||
* 7 - Page size, 0 - 4 kiB, 1 - 2 MiB or 1 GiB
|
||||
* 8-11 and 52-62 - Available to be used by kernel
|
||||
* 63 - No execute, 0 - executable, 1 - not executable
|
||||
|
||||
There are some flags that only apply to certain levels and page sizes, Please
|
||||
see the diagram at https://wiki.osdev.org/Paging for more info.
|
||||
|
||||
Large pages
|
||||
-----------
|
||||
I don't know man.
|
||||
|
||||
Caching
|
||||
-------
|
||||
I couldn't tell ya.
|
||||
|
||||
+75
-15
@@ -1,19 +1,79 @@
|
||||
=== System Calls ===
|
||||
System Calls
|
||||
============
|
||||
|
||||
Syscall handlers are prefixed by 'sys_'
|
||||
Syscalls can be called using interrupt 0x80
|
||||
The EAX register should countain a syscall number on calling and it will contain a return value (if applicable) after calling
|
||||
System calls are a way of interfacing with the kernel from userspace.
|
||||
|
||||
--- Syscall Table ---
|
||||
Calling
|
||||
-------
|
||||
System calls are called via interrupt 0x80. Arguments can be passed through
|
||||
registers in this order with EAX containing the system call number (see [Table](#Table))
|
||||
and arguments in EBX, ECX, EDX, ESI, EDI and EBP respectively.
|
||||
|
||||
Table
|
||||
-----
|
||||
|
||||
|
||||
Syscalls
|
||||
--------
|
||||
|
||||
pid_t fork(void);
|
||||
Creates a child process.
|
||||
|
||||
void exit(int status);
|
||||
Terminate the calling process.
|
||||
|
||||
pid_t waitpid(pid_t pid);
|
||||
Wait untill a process changes state.
|
||||
|
||||
int kill(pid_t, int sig);
|
||||
Send a signal to a process.
|
||||
|
||||
pid_t getpid(void);
|
||||
Get PID of calling process.
|
||||
|
||||
void sleep(size_t t);
|
||||
Sleep for **t** clock ticks.
|
||||
|
||||
int exec(char* path, char** argv);
|
||||
Execute a program.
|
||||
|
||||
int brk(void* addr);
|
||||
Change data segment size.
|
||||
|
||||
int open(char* path, int flags);
|
||||
Open and possibly create a file.
|
||||
|
||||
int close(int fd);
|
||||
Close a file descriptor.
|
||||
|
||||
ssize_t read(int fd, void* buf, size_t count);
|
||||
Read up to **count** bytes into **buf**.
|
||||
|
||||
ssize_t write(int fd, void* buf, size_t count);
|
||||
Write up to **count** bytes from **buf**.
|
||||
|
||||
int dup(int oldfd);
|
||||
Duplicate a file descriptor.
|
||||
|
||||
int pipe(int pipe[2]);
|
||||
Create a pipe and return it's file descriptors in **pipe**.
|
||||
|
||||
int chdir(char* path);
|
||||
Change the current directory of calling process.
|
||||
|
||||
int mkdir(char* path);
|
||||
Create a new directory.
|
||||
|
||||
int mknod(char* path, int maj, int min);
|
||||
Create a new device file.
|
||||
|
||||
int link(char* f1, char* f2);
|
||||
Creates another filename (**f2**) for **f1**.
|
||||
|
||||
int unlink(char* path);
|
||||
Delete a filename.
|
||||
|
||||
int fstat(int fd, struct stat* statbuf);
|
||||
Return info about a file.
|
||||
|
||||
| NR | SYSC NAME | RETURN (EAX) | ARG0 (EBX) | ARG1 (ECX) | ARG2 (EDX) |
|
||||
| 00 | reserved | - | - | - | - |
|
||||
| 01 | sleep | - | uint ms | - | - |
|
||||
| 02 | read | int count | int fd | char* buf | uint count |
|
||||
| 03 | write | int count | int fd | char* buf | uint count |
|
||||
| 04 | open | int fd | char* path | int oflag | - |
|
||||
| 05 | close | int status | int fd | - | - |
|
||||
| 06 | malloc | void* buf | int count | - | - |
|
||||
| 07 | free | - | void* buf | - | - |
|
||||
| 08 | seek | #TBD | | | |
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
Unix-like system calls
|
||||
======================
|
||||
|
||||
pid_t fork(void);
|
||||
Creates a child process.
|
||||
|
||||
void exit(int status);
|
||||
Terminate the calling process.
|
||||
|
||||
pid_t waitpid(pid_t pid);
|
||||
Wait untill a process changes state.
|
||||
|
||||
int kill(pid_t, int sig);
|
||||
Send a signal to a process.
|
||||
|
||||
pid_t getpid(void);
|
||||
Get PID of calling process.
|
||||
|
||||
void sleep(size_t t);
|
||||
Sleep for **t** clock ticks.
|
||||
|
||||
int exec(char* path, char** argv);
|
||||
Execute a program.
|
||||
|
||||
int brk(void* addr);
|
||||
Change data segment size.
|
||||
|
||||
int open(char* path, int flags);
|
||||
Open and possibly create a file.
|
||||
|
||||
int close(int fd);
|
||||
Close a file descriptor.
|
||||
|
||||
ssize_t read(int fd, void* buf, size_t count);
|
||||
Read up to **count** bytes into **buf**.
|
||||
|
||||
ssize_t write(int fd, void* buf, size_t count);
|
||||
Write up to **count** bytes from **buf**.
|
||||
|
||||
int dup(int oldfd);
|
||||
Duplicate a file descriptor.
|
||||
|
||||
int pipe(int pipe[2]);
|
||||
Create a pipe and return it's file descriptors in **pipe**.
|
||||
|
||||
int chdir(char* path);
|
||||
Change the current directory of calling process.
|
||||
|
||||
int mkdir(char* path);
|
||||
Create a new directory.
|
||||
|
||||
int mknod(char* path, int maj, int min);
|
||||
Create a new device file.
|
||||
|
||||
int link(char* f1, char* f2);
|
||||
Creates another filename (**f2**) for **f1**.
|
||||
|
||||
int unlink(char* path);
|
||||
Delete a filename.
|
||||
|
||||
int fstat(int fd, struct stat* statbuf);
|
||||
Return info about a file.
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef _BOOTLOADER_H
|
||||
#define _BOOTLOADER_H
|
||||
|
||||
#include <kernel.h>
|
||||
#include <limine.h>
|
||||
|
||||
struct bootloader {
|
||||
offset_t hhdm_offset;
|
||||
uintptr_t kernel_virt_base;
|
||||
intptr_t kernel_phys_base;
|
||||
size_t mm_total_memory;
|
||||
size_t mm_entry_count;
|
||||
LIMINE_PTR(struct limine_memmap_entry**) mm_entries;
|
||||
size_t fb_entry_count;
|
||||
LIMINE_PTR(struct limine_framebuffer**) fb_entries;
|
||||
LIMINE_PTR(struct limine_file*) executable;
|
||||
};
|
||||
|
||||
extern struct bootloader bootloader;
|
||||
|
||||
#define IS_INSIDE_HHDM(_addr) \
|
||||
((size_t)(_addr) >= bootloader.hhdm_offset && \
|
||||
(size_t)(_addr) <= (bootloader.hhdm_offset + bootloader.mm_total))
|
||||
|
||||
int boot_init(void);
|
||||
|
||||
#endif
|
||||
@@ -1,20 +1,6 @@
|
||||
#ifndef _CTYPE_H
|
||||
#define _CTYPE_H
|
||||
|
||||
/*
|
||||
* Bitfield values
|
||||
*
|
||||
* Property | Bit
|
||||
* ------------|-----
|
||||
* Digit | 0
|
||||
* Letter | 1
|
||||
* Lowercase | 2
|
||||
* Punct | 3
|
||||
* Space | 4
|
||||
* Control | 5
|
||||
* Printable | 6
|
||||
* Hex digit | 7
|
||||
*/
|
||||
#define _DIGIT_MASK (1<<0)
|
||||
#define _ALPHA_MASK (1<<1)
|
||||
#define _LOWER_MASK (1<<2)
|
||||
@@ -44,8 +30,4 @@ extern const unsigned char _CTYPE_TABLE[256];
|
||||
// Why is this one's name longer :((
|
||||
#define isxdigit(_c) _CTYPE_CHECK((_c), _HEXDG_MASK);
|
||||
|
||||
// TODO:
|
||||
// tolower()
|
||||
// toupper()
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef _ERRNO_H
|
||||
#define _ERRNO_H
|
||||
|
||||
#include <kernel.h>
|
||||
|
||||
#define ERRNO_MAX 4095
|
||||
|
||||
#define IS_ERR(_ptr) ((uintptr_t)(_ptr) >= (uintptr_t)(-ERRNO_MAX))
|
||||
|
||||
#define ERR_PTR(_err) ((void*)(_err))
|
||||
#define PTR_ERR(_ptr) ((int)(intptr_t)(_ptr))
|
||||
|
||||
// TODO: Add correct errno.h numbers
|
||||
enum {
|
||||
SUCCESS = 0,
|
||||
ENOMEM, // Cannot allocate memory
|
||||
EPERM, // Operation not permitted
|
||||
ENOENT, // No entry (no such file or directory)
|
||||
EIO, // Input/Output error
|
||||
ENXIO, // No such device or address
|
||||
EAGAIN, // Resource temporarly busy
|
||||
EACCES, // Permission denied
|
||||
EFAULT, // Bad address
|
||||
ENODEV, // No such device
|
||||
EINVAL, // Invalid argument
|
||||
EDOM, // Numerical argument out of domain
|
||||
ERANGE, // Numerical result out of range
|
||||
ENOSYS, // Function not implemented
|
||||
ENOTSUP, // Not supported
|
||||
EILLSEQ, // Illegal byte sequence
|
||||
EOVERFLOW, //
|
||||
EALIGN, // Not aligned
|
||||
EEXIST, // already exists
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef _EXCEPTIONS_H
|
||||
#define _EXCEPTIONS_H
|
||||
|
||||
#include "isr.h"
|
||||
|
||||
#define EXCEPTION_DE 0
|
||||
#define EXCEPTION_BP 3
|
||||
#define EXCEPTION_OF 4
|
||||
#define EXCEPTION_BR 5
|
||||
#define EXCEPTION_UD 6
|
||||
#define EXCEPTION_NM 7
|
||||
#define EXCEPTION_DF 8
|
||||
#define EXCEPTION_GP 13
|
||||
#define EXCEPTION_PF 14
|
||||
#define EXCEPTION_AC 17
|
||||
|
||||
typedef void (*exception_handler_ptr)(struct isr_int_frame* iframe, bool user);
|
||||
|
||||
const extern char* exception_strings[];
|
||||
|
||||
int exception_init(void);
|
||||
void exception_handle(struct isr_int_frame* iframe);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,124 @@
|
||||
#ifndef _GDT_H
|
||||
#define _GDT_H
|
||||
|
||||
#include <kernel.h>
|
||||
|
||||
// Privilege levels
|
||||
#define DPL_KERNEL 0
|
||||
#define DPL_USER 3
|
||||
|
||||
/*
|
||||
* Segment selector explanation (why is kcode 0x08?)
|
||||
*
|
||||
* Each segment selector must be 16 bits. These bits
|
||||
* have the following layout: (example is 0x08)
|
||||
* 0000000000001 0 00 (lsb)
|
||||
* | | '- Privilege level
|
||||
* | '--- Table indicator
|
||||
* '------ Index in table
|
||||
*
|
||||
* Bits 0-1 are the privilege level. x86(_64) has four,
|
||||
* where 00 is the highest and 11 is the lowest. Only
|
||||
* these two are widely used. 00 being kernel space &
|
||||
* 11 being userspace. Bit 3 is the table indicator.
|
||||
* 0 means the GDT and 1 means the LDT. This will most
|
||||
* likely be 0. Bits 4-15 are the index. This is just
|
||||
* which descriptor in the table is used.
|
||||
*
|
||||
* SO, for the kernel code segment:
|
||||
* Privilege is 00 for kernel space, table indicator
|
||||
* s 0 for the GDT and the index is one, because it
|
||||
* is the second entry in our GDT (after null desc.)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Entries:
|
||||
* 0 Null desc.
|
||||
* 1 Kernel code desc.
|
||||
* 2 Kernel data desc.
|
||||
* 3 User data desc.
|
||||
* 4 User code desc.
|
||||
* 5 Task State Segment
|
||||
*/
|
||||
#define GDT_ENTRIES 7
|
||||
#define GDT_NULL 0x00
|
||||
#define GDT_KERNEL_CODE 0x08
|
||||
#define GDT_KERNEL_DATA 0x10
|
||||
#define GDT_USER_DATA 0x18
|
||||
#define GDT_USER_CODE 0x20
|
||||
#define GDT_TSS 0x28
|
||||
|
||||
/*
|
||||
* GDT descriptor/entry explanation
|
||||
*
|
||||
* 0-15 low 16 bits of limit
|
||||
* 15-31 low 16 bits of base
|
||||
* 32-39 mid 8 bits of base
|
||||
* 40-47 access byte
|
||||
* 40 Accessed
|
||||
* 41 Read/Write
|
||||
* 42 Direction/Conforming
|
||||
* 43 Executable
|
||||
* 44 Descriptor type
|
||||
* 45-46 DPL
|
||||
* 47 Present
|
||||
* 48-51 high 4 bits of limit
|
||||
* 52-55 flags
|
||||
* 52 Reserved
|
||||
* 53 Long-mode
|
||||
* 54 Size (0 - 16-bit, 1 - 32-bit)
|
||||
* 55 Granularity (0 - limit in bytes, 1 - limit in pages)
|
||||
* 56-63 high 8 bits of base
|
||||
*/
|
||||
struct gdt_entry {
|
||||
uint16_t limit;
|
||||
uint16_t base_low;
|
||||
uint8_t base_mid;
|
||||
uint8_t access;
|
||||
uint8_t flags; // low 4 bits are 4 msbs of limit, high 4 bits are flags
|
||||
uint8_t base_high;
|
||||
} __packed;
|
||||
|
||||
struct gdt_pointer {
|
||||
uint16_t limit;
|
||||
uint64_t base;
|
||||
} __packed;
|
||||
|
||||
struct tss_entry {
|
||||
uint16_t length;
|
||||
uint16_t base_low;
|
||||
uint8_t base_mid;
|
||||
uint8_t access;
|
||||
uint8_t flags;
|
||||
uint8_t base_high;
|
||||
uint32_t base_upper32;
|
||||
uint32_t __reserved;
|
||||
} __packed;
|
||||
|
||||
struct tss_pointer {
|
||||
uint32_t __reserved0;
|
||||
uint64_t rsp0;
|
||||
uint64_t rsp1;
|
||||
uint64_t rsp2;
|
||||
uint64_t __reserved1;
|
||||
uint64_t ist1;
|
||||
uint64_t ist2;
|
||||
uint64_t ist3;
|
||||
uint64_t ist4;
|
||||
uint64_t ist5;
|
||||
uint64_t ist6;
|
||||
uint64_t ist7;
|
||||
uint64_t __reserved2;
|
||||
uint16_t __reserved3;
|
||||
uint16_t iopb;
|
||||
} __packed;
|
||||
|
||||
struct gdt_entries {
|
||||
// GDT_ENTRIES - 2 to leave space for TSS
|
||||
struct gdt_entry entries[GDT_ENTRIES - 2];
|
||||
struct tss_entry tss;
|
||||
} __packed;
|
||||
|
||||
int gdt_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef _IDT_H
|
||||
#define _IDT_H
|
||||
|
||||
#include <kernel.h>
|
||||
|
||||
#define IDT_ENTRIES 256
|
||||
#define IDT_FLAG_TRAP 0x8F // P = 1, Priv = 00, S = 0, Type = 1111 (32-bit trap)
|
||||
#define IDT_FLAG_INT 0x8E // P = 1, Priv = 00, S = 0, Type = 1110 (32-bit int)
|
||||
#define IDT_FLAG_USER 0xEE // P = 1, Priv = 11, S = 0, Type = 1110 (32-bit int)
|
||||
|
||||
/*
|
||||
* Attribute field explanation
|
||||
* 0..3 Gate type
|
||||
* 4 Zero (unused)
|
||||
* 5..6 DPL (privilege)
|
||||
* 7 Present
|
||||
*/
|
||||
|
||||
struct idt_entry {
|
||||
uint16_t offset_low;
|
||||
uint16_t selector;
|
||||
uint8_t ist; // Only 3 low bits, rest is reserved
|
||||
uint8_t attrib;
|
||||
uint16_t offset_mid;
|
||||
uint32_t offset_high;
|
||||
uint32_t __reserved;
|
||||
} __packed;
|
||||
|
||||
struct idt_pointer {
|
||||
uint16_t size;
|
||||
uint64_t offset;
|
||||
} __packed;
|
||||
|
||||
int idt_init(void);
|
||||
void idt_set_gate(uint8_t i, void* handler, uint8_t flags, uint8_t ist);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef _ISR_H
|
||||
#define _ISR_H
|
||||
|
||||
#include <kernel.h>
|
||||
|
||||
#define EXCEPTION_COUNT 32
|
||||
#define ISR_COUNT 16
|
||||
|
||||
// Interrupt frame (ie. what's on the stack on interrupt)
|
||||
struct isr_int_frame {
|
||||
// Pushed by OS
|
||||
uint64_t ds; // + es
|
||||
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
|
||||
uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
|
||||
uint64_t interrupt, error;
|
||||
|
||||
// Pushed by CPU
|
||||
uint64_t rip, cs, rflags, user_rsp, user_ss;
|
||||
} __packed;
|
||||
typedef void (*isr_handler_ptr)(struct isr_int_frame* iframe);
|
||||
|
||||
int isr_init(void);
|
||||
void isr_register(uint8_t i, isr_handler_ptr handler);
|
||||
void isr_handle_interrupt(size_t rsp);
|
||||
|
||||
// Assembly definitions (isr.s)
|
||||
extern void isr_return(void);
|
||||
extern void* isr_redirect_table[48]; // ISR Table
|
||||
extern void isr128(void); // int 0x80 - syscall
|
||||
extern void isr255(void); // int 0xFF -
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,90 @@
|
||||
#ifndef _KERNEL_H
|
||||
#define _KERNEL_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <types.h>
|
||||
|
||||
#define __alias(symbol) __attribute__((alias(#symbol)))
|
||||
#define __align(x) __attribute__((aligned(x)))
|
||||
#define __printf(a, b) __attribute__((format(printf, a, b)))
|
||||
#define __scanf(a, b) __attribute__((format(scanf, a, b)))
|
||||
#define __align_largest __attribute__((aligned))
|
||||
#define __depricated __attribute__((depricated))
|
||||
#define __packed __attribute__((packed))
|
||||
#define __noreturn __attribute__((noreturn))
|
||||
#define __const __attribute__((const))
|
||||
#define __pure __attribute__((pure))
|
||||
#define __section(_s) __attribute__((section(_s)))
|
||||
#define __cold __attribute__((cold))
|
||||
#define __hot __attribute__((hot))
|
||||
#define __naked __attribute__((naked))
|
||||
#define __always_inline __attribute__((always_inline))
|
||||
#define noinline __attribute__((never_inline))
|
||||
|
||||
#define ALIGN(_addr, _align) (((_addr) + (_align) - 1) & ~((_align) - 1))
|
||||
#define ALIGN_DOWN(_addr, _align) ((_addr) & ~((_align) - 1))
|
||||
#define BIT(_n) (1ULL << (_n))
|
||||
|
||||
#define swap(_a, _b) ({ typeof(_a) _tmp = (_a); (_a) = (_b); (_b) = (_a); })
|
||||
#define min(_x, _y) ({ typeof(_x) __x = (_x); typeof(_y) __y = (_y); __x < __y ? __x : __y; })
|
||||
#define max(_x, _y) ({ typeof(_x) __x = (_x); typeof(_y) __y = (_y); __x > __y ? __x : __y; })
|
||||
#define ceil(_x, _y) ((((_x) + (_y)) (_y)) * (_y))
|
||||
#define floor(_x, _y) ((_x) - ((_x) % (_y)))
|
||||
#define dceil(_x, _y) (((_x) + (_y) - 1) / (_y))
|
||||
|
||||
#define fence() __asm__ volatile ("" ::: "memory")
|
||||
|
||||
#define KERN_SOH "\001"
|
||||
#define KERN_SOH_ASCII '\001'
|
||||
#define KERN_EMERG KERN_SOH "0"
|
||||
#define KERN_ALERT KERN_SOH "1"
|
||||
#define KERN_CRIT KERN_SOH "2"
|
||||
#define KERN_ERROR KERN_SOH "3"
|
||||
#define KERN_WARNING KERN_SOH "4"
|
||||
#define KERN_NOTICE KERN_SOH "5"
|
||||
#define KERN_INFO KERN_SOH "6"
|
||||
#define KERN_DEBUG KERN_SOH "7"
|
||||
#define KERN_DEFAULT ""
|
||||
|
||||
#define LOGLEVEL_EMERG 0
|
||||
#define LOGLEVEL_ALERT 1
|
||||
#define LOGLEVEL_CRIT 2
|
||||
#define LOGLEVEL_ERROR 3
|
||||
#define LOGLEVEL_WARNING 4
|
||||
#define LOGLEVEL_NOTICE 5
|
||||
#define LOGLEVEL_INFO 6
|
||||
#define LOGLEVEL_DEBUG 7
|
||||
|
||||
#ifndef LOGLEVEL_DEFAULT
|
||||
#define LOGLEVEL_DEFAULT LOGLEVEL_ERROR
|
||||
#endif
|
||||
|
||||
#ifndef CONSOLE_LOGLEVEL
|
||||
#define CONSOLE_LOGLEVEL 4
|
||||
#endif
|
||||
|
||||
extern uint8_t console_loglevel;
|
||||
|
||||
// TODO: Add a ring buffer for the logs
|
||||
int printk(const char* fmt, ...) __printf(1, 2);
|
||||
int vprintk(const char* fmt, va_list ap);
|
||||
|
||||
#define pr_emerg(fmt, ...) printk(KERN_EMERG fmt, ##__VA_ARGS__)
|
||||
#define pr_alert(fmt, ...) printk(KERN_ALERT fmt, ##__VA_ARGS__)
|
||||
#define pr_crit(fmt, ...) printk(KERN_CRIT fmt, ##__VA_ARGS__)
|
||||
#define pr_error(fmt, ...) printk(KERN_ERROR fmt, ##__VA_ARGS__)
|
||||
#define pr_warn(fmt, ...) printk(KERN_WARNING fmt, ##__VA_ARGS__)
|
||||
#define pr_notice(fmt, ...) printk(KERN_NOTICE fmt, ##__VA_ARGS__)
|
||||
#define pr_info(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__)
|
||||
#define pr_debug(fmt, ...) printk(KERN_DEBUG fmt, ##__VA_ARGS__)
|
||||
|
||||
#define PANIC_MSG_BUFSZ 1024
|
||||
|
||||
struct isr_int_frame;
|
||||
void panic(struct isr_int_frame* regs, const char* fmt, ...) __noreturn __cold __printf(2, 3);
|
||||
void vpanic(struct isr_int_frame* regs, const char *fmt, va_list ap) __noreturn __cold;
|
||||
|
||||
extern uintptr_t __kernel_start, __kernel_text_start, __kernel_rodata_start, __kernel_data_start;
|
||||
extern uintptr_t __kernel_end, __kernel_text_end, __kernel_rodata_end, __kernel_data_end;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,105 @@
|
||||
#ifndef _KMALLOC_H
|
||||
#define _KMALLOC_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
// This function allocates size bytes of contiguous memory.
|
||||
// Returns a pointer to allocated memory or NULL.
|
||||
void* kmalloc(size_t size);
|
||||
|
||||
// This function allocates size bytes of contiguous, zeroed-out memory.
|
||||
// Returns a pointer to allocated memory or NULL.
|
||||
void* kzalloc(size_t size);
|
||||
|
||||
// This function allocates memory for count elements each of size bytes,
|
||||
// zeroed-out memory. Returns a pointer to allocated memory or NULL.
|
||||
void* kcalloc(size_t count, size_t size);
|
||||
|
||||
// 9 bytes in 8 bytes
|
||||
#define TAG_SHIFT 56
|
||||
#define TAG_MASK ((uintptr_t)0xFF << TAG_SHIFT)
|
||||
#define SIGN_BIT ((uintptr_t)1 << 55)
|
||||
|
||||
typedef struct {
|
||||
uintptr_t bits;
|
||||
} tagged_ptr;
|
||||
|
||||
static inline tagged_ptr tp_make(void* p, uint8_t tag) {
|
||||
uintptr_t addr = (uintptr_t)p & ~TAG_MASK;
|
||||
return (tagged_ptr){addr | ((uintptr_t)tag << TAG_SHIFT)};
|
||||
}
|
||||
|
||||
static inline uint8_t tp_tag(tagged_ptr t) {
|
||||
return (uint8_t)(t.bits >> TAG_SHIFT);
|
||||
}
|
||||
|
||||
static inline void* tp_ptr(tagged_ptr t) {
|
||||
/* Bits 48..55 were untouched and still equal the canonical sign.
|
||||
Copy bit 55 into bits 56..63. */
|
||||
uintptr_t addr =
|
||||
(t.bits & SIGN_BIT) ? (t.bits | TAG_MASK) : (t.bits & ~TAG_MASK);
|
||||
return (void*)addr;
|
||||
}
|
||||
|
||||
// powers of 2
|
||||
#define KMALLOC_MAX_SIZE 17
|
||||
#define LOWEST_POWER 3
|
||||
|
||||
struct freelist {
|
||||
struct freelist* nextnode;
|
||||
};
|
||||
|
||||
struct partialy_freelist {
|
||||
struct freelist* freelist_nextnode;
|
||||
struct partialy_freelist* partialy_freelist_nextnode;
|
||||
};
|
||||
|
||||
// this is used when object is too small to hold the big one in this case we use
|
||||
// first object as pointer storage and dont allocate it
|
||||
struct partialy_freelist_short {
|
||||
struct partialy_freelist_short* partialy_freelist_nextnode;
|
||||
};
|
||||
|
||||
union freelists_list {
|
||||
struct freelist* freelists[KMALLOC_MAX_SIZE];
|
||||
struct {
|
||||
struct freelist* kmalloc_8;
|
||||
struct freelist* kmalloc_16;
|
||||
struct freelist* kmalloc_32;
|
||||
struct freelist* kmalloc_64;
|
||||
struct freelist* kmalloc_128;
|
||||
struct freelist* kmalloc_256;
|
||||
struct freelist* kmalloc_512;
|
||||
struct freelist* kmalloc_1024;
|
||||
struct freelist* kmalloc_2048;
|
||||
struct freelist* kmalloc_4096;
|
||||
struct freelist* kmalloc_8192;
|
||||
struct freelist* kmalloc_16384;
|
||||
struct freelist* kmalloc_32768;
|
||||
struct freelist* kmalloc_65536;
|
||||
struct freelist* kmalloc_131072;
|
||||
};
|
||||
};
|
||||
|
||||
union partialy_freelists_list {
|
||||
struct partialy_freelist* partialy_freelists[KMALLOC_MAX_SIZE];
|
||||
struct {
|
||||
struct partialy_freelist* kmalloc_8;
|
||||
struct partialy_freelist* kmalloc_16;
|
||||
struct partialy_freelist* kmalloc_32;
|
||||
struct partialy_freelist* kmalloc_64;
|
||||
struct partialy_freelist* kmalloc_128;
|
||||
struct partialy_freelist* kmalloc_256;
|
||||
struct partialy_freelist* kmalloc_512;
|
||||
struct partialy_freelist* kmalloc_1024;
|
||||
struct partialy_freelist* kmalloc_2048;
|
||||
struct partialy_freelist* kmalloc_4096;
|
||||
struct partialy_freelist* kmalloc_8192;
|
||||
struct partialy_freelist* kmalloc_16384;
|
||||
struct partialy_freelist* kmalloc_32768;
|
||||
struct partialy_freelist* kmalloc_65536;
|
||||
struct partialy_freelist* kmalloc_131072;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,594 @@
|
||||
/* SPDX-License-Identifier: 0BSD */
|
||||
|
||||
/* Copyright (C) 2022-2026 Mintsuki and contributors.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIMINE_H
|
||||
#define LIMINE_H 1
|
||||
|
||||
#include <kernel.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Misc */
|
||||
|
||||
#ifdef LIMINE_NO_POINTERS
|
||||
# define LIMINE_PTR(TYPE) uint64_t
|
||||
#else
|
||||
# define LIMINE_PTR(TYPE) TYPE
|
||||
#endif
|
||||
|
||||
#define LIMINE_REQUESTS_START_MARKER { 0xf6b8f4b39de7d1ae, 0xfab91a6940fcb9cf, \
|
||||
0x785c6ed015d3e316, 0x181e920a7852b9d9 }
|
||||
#define LIMINE_REQUESTS_END_MARKER { 0xadc0e0531bb10d03, 0x9572709f31764c62 }
|
||||
|
||||
#define LIMINE_BASE_REVISION(N) { 0xf9562b2d5c95a6c8, 0x6a7b384944536bdc, (N) }
|
||||
|
||||
#define LIMINE_BASE_REVISION_SUPPORTED(VAR) ((VAR)[2] == 0)
|
||||
|
||||
#define LIMINE_LOADED_BASE_REVISION_VALID(VAR) ((VAR)[1] != 0x6a7b384944536bdc)
|
||||
#define LIMINE_LOADED_BASE_REVISION(VAR) ((VAR)[1])
|
||||
|
||||
#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b
|
||||
|
||||
struct limine_uuid {
|
||||
uint32_t a;
|
||||
uint16_t b;
|
||||
uint16_t c;
|
||||
uint8_t d[8];
|
||||
};
|
||||
|
||||
#define LIMINE_MEDIA_TYPE_GENERIC 0
|
||||
#define LIMINE_MEDIA_TYPE_OPTICAL 1
|
||||
#define LIMINE_MEDIA_TYPE_TFTP 2
|
||||
|
||||
struct limine_file {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) address;
|
||||
uint64_t size;
|
||||
LIMINE_PTR(char *) path;
|
||||
LIMINE_PTR(char *) string;
|
||||
uint32_t media_type;
|
||||
uint32_t unused;
|
||||
uint32_t tftp_ip;
|
||||
uint32_t tftp_port;
|
||||
uint32_t partition_index;
|
||||
uint32_t mbr_disk_id;
|
||||
struct limine_uuid gpt_disk_uuid;
|
||||
struct limine_uuid gpt_part_uuid;
|
||||
struct limine_uuid part_uuid;
|
||||
};
|
||||
|
||||
/* Boot info */
|
||||
|
||||
#define LIMINE_BOOTLOADER_INFO_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xf55038d8e2a1202f, 0x279426fcf5f59740 }
|
||||
|
||||
struct limine_bootloader_info_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(char *) name;
|
||||
LIMINE_PTR(char *) version;
|
||||
};
|
||||
|
||||
struct limine_bootloader_info_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_bootloader_info_response *) response;
|
||||
};
|
||||
|
||||
/* Executable command line */
|
||||
|
||||
#define LIMINE_EXECUTABLE_CMDLINE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x4b161536e598651e, 0xb390ad4a2f1f303a }
|
||||
|
||||
struct limine_executable_cmdline_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(char *) cmdline;
|
||||
};
|
||||
|
||||
struct limine_executable_cmdline_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_executable_cmdline_response *) response;
|
||||
};
|
||||
|
||||
/* Firmware type */
|
||||
|
||||
#define LIMINE_FIRMWARE_TYPE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x8c2f75d90bef28a8, 0x7045a4688eac00c3 }
|
||||
|
||||
#define LIMINE_FIRMWARE_TYPE_X86BIOS 0
|
||||
#define LIMINE_FIRMWARE_TYPE_EFI32 1
|
||||
#define LIMINE_FIRMWARE_TYPE_EFI64 2
|
||||
#define LIMINE_FIRMWARE_TYPE_SBI 3
|
||||
|
||||
struct limine_firmware_type_response {
|
||||
uint64_t revision;
|
||||
uint64_t firmware_type;
|
||||
};
|
||||
|
||||
struct limine_firmware_type_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_firmware_type_response *) response;
|
||||
};
|
||||
|
||||
/* Stack size */
|
||||
|
||||
#define LIMINE_STACK_SIZE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d }
|
||||
|
||||
struct limine_stack_size_response {
|
||||
uint64_t revision;
|
||||
};
|
||||
|
||||
struct limine_stack_size_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_stack_size_response *) response;
|
||||
uint64_t stack_size;
|
||||
};
|
||||
|
||||
/* HHDM */
|
||||
|
||||
#define LIMINE_HHDM_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x48dcf1cb8ad2b852, 0x63984e959a98244b }
|
||||
|
||||
struct limine_hhdm_response {
|
||||
uint64_t revision;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
struct limine_hhdm_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_hhdm_response *) response;
|
||||
};
|
||||
|
||||
/* Framebuffer */
|
||||
|
||||
#define LIMINE_FRAMEBUFFER_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x9d5827dcd881dd75, 0xa3148604f6fab11b }
|
||||
|
||||
#define LIMINE_FRAMEBUFFER_RGB 1
|
||||
|
||||
struct limine_video_mode {
|
||||
uint64_t pitch;
|
||||
uint64_t width;
|
||||
uint64_t height;
|
||||
uint16_t bpp;
|
||||
uint8_t memory_model;
|
||||
uint8_t red_mask_size;
|
||||
uint8_t red_mask_shift;
|
||||
uint8_t green_mask_size;
|
||||
uint8_t green_mask_shift;
|
||||
uint8_t blue_mask_size;
|
||||
uint8_t blue_mask_shift;
|
||||
};
|
||||
|
||||
struct limine_framebuffer {
|
||||
LIMINE_PTR(void *) address;
|
||||
uint64_t width;
|
||||
uint64_t height;
|
||||
uint64_t pitch;
|
||||
uint16_t bpp;
|
||||
uint8_t memory_model;
|
||||
uint8_t red_mask_size;
|
||||
uint8_t red_mask_shift;
|
||||
uint8_t green_mask_size;
|
||||
uint8_t green_mask_shift;
|
||||
uint8_t blue_mask_size;
|
||||
uint8_t blue_mask_shift;
|
||||
uint8_t unused[7];
|
||||
uint64_t edid_size;
|
||||
LIMINE_PTR(void *) edid;
|
||||
/* Response revision 1 */
|
||||
uint64_t mode_count;
|
||||
LIMINE_PTR(struct limine_video_mode **) modes;
|
||||
};
|
||||
|
||||
struct limine_framebuffer_response {
|
||||
uint64_t revision;
|
||||
uint64_t framebuffer_count;
|
||||
LIMINE_PTR(struct limine_framebuffer **) framebuffers;
|
||||
};
|
||||
|
||||
struct limine_framebuffer_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_framebuffer_response *) response;
|
||||
};
|
||||
|
||||
/* Paging mode */
|
||||
|
||||
#define LIMINE_PAGING_MODE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x95c1a0edab0944cb, 0xa4e5cb3842f7488a }
|
||||
|
||||
#define LIMINE_PAGING_MODE_X86_64_4LVL 0
|
||||
#define LIMINE_PAGING_MODE_X86_64_5LVL 1
|
||||
#define LIMINE_PAGING_MODE_X86_64_MIN LIMINE_PAGING_MODE_X86_64_4LVL
|
||||
#define LIMINE_PAGING_MODE_X86_64_DEFAULT LIMINE_PAGING_MODE_X86_64_4LVL
|
||||
|
||||
#define LIMINE_PAGING_MODE_AARCH64_4LVL 0
|
||||
#define LIMINE_PAGING_MODE_AARCH64_5LVL 1
|
||||
#define LIMINE_PAGING_MODE_AARCH64_MIN LIMINE_PAGING_MODE_AARCH64_4LVL
|
||||
#define LIMINE_PAGING_MODE_AARCH64_DEFAULT LIMINE_PAGING_MODE_AARCH64_4LVL
|
||||
|
||||
#define LIMINE_PAGING_MODE_RISCV_SV39 0
|
||||
#define LIMINE_PAGING_MODE_RISCV_SV48 1
|
||||
#define LIMINE_PAGING_MODE_RISCV_SV57 2
|
||||
#define LIMINE_PAGING_MODE_RISCV_MIN LIMINE_PAGING_MODE_RISCV_SV39
|
||||
#define LIMINE_PAGING_MODE_RISCV_DEFAULT LIMINE_PAGING_MODE_RISCV_SV48
|
||||
|
||||
#define LIMINE_PAGING_MODE_LOONGARCH_4LVL 0
|
||||
#define LIMINE_PAGING_MODE_LOONGARCH_MIN LIMINE_PAGING_MODE_LOONGARCH_4LVL
|
||||
#define LIMINE_PAGING_MODE_LOONGARCH_DEFAULT LIMINE_PAGING_MODE_LOONGARCH_4LVL
|
||||
|
||||
struct limine_paging_mode_response {
|
||||
uint64_t revision;
|
||||
uint64_t mode;
|
||||
};
|
||||
|
||||
struct limine_paging_mode_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_paging_mode_response *) response;
|
||||
uint64_t mode;
|
||||
uint64_t max_mode;
|
||||
uint64_t min_mode;
|
||||
};
|
||||
|
||||
/* MP */
|
||||
|
||||
#define LIMINE_MP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 }
|
||||
|
||||
struct limine_mp_info;
|
||||
|
||||
typedef void (*limine_goto_address)(struct limine_mp_info *);
|
||||
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
|
||||
#define LIMINE_MP_RESPONSE_X86_64_X2APIC (1 << 0)
|
||||
|
||||
struct limine_mp_info {
|
||||
uint32_t processor_id;
|
||||
uint32_t lapic_id;
|
||||
uint64_t reserved;
|
||||
LIMINE_PTR(limine_goto_address) goto_address;
|
||||
uint64_t extra_argument;
|
||||
};
|
||||
|
||||
struct limine_mp_response {
|
||||
uint64_t revision;
|
||||
uint32_t flags;
|
||||
uint32_t bsp_lapic_id;
|
||||
uint64_t cpu_count;
|
||||
LIMINE_PTR(struct limine_mp_info **) cpus;
|
||||
};
|
||||
|
||||
#elif defined (__aarch64__)
|
||||
|
||||
struct limine_mp_info {
|
||||
uint32_t processor_id;
|
||||
uint32_t reserved1;
|
||||
uint64_t mpidr;
|
||||
uint64_t reserved;
|
||||
LIMINE_PTR(limine_goto_address) goto_address;
|
||||
uint64_t extra_argument;
|
||||
};
|
||||
|
||||
struct limine_mp_response {
|
||||
uint64_t revision;
|
||||
uint64_t flags;
|
||||
uint64_t bsp_mpidr;
|
||||
uint64_t cpu_count;
|
||||
LIMINE_PTR(struct limine_mp_info **) cpus;
|
||||
};
|
||||
|
||||
#elif defined (__riscv) && (__riscv_xlen == 64)
|
||||
|
||||
struct limine_mp_info {
|
||||
uint64_t processor_id;
|
||||
uint64_t hartid;
|
||||
uint64_t reserved;
|
||||
LIMINE_PTR(limine_goto_address) goto_address;
|
||||
uint64_t extra_argument;
|
||||
};
|
||||
|
||||
struct limine_mp_response {
|
||||
uint64_t revision;
|
||||
uint64_t flags;
|
||||
uint64_t bsp_hartid;
|
||||
uint64_t cpu_count;
|
||||
LIMINE_PTR(struct limine_mp_info **) cpus;
|
||||
};
|
||||
|
||||
#elif defined (__loongarch__) && (__loongarch_grlen == 64)
|
||||
|
||||
struct limine_mp_info {
|
||||
uint64_t processor_id;
|
||||
uint64_t phys_id;
|
||||
uint64_t reserved;
|
||||
LIMINE_PTR(limine_goto_address) goto_address;
|
||||
uint64_t extra_argument;
|
||||
};
|
||||
|
||||
struct limine_mp_response {
|
||||
uint64_t revision;
|
||||
uint64_t flags;
|
||||
uint64_t bsp_phys_id;
|
||||
uint64_t cpu_count;
|
||||
LIMINE_PTR(struct limine_mp_info **) cpus;
|
||||
};
|
||||
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
||||
#define LIMINE_MP_REQUEST_X86_64_X2APIC (1 << 0)
|
||||
|
||||
struct limine_mp_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_mp_response *) response;
|
||||
uint64_t flags;
|
||||
};
|
||||
|
||||
/* Memory map */
|
||||
|
||||
#define LIMINE_MEMMAP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62 }
|
||||
|
||||
#define LIMINE_MEMMAP_USABLE 0
|
||||
#define LIMINE_MEMMAP_RESERVED 1
|
||||
#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2
|
||||
#define LIMINE_MEMMAP_ACPI_NVS 3
|
||||
#define LIMINE_MEMMAP_BAD_MEMORY 4
|
||||
#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5
|
||||
#define LIMINE_MEMMAP_EXECUTABLE_AND_MODULES 6
|
||||
#define LIMINE_MEMMAP_FRAMEBUFFER 7
|
||||
#define LIMINE_MEMMAP_RESERVED_MAPPED 8
|
||||
|
||||
struct limine_memmap_entry {
|
||||
uint64_t base;
|
||||
uint64_t length;
|
||||
uint64_t type;
|
||||
};
|
||||
|
||||
struct limine_memmap_response {
|
||||
uint64_t revision;
|
||||
uint64_t entry_count;
|
||||
LIMINE_PTR(struct limine_memmap_entry **) entries;
|
||||
};
|
||||
|
||||
struct limine_memmap_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_memmap_response *) response;
|
||||
};
|
||||
|
||||
/* Entry point */
|
||||
|
||||
#define LIMINE_ENTRY_POINT_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x13d86c035a1cd3e1, 0x2b0caa89d8f3026a }
|
||||
|
||||
typedef void (*limine_entry_point)(void);
|
||||
|
||||
struct limine_entry_point_response {
|
||||
uint64_t revision;
|
||||
};
|
||||
|
||||
struct limine_entry_point_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_entry_point_response *) response;
|
||||
LIMINE_PTR(limine_entry_point) entry;
|
||||
};
|
||||
|
||||
/* Executable File */
|
||||
|
||||
#define LIMINE_EXECUTABLE_FILE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69 }
|
||||
|
||||
struct limine_executable_file_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_file *) executable_file;
|
||||
};
|
||||
|
||||
struct limine_executable_file_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_executable_file_response *) response;
|
||||
};
|
||||
|
||||
/* Module */
|
||||
|
||||
#define LIMINE_MODULE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x3e7e279702be32af, 0xca1c4f3bd1280cee }
|
||||
|
||||
#define LIMINE_INTERNAL_MODULE_REQUIRED (1 << 0)
|
||||
#define LIMINE_INTERNAL_MODULE_COMPRESSED (1 << 1)
|
||||
|
||||
struct limine_internal_module {
|
||||
LIMINE_PTR(const char *) path;
|
||||
LIMINE_PTR(const char *) string;
|
||||
uint64_t flags;
|
||||
};
|
||||
|
||||
struct limine_module_response {
|
||||
uint64_t revision;
|
||||
uint64_t module_count;
|
||||
LIMINE_PTR(struct limine_file **) modules;
|
||||
};
|
||||
|
||||
struct limine_module_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_module_response *) response;
|
||||
|
||||
/* Request revision 1 */
|
||||
uint64_t internal_module_count;
|
||||
LIMINE_PTR(struct limine_internal_module **) internal_modules;
|
||||
};
|
||||
|
||||
/* RSDP */
|
||||
|
||||
#define LIMINE_RSDP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xc5e77b6b397e7b43, 0x27637845accdcf3c }
|
||||
|
||||
struct limine_rsdp_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) address;
|
||||
};
|
||||
|
||||
struct limine_rsdp_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_rsdp_response *) response;
|
||||
};
|
||||
|
||||
/* SMBIOS */
|
||||
|
||||
#define LIMINE_SMBIOS_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x9e9046f11e095391, 0xaa4a520fefbde5ee }
|
||||
|
||||
struct limine_smbios_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) entry_32;
|
||||
LIMINE_PTR(void *) entry_64;
|
||||
};
|
||||
|
||||
struct limine_smbios_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_smbios_response *) response;
|
||||
};
|
||||
|
||||
/* EFI system table */
|
||||
|
||||
#define LIMINE_EFI_SYSTEM_TABLE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x5ceba5163eaaf6d6, 0x0a6981610cf65fcc }
|
||||
|
||||
struct limine_efi_system_table_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) address;
|
||||
};
|
||||
|
||||
struct limine_efi_system_table_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_efi_system_table_response *) response;
|
||||
};
|
||||
|
||||
/* EFI memory map */
|
||||
|
||||
#define LIMINE_EFI_MEMMAP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x7df62a431d6872d5, 0xa4fcdfb3e57306c8 }
|
||||
|
||||
struct limine_efi_memmap_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) memmap;
|
||||
uint64_t memmap_size;
|
||||
uint64_t desc_size;
|
||||
uint64_t desc_version;
|
||||
};
|
||||
|
||||
struct limine_efi_memmap_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_efi_memmap_response *) response;
|
||||
};
|
||||
|
||||
/* Date at boot */
|
||||
|
||||
#define LIMINE_DATE_AT_BOOT_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893 }
|
||||
|
||||
struct limine_date_at_boot_response {
|
||||
uint64_t revision;
|
||||
int64_t timestamp;
|
||||
};
|
||||
|
||||
struct limine_date_at_boot_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_date_at_boot_response *) response;
|
||||
};
|
||||
|
||||
/* Executable address */
|
||||
|
||||
#define LIMINE_EXECUTABLE_ADDRESS_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487 }
|
||||
|
||||
struct limine_executable_address_response {
|
||||
uint64_t revision;
|
||||
uint64_t physical_base;
|
||||
uint64_t virtual_base;
|
||||
};
|
||||
|
||||
struct limine_executable_address_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_executable_address_response *) response;
|
||||
};
|
||||
|
||||
/* Device Tree Blob */
|
||||
|
||||
#define LIMINE_DTB_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xb40ddb48fb54bac7, 0x545081493f81ffb7 }
|
||||
|
||||
struct limine_dtb_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) dtb_ptr;
|
||||
};
|
||||
|
||||
struct limine_dtb_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_dtb_response *) response;
|
||||
};
|
||||
|
||||
/* RISC-V Boot Hart ID */
|
||||
|
||||
#define LIMINE_RISCV_BSP_HARTID_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x1369359f025525f9, 0x2ff2a56178391bb6 }
|
||||
|
||||
struct limine_riscv_bsp_hartid_response {
|
||||
uint64_t revision;
|
||||
uint64_t bsp_hartid;
|
||||
};
|
||||
|
||||
struct limine_riscv_bsp_hartid_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_riscv_bsp_hartid_response *) response;
|
||||
};
|
||||
|
||||
/* Bootloader Performance */
|
||||
|
||||
#define LIMINE_BOOTLOADER_PERFORMANCE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x6b50ad9bf36d13ad, 0xdc4c7e88fc759e17 }
|
||||
|
||||
struct limine_bootloader_performance_response {
|
||||
uint64_t revision;
|
||||
uint64_t reset_usec;
|
||||
uint64_t init_usec;
|
||||
uint64_t exec_usec;
|
||||
};
|
||||
|
||||
struct limine_bootloader_performance_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_bootloader_performance_response *) response;
|
||||
};
|
||||
|
||||
#define LIMINE_KEEP_IOMMU_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x8ebaabe51f490179, 0x2aa86a59ffb4ab0f }
|
||||
|
||||
struct limine_keep_iommu_response {
|
||||
uint64_t revision;
|
||||
};
|
||||
|
||||
struct limine_keep_iommu_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_keep_iommu_response *) response;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef _LIMIT_H
|
||||
#define _LIMIT_H
|
||||
|
||||
#define CHAR_BIT 8
|
||||
|
||||
#define INT8_WIDTH 8
|
||||
#define INT16_WIDTH 16
|
||||
#define INT32_WIDTH 32
|
||||
#define INT64_WIDTH 64
|
||||
|
||||
#define UINT8_WIDTH 8
|
||||
#define UINT16_WIDTH 16
|
||||
#define UINT32_WIDTH 32
|
||||
#define UINT64_WIDTH 64
|
||||
|
||||
#define INT8_MAX 127
|
||||
#define INT16_MAX 32767
|
||||
#define INT32_MAX 2147483647
|
||||
#define INT64_MAX 9223372036854775807LL
|
||||
|
||||
#define INT8_MIN (-128)
|
||||
#define INT16_MIN (-32768)
|
||||
#define INT32_MIN (-2147483647 - 1)
|
||||
#define INT64_MIN (-9223372036854775807LL - 1LL)
|
||||
|
||||
#define UINT8_MAX 255U
|
||||
#define UINT16_MAX 65535U
|
||||
#define UINT32_MAX 4294967295U
|
||||
#define UINT64_MAX 18446744073709551615ULL
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef _PAGING_H
|
||||
#define _PAGING_H
|
||||
|
||||
#include <bootloader.h>
|
||||
#include <kernel.h>
|
||||
|
||||
#define PTE_FLAG_PRESENT (1UL << 0) // Page is present in the table
|
||||
#define PTE_FLAG_WRITE (1UL << 1) // Read-write
|
||||
#define PTE_FLAG_USER (1UL << 2) // User-mode (DPL3) access allowed
|
||||
#define PTE_FLAG_PWT (1UL << 3) // Page write-thru
|
||||
#define PTE_FLAG_NOCACHE (1UL << 4) // Cache disable
|
||||
#define PTE_FLAG_FETCH (1UL << 4) // Fetch
|
||||
#define PTE_FLAG_ACCESSED (1UL << 5) // Indicates whether page was read/written
|
||||
#define PTE_FLAG_DIRTY (1UL << 6) // Indicates whether page was written to (valid for PT only)
|
||||
#define PTE_FLAG_PAT (1UL << 7) // Page Attribute Table (valid for PT only)
|
||||
#define PTE_FLAG_PAGESIZE (1UL << 7) // Page size (valid for PD and PDPT only)
|
||||
#define PTE_FLAG_RSVD (1UL << 7) // No idea (valid for PML4 and PML5 only)
|
||||
#define PTE_FLAG_GLOBAL (1UL << 8) // Global caching or sum (valid for PT only)
|
||||
#define PTE_FLAG_NOEXEC (1UL << 63) // No execute (the XD bit)
|
||||
// Region caching according to the Limine protocol
|
||||
#define PTE_FLAG_CACHE (PTE_FLAG_PWT | PTE_FLAG_PAT)
|
||||
|
||||
#define PTE_ADDR_MASK 0x000FFFFFFFFFF000UL
|
||||
#define PTE_ADDR(_pte) ((_pte) & PTE_ADDR_MASK)
|
||||
|
||||
#define PML4_IDX(_ptr) (((_ptr) >> 39) & 0x1FFUL)
|
||||
#define PDPT_IDX(_ptr) (((_ptr) >> 30) & 0x1FFUL)
|
||||
#define PD_IDX(_ptr) (((_ptr) >> 21) & 0x1FFUL)
|
||||
#define PT_IDX(_ptr) (((_ptr) >> 12) & 0x1FFUL)
|
||||
|
||||
#define TO_VIRT(_ptr) ((void*)((uintptr_t)(_ptr) + bootloader.hhdm_offset))
|
||||
#define TO_PHYS(_ptr) ((void*)((uintptr_t)(_ptr) - bootloader.hhdm_offset))
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_SIZE_LARGE 0x200000
|
||||
#define PAGE_SIZE_HUGE 0x40000000
|
||||
|
||||
// WARN: This will only invalidate on one core
|
||||
static inline void pag_invalidate(void* vaddr) { __asm__ volatile("invlpg (%0)" :: "r" (vaddr) : "memory"); }
|
||||
static inline bool pag_is_user_addr(void* vaddr) { return (uintptr_t)vaddr < 0x0000800000000000UL; }
|
||||
|
||||
// NOTE: All uint64_t* are VIRTUAL addresses
|
||||
int pag_init(void);
|
||||
uint64_t* pag_get_pte(uint64_t* pml4, void* vaddr);
|
||||
int pag_map(uint64_t* pml4, void* vaddr, void* paddr, uint64_t flags);
|
||||
int pag_map_region(uint64_t* pml4, void* vaddr, void* paddr, size_t count, uint64_t flags);
|
||||
int pag_unmap(uint64_t* pml4, void* vaddr);
|
||||
int pag_unmap_region(uint64_t* pml4, void* vaddr, size_t count);
|
||||
int pag_protect(uint64_t* pml4, void* vaddr, uint64_t flags);
|
||||
void* pag_get_phys(uint64_t* pml4, void* vaddr);
|
||||
void pag_set_pml4(uint64_t* pml4);
|
||||
uint64_t* pag_get_pml4(void);
|
||||
uint64_t* pag_get_next_tab(uint64_t* tab, offset_t index);
|
||||
uint64_t* pag_new_next_tab(uint64_t* tab, offset_t index);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef _PMM_H
|
||||
#define _PMM_H
|
||||
|
||||
#include <kernel.h>
|
||||
|
||||
extern size_t pmm_total_pages;
|
||||
extern size_t pmm_free_pages;
|
||||
|
||||
int pmm_init(void);
|
||||
void* pmm_alloc(void);
|
||||
int pmm_free(void*);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef _RANDOM_H
|
||||
#define _RANDOM_H
|
||||
|
||||
#include <types.h>
|
||||
void rand_init(bool rdrand, bool rdseed);
|
||||
|
||||
extern uint64_t (*get_random_number)();
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef _SERIAL_H
|
||||
#define _SERIAL_H
|
||||
|
||||
#include <kernel.h>
|
||||
|
||||
#define COM1 0x3f8
|
||||
#define COM2 0x2f8
|
||||
#define COM3 0x3e8
|
||||
#define COM4 0x2e8
|
||||
|
||||
// Buffer for (v)debugf()
|
||||
#define DF_BUF_LEN 2048
|
||||
|
||||
int serial_init(int dev);
|
||||
int serial_txem(int dev);
|
||||
void serial_send(int dev, char data);
|
||||
int serial_rcvd(int dev);
|
||||
char serial_recv(int dev);
|
||||
void serial_write(int dev, const char* buf, size_t len);
|
||||
void serial_puts(int dev, const char* s);
|
||||
void serial_cls(int dev);
|
||||
|
||||
int debugf(const char* fmt, ...) __printf(1, 2);
|
||||
int vdebugf(const char* fmt, va_list args);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef _SPLASH_H
|
||||
#define _SPLASH_H
|
||||
|
||||
/*
|
||||
* This is the most important function in the world.
|
||||
*
|
||||
* It draws this to the zeroth framebuffer:
|
||||
* #
|
||||
* #
|
||||
* #
|
||||
* # # ## # ## # ##
|
||||
* # # # # ## # ## #
|
||||
* ## ### # # #
|
||||
* # # # # # #
|
||||
* # # ### # # # #
|
||||
*/
|
||||
void splash(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef _STDARG_H
|
||||
#define _STDARG_H
|
||||
|
||||
typedef __builtin_va_list va_list;
|
||||
#define va_start(_ap, _last) __builtin_va_start(_ap, _last)
|
||||
#define va_end(_ap) __builtin_va_end(_ap)
|
||||
#define va_arg(_ap, _type) __builtin_va_arg(_ap, _type)
|
||||
|
||||
#endif
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef _STDINT_H
|
||||
#define _STDINT_H
|
||||
|
||||
#define NULL ((void*)0)
|
||||
|
||||
// Naitive size
|
||||
typedef unsigned int size_t;
|
||||
typedef signed int ssize_t;
|
||||
|
||||
// Signed ints
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed long long int64_t;
|
||||
|
||||
// Unsigned ints
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef _STRING_H
|
||||
#define _STRING_H
|
||||
|
||||
#include <kernel.h>
|
||||
|
||||
// Memory functions
|
||||
void* memchr(const void* ptr, uint8_t val, size_t len);
|
||||
int memcmp(const void* ptr1, const void* ptr2, size_t len);
|
||||
void* memcpy(void* dst, const void* src, size_t len);
|
||||
void* memmov(void* dst, const void* src, size_t len);
|
||||
void* memset(void* dst, uint8_t val, size_t len);
|
||||
|
||||
// String functions
|
||||
char* strbrk(char* str, const char* accept);
|
||||
char* strcat(char* dst, const char* src);
|
||||
char* strchr(const char* str, char c);
|
||||
int strcmp(const char* str1, const char* str2);
|
||||
char* strcpy(char* dst, const char* src);
|
||||
size_t strlen(const char* str);
|
||||
size_t strspn(const char* str, const char* accept);
|
||||
char* strstr(const char* str1, const char* str2);
|
||||
char* strtok(char* str, const char* delim);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
#ifndef _SYSTEM_H
|
||||
#define _SYSTEM_H
|
||||
|
||||
#include <kernel.h>
|
||||
#include <gdt.h>
|
||||
#include <idt.h>
|
||||
|
||||
/*
|
||||
* CPUID
|
||||
*/
|
||||
enum {
|
||||
CPUID_FEAT_EBX_RDSEED = 1 << 18,
|
||||
|
||||
CPUID_FEAT_ECX_SSE3 = 1 << 0,
|
||||
CPUID_FEAT_ECX_PCLMUL = 1 << 1,
|
||||
CPUID_FEAT_ECX_DTES64 = 1 << 2,
|
||||
CPUID_FEAT_ECX_MONITOR = 1 << 3,
|
||||
CPUID_FEAT_ECX_DS_CPL = 1 << 4,
|
||||
CPUID_FEAT_ECX_VMX = 1 << 5,
|
||||
CPUID_FEAT_ECX_SMX = 1 << 6,
|
||||
CPUID_FEAT_ECX_EST = 1 << 7,
|
||||
CPUID_FEAT_ECX_TM2 = 1 << 8,
|
||||
CPUID_FEAT_ECX_SSSE3 = 1 << 9,
|
||||
CPUID_FEAT_ECX_CID = 1 << 10,
|
||||
CPUID_FEAT_ECX_SDBG = 1 << 11,
|
||||
CPUID_FEAT_ECX_FMA = 1 << 12,
|
||||
CPUID_FEAT_ECX_CX16 = 1 << 13,
|
||||
CPUID_FEAT_ECX_XTPR = 1 << 14,
|
||||
CPUID_FEAT_ECX_PDCM = 1 << 15,
|
||||
CPUID_FEAT_ECX_PCID = 1 << 17,
|
||||
CPUID_FEAT_ECX_DCA = 1 << 18,
|
||||
CPUID_FEAT_ECX_SSE4_1 = 1 << 19,
|
||||
CPUID_FEAT_ECX_SSE4_2 = 1 << 20,
|
||||
CPUID_FEAT_ECX_X2APIC = 1 << 21,
|
||||
CPUID_FEAT_ECX_MOVBE = 1 << 22,
|
||||
CPUID_FEAT_ECX_POPCNT = 1 << 23,
|
||||
CPUID_FEAT_ECX_TSC = 1 << 24,
|
||||
CPUID_FEAT_ECX_AES = 1 << 25,
|
||||
CPUID_FEAT_ECX_XSAVE = 1 << 26,
|
||||
CPUID_FEAT_ECX_OSXSAVE = 1 << 27,
|
||||
CPUID_FEAT_ECX_AVX = 1 << 28,
|
||||
CPUID_FEAT_ECX_F16C = 1 << 29,
|
||||
CPUID_FEAT_ECX_RDRAND = 1 << 30,
|
||||
CPUID_FEAT_ECX_HYPERVISOR = 1 << 31,
|
||||
|
||||
CPUID_FEAT_EDX_FPU = 1 << 0,
|
||||
CPUID_FEAT_EDX_VME = 1 << 1,
|
||||
CPUID_FEAT_EDX_DE = 1 << 2,
|
||||
CPUID_FEAT_EDX_PSE = 1 << 3,
|
||||
CPUID_FEAT_EDX_TSC = 1 << 4,
|
||||
CPUID_FEAT_EDX_MSR = 1 << 5,
|
||||
CPUID_FEAT_EDX_PAE = 1 << 6,
|
||||
CPUID_FEAT_EDX_MCE = 1 << 7,
|
||||
CPUID_FEAT_EDX_CX8 = 1 << 8,
|
||||
CPUID_FEAT_EDX_APIC = 1 << 9,
|
||||
CPUID_FEAT_EDX_SEP = 1 << 11,
|
||||
CPUID_FEAT_EDX_MTRR = 1 << 12,
|
||||
CPUID_FEAT_EDX_PGE = 1 << 13,
|
||||
CPUID_FEAT_EDX_MCA = 1 << 14,
|
||||
CPUID_FEAT_EDX_CMOV = 1 << 15,
|
||||
CPUID_FEAT_EDX_PAT = 1 << 16,
|
||||
CPUID_FEAT_EDX_PSE36 = 1 << 17,
|
||||
CPUID_FEAT_EDX_PSN = 1 << 18,
|
||||
CPUID_FEAT_EDX_CLFLUSH = 1 << 19,
|
||||
CPUID_FEAT_EDX_DS = 1 << 21,
|
||||
CPUID_FEAT_EDX_ACPI = 1 << 22,
|
||||
CPUID_FEAT_EDX_MMX = 1 << 23,
|
||||
CPUID_FEAT_EDX_FXSR = 1 << 24,
|
||||
CPUID_FEAT_EDX_SSE = 1 << 25,
|
||||
CPUID_FEAT_EDX_SSE2 = 1 << 26,
|
||||
CPUID_FEAT_EDX_SS = 1 << 27,
|
||||
CPUID_FEAT_EDX_HTT = 1 << 28,
|
||||
CPUID_FEAT_EDX_TM = 1 << 29,
|
||||
CPUID_FEAT_EDX_IA64 = 1 << 30,
|
||||
CPUID_FEAT_EDX_PBE = 1 << 31
|
||||
};
|
||||
void cpuid(uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx);
|
||||
|
||||
// Ports
|
||||
void iowait(void);
|
||||
uint8_t inb(uint16_t port);
|
||||
void outb(uint16_t port, uint8_t data);
|
||||
uint16_t inw(uint16_t port);
|
||||
void outw(uint16_t port, uint16_t data);
|
||||
uint32_t inl(uint16_t port);
|
||||
void outl(uint16_t port, uint32_t data);
|
||||
|
||||
// x86
|
||||
void cli(void);
|
||||
void sti(void);
|
||||
|
||||
extern uint8_t (*popcountll)(uint64_t num);
|
||||
void detect_processor_features();
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef _TYPES_H
|
||||
#define _TYPES_H
|
||||
|
||||
// NULL pointer
|
||||
#define NULL ((void*)0)
|
||||
|
||||
/*
|
||||
* Integral types
|
||||
*/
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long uint64_t;
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed long int64_t;
|
||||
_Static_assert(sizeof(int8_t) == 1, "int8_t not 8 bits.");
|
||||
_Static_assert(sizeof(int16_t) == 2, "int16_t not 16 bits.");
|
||||
_Static_assert(sizeof(int32_t) == 4, "int32_t not 32 bits.");
|
||||
_Static_assert(sizeof(int64_t) == 8, "int64_t not 64 bits.");
|
||||
_Static_assert(sizeof(uint8_t) == 1, "uint8_t not 8 bits.");
|
||||
_Static_assert(sizeof(uint16_t) == 2, "uint16_t not 16 bits.");
|
||||
_Static_assert(sizeof(uint32_t) == 4, "uint32_t not 32 bits.");
|
||||
_Static_assert(sizeof(uint64_t) == 8, "uint64_t not 64 bits.");
|
||||
|
||||
// TODO: Add a static assertion here
|
||||
typedef uint64_t size_t;
|
||||
typedef int64_t ssize_t;
|
||||
typedef size_t offset_t;
|
||||
|
||||
typedef uint64_t uintptr_t;
|
||||
typedef int64_t intptr_t;
|
||||
_Static_assert(sizeof(intptr_t) == sizeof(void*), "intptr_t must match pointer size.");
|
||||
_Static_assert(sizeof(uintptr_t) == sizeof(void*), "uintptr_t must match pointer size.");
|
||||
|
||||
/*
|
||||
* Boolean
|
||||
*/
|
||||
#define bool _Bool
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef _VMM_H
|
||||
#define _VMM_H
|
||||
#include "types.h"
|
||||
|
||||
#define CANONICAL_MASK_KERNEL 0xFFFF800000000000
|
||||
#define CANONICAL_MASK_USER 0x00007FFFFFFFFFF000
|
||||
|
||||
int vmm_alloc(void** vaddr, uint64_t count, uint64_t flags);
|
||||
int vmm_free(void* vaddr);
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef _VSNPRINTF_H
|
||||
#define _VSNPRINTF_H
|
||||
|
||||
#include <kernel.h>
|
||||
|
||||
int snprintf(char *buf, size_t n, const char *fmt, ...) __printf(3, 4);
|
||||
int vsnprintf(char* buf, size_t n, const char* fmt, va_list ap);
|
||||
|
||||
#endif
|
||||
+37
-39
@@ -1,52 +1,50 @@
|
||||
OUTPUT_FORMAT(binary)
|
||||
ENTRY(start)
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
OUTPUT_ARCH(i386:x86-64);
|
||||
ENTRY(_start)
|
||||
|
||||
/* Program headers for MMU permissions */
|
||||
PHDRS {
|
||||
text PT_LOAD FLAGS((1 << 0) | (1 << 2)); /* xr */
|
||||
rodata PT_LOAD FLAGS((1 << 2)); /* ro */
|
||||
data PT_LOAD FLAGS((1 << 1) | (1 << 2)); /* rw */
|
||||
}
|
||||
|
||||
SECTIONS {
|
||||
. = 0x00100000;
|
||||
kernel_start = .;
|
||||
. = 0xffffffff80000000;
|
||||
|
||||
/* Multiboot Header */
|
||||
.multiboot ALIGN(4K) : {
|
||||
*(.multiboot)
|
||||
}
|
||||
__kernel_start = .;
|
||||
__kernel_text_start = .;
|
||||
.text : {
|
||||
*(.text .text.*)
|
||||
} :text
|
||||
__kernel_text_end = .;
|
||||
|
||||
.boot ALIGN(4K) : {
|
||||
*(.boot)
|
||||
}
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
. += 0xC000000;
|
||||
__kernel_rodata_start = .;
|
||||
.rodata : {
|
||||
*(.rodata .rodata.*)
|
||||
} :rodata
|
||||
__kernel_rodata_end = .;
|
||||
|
||||
/* Kernel Code */
|
||||
.text ALIGN(4) : AT(ADDR(.text) - 0xC000000) {
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
}
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
/* Read-Only Data */
|
||||
.rodata ALIGN(4) : AT(ADDR(.rodata) - 0xC000000) {
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
}
|
||||
__kernel_data_start = .;
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
} :data
|
||||
|
||||
/* Read/Write Data */
|
||||
.data ALIGN(4) : AT(ADDR(.data) - 0xC000000) {
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
}
|
||||
|
||||
/* BSS Section */
|
||||
.bss ALIGN(4) : AT(ADDR(.bss) - 0xC000000) {
|
||||
/* NOTE: .bss should be the last thing mapped to :data */
|
||||
.bss : {
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
}
|
||||
} :data
|
||||
__kernel_data_end = .;
|
||||
|
||||
/* Discarded Sections */
|
||||
/* Discard .note* and .eh_frame* (wtf is an eh_frame??) to prevent issues */
|
||||
/DISCARD/ : {
|
||||
*(.note)
|
||||
*(.note.*)
|
||||
*(.comment)
|
||||
*(.eh_frame)
|
||||
*(.note .note.*)
|
||||
}
|
||||
|
||||
kernel_end = .;
|
||||
__kernel_end = .;
|
||||
}
|
||||
|
||||
+16
-15
@@ -1,31 +1,32 @@
|
||||
include ../defaults.mk
|
||||
include ../config.mk
|
||||
|
||||
INC = ./include
|
||||
SRC = ./src
|
||||
BIN = ./bin
|
||||
|
||||
SRCS_C = $(shell find $(SRC) -name '*.c')
|
||||
SRCS_S = $(shell find $(SRC) -name '*.s')
|
||||
OBJS = $(patsubst $(SRC)/%.c, $(BIN)/%.o, $(SRCS_C)) \
|
||||
$(patsubst $(SRC)/%.s, $(BIN)/%.s.o, $(SRCS_S))
|
||||
|
||||
INC = ./include
|
||||
SRCS_C = $(wildcard $(SRC)/*.c)
|
||||
SRCS_S = $(wildcard $(SRC)/*.s)
|
||||
OBJS_C = $(patsubst $(SRC)/%.c, $(BIN)/%.c.o, $(SRCS_C))
|
||||
OBJS_S = $(patsubst $(SRC)/%.s, $(BIN)/%.s.o, $(SRCS_S))
|
||||
OUT = $(SYSROOT)/boot/kernel.elf
|
||||
LINKER = ./linker.ld
|
||||
OUT = ./kern.bin
|
||||
SSP = ./.ssp
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(OUT)
|
||||
$(OUT): $(OBJS)
|
||||
$(OUT): $(OBJS_C) $(OBJS_S)
|
||||
$(LD) $(LDFLAGS) -T$(LINKER) -o $@ $^
|
||||
|
||||
$(BIN)/%.o: $(SRC)/%.c
|
||||
$(BIN)/%.c.o: $(SRC)/%.c $(SSP)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -I$(INC) -c -o $@ $<
|
||||
$(CC) $(CCFLAGS) -DCONSOLE_LOGLEVEL='$(CONSOLE_LOGLEVEL)' -DSTACK_CHK_GUARD="$$(cat $(SSP))" -I$(INC) -c -o $@ $<
|
||||
|
||||
$(BIN)/%.s.o: $(SRC)/%.s
|
||||
@mkdir -p $(dir $@)
|
||||
$(AS) $(ASFLAGS) -felf32 -o $@ $<
|
||||
$(AS) $(ASFLAGS) -o $@ $<
|
||||
|
||||
$(SSP):
|
||||
echo "0x$$(openssl rand -hex 8)UL" > $(SSP)
|
||||
|
||||
clean:
|
||||
rm -fr $(BIN) $(OUT)
|
||||
rm -fr $(BIN) $(OUT) $(SSP)
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#include <bootloader.h>
|
||||
#include <kernel.h>
|
||||
#include <limine.h>
|
||||
#include <errno.h>
|
||||
|
||||
// This defines our expected Limine version
|
||||
static volatile uint64_t lim_base_revision[] = LIMINE_BASE_REVISION(4);
|
||||
|
||||
// Limine requests
|
||||
static struct limine_paging_mode_request lim_paging_req =
|
||||
{ .id = LIMINE_PAGING_MODE_REQUEST_ID, .revision = 4,
|
||||
.mode = LIMINE_PAGING_MODE_X86_64_4LVL, };
|
||||
|
||||
static struct limine_executable_address_request lim_kaddr_req =
|
||||
{ .id = LIMINE_EXECUTABLE_ADDRESS_REQUEST_ID, .revision = 4 };
|
||||
|
||||
static struct limine_hhdm_request lim_hhdm_req =
|
||||
{ .id = LIMINE_HHDM_REQUEST_ID, .revision = 4 };
|
||||
|
||||
static struct limine_memmap_request lim_memmap_req =
|
||||
{ .id = LIMINE_MEMMAP_REQUEST_ID, .revision = 4 };
|
||||
|
||||
static struct limine_framebuffer_request lim_fbuf_req =
|
||||
{ .id = LIMINE_FRAMEBUFFER_REQUEST_ID, .revision = 4 };
|
||||
|
||||
static struct limine_executable_file_request lim_exe_req =
|
||||
{ .id = LIMINE_EXECUTABLE_FILE_REQUEST_ID, .revision = 4 };
|
||||
|
||||
// Bootloader data struct
|
||||
struct bootloader bootloader = { 0 };
|
||||
|
||||
int boot_init(void) {
|
||||
if (LIMINE_BASE_REVISION_SUPPORTED(lim_base_revision) == false) panic(NULL, "Unsupported Limine base revision.");
|
||||
|
||||
struct limine_paging_mode_response* lim_paging_res = lim_paging_req.response;
|
||||
struct limine_executable_address_response* lim_kaddr_res = lim_kaddr_req.response;
|
||||
struct limine_hhdm_response* lim_hhdm_res = lim_hhdm_req.response;
|
||||
struct limine_memmap_response* lim_memmap_res = lim_memmap_req.response;
|
||||
struct limine_framebuffer_response* lim_fbuf_res = lim_fbuf_req.response;
|
||||
struct limine_executable_file_response* lim_exe_res = lim_exe_req.response;
|
||||
|
||||
if (lim_paging_res->mode != LIMINE_PAGING_MODE_X86_64_4LVL) panic(NULL, "Expected 4 level paging.");
|
||||
bootloader.hhdm_offset = lim_hhdm_res->offset;
|
||||
bootloader.kernel_phys_base = lim_kaddr_res->physical_base;
|
||||
bootloader.kernel_virt_base = lim_kaddr_res->virtual_base;
|
||||
bootloader.mm_entries = lim_memmap_res->entries;
|
||||
bootloader.mm_entry_count = lim_memmap_res->entry_count;
|
||||
bootloader.executable = lim_exe_res->executable_file;
|
||||
|
||||
bootloader.mm_total_memory = 0;
|
||||
for (size_t i = 0; i < bootloader.mm_entry_count; i++) {
|
||||
struct limine_memmap_entry* entry = bootloader.mm_entries[i];
|
||||
if (entry->type == LIMINE_MEMMAP_USABLE) bootloader.mm_total_memory += entry->length;
|
||||
}
|
||||
|
||||
bootloader.fb_entries = lim_fbuf_res->framebuffers;
|
||||
bootloader.fb_entry_count = lim_fbuf_res->framebuffer_count;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
;
|
||||
; Kernel entry point
|
||||
;
|
||||
|
||||
MBH_MAGIC equ 0xe85250d6
|
||||
MBH_ARCH equ 0x00000000
|
||||
STACK_SIZE equ 4096
|
||||
global VIRT_BASE
|
||||
KERN_VIRT_BASE equ 0xC000000
|
||||
KERN_PAGE_NUM equ (KERN_VIRT_BASE >> 22)
|
||||
|
||||
bits 32
|
||||
|
||||
; Multiboot2 Header
|
||||
section .multiboot
|
||||
align 64
|
||||
mbh:
|
||||
; Magic fields
|
||||
.magic: dd MBH_MAGIC
|
||||
.arch: dd MBH_ARCH
|
||||
.size: dd (mbh.end - mbh)
|
||||
.checksum: dd 0x10000000 - (MBH_MAGIC + MBH_ARCH + (mbh.end - mbh))
|
||||
|
||||
; Framebuffer Tag
|
||||
align 8
|
||||
dw 5 ; Type - Framebuffer
|
||||
dw 1 ; Flags - Optional
|
||||
dd 20 ; Size
|
||||
dd 1920 ; Width
|
||||
dd 1080 ; Height
|
||||
dd 32 ; Depth
|
||||
|
||||
; Zero Tag
|
||||
align 8
|
||||
dw 0 ; Type - Zero
|
||||
dw 0 ; Flags
|
||||
dd 8 ; Size
|
||||
|
||||
.end:
|
||||
|
||||
; Stack
|
||||
section .bss
|
||||
align 16
|
||||
stack_bottom:
|
||||
resb 16384*8
|
||||
stack_top:
|
||||
|
||||
; Entry section
|
||||
section .boot
|
||||
global start
|
||||
|
||||
extern kmain
|
||||
start:
|
||||
; Init temporary paging
|
||||
mov eax, (initpd - 0xC0000000)
|
||||
mov cr3, eax
|
||||
|
||||
mov ecx, cr4
|
||||
or ecx, 0x10 ; Paging enable bit
|
||||
mov cr4, ecx
|
||||
|
||||
mov ecx, cr0
|
||||
or ecx, 0x8000000
|
||||
mov cr0, ecx
|
||||
|
||||
jmp higher_half
|
||||
|
||||
Shutdown:
|
||||
mov ax, 0x1000
|
||||
mov ss, ax
|
||||
mov sp, 0xf000
|
||||
mov ax, 0x5307
|
||||
mov bx, 0x0001
|
||||
mov cx, 0x0003
|
||||
int 0x15
|
||||
|
||||
section .text
|
||||
higher_half:
|
||||
mov esp, stack_top ; Stack Pointer
|
||||
|
||||
add ebx, KERN_VIRT_BASE ; Make address in EBX virtual
|
||||
push ebx ; Push multiboot mem info pointer
|
||||
|
||||
call kmain
|
||||
|
||||
; Halt on return
|
||||
cli
|
||||
h: hlt
|
||||
jmp h
|
||||
|
||||
section .data
|
||||
|
||||
; Inital Page Directory
|
||||
align 4096
|
||||
global initpd
|
||||
initpd:
|
||||
dd 0b10000011 ; Initial 4MB identity map
|
||||
|
||||
times 768-1 dd 0 ; Padding
|
||||
|
||||
; Higher half kernel start, map 16MB
|
||||
dd (0 << 22) | 0b10000011
|
||||
dd (1 << 22) | 0b10000011
|
||||
dd (2 << 22) | 0b10000011
|
||||
dd (3 << 22) | 0b10000011
|
||||
|
||||
times 256-4 dd 0 ; More padding
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
#include "paging.h"
|
||||
#include <exceptions.h>
|
||||
#include <kernel.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <isr.h>
|
||||
|
||||
exception_handler_ptr exception_handlers[EXCEPTION_COUNT];
|
||||
|
||||
const char* exception_strings[] = {
|
||||
"Division Error",
|
||||
"Debug",
|
||||
"Non-maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Overflow",
|
||||
"Bound Range Exceeded",
|
||||
"Invalid Opcode",
|
||||
"Device Not Available",
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Invalid TSS",
|
||||
"Segment Not Present",
|
||||
"Stack-Segment Fault",
|
||||
"General Protection Fault",
|
||||
"Page Fault",
|
||||
"Reserved",
|
||||
"x87 Floating-Point Exception",
|
||||
"Alignment Check",
|
||||
"Machine Check",
|
||||
"SIMD Floating-Point Exception",
|
||||
"Virtualization Exception",
|
||||
"Control Protection Exception",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Hypervisor Injection Exception",
|
||||
"VMM Communication Exception",
|
||||
"Security Exception",
|
||||
"Reserved",
|
||||
};
|
||||
|
||||
void exception_handle(struct isr_int_frame* iframe) {
|
||||
bool user = (iframe->cs & 3) == 3;
|
||||
|
||||
if (exception_handlers[iframe->interrupt]) {
|
||||
exception_handlers[iframe->interrupt](iframe, user);
|
||||
} else {
|
||||
panic(iframe, "Unhandled %s exception, err 0x%lx", exception_strings[iframe->interrupt], iframe->error);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_division_error(struct isr_int_frame* iframe, bool user) {
|
||||
if (user) {
|
||||
// TODO: Kill process
|
||||
} else panic(iframe, "Division by 0 @ %p", (void*)iframe->rip);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void handle_invalid_opcode(struct isr_int_frame* iframe, bool user) {
|
||||
if (user) {
|
||||
pr_error("Userspace #UD @ %p\n", (void*)iframe->rip);
|
||||
// TODO: Kill process
|
||||
} else {
|
||||
panic(iframe, "Kernel #UD");
|
||||
}
|
||||
}
|
||||
|
||||
void handle_device_not_available(struct isr_int_frame* iframe, bool user) {
|
||||
(void)iframe;
|
||||
(void)user;
|
||||
|
||||
__asm__ volatile("clts");
|
||||
|
||||
// TODO:
|
||||
// if (last_fpu_user != current) {
|
||||
// if (last_fpu_user) {
|
||||
// __asm__ volatile("fxsaveq %0" : "=m"(last_fpu_user->fpu_state));
|
||||
// }
|
||||
// __asm__ volatile("fxrstorq %0" : : "m"(current->fpu_state));
|
||||
// set_last_fpu_owner(current);
|
||||
// }
|
||||
|
||||
pr_notice("FPU/SSE initialized lazily for current thread.\n");
|
||||
}
|
||||
|
||||
// Do not attempt to log gracefully using complex structures or locks
|
||||
// The kernel stack might be completely shredded
|
||||
void handle_double_fault(struct isr_int_frame* iframe, bool user) {
|
||||
(void)user;
|
||||
|
||||
pr_emerg(
|
||||
"Beware human. This thing is beyond comprehension. Beyond this corporeal realm.\n"
|
||||
"Oh may the those unlucky enough to encouter it be spared of their pain.\n"
|
||||
"Through it you pass into the city of woe.\n"
|
||||
"Through it you pass into eternal pain.\n"
|
||||
"To rear it was the task of power divine.\n"
|
||||
"Supremes wisdom, and primeval love.\n"
|
||||
"Before it things create were none, save things.\n"
|
||||
"Eternal, and eternal It endures.\n"
|
||||
"Abandon all hope, all ye who enter here.\n\n"
|
||||
);
|
||||
panic(iframe, "[ D O U B L E F A U L T ]");
|
||||
}
|
||||
|
||||
void handle_general_protection_fault(struct isr_int_frame* iframe, bool user) {
|
||||
if (user) {
|
||||
pr_error("Userspace #GP @ %p (err: 0x%lx)\n", (void*)iframe->rip, iframe->error);
|
||||
// TODO: Kill process
|
||||
}
|
||||
}
|
||||
|
||||
void handle_page_fault(struct isr_int_frame* iframe, bool user) {
|
||||
uint64_t fault_addr;
|
||||
__asm__ volatile("mov %%cr2, %0" : "=r"(fault_addr));
|
||||
|
||||
uint64_t err = iframe->error;
|
||||
bool present = err & 0x1;
|
||||
bool write = err & 0x2;
|
||||
bool usersp = err & 0x4;
|
||||
bool fetch = err & 0xA;
|
||||
|
||||
if (user) {
|
||||
pr_error("Userspace #PF: Segfault @ %p, tried to access %p\n", (void*)iframe->rip, (void*)fault_addr);
|
||||
pr_error("\x1b[9m Reason: Retard\x1b[m\n"); // reference
|
||||
pr_error(" Reason: %s %s in %s mode %s\n",
|
||||
present ? "Protection violation" : "Non-present page",
|
||||
write ? "during WRITE" : "during READ",
|
||||
usersp ? "user" : "supervisor",
|
||||
fetch ? "during instruction fetch" : ""
|
||||
);
|
||||
// TODO: Kill process
|
||||
} else {
|
||||
panic(iframe, "Kernel: Segmentation fault @ %p, tried to access %p (err: 0x%lx)", (void*)iframe->rip, (void*)fault_addr, err);
|
||||
}
|
||||
}
|
||||
|
||||
int exception_init(void) {
|
||||
memset(exception_handlers, 0, sizeof(exception_handlers));
|
||||
|
||||
exception_handlers[EXCEPTION_DE] = handle_division_error;
|
||||
exception_handlers[EXCEPTION_UD] = handle_invalid_opcode;
|
||||
exception_handlers[EXCEPTION_NM] = handle_device_not_available;
|
||||
exception_handlers[EXCEPTION_DF] = handle_double_fault;
|
||||
exception_handlers[EXCEPTION_PF] = handle_page_fault;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#include <kernel.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <gdt.h>
|
||||
|
||||
static struct gdt_entries gdt;
|
||||
static struct gdt_pointer gdtp;
|
||||
static struct tss_pointer tss;
|
||||
|
||||
void gdt_reload(void) {
|
||||
__asm__ volatile (
|
||||
"lgdt %0\n"
|
||||
"pushq %[kcs]\n"
|
||||
"lea 1f(%%rip), %%rax\n"
|
||||
"pushq %%rax\n"
|
||||
"lretq\n"
|
||||
"1:\n"
|
||||
"mov %[kds], %%ax\n"
|
||||
"mov %%ax, %%ds\n"
|
||||
"mov %%ax, %%es\n"
|
||||
"mov %%ax, %%fs\n"
|
||||
"mov %%ax, %%gs\n"
|
||||
"mov %%ax, %%ss\n"
|
||||
:
|
||||
: "m"(gdtp),
|
||||
[kcs] "i"(GDT_KERNEL_CODE),
|
||||
[kds] "i"(GDT_KERNEL_DATA)
|
||||
: "rax", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
void tss_load(struct tss_pointer* tss) {
|
||||
size_t addr = (size_t)tss;
|
||||
|
||||
gdt.tss.length = 104;
|
||||
gdt.tss.base_low = (uint16_t)addr;
|
||||
gdt.tss.base_mid = (uint8_t)(addr >> 16);
|
||||
gdt.tss.access = 0x89;
|
||||
gdt.tss.flags = 0;
|
||||
gdt.tss.base_high = (uint8_t)(addr >> 24);
|
||||
gdt.tss.base_upper32 = (uint32_t)(addr >> 32);
|
||||
gdt.tss.__reserved = 0;
|
||||
|
||||
__asm__ volatile ("ltr %0" : : "rm"(GDT_TSS) : "memory");
|
||||
}
|
||||
|
||||
int gdt_init(void) {
|
||||
// Null descriptor
|
||||
gdt.entries[0].limit = 0;
|
||||
gdt.entries[0].base_low = 0;
|
||||
gdt.entries[0].base_mid = 0;
|
||||
gdt.entries[0].access = 0;
|
||||
gdt.entries[0].flags = 0;
|
||||
gdt.entries[0].base_high = 0;
|
||||
|
||||
// Kernel code
|
||||
gdt.entries[1].limit = 0xFFFF;
|
||||
gdt.entries[1].base_low = 0;
|
||||
gdt.entries[1].base_mid = 0;
|
||||
gdt.entries[1].access = 0x9A;
|
||||
gdt.entries[1].flags = 0xAF;
|
||||
gdt.entries[1].base_high = 0;
|
||||
|
||||
// Kernel data
|
||||
gdt.entries[2].limit = 0xFFFF;
|
||||
gdt.entries[2].base_low = 0;
|
||||
gdt.entries[2].base_mid = 0;
|
||||
gdt.entries[2].access = 0x92;
|
||||
gdt.entries[2].flags = 0xCF;
|
||||
gdt.entries[2].base_high = 0;
|
||||
|
||||
// User data
|
||||
gdt.entries[3].limit = 0xFFFF;
|
||||
gdt.entries[3].base_low = 0;
|
||||
gdt.entries[3].base_mid = 0;
|
||||
gdt.entries[3].access = 0xF2;
|
||||
gdt.entries[3].flags = 0xCF;
|
||||
gdt.entries[3].base_high = 0;
|
||||
|
||||
// User code
|
||||
gdt.entries[4].limit = 0xFFFF;
|
||||
gdt.entries[4].base_low = 0;
|
||||
gdt.entries[4].base_mid = 0;
|
||||
gdt.entries[4].access = 0xFA;
|
||||
gdt.entries[4].flags = 0xAF;
|
||||
gdt.entries[4].base_high = 0;
|
||||
|
||||
// Task State Segment (TSS)
|
||||
gdt.tss.length = 104;
|
||||
gdt.tss.base_low = 0;
|
||||
gdt.tss.base_mid = 0;
|
||||
gdt.tss.access = 0x89; //0b10001001;
|
||||
gdt.tss.flags = 0;
|
||||
gdt.tss.base_high = 0;
|
||||
gdt.tss.base_upper32 = 0;
|
||||
gdt.tss.__reserved = 0;
|
||||
|
||||
// GDT Pointer
|
||||
gdtp.limit = sizeof(gdt) - 1;
|
||||
gdtp.base = (uint64_t)&gdt;
|
||||
|
||||
gdt_reload();
|
||||
|
||||
memset(&tss, 0, sizeof(tss));
|
||||
tss_load(&tss);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#include <kernel.h>
|
||||
#include <string.h>
|
||||
#include <system.h>
|
||||
#include <errno.h>
|
||||
#include <gdt.h>
|
||||
#include <idt.h>
|
||||
|
||||
__align(16) // performace
|
||||
static struct idt_entry idt[IDT_ENTRIES];
|
||||
static struct idt_pointer idtp;
|
||||
|
||||
void idt_set_gate(uint8_t i, void* handler, uint8_t attrib, uint8_t ist) {
|
||||
size_t addr = (size_t)handler;
|
||||
idt[i].offset_low = (uint16_t)addr;
|
||||
idt[i].selector = GDT_KERNEL_CODE;
|
||||
idt[i].ist = ist & 7;
|
||||
idt[i].attrib = attrib;
|
||||
idt[i].offset_mid = (uint16_t)(addr >> 16);
|
||||
idt[i].offset_high = (uint32_t)(addr >> 32);
|
||||
idt[i].__reserved = 0;
|
||||
}
|
||||
|
||||
int idt_init(void) {
|
||||
memset(idt, 0, sizeof(idt));
|
||||
|
||||
idtp.size = sizeof(idt) - 1;
|
||||
idtp.offset = (uintptr_t)&idt;
|
||||
|
||||
// Load IDT instruction
|
||||
cli();
|
||||
__asm__ volatile ("lidt %0" : : "m"(idtp));
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
#include <exceptions.h>
|
||||
#include <kernel.h>
|
||||
#include <string.h>
|
||||
#include <system.h>
|
||||
#include <errno.h>
|
||||
#include <idt.h>
|
||||
#include <isr.h>
|
||||
|
||||
isr_handler_ptr irq_handlers[ISR_COUNT];
|
||||
|
||||
void pic_disable(void) {
|
||||
outb(0x21, 0xFF); iowait();
|
||||
outb(0xA1, 0xFF); iowait();
|
||||
}
|
||||
|
||||
void pic_remap(void) {
|
||||
outb(0x20, 0x11); iowait();
|
||||
outb(0xA0, 0x11); iowait();
|
||||
outb(0x21, 0x20); iowait();
|
||||
outb(0xA1, 0x28); iowait();
|
||||
outb(0x21, 0x04); iowait();
|
||||
outb(0xA1, 0x02); iowait();
|
||||
outb(0x21, 0x01); iowait();
|
||||
outb(0xA1, 0x01); iowait();
|
||||
outb(0x21, 0x00); iowait();
|
||||
outb(0xA1, 0x00); iowait();
|
||||
// pic_disable(); For APIC
|
||||
}
|
||||
|
||||
int isr_init(void) {
|
||||
exception_init();
|
||||
memset(irq_handlers, 0, sizeof(irq_handlers));
|
||||
|
||||
idt_init();
|
||||
|
||||
for (int i = 0; i < 48; i++) {
|
||||
// First 32 IRSs are exceptions (traps) and the next 16 are hardware interrupts
|
||||
idt_set_gate(i, isr_redirect_table[i], i < 32 ? IDT_FLAG_TRAP : IDT_FLAG_INT, 0);
|
||||
}
|
||||
|
||||
idt_set_gate(0x02, isr_redirect_table[2], IDT_FLAG_TRAP, 2); // Use IST2 for NMIs
|
||||
idt_set_gate(0x03, isr_redirect_table[3], IDT_FLAG_USER, 0); // Allow breakpoints
|
||||
idt_set_gate(0x08, isr_redirect_table[8], IDT_FLAG_TRAP, 1); // Use IST1 for Double Faults
|
||||
idt_set_gate(0x80, isr128, IDT_FLAG_USER, 0); // Syscall
|
||||
|
||||
pic_remap();
|
||||
// TODO: apic_init();
|
||||
|
||||
sti();
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void isr_register(uint8_t i, isr_handler_ptr handler) {
|
||||
if (i >= ISR_COUNT) return; // secutiry B)
|
||||
irq_handlers[i] = handler;
|
||||
}
|
||||
|
||||
void isr_send_eoi(uint8_t irq) {
|
||||
if (irq >= 8) outb(0xA0, 0x20);
|
||||
outb(0x20, 0x20);
|
||||
}
|
||||
|
||||
// TODO: Write fault handlers and make this more robust
|
||||
void isr_handle_interrupt(size_t rsp) {
|
||||
struct isr_int_frame* iframe = (void*)rsp;
|
||||
|
||||
if (iframe->interrupt < 32) exception_handle(iframe);
|
||||
else if (iframe->interrupt >= 32 && iframe->interrupt < 48) {
|
||||
uint8_t irq = iframe->interrupt - 32;
|
||||
|
||||
if (irq_handlers[irq]) irq_handlers[irq](iframe);
|
||||
// else pr_debug("Unhandled IRQ #%d\n", irq);
|
||||
|
||||
isr_send_eoi(irq);
|
||||
} else if (iframe->interrupt == 0x80) {
|
||||
// ISR 128 - System call
|
||||
pr_notice("SYSCALL!\n");
|
||||
} else {
|
||||
pr_warn("Unknown interrupt vector: %lu", iframe->interrupt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
[bits 64]
|
||||
|
||||
[section .text]
|
||||
isr_common:
|
||||
push rax
|
||||
push rbx
|
||||
push rcx
|
||||
push rdx
|
||||
push rsi
|
||||
push rdi
|
||||
push rbp
|
||||
push r8
|
||||
push r9
|
||||
push r10
|
||||
push r11
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
mov rbp, ds
|
||||
push rbp
|
||||
|
||||
mov rdi, rsp
|
||||
|
||||
[extern isr_handle_interrupt]
|
||||
call isr_handle_interrupt
|
||||
|
||||
[global isr_return]
|
||||
isr_return:
|
||||
pop rbp
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
pop rbp
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rbx
|
||||
pop rax
|
||||
|
||||
add rsp, 16 ; Pop errno and int number
|
||||
iretq
|
||||
|
||||
%macro ISR_WITH_ERRNO 1
|
||||
[global isr%1]
|
||||
isr%1:
|
||||
push %1
|
||||
jmp isr_common
|
||||
%endmacro
|
||||
|
||||
%macro ISR_WITHOUT_ERRNO 1
|
||||
[global isr%1]
|
||||
isr%1:
|
||||
push 0
|
||||
push %1
|
||||
jmp isr_common
|
||||
%endmacro
|
||||
|
||||
;; Exceptions
|
||||
ISR_WITHOUT_ERRNO 0
|
||||
ISR_WITHOUT_ERRNO 1
|
||||
ISR_WITHOUT_ERRNO 2
|
||||
ISR_WITHOUT_ERRNO 3
|
||||
ISR_WITHOUT_ERRNO 4
|
||||
ISR_WITHOUT_ERRNO 5
|
||||
ISR_WITHOUT_ERRNO 6
|
||||
ISR_WITHOUT_ERRNO 7
|
||||
ISR_WITH_ERRNO 8
|
||||
ISR_WITHOUT_ERRNO 9
|
||||
ISR_WITH_ERRNO 10
|
||||
ISR_WITH_ERRNO 11
|
||||
ISR_WITH_ERRNO 12
|
||||
ISR_WITH_ERRNO 13
|
||||
ISR_WITH_ERRNO 14
|
||||
ISR_WITHOUT_ERRNO 15
|
||||
ISR_WITHOUT_ERRNO 16
|
||||
ISR_WITHOUT_ERRNO 17
|
||||
ISR_WITHOUT_ERRNO 18
|
||||
ISR_WITHOUT_ERRNO 19
|
||||
ISR_WITHOUT_ERRNO 20
|
||||
ISR_WITHOUT_ERRNO 21
|
||||
ISR_WITHOUT_ERRNO 22
|
||||
ISR_WITHOUT_ERRNO 23
|
||||
ISR_WITHOUT_ERRNO 24
|
||||
ISR_WITHOUT_ERRNO 25
|
||||
ISR_WITHOUT_ERRNO 26
|
||||
ISR_WITHOUT_ERRNO 27
|
||||
ISR_WITHOUT_ERRNO 28
|
||||
ISR_WITHOUT_ERRNO 29
|
||||
ISR_WITHOUT_ERRNO 30
|
||||
ISR_WITHOUT_ERRNO 31
|
||||
|
||||
;; IRQs
|
||||
ISR_WITHOUT_ERRNO 32
|
||||
ISR_WITHOUT_ERRNO 33
|
||||
ISR_WITHOUT_ERRNO 34
|
||||
ISR_WITHOUT_ERRNO 35
|
||||
ISR_WITHOUT_ERRNO 36
|
||||
ISR_WITHOUT_ERRNO 37
|
||||
ISR_WITHOUT_ERRNO 38
|
||||
ISR_WITHOUT_ERRNO 39
|
||||
ISR_WITHOUT_ERRNO 40
|
||||
ISR_WITHOUT_ERRNO 41
|
||||
ISR_WITHOUT_ERRNO 42
|
||||
ISR_WITHOUT_ERRNO 43
|
||||
ISR_WITHOUT_ERRNO 44
|
||||
ISR_WITHOUT_ERRNO 45
|
||||
ISR_WITHOUT_ERRNO 46
|
||||
ISR_WITHOUT_ERRNO 47
|
||||
|
||||
; Syscall
|
||||
ISR_WITHOUT_ERRNO 128
|
||||
ISR_WITHOUT_ERRNO 255
|
||||
|
||||
[section .data]
|
||||
[global isr_redirect_table]
|
||||
isr_redirect_table:
|
||||
%assign i 0
|
||||
%rep 48
|
||||
dq isr%+i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#include <stdint.h>
|
||||
|
||||
void kmain(uint32_t addr) {}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "errno.h"
|
||||
#include "types.h"
|
||||
#include <bootloader.h>
|
||||
#include <gdt.h>
|
||||
#include <isr.h>
|
||||
#include <kernel.h>
|
||||
#include <paging.h>
|
||||
#include <pmm.h>
|
||||
#include <random.h>
|
||||
#include <serial.h>
|
||||
#include <splash.h>
|
||||
#include <string.h>
|
||||
#include <system.h>
|
||||
#include <vmm.h>
|
||||
|
||||
__noreturn void _start(void) {
|
||||
int err = 0;
|
||||
|
||||
// Serial console for debugging
|
||||
if ((err = serial_init(COM1)) < 0)
|
||||
panic(NULL, "Failed to initialize Serial driver. (%d)", err);
|
||||
|
||||
// Load structures from bootloader
|
||||
if ((err = boot_init()) < 0)
|
||||
panic(NULL, "Failed to parse bootloader structures. (%d)", err);
|
||||
|
||||
// CPUID thingy :p
|
||||
uint32_t eax = 0;
|
||||
char s[12];
|
||||
cpuid(&eax, (void*)&s[0], (void*)&s[8], (void*)&s[4]);
|
||||
pr_info("[kernel] CPUID_GETVENDORID: %s\n", s);
|
||||
|
||||
// enable processor extensions
|
||||
detect_processor_features();
|
||||
|
||||
// System init
|
||||
if ((err = gdt_init()) < 0)
|
||||
panic(NULL, "Failed to initalize GDT. (%d)", err);
|
||||
if ((err = isr_init()) < 0)
|
||||
panic(NULL, "Failed to initalize ISRs. (%d)", err);
|
||||
|
||||
// Memory management
|
||||
if ((err = pmm_init()) < 0)
|
||||
panic(NULL, "Failed to initalize Physical Memory Manager. (%d)",
|
||||
err);
|
||||
if ((err = pag_init()) < 0)
|
||||
panic(NULL, "Failed to initalize Paging. (%d)", err);
|
||||
|
||||
|
||||
// test random number generation
|
||||
printk("Random number generation test:\n");
|
||||
for (uint8_t i = 0; i <= 16; i++) {
|
||||
printk("%d: %lu\n", i, get_random_number());
|
||||
}
|
||||
|
||||
// The most important function in the world.
|
||||
splash();
|
||||
|
||||
// Patiently wait for things to do :)
|
||||
while (1)
|
||||
;
|
||||
};
|
||||
@@ -0,0 +1,177 @@
|
||||
#include "errno.h"
|
||||
#include "kernel.h"
|
||||
#include "paging.h"
|
||||
#include "types.h"
|
||||
#include "vmm.h"
|
||||
#include <kmalloc.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <system.h>
|
||||
// this file contains SLUB inspired HEAP allocator
|
||||
|
||||
// TODO this will be an allocated array later when we have APIC MADT
|
||||
union freelists_list freelists_all_cpus[1];
|
||||
union partialy_freelists_list partial_free_lists[1];
|
||||
|
||||
void* kcalloc(size_t count, size_t size) {
|
||||
size_t size_to_alloc;
|
||||
__asm__ volatile goto(".intel_syntax noprefix\n\t"
|
||||
"mov rax, %1\n\t"
|
||||
"mov rdx, %2\n\t"
|
||||
"mul rdx\n\t"
|
||||
"jo %l[overflow]\n\t"
|
||||
"mov %0, rax\n\t"
|
||||
".att_syntax prefix\n\t"
|
||||
: "=r"(size_to_alloc)
|
||||
: "r"(count), "r"(size)
|
||||
: "rax", "rdx", "cc"
|
||||
: overflow);
|
||||
return kzalloc(size_to_alloc);
|
||||
|
||||
overflow:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* kzalloc(size_t size) {
|
||||
void* allocated = kmalloc(size);
|
||||
if (!allocated) {
|
||||
return NULL;
|
||||
}
|
||||
memset(allocated, 0, size);
|
||||
return allocated;
|
||||
}
|
||||
|
||||
void* kmalloc(size_t size) {
|
||||
if (!size) {
|
||||
return NULL;
|
||||
}
|
||||
uint32_t core_id;
|
||||
__asm__ volatile(
|
||||
"rdtscp"
|
||||
: "=c"(core_id) // Core ID from IA32_TSC_AUX is placed in ECX
|
||||
:
|
||||
: "eax", "edx");
|
||||
|
||||
// freelists_all_cpus[core_id];
|
||||
// TODO disable when we actualy know how many CPUs we have
|
||||
core_id = 0;
|
||||
|
||||
size_t alloc_index;
|
||||
{
|
||||
// TODO remove buildin
|
||||
uint8_t leading_zeros = __builtin_clzll(size);
|
||||
if (popcountll(size) == 1) {
|
||||
alloc_index = leading_zeros;
|
||||
} else {
|
||||
alloc_index = sizeof(size) * CHAR_BIT - leading_zeros;
|
||||
}
|
||||
if (alloc_index > KMALLOC_MAX_SIZE) {
|
||||
// NOT IMPLEMENTED
|
||||
printk("Cannot allocate [%lu] bytes: \e[1mNOT "
|
||||
"IMPLEMENTED!\e[0m\n",
|
||||
size);
|
||||
return NULL;
|
||||
}
|
||||
alloc_index -= LOWEST_POWER;
|
||||
}
|
||||
size_t object_size = (1 << (alloc_index + LOWEST_POWER));
|
||||
|
||||
struct freelist* selected_freelist =
|
||||
freelists_all_cpus[core_id].freelists[alloc_index];
|
||||
if (selected_freelist != NULL) {
|
||||
// fast path
|
||||
if (selected_freelist->nextnode == NULL) {
|
||||
freelists_all_cpus[core_id].freelists[alloc_index] =
|
||||
NULL;
|
||||
} else {
|
||||
freelists_all_cpus[core_id].freelists[alloc_index] =
|
||||
selected_freelist->nextnode;
|
||||
}
|
||||
return selected_freelist;
|
||||
|
||||
} else {
|
||||
// slower path
|
||||
if (partial_free_lists[core_id]
|
||||
.partialy_freelists[alloc_index] != NULL) {
|
||||
// partialy freelist available
|
||||
struct partialy_freelist* selected_partialy_freelist =
|
||||
partial_free_lists[core_id]
|
||||
.partialy_freelists[alloc_index];
|
||||
|
||||
if (selected_partialy_freelist->freelist_nextnode ==
|
||||
NULL) {
|
||||
// only one free object available
|
||||
if (selected_partialy_freelist
|
||||
->partialy_freelist_nextnode != NULL) {
|
||||
// next partialy free list
|
||||
// available
|
||||
partial_free_lists[core_id]
|
||||
.partialy_freelists[alloc_index] =
|
||||
selected_partialy_freelist
|
||||
->partialy_freelist_nextnode;
|
||||
|
||||
} else {
|
||||
// no other partialy free list
|
||||
// available
|
||||
partial_free_lists[core_id]
|
||||
.partialy_freelists[alloc_index] =
|
||||
NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
// multiple free objects available
|
||||
partial_free_lists[core_id]
|
||||
.partialy_freelists[alloc_index] =
|
||||
selected_partialy_freelist
|
||||
->partialy_freelist_nextnode;
|
||||
|
||||
freelists_all_cpus[core_id]
|
||||
.freelists[alloc_index] =
|
||||
selected_partialy_freelist
|
||||
->freelist_nextnode;
|
||||
}
|
||||
return selected_partialy_freelist;
|
||||
|
||||
} else {
|
||||
// slowest path
|
||||
|
||||
uint8_t page_count =
|
||||
object_size < PAGE_SIZE
|
||||
? 1
|
||||
: (object_size * 2) / PAGE_SIZE;
|
||||
|
||||
void** alloc_addr = 0;
|
||||
{
|
||||
int ret;
|
||||
ret = vmm_alloc((void**)&alloc_addr, page_count,
|
||||
0);
|
||||
if (ret != SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// construct the linked list
|
||||
// start at offset if object too small for partial free
|
||||
// list pointer
|
||||
for (size_t i =
|
||||
object_size < sizeof(struct partialy_freelist)
|
||||
? object_size
|
||||
: 0;
|
||||
i < page_count * PAGE_SIZE; i += object_size) {
|
||||
if ((i + 1) * object_size >=
|
||||
page_count * PAGE_SIZE) {
|
||||
alloc_addr[i * object_size] = NULL;
|
||||
} else {
|
||||
alloc_addr[i * object_size] =
|
||||
alloc_addr +
|
||||
((i + 1) * object_size);
|
||||
}
|
||||
}
|
||||
|
||||
freelists_all_cpus[core_id].freelists[alloc_index] =
|
||||
(struct freelist*)(alloc_addr + object_size);
|
||||
return alloc_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
void* kfree(void* p) {}
|
||||
@@ -0,0 +1,185 @@
|
||||
#include <bootloader.h>
|
||||
#include <kernel.h>
|
||||
#include <limine.h>
|
||||
#include <string.h>
|
||||
#include <serial.h>
|
||||
#include <errno.h>
|
||||
#include <pmm.h>
|
||||
|
||||
#include <paging.h>
|
||||
|
||||
// VIRTUAL address of the kernels PML4
|
||||
uint64_t* pag_kernel_pml4 = NULL;
|
||||
|
||||
int pag_init(void) {
|
||||
pag_kernel_pml4 = TO_VIRT(pmm_alloc());
|
||||
if (IS_ERR(pag_kernel_pml4)) return PTR_ERR(pag_kernel_pml4);
|
||||
memset(pag_kernel_pml4, 0, PAGE_SIZE);
|
||||
|
||||
int ret = pag_map_region(
|
||||
pag_kernel_pml4,
|
||||
(void*)bootloader.kernel_virt_base,
|
||||
(void*)bootloader.kernel_phys_base,
|
||||
dceil(bootloader.executable->size, PAGE_SIZE),
|
||||
PTE_FLAG_WRITE | PTE_FLAG_PRESENT
|
||||
);
|
||||
if (ret != SUCCESS) return ret;
|
||||
|
||||
for (size_t i = 0; i < bootloader.mm_entry_count; i++) {
|
||||
struct limine_memmap_entry* entry = bootloader.mm_entries[i];
|
||||
|
||||
uint64_t flags = 0;
|
||||
switch (entry->type) {
|
||||
case LIMINE_MEMMAP_USABLE: flags = PTE_FLAG_WRITE; break;
|
||||
case LIMINE_MEMMAP_RESERVED: continue;
|
||||
case LIMINE_MEMMAP_ACPI_RECLAIMABLE: flags = PTE_FLAG_WRITE; break;
|
||||
case LIMINE_MEMMAP_ACPI_NVS: break;
|
||||
case LIMINE_MEMMAP_BAD_MEMORY: continue;
|
||||
case LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE: flags = PTE_FLAG_WRITE; break;
|
||||
case LIMINE_MEMMAP_EXECUTABLE_AND_MODULES: flags = PTE_FLAG_WRITE; break;
|
||||
case LIMINE_MEMMAP_FRAMEBUFFER: flags = PTE_FLAG_WRITE | PTE_FLAG_PWT; break;
|
||||
case LIMINE_MEMMAP_RESERVED_MAPPED: flags = 0; break;
|
||||
default:
|
||||
pr_warn(
|
||||
"[pag] %p - %p: Unknown memmap type %lu. Will remain unmapped.\n",
|
||||
(void*)entry->base, (void*)entry->base + entry->length, entry->type
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = pag_map_region(
|
||||
pag_kernel_pml4,
|
||||
(void*)(entry->base + bootloader.hhdm_offset), (void*)entry->base,
|
||||
dceil(entry->length, PAGE_SIZE),
|
||||
flags | PTE_FLAG_PRESENT
|
||||
);
|
||||
if (ret != SUCCESS) return ret;
|
||||
}
|
||||
|
||||
pag_set_pml4(pag_kernel_pml4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t* pag_get_pte(uint64_t* pml4, void* vaddr) {
|
||||
uintptr_t v = (uintptr_t)vaddr;
|
||||
if (v % PAGE_SIZE != 0) return ERR_PTR(-EALIGN);
|
||||
|
||||
uint64_t* pdpt = pag_get_next_tab(pml4, PML4_IDX(v));
|
||||
if (IS_ERR(pdpt)) return pdpt;
|
||||
|
||||
uint64_t* pd = pag_get_next_tab(pdpt, PDPT_IDX(v));
|
||||
if (IS_ERR(pd)) return pd;
|
||||
|
||||
uint64_t* pt = pag_get_next_tab(pd, PD_IDX(v));
|
||||
if (IS_ERR(pt)) return pt;
|
||||
|
||||
return &pt[PT_IDX(v)];
|
||||
}
|
||||
|
||||
uint64_t* pag_new_pte(uint64_t* pml4, void* vaddr) {
|
||||
uintptr_t v = (uintptr_t)vaddr;
|
||||
if (v % PAGE_SIZE != 0) return ERR_PTR(-EALIGN);
|
||||
|
||||
uint64_t* pdpt = pag_new_next_tab(pml4, PML4_IDX(v));
|
||||
if (IS_ERR(pdpt)) return pdpt;
|
||||
|
||||
uint64_t* pd = pag_new_next_tab(pdpt, PDPT_IDX(v));
|
||||
if (IS_ERR(pd)) return pd;
|
||||
|
||||
uint64_t* pt = pag_new_next_tab(pd, PD_IDX(v));
|
||||
if (IS_ERR(pt)) return pt;
|
||||
|
||||
return &pt[PT_IDX(v)];
|
||||
}
|
||||
|
||||
int pag_map(uint64_t* pml4, void* vaddr, void* paddr, uint64_t flags) {
|
||||
uintptr_t p = (uintptr_t)paddr;
|
||||
if (p % PAGE_SIZE != 0) return -EALIGN;
|
||||
|
||||
uint64_t* pte = pag_new_pte(pml4, vaddr);
|
||||
if (IS_ERR(pte)) return PTR_ERR(pte);
|
||||
|
||||
*pte = PTE_ADDR(p) | flags | PTE_FLAG_PRESENT;
|
||||
pag_invalidate(vaddr);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int pag_map_region(uint64_t* pml4, void* vaddr, void* paddr, size_t count, uint64_t flags) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
int ret = pag_map(pml4, vaddr + i * PAGE_SIZE, paddr + i * PAGE_SIZE, flags);
|
||||
if (ret != SUCCESS) return ret;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
// TODO: This is a pmm memory leak. If all pages in a PT are unmapped, remove
|
||||
// that PT from it's PD. This applies to PDs & PDPTs too.
|
||||
int pag_unmap(uint64_t* pml4, void* vaddr) {
|
||||
uint64_t* pte = pag_get_pte(pml4, vaddr);
|
||||
if (IS_ERR(pte)) return PTR_ERR(pte);
|
||||
|
||||
*pte = 0;
|
||||
pag_invalidate(vaddr);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int pag_unmap_region(uint64_t* pml4, void* vaddr, size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
int ret = pag_unmap(pml4, vaddr + i * PAGE_SIZE);
|
||||
if (ret != SUCCESS) return ret;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int pag_protect(uint64_t* pml4, void* vaddr, uint64_t flags) {
|
||||
uint64_t* pte = pag_get_pte(pml4, vaddr);
|
||||
if (IS_ERR(pte)) return PTR_ERR(pte);
|
||||
|
||||
*pte = PTE_ADDR(*pte) | flags | PTE_FLAG_PRESENT;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void* pag_get_phys(uint64_t* pml4, void* vaddr) {
|
||||
uint64_t* pte = pag_get_pte(pml4, vaddr);
|
||||
if (IS_ERR(pte)) return pte;
|
||||
|
||||
return (void*)PTE_ADDR(*pte);
|
||||
}
|
||||
|
||||
void pag_set_pml4(uint64_t* pml4) {
|
||||
__asm__ volatile("mov %0, %%cr3" :: "r" (TO_PHYS(pml4)) : "memory");
|
||||
}
|
||||
|
||||
uint64_t* pag_get_pml4(void) {
|
||||
uint64_t* pml4;
|
||||
__asm__ volatile("movq %%cr3, %0" : "=r"(pml4) :: "memory");
|
||||
return TO_VIRT(pml4);
|
||||
}
|
||||
|
||||
uint64_t* pag_get_next_tab(uint64_t* tab, offset_t index) {
|
||||
if (tab == NULL || IS_ERR(tab)) return ERR_PTR(-EFAULT);
|
||||
if (index >= 512) return ERR_PTR(-EINVAL);
|
||||
|
||||
if (tab[index] & PTE_FLAG_PRESENT) return TO_VIRT(PTE_ADDR(tab[index]));
|
||||
else return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
uint64_t* pag_new_next_tab(uint64_t* tab, offset_t index) {
|
||||
uint64_t* vaddr = pag_get_next_tab(tab, index);
|
||||
if (!IS_ERR(vaddr)) return vaddr;
|
||||
if (PTR_ERR(vaddr) != -ENOENT) return vaddr;
|
||||
|
||||
void* paddr = pmm_alloc();
|
||||
if (IS_ERR(paddr)) return paddr;
|
||||
|
||||
vaddr = TO_VIRT(paddr);
|
||||
memset(vaddr, 0, PAGE_SIZE);
|
||||
|
||||
tab[index] = (uintptr_t)paddr | PTE_FLAG_PRESENT | PTE_FLAG_WRITE | PTE_FLAG_USER;
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#include <vsnprintf.h>
|
||||
#include <kernel.h>
|
||||
#include <stdarg.h>
|
||||
#include <system.h>
|
||||
#include <isr.h>
|
||||
#include <pmm.h>
|
||||
|
||||
static int crashing = 0;
|
||||
|
||||
void panic_regs_dump(struct isr_int_frame* regs) {
|
||||
if (regs == NULL) return;
|
||||
|
||||
pr_emerg("Register Dump:\n");
|
||||
pr_emerg("\tRAX: %016lx RBX: %016lx RCX: %016lx\n", regs->rax, regs->rbx, regs->rcx);
|
||||
pr_emerg("\tRDX: %016lx RSI: %016lx RDI: %016lx\n", regs->rdx, regs->rsi, regs->rdi);
|
||||
pr_emerg("\tR08: %016lx R09: %016lx R10: %016lx\n", regs->r8, regs->r9, regs->r10);
|
||||
pr_emerg("\tR11: %016lx R12: %016lx R13: %016lx\n", regs->r11, regs->r12, regs->r13);
|
||||
pr_emerg("\tR14: %016lx R15: %016lx DS/ES: %016lx\n", regs->r14, regs->r15, regs->ds);
|
||||
pr_emerg("\tRBP: %016lx RSP: %016lx SS: %016lx\n", regs->rbp, regs->user_rsp, regs->user_ss);
|
||||
pr_emerg("\tRIP: %016lx RFLAGS: %016lx CS: %016lx\n", regs->rip, regs->rflags, regs->cs);
|
||||
pr_emerg("\n");
|
||||
}
|
||||
|
||||
void panic_call_trace(void) {
|
||||
uintptr_t* rbp;
|
||||
__asm__ volatile ("movq %%rbp, %0" : "=r"(rbp));
|
||||
|
||||
pr_emerg("Call trace:\n");
|
||||
for (size_t i = 0; i < 16 && (uintptr_t)rbp > 0x1000; i++) {
|
||||
uintptr_t retaddr = rbp[1];
|
||||
offset_t offset = 0;
|
||||
|
||||
// TODO: Parse ELF and print function names
|
||||
char* fname = "???";
|
||||
|
||||
pr_emerg(" [<%p>] %s+0x%lx\n", (void*)retaddr, fname, offset);
|
||||
|
||||
rbp = (uintptr_t*)*rbp;
|
||||
}
|
||||
pr_emerg("\n");
|
||||
}
|
||||
|
||||
void panic(struct isr_int_frame* regs, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vpanic(regs, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void vpanic(struct isr_int_frame* regs, const char *fmt, va_list ap) {
|
||||
static char buf[PANIC_MSG_BUFSZ];
|
||||
size_t len;
|
||||
|
||||
cli();
|
||||
|
||||
if (crashing) { for (;;) __asm__ volatile ("hlt"); }
|
||||
crashing = true;
|
||||
|
||||
len = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
if (len && buf[len - 1] == '\n') buf[len - 1] = '\0';
|
||||
|
||||
pr_emerg("--- [ Kernel panic: %s ] ---\n\n", buf);
|
||||
pr_emerg("%lu / %lu pages free.\n\n", pmm_free_pages, pmm_total_pages);
|
||||
panic_regs_dump(regs);
|
||||
panic_call_trace();
|
||||
pr_emerg("--- [ End kernel panic: %s ] ---\n", buf);
|
||||
|
||||
// We can add some kind of LED blink or smth later :)
|
||||
for (;;) __asm__ volatile ("hlt");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#include <bootloader.h>
|
||||
#include <kernel.h>
|
||||
#include <limine.h>
|
||||
#include <paging.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <pmm.h>
|
||||
|
||||
uint64_t* pmm_head = NULL;
|
||||
size_t pmm_total_pages = 0;
|
||||
size_t pmm_free_pages = 0;
|
||||
|
||||
int pmm_init(void) {
|
||||
pr_info("[pmm] Physical memory map:\n"); // We're gonna use the loop to also print the memmap
|
||||
for (size_t i = 0; i < bootloader.mm_entry_count; i++) {
|
||||
struct limine_memmap_entry* entry = bootloader.mm_entries[i];
|
||||
|
||||
pr_info(
|
||||
"\t%p - %p (%lu bytes), type %lu\n",
|
||||
(void*)entry->base, (void*)entry->base + entry->length, entry->length, entry->type
|
||||
);
|
||||
|
||||
if (entry->type != LIMINE_MEMMAP_USABLE) continue;
|
||||
|
||||
// Limine spec says that it'll be aligned, but just as a sanity check
|
||||
if (entry->base % PAGE_SIZE != 0) {
|
||||
size_t diff = PAGE_SIZE - (entry->base % PAGE_SIZE);
|
||||
pr_info("\t Not 4 kiB aligned, shifting %p -> %p (%lu bytes).\n", (void*)entry->base, (void*)entry->base + diff, diff);
|
||||
entry->base += diff;
|
||||
entry->length -= diff;
|
||||
}
|
||||
|
||||
for (offset_t offset = 0; offset < entry->length; offset += PAGE_SIZE) {
|
||||
uint64_t* addr = TO_VIRT(entry->base) + offset;
|
||||
*addr = (uint64_t)pmm_head;
|
||||
pmm_head = addr;
|
||||
pmm_total_pages++;
|
||||
}
|
||||
}
|
||||
|
||||
pr_info("[pmm] %lu free pages.\n", pmm_total_pages);
|
||||
if (pmm_total_pages == 0) return -ENOMEM;
|
||||
pmm_free_pages = pmm_total_pages;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void* pmm_alloc() {
|
||||
if (pmm_head == NULL) return ERR_PTR(-ENOMEM);
|
||||
|
||||
uint64_t* addr = pmm_head;
|
||||
if ((uintptr_t)addr % PAGE_SIZE != 0) panic(NULL, "pmm_head corrupted.");
|
||||
pmm_head = (uint64_t*)(*addr);
|
||||
pmm_free_pages--;
|
||||
|
||||
return TO_PHYS(addr);
|
||||
}
|
||||
|
||||
int pmm_free(void* page) {
|
||||
if (page == NULL || IS_ERR(page)) return -EFAULT;
|
||||
if ((uintptr_t)page % PAGE_SIZE != 0) return -EALIGN;
|
||||
|
||||
uint64_t* addr = TO_VIRT(page);
|
||||
*addr = (uint64_t)pmm_head;
|
||||
pmm_head = addr;
|
||||
pmm_free_pages++;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <kernel.h>
|
||||
#include <serial.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
uint8_t console_loglevel = CONSOLE_LOGLEVEL;
|
||||
|
||||
int printk(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int ret = vprintk(fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vprintk(const char* fmt, va_list ap) {
|
||||
int loglevel = LOGLEVEL_DEFAULT;
|
||||
if (*fmt == KERN_SOH_ASCII) {
|
||||
fmt++;
|
||||
if (isdigit(*fmt)) loglevel = *fmt++ - '0';
|
||||
}
|
||||
|
||||
if (loglevel > console_loglevel) return 0;
|
||||
|
||||
// Loglevel colors
|
||||
switch (loglevel) {
|
||||
case LOGLEVEL_EMERG: debugf("\x1b[1;31m"); break; // bold red
|
||||
case LOGLEVEL_ALERT: debugf("\x1b[1;31m"); break; // bold red
|
||||
case LOGLEVEL_CRIT: debugf("\x1b[31m"); break; // red
|
||||
case LOGLEVEL_ERROR: debugf("\x1b[31m"); break; // red
|
||||
case LOGLEVEL_WARNING: debugf("\x1b[33m"); break; // yellow
|
||||
case LOGLEVEL_NOTICE: debugf("\x1b[34m"); break; // green
|
||||
case LOGLEVEL_INFO: debugf("\x1b[37m"); break; // white
|
||||
case LOGLEVEL_DEBUG: debugf("\x1b[2;32m"); break; // green
|
||||
}
|
||||
|
||||
// TODO: debugf("[%4d.%6d] ", seconds, milliseconds);
|
||||
int ret = vdebugf(fmt, ap);
|
||||
debugf("\x1b[0m");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "kernel.h"
|
||||
#include <system.h>
|
||||
#include <types.h>
|
||||
|
||||
uint64_t (*get_random_number)();
|
||||
|
||||
// this starting value it truly random i have thrown a dice few times
|
||||
uint64_t LFSR = 61113534451;
|
||||
|
||||
// RDSEED may be backdoored by NSA
|
||||
extern uint64_t rand_rdrand();
|
||||
asm(".intel_syntax noprefix\n"
|
||||
".global rand_rdrand\n"
|
||||
"rand_rdrand:"
|
||||
" rdrand rax\n"
|
||||
" ret\n"
|
||||
".att_syntax prefix\n");
|
||||
|
||||
uint64_t rand_software() {
|
||||
uint64_t lsb = LFSR & 1;
|
||||
LFSR >>= 1;
|
||||
if (lsb) {
|
||||
LFSR ^= 0x800000000000000DULL;
|
||||
}
|
||||
return LFSR;
|
||||
}
|
||||
|
||||
void rand_init(bool rdrand, bool rdseed) {
|
||||
|
||||
// check for RDRAND
|
||||
if (rdrand) {
|
||||
get_random_number = rand_rdrand;
|
||||
} else {
|
||||
printk("[\e[33mWARNING\e[0m] RDRAND not available falling back "
|
||||
"to software\n");
|
||||
// check for RDSEED
|
||||
if (rdseed) {
|
||||
asm(".intel_syntax noprefix\n"
|
||||
"rdseed %0\n"
|
||||
".att_syntax prefix\n"
|
||||
: "=r"(LFSR));
|
||||
} else {
|
||||
printk("[\e[\e[33mWARNING\e[0m] RDSEED not available "
|
||||
"falling back "
|
||||
"to developers dice trows\n");
|
||||
}
|
||||
get_random_number = rand_software;
|
||||
}
|
||||
printk("[\e[32mINFO\e[0m] RNG initialized!\n");
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
#include "errno.h"
|
||||
#include <vsnprintf.h>
|
||||
#include <kernel.h>
|
||||
#include <system.h>
|
||||
#include <serial.h>
|
||||
|
||||
int serial_init(int dev) {
|
||||
outb(dev + 1, 0x00); // Disable serial interrupts
|
||||
outb(dev + 3, 0x80); // Enable DLAB (set baud rate divisor)
|
||||
outb(dev + 0, 0x03); // Set divisor to 3 (low byte) 38400 baud
|
||||
outb(dev + 1, 0x00); // (high byte)
|
||||
outb(dev + 3, 0x03); // 8 bits, no parity, one stop bit
|
||||
outb(dev + 2, 0xC7); // Enable FIFO, clear them, with 14 byte threshold
|
||||
outb(dev + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
||||
|
||||
outb(dev + 4, 0x1E); // Set in loopback mode, test the serial chip
|
||||
outb(dev + 0, 0xAE); // Test serial chip (send byte 0xAE and check if it returns)
|
||||
if (inb(dev + 0) != 0xAE) return -ENODEV;
|
||||
|
||||
outb(dev + 4, 0x0F); // non-loopback, IRQs enabled, OUT#1 and OUT#2 bits enabled
|
||||
|
||||
serial_cls(COM1);
|
||||
serial_puts(COM1, "Serial display (COM1)\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serial_txem(int dev) {
|
||||
return inb(dev + 5) & 0x20;
|
||||
}
|
||||
|
||||
void serial_send(int dev, char data) {
|
||||
while (serial_txem(dev) == 0);
|
||||
outb(dev, data);
|
||||
}
|
||||
|
||||
int serial_rcvd(int dev) {
|
||||
return inb(dev + 5) & 1;
|
||||
}
|
||||
|
||||
char serial_recv(int dev) {
|
||||
while (serial_rcvd(dev) == 0);
|
||||
return inb(dev);
|
||||
}
|
||||
|
||||
void serial_write(int dev, const char* buf, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (buf[i] == '\n') serial_send(dev, '\r');
|
||||
serial_send(dev, buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void serial_puts(int dev, const char* s) {
|
||||
size_t len = 0;
|
||||
const char* p = s;
|
||||
while (*p++ != '\0') len++;
|
||||
serial_write(dev, s, len);
|
||||
}
|
||||
|
||||
void serial_cls(int dev) {
|
||||
serial_write(dev, "\x1b[H\x1b[J", 6);
|
||||
}
|
||||
|
||||
int debugf(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int ret = vdebugf(fmt, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vdebugf(const char* fmt, va_list args) {
|
||||
char buf[DF_BUF_LEN];
|
||||
int len = vsnprintf(buf, DF_BUF_LEN, fmt, args);
|
||||
serial_write(COM1, buf, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <bootloader.h>
|
||||
#include <kernel.h>
|
||||
|
||||
#include <splash.h>
|
||||
|
||||
#define BITMAP_LEN 24
|
||||
#define PX_SIZE 2
|
||||
|
||||
uint8_t bitmap[BITMAP_LEN] = {
|
||||
0xff, 0x04, 0x0a, 0x11, 0x00, 0x0e, 0x15, 0x15,
|
||||
0x09, 0x00, 0x1f, 0x08, 0x10, 0x10, 0x08, 0x00,
|
||||
0x1f, 0x08, 0x10, 0x10, 0x0f, 0x00, 0x01, 0x00,
|
||||
};
|
||||
|
||||
static inline void putpx(uint32_t* fb, uint64_t pitch, uint64_t x, uint64_t y, uint32_t c) {
|
||||
for (uint64_t dx = 0; dx < PX_SIZE; dx++) {
|
||||
for (uint64_t dy = 0; dy < PX_SIZE; dy++) {
|
||||
fb[((y * PX_SIZE) + dy) * pitch + ((x * PX_SIZE) + dx)] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void splash(void) {
|
||||
uint32_t* fb = bootloader.fb_entries[0]->address;
|
||||
uint64_t width = bootloader.fb_entries[0]->width;
|
||||
uint64_t height = bootloader.fb_entries[0]->height;
|
||||
uint64_t pitch = bootloader.fb_entries[0]->pitch / 4;
|
||||
|
||||
uint64_t x = (width - BITMAP_LEN * PX_SIZE) / 2 / PX_SIZE;
|
||||
uint64_t y = (height - 8 * PX_SIZE) / 2 / PX_SIZE;
|
||||
|
||||
for (size_t dx = 0; dx < BITMAP_LEN; dx++) {
|
||||
for (uint8_t dy = 0; dy < 8; dy++) {
|
||||
if (bitmap[dx] & (1 << (7 - dy))) putpx(fb, pitch, x + dx, y + dy, 0xFFC6D6D6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Stack Smash Protector
|
||||
* Source: https://wiki.osdev.org/Stack_Smashing_Protector
|
||||
*/
|
||||
#include <kernel.h>
|
||||
|
||||
#ifndef STACK_CHK_GUARD
|
||||
#error "STACK_CHK_GUARD not defined!"
|
||||
#endif
|
||||
|
||||
uintptr_t __stack_chk_guard = STACK_CHK_GUARD;
|
||||
__noreturn void __stack_chk_fail(void) {
|
||||
panic(NULL, "Stack smashing detected!");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#include <kernel.h>
|
||||
#include <string.h>
|
||||
|
||||
void* memchr(const void* ptr, uint8_t val, size_t len) {
|
||||
const uint8_t* p = ptr;
|
||||
while (len--) if (*p++ == val) return (void*)(p - 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int memcmp(const void* ptr1, const void* ptr2, size_t len) {
|
||||
const uint8_t* p1 = ptr1;
|
||||
const uint8_t* p2 = ptr2;
|
||||
while (len--) if (*p1++ != *p2++) return p1[-1] - p2[-1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* memcpy(void* dst, const void* src, size_t len) {
|
||||
uint8_t* d = dst;
|
||||
const uint8_t* s = src;
|
||||
while (len--) *d++ = *s++;
|
||||
return dst;
|
||||
}
|
||||
|
||||
void* memmov(void* dst, const void* src, size_t len) {
|
||||
uint8_t* d = dst;
|
||||
const uint8_t* s = src;
|
||||
if (d < s) while (len--) *d++ = *s++;
|
||||
else while (len--) d[len] = s[len];
|
||||
return dst;
|
||||
}
|
||||
|
||||
void* memset(void* dst, uint8_t val, size_t len) {
|
||||
uint8_t* d = dst;
|
||||
while (len--) *d++ = val;
|
||||
return dst;
|
||||
}
|
||||
|
||||
char* strbrk(char* str, const char* accept) {
|
||||
while (*str) {
|
||||
if (strchr(accept, *str)) return (char*)str;
|
||||
str++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* strcat(char* dst, const char* src) {
|
||||
char* d = dst;
|
||||
while (*d) d++;
|
||||
while ((*d++ = *src++));
|
||||
return dst;
|
||||
}
|
||||
|
||||
char* strchr(const char* str, char c) {
|
||||
while (*str) if (*str++ == c) return (char*)(str - 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int strcmp(const char* str1, const char* str2) {
|
||||
while (*str1 && (*str1 == *str2)) str1++, str2++;
|
||||
return (int)(*(uint8_t*)str1 - *(uint8_t*)str2);
|
||||
}
|
||||
|
||||
char* strcpy(char* dst, const char* src) {
|
||||
char* d = dst;
|
||||
while ((*d++ = *src++));
|
||||
return dst;
|
||||
}
|
||||
|
||||
size_t strlen(const char* str) {
|
||||
const char* s = str;
|
||||
while (*s++);
|
||||
return s - str;
|
||||
}
|
||||
|
||||
size_t strspn(const char* str, const char* accept) {
|
||||
const char* s = str;
|
||||
while (*s && strchr(accept, *s)) s++;
|
||||
return s - str;
|
||||
}
|
||||
|
||||
char* strstr(const char* str1, const char* str2) {
|
||||
if (!*str2) return (char*)str1;
|
||||
for (; *str1; str1++) {
|
||||
const char* s1 = str1;
|
||||
const char* s2 = str2;
|
||||
while (*s1 && *s2 && (*s1 == *s2)) s1++, s2++;
|
||||
if (!*s2) return (char*)str1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* strtok(char* str, const char* delim) {
|
||||
static char* next;
|
||||
if (!str) str = next;
|
||||
if (!str) return NULL;
|
||||
str += strspn(str, delim);
|
||||
if (!*str) return (next = NULL);
|
||||
char* tok = str;
|
||||
str = strbrk(str, delim);
|
||||
if (str) *str++ = '\0';
|
||||
next = str;
|
||||
return tok;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
#include "types.h"
|
||||
#include <kernel.h>
|
||||
#include <random.h>
|
||||
#include <system.h>
|
||||
void cpuid(uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) {
|
||||
__asm__ volatile("cpuid"
|
||||
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
|
||||
: "a"(*eax)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
void iowait(void) { outb(0x80, 0); }
|
||||
|
||||
uint8_t inb(uint16_t port) {
|
||||
uint8_t r;
|
||||
__asm__ volatile("inb %1, %0" : "=a"(r) : "dN"(port));
|
||||
return r;
|
||||
}
|
||||
|
||||
void outb(uint16_t port, uint8_t data) {
|
||||
__asm__ volatile("outb %1, %0" ::"dN"(port), "a"(data));
|
||||
}
|
||||
|
||||
uint16_t inw(uint16_t port) {
|
||||
uint16_t r;
|
||||
__asm__ volatile("inw %1, %0" : "=a"(r) : "dN"(port));
|
||||
return r;
|
||||
}
|
||||
|
||||
void outw(uint16_t port, uint16_t data) {
|
||||
__asm__ volatile("outw %1, %0" ::"dN"(port), "a"(data));
|
||||
}
|
||||
|
||||
uint32_t inl(uint16_t port) {
|
||||
uint32_t r;
|
||||
__asm__ volatile("inl %1, %0" : "=a"(r) : "dN"(port));
|
||||
return r;
|
||||
}
|
||||
|
||||
void outl(uint16_t port, uint32_t data) {
|
||||
__asm__ volatile("outl %1, %0" ::"dN"(port), "a"(data));
|
||||
}
|
||||
|
||||
void cli(void) { __asm__ volatile("cli"); }
|
||||
|
||||
void sti(void) { __asm__ volatile("sti"); }
|
||||
|
||||
uint8_t (*popcountll)(uint64_t num);
|
||||
|
||||
extern uint8_t popcountll_native(uint64_t num);
|
||||
asm(".intel_syntax noprefix\n"
|
||||
".global popcountll_native\n"
|
||||
"popcountll_native:"
|
||||
" popcnt rax, rdi\n"
|
||||
" ret\n"
|
||||
".att_syntax prefix\n");
|
||||
|
||||
// I have no idea how this works but it is apperently called SWAR
|
||||
uint8_t popcountll_software(uint64_t num) {
|
||||
num = num - ((num >> 1) & 0x5555555555555555ULL);
|
||||
num = (num & 0x3333333333333333ULL) +
|
||||
((num >> 2) & 0x3333333333333333ULL);
|
||||
num = (num + (num >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
|
||||
return (int)((num * 0x0101010101010101ULL) >> 56);
|
||||
}
|
||||
|
||||
void detect_processor_features() {
|
||||
// leaf 1
|
||||
uint32_t eax = 1, ebx = 0, ecx = 0, edx = 0;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
bool rdrand = false;
|
||||
if (ecx & CPUID_FEAT_ECX_RDRAND) {
|
||||
rdrand = true;
|
||||
}
|
||||
|
||||
if (ecx & CPUID_FEAT_ECX_POPCNT) {
|
||||
popcountll = popcountll_native;
|
||||
} else {
|
||||
popcountll = popcountll_software;
|
||||
}
|
||||
|
||||
// leaf 7
|
||||
eax = 7, ebx = 0, ecx = 0, edx = 0;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
bool rdseed = false;
|
||||
if (ebx & CPUID_FEAT_EBX_RDSEED) {
|
||||
rdseed = true;
|
||||
}
|
||||
|
||||
// init rng
|
||||
rand_init(rdrand, rdseed);
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "vmm.h"
|
||||
#include "kernel.h"
|
||||
#include <errno.h>
|
||||
#include <isr.h>
|
||||
#include <limits.h>
|
||||
#include <paging.h>
|
||||
#include <pmm.h>
|
||||
#include <random.h>
|
||||
#include <types.h>
|
||||
|
||||
// allocates set number of pages at address provided
|
||||
// if address is NULL address is chosen internaly
|
||||
int vmm_alloc(void** vaddr, uint64_t count, uint64_t flags) {
|
||||
if (flags == 0) {
|
||||
flags = PTE_FLAG_PRESENT | PTE_FLAG_WRITE | PTE_FLAG_NOEXEC;
|
||||
}
|
||||
bool random_vaddr = *vaddr ? false : true;
|
||||
|
||||
uint64_t* pml4 = pag_get_pml4();
|
||||
{
|
||||
uint8_t limit_counter = 0;
|
||||
while (true) {
|
||||
if (random_vaddr) {
|
||||
retry_selection:
|
||||
*vaddr = (void*)ALIGN_DOWN(get_random_number(),
|
||||
PAGE_SIZE);
|
||||
|
||||
*vaddr = (void*)((uint64_t)(*vaddr) &
|
||||
CANONICAL_MASK_USER);
|
||||
if (!(flags & PTE_FLAG_USER)) {
|
||||
*vaddr = (void*)((uint64_t)(*vaddr) |
|
||||
CANONICAL_MASK_KERNEL);
|
||||
}
|
||||
} else {
|
||||
if (flags & PTE_FLAG_USER) {
|
||||
if ((void*)((uint64_t)(*vaddr) &
|
||||
CANONICAL_MASK_KERNEL)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
if (!((void*)((uint64_t)(*vaddr) &
|
||||
CANONICAL_MASK_KERNEL))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uint64_t i = 0; i < count; i++) {
|
||||
uint64_t* pte =
|
||||
pag_get_pte(pml4, *vaddr + (i * PAGE_SIZE));
|
||||
if (!IS_ERR(pte) && (*pte & PTE_FLAG_PRESENT)) {
|
||||
if (!random_vaddr) {
|
||||
return -EEXIST;
|
||||
} else {
|
||||
if (limit_counter < UINT8_MAX) {
|
||||
goto retry_selection;
|
||||
} else {
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint64_t i = 0; i < count; i++) {
|
||||
void* paddr = pmm_alloc();
|
||||
int pag_map_ret =
|
||||
pag_map(pml4, *vaddr + (i * PAGE_SIZE), paddr, flags);
|
||||
if (pag_map_ret != SUCCESS) {
|
||||
if (i != 0) {
|
||||
for (i -= 1; i != UINT64_MAX; i--) {
|
||||
if (pag_unmap(pml4,
|
||||
*vaddr +
|
||||
(i * PAGE_SIZE)) !=
|
||||
SUCCESS) {
|
||||
panic(NULL,
|
||||
"failed to unmap "
|
||||
"previously mapped "
|
||||
"page. %s:%d",
|
||||
__FILE_NAME__, __LINE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
return pag_map_ret;
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int vmm_free(void* vaddr) {
|
||||
uint64_t* pml4 = pag_get_pml4();
|
||||
return pag_unmap(pml4, vaddr);
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
#include <kernel.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vsnprintf.h>
|
||||
|
||||
static inline int _isdigit(int c) { return (c >= '0' && c <= '9') ? 1 : 0; }
|
||||
|
||||
static size_t _utoa(char* out, uint64_t v, uint32_t base) {
|
||||
static char* digits = "0123456789abcdef";
|
||||
|
||||
size_t i = 0;
|
||||
if (v == 0) {
|
||||
out[i++] = '0';
|
||||
return i;
|
||||
}
|
||||
|
||||
while (v) {
|
||||
out[i++] = digits[v % base];
|
||||
v /= base;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static void _putc(char* buf, size_t n, size_t* idx, char c) {
|
||||
if (*idx < n - 1) buf[*idx] = c;
|
||||
(*idx)++;
|
||||
}
|
||||
|
||||
static void _puts(char* buf, size_t n, size_t* idx, char* s, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) _putc(buf, n, idx, s[i]);
|
||||
}
|
||||
|
||||
static void fmt_string(char* buf, size_t n, size_t* idx, char* s, size_t len, int width, char pad, int left) {
|
||||
int pad_len = width > (int)len ? width - (int)len : 0;
|
||||
if (!left) { while (pad_len--) _putc(buf, n, idx, pad); }
|
||||
_puts(buf, n, idx, s, len);
|
||||
if (left) { while (pad_len--) _putc(buf, n, idx, pad); }
|
||||
}
|
||||
|
||||
static void fmt_int(char* buf, size_t n, size_t* idx, int64_t v, int width, char pad, int left) {
|
||||
char tmp[32];
|
||||
size_t len;
|
||||
int neg = v < 0;
|
||||
|
||||
uint64_t uv = neg ? -v : v;
|
||||
len = _utoa(tmp, uv, 10);
|
||||
|
||||
if (neg) tmp[len++] = '-';
|
||||
|
||||
for (size_t i = 0; i < len / 2; i++) {
|
||||
char c = tmp[i];
|
||||
tmp[i] = tmp[len - 1 - i];
|
||||
tmp[len - 1 - i] = c;
|
||||
}
|
||||
|
||||
fmt_string(buf, n, idx, tmp, len, width, pad, left);
|
||||
}
|
||||
|
||||
static void fmt_uint(char* buf, size_t n, size_t* idx, uint64_t v, uint32_t base, int width, char pad, int left) {
|
||||
char tmp[32];
|
||||
size_t len = _utoa(tmp, v, base);
|
||||
|
||||
for (size_t i = 0; i < len / 2; i++) {
|
||||
char c = tmp[i];
|
||||
tmp[i] = tmp[len - 1 - i];
|
||||
tmp[len - 1 - i] = c;
|
||||
}
|
||||
|
||||
fmt_string(buf, n, idx, tmp, len, width, pad, left);
|
||||
}
|
||||
|
||||
// WARN: I took this from somewhere and idk how good it is and i'm too lazy to check
|
||||
static void fmt_float(char* buf, size_t n, size_t* idx, double v, int prec, int width, char pad, int left) {
|
||||
if (prec < 0) prec = 6;
|
||||
|
||||
if (v < 0) {
|
||||
_putc(buf, n, idx, '-');
|
||||
v = -v;
|
||||
if (width > 0) width--;
|
||||
}
|
||||
|
||||
long long ip = (long long)v;
|
||||
double frac = v - (double)ip;
|
||||
|
||||
char tmp[64];
|
||||
size_t len = _utoa(tmp, ip, 10);
|
||||
|
||||
for (size_t i = 0; i < len / 2; i++) {
|
||||
char c = tmp[i];
|
||||
tmp[i] = tmp[len - 1 - i];
|
||||
tmp[len - 1 - i] = c;
|
||||
}
|
||||
|
||||
size_t total = len + 1 + prec;
|
||||
int pad_len = width > (int)total ? width - (int)total : 0;
|
||||
|
||||
if (!left) { while (pad_len--) _putc(buf, n, idx, pad); }
|
||||
|
||||
_puts(buf, n, idx, tmp, len);
|
||||
_putc(buf, n, idx, '.');
|
||||
|
||||
for (int i = 0; i < prec; i++) {
|
||||
frac *= 10.0;
|
||||
int d = (int)frac;
|
||||
_putc(buf, n, idx, '0' + d);
|
||||
frac -= d;
|
||||
}
|
||||
|
||||
if (left) { while (pad_len--) _putc(buf, n, idx, pad); }
|
||||
}
|
||||
|
||||
int vsnprintf(char* buf, size_t n, const char* fmt, va_list ap) {
|
||||
size_t idx = 0;
|
||||
|
||||
for (; *fmt != '\0'; fmt++) {
|
||||
if (*fmt != '%') {
|
||||
_putc(buf, n, &idx, *fmt);
|
||||
continue;
|
||||
}
|
||||
|
||||
fmt++;
|
||||
|
||||
int left = 0;
|
||||
char pad = ' ';
|
||||
int width = 0;
|
||||
int prec = -1;
|
||||
int is_long = 0;
|
||||
|
||||
if (*fmt == '-') {
|
||||
left = 1;
|
||||
fmt++;
|
||||
}
|
||||
|
||||
if (*fmt == '0') {
|
||||
pad = '0';
|
||||
fmt++;
|
||||
}
|
||||
|
||||
while (_isdigit((int)*fmt)) {
|
||||
width = width * 10 + (*fmt - '0');
|
||||
fmt++;
|
||||
}
|
||||
|
||||
if (*fmt == '.') {
|
||||
fmt++;
|
||||
prec = 0;
|
||||
while (_isdigit((int)*fmt)) {
|
||||
prec = prec * 10 + (*fmt - '0');
|
||||
fmt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*fmt == 'l') {
|
||||
is_long = 1;
|
||||
fmt++;
|
||||
if (*fmt == 'l') { // handle ll
|
||||
fmt++;
|
||||
}
|
||||
}
|
||||
|
||||
switch (*fmt) {
|
||||
case 'd': fmt_int(buf, n, &idx, is_long ? va_arg(ap, int64_t) : va_arg(ap, int32_t), width, pad, left); break;
|
||||
case 'u': fmt_uint(buf, n, &idx, is_long ? va_arg(ap, uint64_t) : va_arg(ap, uint32_t), 10, width, pad, left); break;
|
||||
case 'x': fmt_uint(buf, n, &idx, is_long ? va_arg(ap, uint64_t) : va_arg(ap, uint32_t), 16, width, pad, left); break;
|
||||
case 'p':
|
||||
fmt_string(buf, n, &idx, "0x", 2, 0, ' ', 0);
|
||||
fmt_uint(buf, n, &idx, va_arg(ap, uintptr_t), 16, 16, '0', 0);
|
||||
break;
|
||||
case 'f': fmt_float(buf, n, &idx, va_arg(ap, double), prec, width, pad, left); break;
|
||||
case 's': {
|
||||
char* s = va_arg(ap, char*);
|
||||
if (s == NULL) s = "(null)";
|
||||
size_t len = strlen(s);
|
||||
if (prec >= 0) len = min(len, (size_t)prec);
|
||||
fmt_string(buf, n, &idx, s, len, width, pad, left);
|
||||
} break;
|
||||
case 'c': _putc(buf, n, &idx, (char)va_arg(ap, int)); break;
|
||||
case '%': _putc(buf, n, &idx, '%'); break;
|
||||
default:
|
||||
// Undo all the parsing we just did :')
|
||||
_putc(buf, n, &idx, '%');
|
||||
if (left) _putc(buf, n, &idx, '-');
|
||||
if (pad == '0') _putc(buf, n, &idx, '0');
|
||||
if (width > 0) fmt_uint(buf, n, &idx, width, 10, 0, 0, 0);
|
||||
if (prec != -1) {
|
||||
_putc(buf, n, &idx, '.');
|
||||
fmt_uint(buf, n, &idx, prec, 10, 0, 0, 0);
|
||||
}
|
||||
_putc(buf, n, &idx, *fmt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (n) buf[min(idx, n - 1)] = '\0';
|
||||
return (int)idx;
|
||||
}
|
||||
|
||||
int snprintf(char *buf, size_t n, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int ret = vsnprintf(buf, n, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#include <errno.h>
|
||||
|
||||
int errno = 0;
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef _ASSERT_H
|
||||
#define _ASSERT_H
|
||||
|
||||
// TODO:
|
||||
#define assert(_ignore) ((void)0)
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user