68 Commits
Author SHA1 Message Date
Tom-on 9c386bf447 Merge pull request #1 from PoliEcho/rewrite
remove random nbsp and fix markdown
2026-09-23 09:47:55 +02:00
PoliEcho 041f1f886b remove random nbsp and fix markdown 2026-09-22 19:10:58 +02:00
Tomáš Kubeček 4bc3382abb Got decent exception handling 2026-05-29 11:42:20 +02:00
Tom-on 22852599df Added register dump to panic() and colors to printk() 2026-03-29 20:39:06 +02:00
Tom-on 12ec371196 Improved disk building 2026-03-29 20:33:02 +02:00
Tom-on f10f065e91 Added __printf() attributes to printf-like functions 2026-03-28 18:03:46 +01:00
Tom-on ad45de562a Added free page count to panic() 2026-03-27 15:05:47 +01:00
Tom-on f316916ff1 Fixed isr trap register dump not printing in hex 2026-03-27 14:35:49 +01:00
Tom-on 5d67cbd958 Fixed using ALIGN() instead of dceil() in vmm 2026-03-26 21:37:32 +01:00
Tom-on 63a238d2c4 The printk(), panic() and kernel.h update 2026-03-26 21:07:29 +01:00
Tom-on 2f05396651 Added <errno.h> and made kernel use it 2026-03-25 18:17:42 +01:00
Tom-on 7a57999d05 Cleanup 2026-03-22 19:57:51 +01:00
Tom-on e43bc126b5 Made PMM not do #PFs 2026-03-22 19:15:11 +01:00
Tom-on 004399c122 Major TODO rewrite and minor README changes :) 2026-03-22 15:25:33 +01:00
Tom-on eca7c957e2 Slight cleanup and fixed SSP 2026-03-22 14:55:37 +01:00
Tom-on 8cbe050f35 Implemented 64-bit paging 2026-03-22 14:27:48 +01:00
Tom-on 74d1edbf9f Fixed #GP from pmm_free() 2026-03-22 14:27:30 +01:00
Tom-on e8d5a8be35 Added register dump to Trap IRQs 2026-03-22 14:26:53 +01:00
Tom-on 421a83d202 Added logging, %lu and %p format specifiers to vnsprintf() 2026-03-22 14:25:49 +01:00
Tom-on 9c66d7228a Updated limine.h & added bootloader.executable 2026-03-22 14:24:31 +01:00
Tom-on 93ef197e58 Wrote physical memory manager 2026-03-20 18:18:15 +01:00
Tom-on 0214b4da31 Minor changes
* Added CPUID thing
* Reworked some kernel.h macros and definitions
2026-03-20 18:17:25 +01:00
Tom-on 1542cf0ada Oop forgot to add this 2026-02-08 13:05:04 +01:00
Tom-on 50a1d6198e The great 64-bit rewrite
* We did loose tasking and only have a paging skeleton, but hey it took like 4 months so i'm happy that there's something :p
2026-02-08 13:04:39 +01:00
Tom-on d9471572b8 The most important thing in the world 2026-02-03 18:49:12 +01:00
Tom-on 2b4beae3c5 Added IPC skeleton 2025-05-07 18:53:41 +02:00
Tom-on 2cd84b5e89 Added clobber list to inline asm 2025-05-07 13:26:45 +02:00
Tom-on 024dcfffcc Implemented a basic syscall handler 2025-05-07 13:25:18 +02:00
Tom-on d6035dff80 Added sti() and cli() assembly wrappers 2025-05-07 08:56:09 +02:00
Tom-on c646404cf0 PREEMPTIVE MULTITASKING!!!! 2025-05-06 19:29:35 +02:00
Tom-on a48fa362d0 IMPLEMENTED TASKS! 2025-04-30 18:27:18 +02:00
Tom-on f4b10746d6 Doc changes 2025-04-29 20:20:50 +02:00
Tom-on 1a58cfee97 Minor kmalloc() fix 2025-04-29 20:16:22 +02:00
Tom-on 5522218767 Implemented a simple kernel heap 2025-04-29 20:10:59 +02:00
Tom-on 9181f3afd3 Minor PIT change 2025-04-28 20:45:11 +02:00
Tom-on b8fba03773 Implemented PIT 2025-04-28 18:48:40 +02:00
Tom-on bbb3c131b3 Nothing much 2025-04-27 22:05:58 +02:00
Tom-on 1bc758f3c1 Changed camelCase to snake_case 2025-04-27 19:18:33 +02:00
Tom-on 7b5efc1837 Added memory map docs 2025-04-16 10:02:32 +02:00
Tom-on c5193dd188 Minor change 2025-04-15 11:25:03 +02:00
Tom-on 0c2bba8c33 Updated docs 2025-04-15 11:22:50 +02:00
Tom-on 30445e9d25 Fixed the pmm_init() page fault, but i have no clue why pag_init() sometimes causes it. 2025-04-15 10:39:25 +02:00
Tom-on a73eb77418 Changed default ouput image name from kern.img to disk.img so tabbing for kernel/ doesn't stop at kern :) 2025-04-14 20:17:01 +02:00
Tom-on 354339e831 Began using Limine as a bootloader instead of QEMUs mb1 bootloader. 2025-04-14 20:15:05 +02:00
Tom-on f1bdfc9c9f Fixed TTY not working because of paging 2025-04-10 11:50:32 +02:00
Tom-on ba28eafb20 Minor changes 2025-04-10 11:50:10 +02:00
Tom-on 7c2fcd8e9f Implemented VMM! 2025-04-08 15:09:57 +02:00
Tom-on ced6cb250f More docs 2025-04-08 15:09:42 +02:00
Tom-on c2b0f0baa2 Changed pmm_ready to pmm_bitmap.ready 2025-04-05 15:46:49 +02:00
Tom-on b104755904 Added bitmap_t type and bmap_* functions & used them in PMM 2025-04-05 15:44:55 +02:00
Tom-on 25771de53e Full PMM implementation 2025-04-04 16:58:54 +02:00
Tom-on 5d7a4d790f PMM finally works?? 2025-04-03 15:40:01 +02:00
Tom-on dd7e621640 Implemented paging 2025-03-29 12:06:56 +01:00
Tom-on 9d931f9e9d Updated coding-style.txt 2025-03-29 12:06:37 +01:00
Tom-on 5cee647ff0 Added basic paging.h & paging.c 2025-03-28 11:30:43 +01:00
Tom-on f73a6f9ccb Fixed it :( 2025-03-22 18:39:54 +01:00
Tom-on 4f543f3fd0 Broke it :) 2025-03-22 18:19:26 +01:00
Tom-on c3f8d7d8f2 Got IDT & ISRs working! 2025-03-21 14:09:15 +01:00
Tom-on 05c8ee8f67 Got GDT working 2025-03-21 12:30:04 +01:00
Tom-on 5076d1c56b Added string.h 2025-03-20 12:01:24 +01:00
Tom-on 05561cd857 Got memory map almost working 2025-03-19 11:25:45 +01:00
Tom-on 883cd5c1d4 Some unfinished changes + TODO chnages 2025-03-18 20:40:29 +01:00
Tom-on 244b83d370 Write vsnprintf() implementation 2025-03-18 17:41:16 +01:00
Tom-on 8674d32f77 Got memory info from multiboot & minor adjustments 2025-02-19 10:46:35 +01:00
Tom-on 609e10e13c Implemented serial driver 2025-02-18 14:06:41 +01:00
Tom-on f9dece59ce Got basic tty driver & implemented Stack Smash Protector 2025-02-17 21:02:10 +01:00
Tom-on 983174a081 Began work on tty driver 2025-02-16 20:32:19 +01:00
Tom-on 7d41cf45ed Began rewrite 2025-02-16 16:27:46 +01:00
142 changed files with 4373 additions and 3344 deletions
+297
View File
@@ -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: Never
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: 2
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: Right
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: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
WrapNamespaceBodyWithEmptyLines: Leave
...
+7
View File
@@ -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
+672 -11
View File
@@ -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>.
+25 -14
View File
@@ -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
+57 -179
View File
@@ -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
-31
View File
@@ -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)
-133
View File
@@ -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
-26
View File
@@ -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
-28
View File
@@ -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
-10
View File
@@ -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
-38
View File
@@ -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);
}
}
-37
View File
@@ -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
-115
View File
@@ -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);
}
-33
View File
@@ -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) {}
-124
View 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
-12
View File
@@ -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);
}
-19
View File
@@ -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
-24
View File
@@ -1,24 +0,0 @@
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386)
SECTIONS {
. = 0x70000;
.text : {
*(entry)
*(.text)
}
.rodata : {
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(COMMON)
*(.bss)
}
}
-73
View File
@@ -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++]);
}
-33
View File
@@ -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
-33
View File
@@ -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
-10
View File
@@ -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
-22
View File
@@ -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
-143
View File
@@ -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;
}
-25
View File
@@ -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
-74
View File
@@ -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;
}
-15
View File
@@ -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
+45
View File
@@ -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
View File
@@ -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 =
-17
View File
@@ -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'
+13
View File
@@ -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.
-25
View File
@@ -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
View File
@@ -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
+57
View File
@@ -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`
+32
View File
@@ -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
View File
@@ -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
-16
View File
@@ -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
-57
View File
@@ -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

BIN
View File
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

+50
View File
@@ -0,0 +1,50 @@
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` -
+16
View File
@@ -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 |
-38
View File
@@ -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
+17
View File
@@ -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
+63
View File
@@ -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
View File
@@ -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 | | | |
+62
View File
@@ -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.
+27
View 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
+35
View File
@@ -0,0 +1,35 @@
#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
};
#endif
+24
View File
@@ -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
+124
View File
@@ -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
+37
View File
@@ -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
+32
View File
@@ -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
+90
View File
@@ -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
+594
View File
@@ -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
+56
View File
@@ -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
+13
View File
@@ -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
+26
View File
@@ -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
+19
View File
@@ -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
+9
View File
@@ -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
-22
View File
@@ -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
+24
View File
@@ -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
+90
View File
@@ -0,0 +1,90 @@
#ifndef _SYSTEM_H
#define _SYSTEM_H
#include <kernel.h>
#include <gdt.h>
#include <idt.h>
/*
* CPUID
*/
enum {
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);
#endif
+44
View File
@@ -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
+9
View File
@@ -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
View File
@@ -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
View File
@@ -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)
+61
View File
@@ -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;
}
-108
View File
@@ -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
+152
View File
@@ -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;
}
+109
View File
@@ -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;
}
+35
View File
@@ -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;
}
+82
View File
@@ -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);
}
}
+129
View File
@@ -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
-4
View File
@@ -1,4 +0,0 @@
#include <stdint.h>
void kmain(uint32_t addr) {}
+41
View File
@@ -0,0 +1,41 @@
#include <bootloader.h>
#include <kernel.h>
#include <paging.h>
#include <serial.h>
#include <splash.h>
#include <system.h>
#include <gdt.h>
#include <isr.h>
#include <pmm.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);
// 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);
// The most important function in the world.
splash();
// Patiently wait for things to do :)
while (1);
};
+185
View File
@@ -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;
}
+71
View File
@@ -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");
}
+70
View File
@@ -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;
}
+42
View File
@@ -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;
}
+78
View File
@@ -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;
}
+38
View File
@@ -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);
}
}
}
+15
View File
@@ -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!");
}
+104
View File
@@ -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;
}
+52
View File
@@ -0,0 +1,52 @@
#include <kernel.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");
}
+205
View File
@@ -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;
}
-4
View File
@@ -1,4 +0,0 @@
#include <errno.h>
int errno = 0;
-8
View File
@@ -1,8 +0,0 @@
#ifndef _ASSERT_H
#define _ASSERT_H
// TODO:
#define assert(_ignore) ((void)0)
#endif
-46
View File
@@ -1,46 +0,0 @@
#ifndef _ERRNO_H
#define _ERRNO_H
// Basic POSIX defined error idk
enum {
EPERM = 1, // Operation not permitted
ENOENT, // No such file or directory
ESRCH, // No such process
EINTR, // Interrupted system call
EIO, // I/O error
ENXIO, // No such device or address
E2BIG, // Argument list too long
ENOEXEC, // Exec format error
EBADF, // Bad file descriptor
ECHILD, // No child processes
EAGAIN, // Resource temporarily unavailable
ENOMEM, // Out of memory
EACCES, // Permission denied
EFAULT, // Bad address
EBUSY, // Device or resource busy
EEXIST, // File exists
ENOTDIR, // Not a directory
EISDIR, // Is a directory
EIMPL, // TODO: Implementation defined
ENOMSG, // No message of desired type
EINVAL, // Invalid argument
ENFILE, // File table overflow
EMFILE, // Too many open files
ENOTTY, // Not a typewriter
ETXTBSY, // Text file busy
EFBIG, // File too large
ENOSPC, // No space left on device
ESPIPE, // Illegal seek
EROFS, // Read-only file system
EMLINK, // Too many links
EPIPE, // Broken pipe
EDQUOT, // Disk quota exceeded
EDOM, // Function arg domain error
ERANGE, // Out of range
// TODO: more
EILSEQ = 42,// Invalid byte seqence
};
extern int errno;
#endif
-23
View File
@@ -1,23 +0,0 @@
#ifndef _FCNTL_H
#define _FCNTL_H
/* Standard file decriptors */
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
/* File access modes */
#define O_CREAT 0x0001 // Create if does not exist
#define O_RDONLY 0x0002 // Read only
#define O_WRONLY 0x0004 // Write only
#define O_RDWR 0x0008 // Read and write
#define O_APPEND 0x0010 // Always writes at the end (appends)
#define O_TRUNC 0x0020 // Truncate file size and position to 0 on Open
#define O_EXCL 0x0040 // Error if file exists (with O_CREAT)
#define O_BIN 0x0080 // Read bytes, not text
#define O_DIRECTORY 0x0100 // Error if file is not a directory
// TODO: more!
/* TODO: File lock */
#endif
-33
View File
@@ -1,33 +0,0 @@
#ifndef _FLOAT_H
#define _FLOAT_H
#define FLT_DIG 6 // Float precision: 6 decimal digits
#define DBL_DIG 15 // Double precision: 15 decimal digits
#define LDBL_DIG 18 // Long double precision: 18 decimal digits
#define FLT_MAX 3.40282347e+38F // Maximum float value
#define DBL_MAX 1.7976931348623157e+308 // Maximum double value
#define LDBL_MAX 1.189731495357231765e+4932L // Max long double
#define FLT_MIN 1.17549435e-38F // Minimum positive normalized float
#define DBL_MIN 2.2250738585072014e-308 // Min positive double
#define LDBL_MIN 3.36210314311209350626e-4932L // Min positive long double
#define FLT_EPSILON 1.19209290e-7F // Smallest float increment
#define DBL_EPSILON 2.2204460492503131e-16 // Smallest double increment
#define LDBL_EPSILON 1.08420217248550443401e-19L // Smallest long double increment
#define FLT_MAX_EXP 128 // Max exponent for float
#define DBL_MAX_EXP 1024 // Max exponent for double
#define LDBL_MAX_EXP 16384 // Max exponent for long double
#define FLT_MIN_EXP -125 // Min exponent for float
#define DBL_MIN_EXP -1021 // Min exponent for double
#define LDBL_MIN_EXP -16381 // Min exponent for long double
#define FLT_RADIX 2 // Floating-point base (usually 2)
#define FLT_MANT_DIG 24 // Number of digits in float mantissa
#define DBL_MANT_DIG 53 // Number of digits in double mantissa
#define LDBL_MANT_DIG 64 // Number of digits in long double mantissa
#endif
-29
View File
@@ -1,29 +0,0 @@
#ifndef _LIMITS_H
#define _LIMITS_H
// Chars are spectial :)
#define CHAR_BIT 8
#define CHAR_MIN 0
// Signed min
#define SCHAR_MIN -127
#define SHRT_MIN -32768
#define INT_MIN -2147483648
#define LONG_MIN -2147483648L
#define LLONG_MIN -9223372036854775808LL
// Signed max
#define SCHAR_MAX 127
#define SHRT_MAX 32767
#define INT_MAX 2147483647
#define LONG_MAX 2147483647L
#define LLONG_MAX 9223372036854775807LL
// Unsigned max
#define CHAR_MAX 255
#define USHRT_MAX 65535
#define UINT_MAX 4294967295U
#define ULONG_MAX 4294967295UL
#define ULLONG_MAX 18446744073709551615ULL
#endif
-69
View File
@@ -1,69 +0,0 @@
#ifndef _MATH_H
#define _MATH_H
// Constants
#define M_E 2.71828182845904523536 // e
#define M_LOG2E 1.44269504088896340736 // log_2 e
#define M_LOG10E 0.43429448190325182765 // log_10 e
#define M_LN2 0.69314718055994530941 // ln(2)
#define M_LN10 2.30258509299404568402 // ln(10)
#define M_PI 3.14159265358979323846 // pi
#define M_PI_2 1.57079632679489661923 // pi/2
#define M_PI_4 0.78539816339744830961 // pi/4
#define M_1_PI 0.31830988618379067153 // 1/pi
#define M_2_PI 0.63661977236758134307 // 2/pi
#define M_SQRT2 1.41421356237309504880 // sqrt(2)
#define M_SQRT1_2 0.70710678118654752440 // 1/sqrt(2)
// TODO:
#define NAN (__builtin_inff())
#define INFINITY (__builtin_nanf(""))
// Absolute value
int abs(int n);
double fabs(double n);
// Exponential & logarithmic
double exp(double x);
double exp2(double x);
double log(double x);
double log2(double x);
double log10(double x);
double logn(double x, double n);
// Power
double sqrt(double x);
double cbrt(double x);
double hypot(double x, double y);
double pow(double base, double expn);
// Trigonometric
double sin(double x);
double cos(double x);
double tan(double x);
double asin(double x);
double acos(double x);
double atan(double x);
double atan2(double y, double x);
// Hyperbolic
double sinh(double x);
double cosh(double x);
double tanh(double x);
// Rounding & remainder
double floor(double x);
double ceil(double x);
double round(double x);
double trunc(double x);
double fmod(double x, double y);
double modf(double x, double* iptr);
// Error handling
double nan(const char* tagp);
double inf();
int isfinite(double x);
int isinf(double x);
int isnan(double x);
#endif
-13
View File
@@ -1,13 +0,0 @@
#ifndef _SETJMP_H
#define _SETJMP_H
typedef struct {
void* _bp; // Base pointer
void* _sp; // Stack pointer
void* _pc; // Program counter
} jmp_buf;
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int value);
#endif
-10
View File
@@ -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

Some files were not shown because too many files have changed in this diff Show More