├── .github
└── workflows
│ └── Build example.yml
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── arch
├── Makefile
└── x86_64
│ ├── arch_configurations.hpp
│ ├── arch_configurations.ld
│ ├── build_kernel.mk
│ ├── include
│ └── architecture_limit.hpp
│ ├── linker.ld
│ └── src
│ ├── debugout_0xb8000.cpp
│ └── entry.asm
├── configurations.mk
├── docs
├── ARCHITECTURE.md
├── CONTRIBUTING.md
├── Compile Process.md
├── framework
│ └── Debug System.md
└── img
│ ├── Architecture.png
│ ├── GitBranch.png
│ └── Logo.png
├── examples
└── x86_64
│ └── HelloWorld
│ └── main.cpp
├── framework.mk
├── global_variables.mk
├── kernel
├── Makefile
├── include
│ ├── configuration.hpp
│ ├── fosd
│ │ ├── debug.hpp
│ │ └── types.hpp
│ └── string.hpp
└── src
│ ├── debug.cpp
│ ├── kernel_init.cpp
│ └── string
│ ├── string.cpp
│ └── vsprintf.cpp
└── loader
├── build_common.mk
└── x86_64
└── img
├── Makefile
├── bootloader.asm
├── imgmaker
├── imgmaker.c
├── include
├── basicstring.h
└── intel_paging.h
├── linker.ld
└── src
├── basicstring.c
├── entry.asm
├── intel_paging.c
├── longmode.asm
└── main.c
/.github/workflows/Build example.yml:
--------------------------------------------------------------------------------
1 | name: C/C++ CI
2 |
3 | on:
4 | push:
5 | branches: [ "main" ]
6 | pull_request:
7 | branches: [ "main" ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v4
16 | - name: Install
17 | run: sudo apt install nasm
18 | - name: Build
19 | run: make all
20 | - uses: actions/upload-artifact@v3
21 | with:
22 | name: Output
23 | path: output
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | test_*.cpp
2 | *.obj
3 | bin/
4 | OS.*
5 | *.code-workspace
6 | debug.log
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | include ./global_variables.mk
2 | include ./configurations.mk
3 |
4 | BINARYFOLDER = ./$(ROOTBINARYFOLDER)/$(USERBINARYFOLDER)
5 |
6 | INCLUDEPATHS = . ./$(ARCHFOLDER)/$(ARCH)/$(COMMON_HEADERFOLDER) \
7 | ./$(KERNELFOLDER)/$(COMMON_HEADERFOLDER) \
8 | ./$(ARCH_CONFIGURATION_FILE_LOC) \
9 | $(USER_INCLUDEPATH) \
10 |
11 | # Compile targets for user sources
12 | MAINTARGETS = $(subst .cpp,.obj,$(wildcard $(USER_SOURCESPATH)/*.cpp) $(wildcard $(USER_SOURCESPATH)/*/*.cpp))
13 | ASMTARGETS = $(subst .asm,.aobj,$(wildcard $(USER_SOURCESPATH)/*.asm))
14 |
15 | all: prepare build_user build_os
16 |
17 | clean:
18 | rm -rf $(BINARYFOLDER)
19 | make -f framework.mk clean
20 |
21 | prepare:
22 | mkdir -p $(BINARYFOLDER)
23 | make -f framework.mk build_framework
24 |
25 |
26 | build_user: $(ASMTARGETS) $(MAINTARGETS)
27 |
28 | build_os: # finally build kernel and loader
29 | make -f framework.mk build_kernel build_loader
30 |
31 | %.obj: %.cpp
32 | $(KERNEL_CC) $(KERNEL_CCOPTIONS) -c $< -o $(subst $(USER_SOURCESPATH),$(BINARYFOLDER),$@) $(KERNEL_CCOPTIONS)\
33 | $(addprefix -I,$(INCLUDEPATHS))
34 |
35 | %.aobj: %.asm
36 | $(KERNEL_AS) $< -o $(subst $(USER_SOURCESFOLDER),$(BINARYFOLDER),$@) $(KERNEL_ASOPTIONS)
37 |
38 | run:
39 | make -C $(LOADERFOLDER)/$(ARCH)/$(IMAGE) run_os ROOTDIR=$(PWD)
40 |
41 | .PHONY: clean all
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Framework Of Operating System Development
7 |
8 |
9 | ---
10 |
11 | FOSD is an innovative and **flexible framework for operating system development**.
12 |
13 | It provides tools and resources that help developers efficiently and effectively design, develop, and deploy operating systems.
14 |
15 | With its modular structure and user-friendly interface, FOSD offers an environment suitable for developers of all levels.
16 |
17 | ## Key Features
18 |
19 | * **Modular design** supporting various operating system architectures.
20 | * **Component-based structure** that is easily extendable as needed.
21 | * **Maximizes code** reusability to reduce development time.
22 | * Provides **optimized build systems and debugging tools**.
23 |
24 | ## Key Components
25 |
26 | * **Core Modules:** Essential modules that provide fundamental operating system functions.
27 | * **Extension Libraries:** Libraries for additional features and extensibility.
28 | * **Development Tools:** Integrated Development Environment (IDE), debuggers, performance analysis tools, etc.
29 | * **Documentation & Tutorials:** Detailed documentation and step-by-step tutorials.
30 |
--------------------------------------------------------------------------------
/arch/Makefile:
--------------------------------------------------------------------------------
1 | # ROOTDIR variable is passed by the makefile
2 |
3 | include $(ROOTDIR)/configurations.mk
4 | include $(ROOTDIR)/global_variables.mk
5 |
6 | BINARYFOLDER = $(ROOTDIR)/$(ROOTBINARYFOLDER)/$(KERNELBINARYFOLDER)
7 |
8 | MAINTARGETS = $(subst .cpp,.obj,$(wildcard $(ARCH)/$(COMMON_SOURCEFOLDER)/*.cpp) $(wildcard $(ARCH)/$(COMMON_SOURCEFOLDER)/*/*.cpp))
9 | ASMTARGETS = $(subst .asm,.aobj,$(wildcard $(ARCH)/$(COMMON_SOURCEFOLDER)/*.asm))
10 | SUBDIRECTORIES = $(subst $(COMMON_SOURCEFOLDER),$(BINARYFOLDER),$(sort $(dir $(wildcard $(COMMON_SOURCEFOLDER)/*/))))
11 |
12 | INCLUDEPATHS = ../$(KERNELFOLDER)/$(COMMON_HEADERFOLDER) \
13 | $(ARCH)/$(COMMON_HEADERFOLDER) \
14 | ../$(ARCH_CONFIGURATION_FILE_LOC)
15 |
16 | all: prepare $(ASMTARGETS) $(MAINTARGETS)
17 |
18 | prepare:
19 | mkdir -p $(BINARYFOLDER)
20 | ifneq "$(SUBDIRECTORIES)" ""
21 | mkdir -p $(SUBDIRECTORIES)
22 | endif
23 |
24 | clean:
25 | rm -rf $(BINARYFOLDER)
26 |
27 | %.obj: %.cpp
28 | $(KERNEL_CC) $(KERNEL_CCOPTIONS) -c $< -o $(subst $(ARCH)/$(COMMON_SOURCEFOLDER),$(BINARYFOLDER),$@) $(KERNEL_CCOPTIONS)\
29 | $(addprefix -I,$(INCLUDEPATHS))
30 |
31 | %.aobj: %.asm
32 | $(KERNEL_AS) $< -o $(subst $(ARCH)/$(COMMON_SOURCEFOLDER),$(BINARYFOLDER),$@) $(KERNEL_ASOPTIONS)
33 |
34 | .PHONY: clean all
35 |
--------------------------------------------------------------------------------
/arch/x86_64/arch_configurations.hpp:
--------------------------------------------------------------------------------
1 | // Global architecture-specific configurations for both kernel and loader.
2 |
3 | #ifndef _ARCH_CONFIGURATIONS_HPP_
4 | #define _ARCH_CONFIGURATIONS_HPP_
5 |
6 | #define KERNEL_LOAD_LOCATION 0x200000
7 |
8 | #ifdef LINKER_SCRIPT
9 |
10 | _KERNEL_LOAD_LOCATION = KERNEL_LOAD_LOCATION;
11 |
12 | #endif
13 |
14 | #endif
--------------------------------------------------------------------------------
/arch/x86_64/arch_configurations.ld:
--------------------------------------------------------------------------------
1 | _KERNEL_LOAD_LOCATION = 0x200000;
2 |
--------------------------------------------------------------------------------
/arch/x86_64/build_kernel.mk:
--------------------------------------------------------------------------------
1 | # build_kernel : Architecture-dependent part of compiling the final kernel image from the previously compiled object files
2 | # objects are passed by the variable TARGET_OBJECTS, and the resulting file name of the kernel image is also passed by the variable KERNEL_ELF KERNEL_IMG.
3 | # Location of the library and the lists of the required library options are passed to the argument as the variable LIBRARYFOLDER and LIBRARY_OPTIONS, respectively.
4 | # ROOTDIR is also passed to the argument
5 |
6 | include $(ROOTDIR)/configurations.mk
7 | include $(ROOTDIR)/global_variables.mk
8 |
9 | ARCH_CONFIGURATION_LINKER_HEADER = $(ARCH_CONFIGURATION_FILE_LOC)/$(ARCH_CONFIGURATION_FILE)
10 |
11 | build_kernel:
12 | # convert the architecture configuration macros to the linker script
13 | $(call convert_hpp_to_ld,$(ARCHFOLDER)/$(ARCH)/$(KERNEL_LINKERSCRIPT),$(ARCH_CONFIGURATION_LINKER_HEADER))
14 |
15 | $(KERNEL_LD) $(KERNEL_LDOPTIONS) -L $(ARCH_CONFIGURATION_FILE_LOC) -T $(ARCHFOLDER)/$(ARCH)/$(KERNEL_LINKERSCRIPT) $(TARGET_OBJECTS) -o $(KERNEL_ELF)
16 | $(KERNEL_OBJCOPY) -O binary $(KERNEL_ELF) $(KERNEL_IMG)
17 |
--------------------------------------------------------------------------------
/arch/x86_64/include/architecture_limit.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _ARCHITECTURE_LIMIT_HPP_
2 | #define _ARCHITECTURE_LIMIT_HPP_
3 |
4 | #include
5 |
6 | #define WORD_SIZE 64
7 | #define ARCH_STRING "x86_64"
8 |
9 | #endif
--------------------------------------------------------------------------------
/arch/x86_64/linker.ld:
--------------------------------------------------------------------------------
1 | OUTPUT_FORMAT(elf64-x86-64)
2 | ENTRY(entry)
3 |
4 | INCLUDE arch_configurations.ld
5 |
6 | SECTIONS {
7 | . = _KERNEL_LOAD_LOCATION;
8 | .entry _KERNEL_LOAD_LOCATION : {
9 | *(.entry)
10 | }
11 | .text : {
12 | *(.text .text.*)
13 | }
14 | .data : {
15 | *(.data .data.*)
16 | }
17 | .rodata : {
18 | *(.rodata .rodata.*)
19 | }
20 | .rodata1 : {
21 | *(.rodata1)
22 | }
23 | .bss : {
24 | *(.bss .bss.*)
25 | }
26 | }
--------------------------------------------------------------------------------
/arch/x86_64/src/debugout_0xb8000.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | static struct TextScreenInformation {
4 | unsigned char *vmem;
5 | int width;
6 | int height;
7 | debug_color_t color_background;
8 | debug_color_t color_foreground;
9 | int x;
10 | int y;
11 | }scrinfo;
12 |
13 | void debug::out::init(void) {
14 | scrinfo.vmem = (unsigned char *)0xB8000;
15 | scrinfo.width = 80;
16 | scrinfo.height = 25;
17 | scrinfo.color_background = 0x00;
18 | scrinfo.color_foreground = 0x07;
19 | }
20 |
21 | void debug::out::clear_screen(debug_color_t color) {
22 | unsigned char *vmem = (unsigned char *)scrinfo.vmem;
23 | for(int i = 0; i < scrinfo.width*scrinfo.height*2; i += 2) {
24 | vmem[i] = 0x00;
25 | vmem[i+1] = color;
26 | }
27 | set_position(0 , 0);
28 | }
29 |
30 | debug_color_t debug::out::debugcolor(debug_mode_t mode) {
31 | switch(mode) {
32 | case DEBUG_NONE: return 0x07;
33 | case DEBUG_TEXT: return 0x07;
34 | case DEBUG_INFO: return 0x03;
35 | case DEBUG_SPECIAL: return 0x02;
36 | case DEBUG_ERROR: return 0x04;
37 | case DEBUG_PANIC: return 0x04;
38 | case DEBUG_WARNING: return 0x06;
39 | case DEBUG_RAW_PRINT: return 0x07;
40 | }
41 | return 0x07;
42 | }
43 |
44 | static void process_newline(void) {
45 | if(scrinfo.y > 24) { // fix scrolling problem
46 | int x = 0 , y = 0;
47 | int elev = 1;
48 | for(y = 0; y < scrinfo.height-elev; y++) {
49 | for(x = 0; x < scrinfo.width; x++) {
50 | scrinfo.vmem[(y*scrinfo.width+x)*2] = scrinfo.vmem[((y+elev)*scrinfo.width+x)*2];
51 | scrinfo.vmem[(y*scrinfo.width+x)*2+1] = scrinfo.vmem[((y+elev)*scrinfo.width+x)*2+1];
52 | }
53 | }
54 | for(int y = scrinfo.height-elev; y < scrinfo.height; y++) {
55 | for(x = 0; x < scrinfo.width; x++) {
56 | scrinfo.vmem[(y*scrinfo.width+x)*2] = 0x00;
57 | scrinfo.vmem[(y*scrinfo.width+x)*2+1] = scrinfo.color_background;
58 | }
59 | }
60 | scrinfo.y = 24;
61 | }
62 | }
63 |
64 | void debug::out::print_str(const char *str) {
65 | int off;
66 | for(int i = 0; str[i] != 0; i++) {
67 | off = (scrinfo.y*scrinfo.width*2)+scrinfo.x*2;
68 | switch(str[i]) {
69 | case '\n':
70 | scrinfo.x = 0;
71 | scrinfo.y++;
72 | process_newline();
73 | break;
74 | case '\b':
75 | scrinfo.x -= 1;
76 | if(scrinfo.x < 0) {
77 | scrinfo.x = 0;
78 | }
79 | scrinfo.vmem[(scrinfo.y*scrinfo.width*2)+scrinfo.x*2] = 0x00;
80 | break;
81 | case '\r':
82 | scrinfo.x = 0;
83 | break;
84 | case '\t':
85 | scrinfo.x += 5;
86 | break;
87 | default:
88 | scrinfo.vmem[off] = str[i];
89 | scrinfo.vmem[off+1] = (scrinfo.color_background << 4)|scrinfo.color_foreground;
90 | scrinfo.x++;
91 | if(scrinfo.x > 79) {
92 | scrinfo.x = 0;
93 | scrinfo.y++;
94 | }
95 | process_newline();
96 | break;
97 | }
98 | }
99 | }
100 |
101 |
102 | void debug::out::set_position(int x , int y) {
103 | scrinfo.x = x;
104 | scrinfo.y = y;
105 | }
106 |
107 | void debug::out::move_position(int x , int y) {
108 | scrinfo.x += x;
109 | scrinfo.y += y;
110 | if(scrinfo.x < 0) {
111 | scrinfo.x = 0;
112 | }
113 | if(scrinfo.y < 0) {
114 | scrinfo.y = 0;
115 | }
116 | if(scrinfo.x >= scrinfo.width-1) {
117 | scrinfo.x = scrinfo.width-1;
118 | }
119 | if(scrinfo.y >= scrinfo.height-1) {
120 | scrinfo.y = scrinfo.height-1;
121 | }
122 | }
123 |
124 | void debug::out::get_scr_info(int &x , int &y , debug_color_t &background_color , debug_color_t &foreground_color) {
125 | x = scrinfo.x;
126 | x = scrinfo.y;
127 | background_color = scrinfo.color_background;
128 | foreground_color = scrinfo.color_foreground;
129 | }
130 |
131 | void debug::out::set_background_color(debug_color_t background_color) {
132 | scrinfo.color_background = background_color;
133 | }
134 |
135 | void debug::out::set_foreground_color(debug_color_t foreground_color) {
136 | scrinfo.color_foreground = foreground_color;
137 | }
--------------------------------------------------------------------------------
/arch/x86_64/src/entry.asm:
--------------------------------------------------------------------------------
1 | [BITS 64]
2 |
3 | SECTION .entry
4 |
5 | extern kernel_init
6 | global entry
7 |
8 | entry:
9 | mov ax , 0x10
10 | mov ds , ax
11 | mov es , ax
12 | mov fs , ax
13 | mov gs , ax
14 | mov ss , ax
15 |
16 | ; Temporary stack
17 | mov rbp , 0x4FFFF8
18 | mov rsp , 0x4FFFF8
19 |
20 | call kernel_init
21 |
22 | jmp $
--------------------------------------------------------------------------------
/configurations.mk:
--------------------------------------------------------------------------------
1 | ARCH = x86_64
2 | IMAGE = img
3 |
4 | KERNEL_COMPILER =
5 | KERNEL_CCOPTIONS = -m64 -ffreestanding -nostdlib -mcmodel=large \
6 | -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 \
7 | -fpack-struct=1 -masm=intel \
8 | -Werror=return-type -fno-stack-protector \
9 | -fno-use-cxa-atexit -fno-threadsafe-statics \
10 | -fno-rtti -fno-exceptions -fno-leading-underscore -Wno-write-strings
11 | KERNEL_LINKERSCRIPT = linker.ld
12 | KERNEL_LDOPTIONS = -m elf_x86_64 -nostdlib
13 |
14 | KERNEL_ASOPTIONS = -f elf64
15 |
16 | USER_SOURCESPATH = examples/x86_64/HelloWorld
17 | USER_INCLUDEPATH =
18 |
19 | OUTPUT_FILENAME = OS
20 |
21 | # compiler settings
22 |
23 | AS = nasm
24 | CC = g++
25 | LD = ld
26 | OBJDUMP = objdump
27 | OBJCOPY = objcopy
28 |
--------------------------------------------------------------------------------
/docs/ARCHITECTURE.md:
--------------------------------------------------------------------------------
1 | # FOSD Architecture
2 |
3 | This document pertains to the software architecture design of the FOSD project. It will be highly beneficial to have a foundational understanding of this document before contributing to the FOSD project or analyzing its source code.
4 |
5 | 
6 |
7 | From a software design perspective, the architecture of FOSD has been designed to **enhance extensibility and flexibility within the framework**. Overall, it increases extensibility by appropriately integrating **Plug-in Architecture and Feature-Based Architecture**.
8 |
9 | Following the design of the Plug-in Architecture, **the Core, which is positioned accordingly, follows a Component-Based Architecture** and includes the Kernel and BootLoader.
10 |
11 | Recursively, **each component further emulates the overall Plug-in Architecture structure**, allowing it to handle **various system architectures beyond x86-64, such as RISC-V**.
--------------------------------------------------------------------------------
/docs/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | When contributing to this repository, please first discuss the change you wish to make via issue,
4 | email, or any other method with the owners of this repository before making a change.
5 |
6 | ## Our Git Branch Strategy
7 |
8 | 
9 |
--------------------------------------------------------------------------------
/docs/Compile Process.md:
--------------------------------------------------------------------------------
1 | # The FOSD Framework Specification: The Compile Process
2 | ## Overview
3 | The framework consists of two main parts: the **Kernel Image** and the **Loader**. The kernel image is compiled with the **core kernel sources**(located in "kernel" folder), **architecture-dependent sources**(located in "arch" folder), and **user-side sources**(located in the root directory of the project.) All the sources(sources of kernel, architecture and user) are all compiled into object files, and all those objects are linked into one kernel image using the linker script. Finally, the kernel loader is compiled and combined with the compiled kernel image, creating the final operating system image.
4 |
5 | The architecture, the compiler and the file type of the final operating system image are all customizable by **configuration makefile(configurations.mk)**, which contains variables that can be customized by user.
6 |
7 | ## The Structure of the Project
8 | ```
9 | FOSD(Project Root Directory)/
10 | ├── framework/
11 | │ ├── arch/
12 | │ │ ├── arch-1/
13 | │ │ │ ├── include
14 | │ │ │ ├── src
15 | │ │ │ ├── build_kernel.mk
16 | │ │ │ └── linker.ld
17 | │ │ ├── arch-2
18 | │ │ └── ...
19 | │ ├── kernel/
20 | │ │ ├── include
21 | │ │ ├── src
22 | │ │ └── Makefile
23 | │ ├── loader/
24 | │ │ ├── arch-1/
25 | │ │ │ ├── file-type-1/
26 | │ │ │ │ ├── include
27 | │ │ │ │ ├── src
28 | │ │ │ │ └── Makefile
29 | │ │ │ ├── file-type-2
30 | │ │ │ └── ...
31 | │ │ ├── arch-2
32 | │ │ ├── ...
33 | │ │ └── build_common.mk
34 | │ ├── configurations.mk
35 | │ ├── framework.mk
36 | │ ├── global_variables.mk
37 | │ └── Makefile
38 | ├── [user source files]
39 | └── Makefile
40 | ```
41 | The framework consists of big three parts: **arch**, **kernel**, and **loader**. The "arch" folder contains the architecture-dependent parts of the kernel of the framework, and "kernel" folder contains the core parts of the framework kernel. The "loader" folder contains the source for kernel loader, which is in charge of compiling both the kernel loader and the final operating system image.
42 | ### 1. The Main Kernel Folder
43 | The "kernel" folder contains the core parts of the framework's kernel. Using the Makefile on the "kernel" folder, the sources and headers are automatically compiled into the objects, according to the compile options defined on the configuration file.
44 | ### 2. The Architecture Folder
45 | The architecture folder contains the folders for each architecture. Each folder contains the corresponding architecture's architecturally dependent part of the kernel.
46 |
47 | Following is the structure of the architecture folder :
48 | ```
49 | arch/
50 | └── [architecture name]/
51 | ├── include/
52 | │ └── header files
53 | ├── src/
54 | │ └── source files
55 | ├── build_kernel.mk
56 | └── linker.ld (optional)
57 | ```
58 | Each architecture folder must contain "build_kernel.mk" makefile that is used for building the final kernel image from the object files. No additional makefile is required, as the makefile system automatically detects the source files on the "src" folder and compiles into the object files.
59 | ### 3. The Loader Folder
60 | The loader folder contains sources of each architecture's loaders. In each architecture folder loaders corresponding to its designated file type are contained on each individual folder.
61 |
62 | Following is the structure of the loader folder :
63 | ```
64 | loader/
65 | ├── [architecture XXX]/
66 | │ ├── [file type aaa]/
67 | │ │ ├── include
68 | │ │ ├── src
69 | │ │ └── Makefile
70 | │ └── [file type bbb]/
71 | │ ├── include
72 | │ ├── src
73 | │ └── Makefile
74 | ├── [architecture YYY]/
75 | │ ├── [file type aaa]/
76 | │ │ ├── ...
77 | │ │ └── Makefile
78 | │ └── [file type bbb]/
79 | │ ├── ...
80 | │ └── Makefile
81 | └── build_common.mk
82 | ```
83 | The compile process of the loader is highly flexible, unlike the compilation of kernel or architecture having an automated compilation of the source files. The compile process of the loader depends mostly on the individual makefile.
84 | ## The Overview of the Makefile Process
85 | The making process of the operating system follows :
86 | 1. **Compile the user-made sources** : The user-made sources in the user directory are compiled into object files.
87 | 2. **Compile the kernel sources** : The source files on the kernel and architecture folder are compiled.
88 | 3. **Link all the objects** : All the objects(user,kernel and architecture) are linked using the (architecture-dependent) linker script. (The process uses "build_kernel.mk" file to link the kernel image)
89 | 4. **Compile the loader sources** : The sources of the loader are compiled.
90 | 5. **Combine the loader and the kernel image** : The compiled loader and the kernel image are combined into the final operating system image.
91 |
92 | ### The Configuration Variables
93 | The makefile build system is designed to be customized by the makefile variables defined in the configuration files. All the configuration variables must be defined in "configurations.mk" file on the framework directory.
94 |
95 | Following variables are designated to be customized by the user :
96 | * **ARCH** : Target operating system architecture
97 | * **IMAGE** : Target operating system image
98 | * **KERNEL_COMPILER** : Cross compiler for kernel
99 | * **KERNEL_CCOPTIONS** : Compiler options for g++(or gcc)
100 | * **KERNEL_LDOPTIONS** : Compiler options for the linker
101 | * **KERNEL_ASOPTIONS** : Compiler options for the assembler
102 | * **KERNEL_LINKERSCRIPT** : The linker script file name
103 | * **USER_SOURCESPATH** : Directory location of user's sources
104 | * **USER_INCLUDEPATH** : Directory location of user's includepaths
105 |
106 | The **"ARCH"** variable points to the architecture folder to be compiled in the "arch" folder. Similarly, the **"IMAGE"** variable points to the loader folder to be compiled in the loader's architecture folder.
107 |
108 | Following is an example of "configurations.mk" file :
109 | ```makefile
110 | ARCH = x86_64
111 | IMAGE = iso
112 |
113 | KERNEL_COMPILER = x86_64-elf
114 | KERNEL_CCOPTIONS = -m64 -ffreestanding -nostdlib -mcmodel=large \
115 | -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 \
116 | -fpack-struct=1 -masm=intel ...
117 | KERNEL_LINKERSCRIPT = linker.ld
118 | KERNEL_LDOPTIONS = -m elf_x86_64 -nostdlib
119 |
120 | # The directory to the user's sources and include from the root project directory
121 | USER_SOURCESPATH = ...
122 | USER_INCLUDEPATH = ...
123 | ...
124 | ```
125 | ### Detailed Compile Process of the Framework
126 | ### 1. The Compiling Process of Kernel
127 | #### The "framework.mk" Makefile
128 | The compiling of the operating system can be initiated by the [**"framework.mk"**](https://github.com/fosd-project/FOSD/blob/core/framework/framework.mk) Makefile. The "framework.mk" first compiles the user's source codes and then the full operating system combined with the framework sources.
129 |
130 | "framework.mk" consists of following sections:
131 | - **clean** : Clean all the object files and target operating system image
132 | - **all** : Compile the full operating system
133 | - **build_os** : Only compile the framework, not the user's sources
134 |
135 |
136 | "framework.mk" file uses the [Makefile located on the framework root directory](https://github.com/fosd-project/FOSD/blob/core/framework/Makefile) to build the framework's kernel and loader.
137 | #### The Central Makefile of the Framework
138 | [The central makefile of the framework](https://github.com/fosd-project/FOSD/blob/core/framework/Makefile) reads the configuration variables from the **configurations.mk** and compiles the operating system according to the variables. The makefile sequentially compiles architecture and kernel and builds the kernel image using **the "build_kernel.mk" makefile.** The makefile then initiates the compilation of the loader, synthesizing the final operating system image.
139 |
140 | #### The "build_kernel.mk" Makefile
141 | As the method of building the final kernel image from the C/C++ objects are dependent to the architecture, **build_kernel.mk** is created to account for the difference in the method. Each architecture must contain "build_kernel.mk" that describes the linking method.
142 |
143 | Following is the convention of the "build_kernel.mk" :
144 | ```makefile
145 | include $(ROOTDIR)/configurations.mk
146 | include $(ROOTDIR)/global_variables.mk
147 |
148 | build_kernel:
149 | [commands for building the kernel image from compiled objects]
150 | ```
151 | The commands for linking the kernel objects must be implemented on the "build_kernel" section of the makefile.
152 |
153 | Following is the list of several variables passed onto the "build_kernel.mk" makefile :
154 | - **TARGET_OBJECTS** : Object files that are to be linked
155 | - **KERNEL_ELF** : The target ELF file of the kernel image
156 | - **KERNEL_IMG** : The final target kernel image
157 |
158 | "build_kernel.mk" must compile the objects passed onto the pre-declared variable into the final kernel image, also its path passed onto the variable.
159 |
160 | (An example of "build_kernel.mk" implementation on x86_64 architecture : )
161 | ```makefile
162 | include $(ROOTDIR)/configurations.mk
163 | include $(ROOTDIR)/global_variables.mk
164 |
165 | build_kernel:
166 | x86_64-elf-ld $(KERNEL_LDOPTIONS)
167 | -T $(ARCHFOLDER)/$(ARCH)/$(KERNEL_LINKERSCRIPT) $(TARGET_OBJECTS)
168 | -o $(KERNEL_ELF)
169 | x86_64-elf-objcopy -O binary $(KERNEL_ELF) $(KERNEL_IMG)
170 | ```
171 | ### 2. The Compiling Process of the OS Image(and Loader)
172 |
--------------------------------------------------------------------------------
/docs/framework/Debug System.md:
--------------------------------------------------------------------------------
1 | # The FOSD Framework Specification: The Debug System (debug.hpp)
2 |
3 | coming soon
--------------------------------------------------------------------------------
/docs/img/Architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fosd-project/FOSD/8daa0134ce7c0bc8c2fefd62a5b7d07c5339a3f9/docs/img/Architecture.png
--------------------------------------------------------------------------------
/docs/img/GitBranch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fosd-project/FOSD/8daa0134ce7c0bc8c2fefd62a5b7d07c5339a3f9/docs/img/GitBranch.png
--------------------------------------------------------------------------------
/docs/img/Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fosd-project/FOSD/8daa0134ce7c0bc8c2fefd62a5b7d07c5339a3f9/docs/img/Logo.png
--------------------------------------------------------------------------------
/examples/x86_64/HelloWorld/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(int argc , char **argv) {
4 | debug::out::printf("Hello, world!\n");
5 | return 0;
6 | }
--------------------------------------------------------------------------------
/framework.mk:
--------------------------------------------------------------------------------
1 | include configurations.mk
2 | include global_variables.mk
3 |
4 | BASH = bash
5 | ROOTDIR = $(PWD)
6 |
7 | MAKEFILE_ARGUMENTS = ROOTDIR=$(PWD)
8 | KERNEL_TARGET_OBJECTS = $(wildcard $(ROOTBINARYFOLDER)/$(KERNELBINARYFOLDER)/*.*) \
9 | $(wildcard $(ROOTBINARYFOLDER)/$(KERNELBINARYFOLDER)/*/*.*) # for nested objects
10 | USER_TARGET_OBJECTS = $(wildcard $(ROOTBINARYFOLDER)/$(USERBINARYFOLDER)/*.*) \
11 | $(wildcard $(ROOTBINARYFOLDER)/$(USERBINARYFOLDER)/*/*.*)
12 |
13 | prepare:
14 | @echo "$(shell tput bold)Preparing the directory structure..$(shell tput sgr0)"
15 | mkdir -p $(ROOTBINARYFOLDER)/$(LOADERFOLDER)/$(ARCH)/$(IMAGE)
16 |
17 | remove_binaries:
18 | rm -rf $(ROOTBINARYFOLDER)/*
19 |
20 | clean: remove_binaries
21 | @echo "$(shell tput bold)Cleaning the files..$(shell tput sgr0)"
22 |
23 | for build_dir in $(BUILD_TARGET_FOLDERS); do\
24 | make -C $$build_dir clean $(MAKEFILE_ARGUMENTS); \
25 | done
26 | make -C $(LOADERFOLDER)/$(ARCH)/$(IMAGE) clean $(MAKEFILE_ARGUMENTS) TARGET_DIR=./output/$(ARCH)/$(IMAGE)
27 |
28 | all: prepare build_all_directories build_kernel build_loader
29 | build_framework: prepare build_all_directories
30 |
31 | build_all_directories:
32 | @echo "$(shell tput bold)Building the kernel sources...$(shell tput sgr0)"
33 | for build_dir in $(BUILD_TARGET_FOLDERS); do\
34 | make -C $$build_dir all $(MAKEFILE_ARGUMENTS); \
35 | done
36 |
37 | # Assume that the user objects are all compiled
38 | build_kernel:
39 | @echo "$(shell tput bold)Building the kernel image...$(shell tput sgr0)"
40 | make -f $(ARCHFOLDER)/$(ARCH)/$(BUILD_KERNEL_IMG_MAKEFILE) build_kernel ROOTDIR=$(PWD) TARGET_OBJECTS="$(KERNEL_TARGET_OBJECTS) $(USER_TARGET_OBJECTS)"\
41 | LIBRARYFOLDER="." KERNEL_ELF=$(ROOTBINARYFOLDER)/$(KERNEL_ELF) KERNEL_IMG=$(ROOTBINARYFOLDER)/$(KERNEL_IMG)
42 |
43 | build_loader:
44 | @echo "$(shell tput bold)Building the final image...$(shell tput sgr0)"
45 | mkdir $(ROOTDIR)/output/$(ARCH)/$(IMAGE) -p
46 | make -C $(LOADERFOLDER)/$(ARCH)/$(IMAGE) all $(MAKEFILE_ARGUMENTS) TARGET_DIR=$(ROOTDIR)/output/$(ARCH)/$(IMAGE) KERNEL_IMG=$(ROOTDIR)/$(ROOTBINARYFOLDER)/$(KERNEL_IMG) KERNEL_ELF=$(ROOTDIR)/$(ROOTBINARYFOLDER)/$(KERNEL_ELF)
47 |
48 | .PHONY: clean all
--------------------------------------------------------------------------------
/global_variables.mk:
--------------------------------------------------------------------------------
1 | BUILD_TARGET_FOLDERS = arch kernel
2 |
3 | COMMON_SOURCEFOLDER = src
4 | COMMON_HEADERFOLDER = include
5 |
6 | ARCHFOLDER = arch
7 | KERNELFOLDER = kernel
8 | LOADERFOLDER = loader
9 | ROOTBINARYFOLDER = bin
10 | KERNELBINARYFOLDER = kernel_objs
11 | USERBINARYFOLDER = user_objs
12 |
13 | BUILD_KERNEL_IMG_MAKEFILE = build_kernel.mk
14 |
15 | KERNEL_ELF = Kernel
16 | KERNEL_IMG = Kernel.bin
17 |
18 | KERNEL_AS = $(AS)
19 | KERNEL_CC = $(KERNEL_COMPILER)-$(CC)
20 | KERNEL_LD = $(KERNEL_COMPILER)-$(LD)
21 | KERNEL_OBJDUMP = $(KERNEL_COMPILER)-$(OBJDUMP)
22 | KERNEL_OBJCOPY = $(KERNEL_COMPILER)-$(OBJCOPY)
23 |
24 | # commonly used things
25 |
26 | PWD = $(shell pwd)
27 | ARCH_CONFIGURATION_FILE_LOC = $(ARCHFOLDER)/$(ARCH)
28 | ARCH_CONFIGURATION_FILE = arch_configurations.hpp
29 |
30 | define convert_hpp_to_ld
31 | echo \#include \"$(notdir $(2))\" > $(dir $(2))dummy.ld
32 | $(KERNEL_CC) -E -P -xc -DLINKER_SCRIPT $(dir $(2))dummy.ld > $(subst .hpp,.ld,$(2))
33 | rm $(dir $(2))dummy.ld
34 | endef
--------------------------------------------------------------------------------
/kernel/Makefile:
--------------------------------------------------------------------------------
1 | # ROOTDIR is passed by the argument
2 | ifndef ROOTDIR
3 | echo "rootdir not specified!"
4 | endif
5 |
6 | include $(ROOTDIR)/configurations.mk
7 | include $(ROOTDIR)/global_variables.mk
8 |
9 | BINARYFOLDER = $(ROOTDIR)/$(ROOTBINARYFOLDER)
10 | MAINBINARYFOLDER = $(BINARYFOLDER)/$(KERNELBINARYFOLDER)
11 |
12 | MAINTARGETS = $(subst .cpp,.obj,$(wildcard $(COMMON_SOURCEFOLDER)/*.cpp) $(wildcard $(COMMON_SOURCEFOLDER)/*/*.cpp))
13 | ASMTARGETS = $(subst .asm,.aobj,$(wildcard $(COMMON_SOURCEFOLDER)/*.asm))
14 | SUBDIRECTORIES = $(subst $(COMMON_SOURCEFOLDER),$(MAINBINARYFOLDER),$(sort $(dir $(wildcard $(COMMON_SOURCEFOLDER)/*/))))
15 | INCLUDEPATHS = $(ROOTDIR)/$(ARCHFOLDER)/$(ARCH)/$(COMMON_HEADERFOLDER) \
16 | $(COMMON_HEADERFOLDER) \
17 | ../$(ARCH_CONFIGURATION_FILE_LOC)
18 |
19 | all: prepare $(ASMTARGETS) $(MAINTARGETS)
20 |
21 | prepare:
22 | mkdir -p $(MAINBINARYFOLDER)
23 | ifneq "$(SUBDIRECTORIES)" ""
24 | mkdir -p $(SUBDIRECTORIES)
25 | endif
26 |
27 | clean:
28 | rm -rf $(MAINBINARYFOLDER)
29 |
30 | %.obj: %.cpp
31 | $(KERNEL_CC) -c $< -o $(subst $(COMMON_SOURCEFOLDER),$(MAINBINARYFOLDER),$@) $(KERNEL_CCOPTIONS)\
32 | $(addprefix -I,$(INCLUDEPATHS))
33 |
34 | %.aobj: %.asm
35 | $(KERNEL_AS) $< -o $(subst $(COMMON_SOURCEFOLDER),$(MAINBINARYFOLDER),$@) $(KERNEL_ASOPTIONS)
36 |
37 | .PHONY: clean all
--------------------------------------------------------------------------------
/kernel/include/configuration.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _CONFIGURATION_HPP_
2 | #define _CONFIGURATION_HPP_
3 |
4 |
5 |
6 | #endif
--------------------------------------------------------------------------------
/kernel/include/fosd/debug.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * The FOSD Debugging System
3 | * Check out document for
4 | */
5 |
6 | #ifndef _DEBUG_HPP_
7 | #define _DEBUG_HPP_
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | #define DEBUG_NONE 0b00000001
14 | #define DEBUG_TEXT 0b00000010 // white
15 | #define DEBUG_INFO 0b00000100 // blue
16 | #define DEBUG_SPECIAL 0b00001000 // light green
17 | #define DEBUG_WARNING 0b00010000 // yellow
18 | #define DEBUG_ERROR 0b00100000 // red
19 | #define DEBUG_PANIC 0b01000000 // red
20 | #define DEBUG_RAW_PRINT 0b10000000 // raw
21 |
22 | #define DEBUG_OPTION_DISPLAY_INFO 0b0000001
23 |
24 | #define DISABLE_DEBUG_MSG debug::disable();
25 | #define ENABLE_DEBUG_MSG debug::enable();
26 |
27 | typedef uint16_t debug_mode_t;
28 | typedef uint32_t debug_color_t;
29 |
30 | namespace debug {
31 | namespace out {
32 | void vprintf(debug_mode_t mode , const char *fmt , va_list ap);
33 | void printf(debug_mode_t mode , const char *fmt , ...);
34 | void printf(const char *fmt , ...);
35 |
36 | void ARCHDEP init(void);
37 | void ARCHDEP clear_screen(debug_color_t color);
38 | void ARCHDEP print_str(const char *str);
39 |
40 | void ARCHDEP set_position(int x , int y);
41 | void ARCHDEP move_position(int relative_x , int relative_y);
42 | void ARCHDEP get_scr_info(int &x , int &y , debug_color_t &background_color , debug_color_t &foreground_color);
43 | uint8_t ARCHDEP get_char(int y , int x);
44 |
45 | void ARCHDEP set_background_color(debug_color_t background_color);
46 | void ARCHDEP set_foreground_color(debug_color_t foreground_color);
47 |
48 | debug_color_t ARCHDEP debugcolor(debug_mode_t mode);
49 | const char *ARCHDEP debugstr(debug_mode_t mode);
50 | }
51 | void init(void);
52 |
53 | void dump_memory(max_t address , max_t length , bool debug_string=false);
54 | void set_option(uint16_t option , bool flag);
55 | void display_set(uint16_t option);
56 | void display_mask(uint16_t option);
57 |
58 | void enable(void);
59 | void disable(void);
60 |
61 | void panic_line(const char *source , int line , const char *fmt , ...);
62 | void panic(const char *fmt , ...);
63 | void panic(void);
64 | }
65 |
66 | #endif
--------------------------------------------------------------------------------
/kernel/include/fosd/types.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _TYPES_HPP_
2 | #define _TYPES_HPP_
3 |
4 | #include
5 |
6 | typedef signed char int8_t;
7 | typedef short int16_t;
8 | typedef int int32_t;
9 | typedef long long int64_t;
10 | typedef unsigned char uint8_t;
11 | typedef unsigned short uint16_t;
12 | typedef unsigned int uint32_t;
13 | typedef unsigned long long uint64_t;
14 | typedef unsigned int size_t;
15 |
16 | #define UINT8_LIMIT 0xFF
17 | #define UINT16_LIMIT 0xFFFF
18 | #define UINT32_LIMIT 0xFFFFFFFF
19 | #define UINT64_LIMIT 0xFFFFFFFFFFFFFFFF
20 |
21 | #if WORD_SIZE == 64
22 | typedef uint64_t max_t;
23 | #define ARCH_LIMIT UINT64_LIMIT
24 | #elif WORD_SIZE == 32
25 | typedef uint32_t max_t;
26 | #define ARCH_LIMIT UINT32_LIMIT
27 | #elif WORD_SIZE == 16
28 | typedef uint16_t max_t;
29 | #define ARCH_LIMIT UINT16_LIMIT
30 | #elif WORD_SIZE == 8
31 | typedef uint8_t max_t;
32 | #define ARCH_LIMIT UINT8_LIMIT
33 | #endif
34 |
35 | #define INVALID ARCH_LIMIT
36 | // The indicator for functions that are architecture-dependent
37 | #define ARCHDEP
38 |
39 | /****** essential stuff ******/
40 | #define MIN(X , Y) ((X) >= (Y) ? (Y) : (X))
41 | #define MAX(X , Y) ((X) >= (Y) ? (X) : (Y))
42 | #define ABS(X) (((X) > 0) ? (X) : (-(X)))
43 |
44 | #endif
--------------------------------------------------------------------------------
/kernel/include/string.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _ESSENTIAL_LIBRARY_HPP_
2 | #define _ESSENTIAL_LIBRARY_HPP_
3 |
4 | #include
5 | #include
6 |
7 | void *memset(void *s , int c , size_t n);
8 | void *memcpy(void *dest , const void *src , size_t n);
9 | int memcmp(const void *s1 , const void *s2 , size_t n);
10 |
11 | size_t strlen(const char *s);
12 | char *strcpy(char *dest , const char *src);
13 | char *strncpy(char *dest , const char *src , size_t n);
14 | char *strcat(char *dest , char *src);
15 | char *strncat(char *dest , const char *src , size_t n);
16 | int strcmp(const char *s1 , const char *s2);
17 | int strncmp(const char *s1 , const char *s2 , size_t n);
18 |
19 | int vsprintf(char *buf , const char *fmt , va_list ap);
20 | int sprintf(char *buf , const char *fmt , ...);
21 |
22 | int atoi(const char *nptr);
23 | long int atol(const char *nptr);
24 | long long int atoll(const char *nptr);
25 | char *itoa(int value , char *result , int base);
26 | template char *itoa_variation(T value , char *result , int base , bool lowercase=true);
27 |
28 | #endif
--------------------------------------------------------------------------------
/kernel/src/debug.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #define DEBUG_PRINTF_STR_STACK 1024
4 |
5 | struct {
6 | bool info_display;
7 | bool function_display;
8 | bool func_indent;
9 | bool enable_debug;
10 |
11 | uint16_t option_flags;
12 | }debug_info;
13 |
14 | void debug::init(void) {
15 | set_option(DEBUG_OPTION_DISPLAY_INFO , true);
16 | debug_info.option_flags = 0b11111111;
17 | debug::out::init();
18 | ENABLE_DEBUG_MSG
19 | }
20 |
21 | void debug::dump_memory(max_t address , max_t length , bool debug_string) {
22 | uint8_t *ptr = (uint8_t *)address;
23 | int margin = 5;
24 | int char_per_line = 80;
25 | int x = (char_per_line-margin-3)/4; // character
26 | debug::out::printf("dumping memory from 0x%X - 0x%X\n" , address , address+length);
27 | int line_count = (length/x)+(length%x != 0);
28 | debug::out::printf("x = %d\n" , x);
29 |
30 | // remove for display
31 | max_t max = 0;
32 | max_t offset = 0;
33 | for(max_t j = 1; j <= line_count; j++) {
34 | debug::out::printf("");
35 |
36 | unsigned char *old_ptr = ptr;
37 | max_t count = MIN(x , length-offset);
38 | for(max_t i = 1; i <= count; i++) {
39 | debug::out::printf(DEBUG_RAW_PRINT , "%02X " , *ptr);
40 | ptr++;
41 | }
42 | max = MAX(max , count);
43 | if(count < max) {
44 | for(max_t i = 0; i < max-count; i++) {
45 | debug::out::printf(DEBUG_RAW_PRINT , " ");
46 | }
47 | }
48 | // debug the string
49 | debug::out::printf(DEBUG_RAW_PRINT , " | ");
50 | for(max_t i = 1; i <= count; i++) {
51 | unsigned char c = *old_ptr;
52 | switch(c) {
53 | case '\n':
54 | case '\t':
55 | case '\b':
56 | case '\r':
57 | case 0:
58 | c = '.';
59 | break ;
60 | }
61 | debug::out::printf(DEBUG_RAW_PRINT , "%c" , c);
62 | old_ptr++;
63 | }
64 | debug::out::print_str("\n");
65 | offset += x;
66 | }
67 | }
68 |
69 | void debug::enable(void) { debug_info.enable_debug = true; }
70 | void debug::disable(void) { debug_info.enable_debug = false; }
71 |
72 | void debug::panic_line(const char *source , int line , const char *fmt , ...) {
73 | va_list ap;
74 | va_start(ap , fmt);
75 | char buffer[512];
76 | vsprintf(buffer , fmt , ap);
77 | debug::out::printf(DEBUG_PANIC , "(%s:%d) %s", source , line , buffer);
78 | va_end(ap);
79 | while(1) {
80 | ;
81 | }
82 | }
83 |
84 | void debug::panic(const char *fmt , ...) {
85 | va_list ap;
86 | va_start(ap , fmt);
87 | char buffer[512];
88 | vsprintf(buffer , fmt , ap);
89 | debug::out::printf(DEBUG_PANIC , buffer);
90 | va_end(ap);
91 | while(1) {
92 | ;
93 | }
94 | }
95 |
96 | void debug::panic(void) {
97 | debug::out::printf(DEBUG_PANIC , "kernel panic\n");
98 | while(1) {
99 | ;
100 | }
101 | }
102 |
103 | const char *debug::out::debugstr(debug_mode_t mode) {
104 | switch(mode) {
105 | case DEBUG_NONE: return "";
106 | case DEBUG_TEXT: return "[ ] ";
107 | case DEBUG_INFO: return "[I] ";
108 | case DEBUG_SPECIAL: return "[S] ";
109 | case DEBUG_WARNING: return "[W] ";
110 | case DEBUG_ERROR: return "[E] ";
111 | case DEBUG_PANIC: return "[P] ";
112 | }
113 | return " ";
114 | }
115 |
116 | void debug::set_option(uint16_t option , bool flag) {
117 | if((option & DEBUG_OPTION_DISPLAY_INFO) == DEBUG_OPTION_DISPLAY_INFO) {
118 | debug_info.info_display = flag;
119 | }
120 | }
121 |
122 | void debug::display_set(uint16_t option) { debug_info.option_flags |= option; }
123 | void debug::display_mask(uint16_t option) { debug_info.option_flags &= ~option; }
124 |
125 | void debug::out::vprintf(debug_mode_t mode , const char *fmt , va_list ap) {
126 | if(debug_info.enable_debug == false) return;
127 | debug_color_t color = debugcolor(mode);
128 | set_foreground_color(color);
129 | if(debug_info.info_display||mode != DEBUG_RAW_PRINT) {
130 | print_str(debugstr(mode));
131 | }
132 |
133 | char string[DEBUG_PRINTF_STR_STACK];
134 | vsprintf(string , fmt , ap);
135 | print_str(string);
136 |
137 | set_foreground_color(debugcolor(DEBUG_TEXT));
138 | }
139 |
140 | void debug::out::printf(debug_mode_t mode , const char *fmt , ...) {
141 | if(debug_info.enable_debug == false) return;
142 | va_list ap;
143 | va_start(ap , fmt);
144 | debug::out::vprintf(mode , fmt , ap);
145 | va_end(ap);
146 | }
147 |
148 | void debug::out::printf(const char *fmt , ...) {
149 | if(debug_info.enable_debug == false) return;
150 | va_list ap;
151 | va_start(ap , fmt);
152 | debug::out::vprintf(DEBUG_TEXT , fmt , ap);
153 | va_end(ap);
154 | }
--------------------------------------------------------------------------------
/kernel/src/kernel_init.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | extern void main(int argc , char **argv);
4 |
5 | extern "C" void kernel_init(void) {
6 | // call the main kernel
7 | debug::init();
8 | debug::out::clear_screen(debug::out::debugcolor(DEBUG_NONE));
9 |
10 | char *argv[] = {};
11 | main(0 , argv);
12 |
13 | while(1) {}
14 | }
--------------------------------------------------------------------------------
/kernel/src/string/string.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #define size_t unsigned int
4 |
5 | void *memset(void *s , int c , size_t n) {
6 | unsigned char *ptr = (unsigned char *)s;
7 | for(size_t i = 0; i < n; i++) {
8 | *ptr++ = c;
9 | }
10 | return ptr;
11 | }
12 |
13 | void *memcpy(void *dest , const void *src , size_t n) {
14 | unsigned char *dest_ptr = (unsigned char *)dest;
15 | unsigned char *src_ptr = (unsigned char *)src;
16 | for(size_t i = 0; i < n; i++) {
17 | *dest_ptr++ = *src_ptr++;
18 | }
19 | return dest;
20 | }
21 |
22 | int memcmp(const void *s1 , const void *s2 , size_t n) {
23 | unsigned char *s1_ptr = (unsigned char *)s1;
24 | unsigned char *s2_ptr = (unsigned char *)s2;
25 | for(size_t i = 0; i < n; i++) {
26 | if(*(s1_ptr+i) < *(s2_ptr+i)) return -1;
27 | else if(*(s1_ptr+i) > *(s2_ptr+i)) return 1;
28 | }
29 | return 0;
30 | }
31 |
32 | size_t strlen(const char *s) {
33 | size_t sz = 0;
34 | while(s[sz] != 0) {
35 | sz++;
36 | }
37 | return sz;
38 | }
39 |
40 | char *strcpy(char *dest , const char *src) {
41 | unsigned long i;
42 | unsigned long OriginLength = strlen(src);
43 | for(i = 0; i < OriginLength; i++) {
44 | dest[i] = src[i];
45 | }
46 | dest[i] = 0x00;
47 | return dest;
48 | }
49 |
50 | char *strncpy(char *dest , const char *src , size_t n) {
51 | size_t i;
52 | size_t length = strlen(src);
53 | if(length > n) length = n;
54 | for(i = 0; i < length; i++) {
55 | dest[i] = src[i];
56 | }
57 | dest[i] = 0;
58 | return dest;
59 | }
60 |
61 | char *strcat(char *dest , char *src) {
62 | size_t i;
63 | size_t dest_sz = strlen(dest);
64 | size_t src_sz = strlen(src);
65 | for(i = dest_sz; i < dest_sz+src_sz; i++) {
66 | dest[i] = src[i-dest_sz];
67 | }
68 | dest[i] = 0;
69 | return dest;
70 | }
71 |
72 | char *strncat(char *dest , const char *src , size_t n) {
73 | size_t i;
74 | size_t dest_sz = strlen(dest);
75 | for(i = dest_sz; i < dest_sz+n; i++) {
76 | dest[i] = src[i-dest_sz];
77 | }
78 | dest[i] = 0;
79 | return dest;
80 | }
81 |
82 | int strcmp(const char *s1 , const char *s2) {
83 | size_t s1_sz = strlen(s1) , s2_sz = strlen(s2);
84 | if(s1_sz > s2_sz) return 1;
85 | if(s1_sz < s2_sz) return -1;
86 | for(size_t i = 0; s1[i] != 0 && s2[i] != 0; i++) {
87 | if(s1[i] > s2[i]) return 1;
88 | else if(s1[i] < s2[i]) return -1;
89 | }
90 | return 0;
91 | }
92 |
93 | int strncmp(const char *s1 , const char *s2 , size_t n) {
94 | for(size_t i = 0; s1[i] != 0 && s2[i] != 0 && i < n; i++) {
95 | if(s1[i] > s2[i]) return 1;
96 | else if(s1[i] < s2[i]) return -1;
97 | }
98 | return 0;
99 | }
100 |
101 |
102 | int atoi(const char *nptr) {
103 | int result = 0;
104 | int sign = (nptr[0] == '-') ? -1 : 1;
105 | int i = (sign > 0) ? 0 : 1;
106 | if(nptr[0] == '+') i = sign = 1;
107 | for(; nptr[i] != 0; i++) {
108 | result = result*10+(nptr[i]-'0');
109 | }
110 | return result*sign;
111 | }
112 |
113 | long int atol(const char *nptr) {
114 | long int result = 0;
115 | long int sign = (nptr[0] == '-') ? -1 : 1;
116 | int i = (sign > 0) ? 0 : 1;
117 | if(nptr[0] == '+') i = sign = 1;
118 | for(; nptr[i] != 0; i++) {
119 | result = result*10+(nptr[i]-'0');
120 | }
121 | return result*sign;
122 | }
123 |
124 | long long int atoll(const char *nptr) {
125 | long long int result = 0;
126 | long long int sign = (nptr[0] == '-') ? -1 : 1;
127 | int i = (sign > 0) ? 0 : 1;
128 | if(nptr[0] == '+') i = sign = 1;
129 | for(; nptr[i] != 0; i++) {
130 | result = result*10+(nptr[i]-'0');
131 | }
132 | return result*sign;
133 | }
134 |
135 | // Source from https://www.strudel.org.uk/itoa/
136 | /**
137 | * C++ version 0.4 char* style "itoa":
138 | * Written by Lukás Chmela
139 | * Released under GPLv3.
140 | *
141 | */
142 | char* itoa(int value, char* result, int base) {
143 | // check that the base if valid
144 | if (base < 2 || base > 36) { *result = '\0'; return result; }
145 | char* ptr = result, *ptr1 = result, tmp_char;
146 | int tmp_value;
147 | do {
148 | tmp_value = value;
149 | value /= base;
150 | *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
151 | } while ( value );
152 | // Apply negative sign
153 | if (tmp_value < 0) *ptr++ = '-';
154 | *ptr-- = '\0';
155 | while(ptr1 < ptr) {
156 | tmp_char = *ptr;
157 | *ptr--= *ptr1;
158 | *ptr1++ = tmp_char;
159 | }
160 | return result;
161 | }
--------------------------------------------------------------------------------
/kernel/src/string/vsprintf.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #define NONE 0
5 |
6 | #define FMT_SIZE_h 1
7 | #define FMT_SIZE_ll 2
8 | #define FMT_SIZE_l 3
9 | #define FMT_SIZE_L 4
10 | #define FMT_SIZE_H 5
11 | #define FMT_SIZE_DD 6
12 | #define FMT_SIZE_D 7
13 |
14 | struct FormatData {
15 | char flag;
16 | int width;
17 | int precision;
18 | int size;
19 | int type;
20 | };
21 |
22 | /// @brief get flag from format string
23 | /// @param fmt format string
24 | /// @param local_i local_i
25 | /// @return flag
26 | char get_flag(const char *fmt , int &local_i) {
27 | char flag_list[] = {'-' , '+' , '#' , '0'};
28 | for(size_t i = 0; i < sizeof(flag_list); i++) {
29 | if(fmt[local_i] == flag_list[i]) {
30 | return fmt[local_i++];
31 | }
32 | }
33 | return NONE;
34 | }
35 |
36 | static bool isnumber(char c) {
37 | if('0' <= c && c <= '9') return true;
38 | return false;
39 | }
40 |
41 | int get_width(const char *fmt , int &local_i , va_list ap) {
42 | int i = 0;
43 | int width = 0;
44 | if(fmt[local_i] == '*') { // use from
45 | width = va_arg(ap , int);
46 | local_i++;
47 | return width;
48 | }
49 | for(; isnumber(fmt[local_i+i]) == true && fmt[local_i+i] != 0; i++) {
50 | width = width*10+(fmt[local_i+i]-'0');
51 | }
52 | local_i = local_i+i;
53 | return width;
54 | }
55 |
56 | int get_precision(const char *fmt , int &local_i , va_list ap) {
57 | int i = 0;
58 | int precision = 0;
59 | if(fmt[local_i] != '.') return precision;
60 | local_i++;
61 | if(fmt[local_i] == '*') {
62 | precision = va_arg(ap , int);
63 | local_i++;
64 | return precision;
65 | }
66 | for(; isnumber(fmt[local_i+i]) == true && fmt[local_i+i] != 0; i++) {
67 | precision = precision*10+(fmt[local_i+i]-'0');
68 | }
69 | local_i = local_i+i;
70 | return precision;
71 | }
72 |
73 | int get_size(const char *fmt , int &local_i) {
74 | char size_lst[7][3] = {
75 | "h" , "ll" , "l" , "L" , "H" , "DD" , "D" ,
76 | };
77 | for(int i = 0; i < 7; i++) {
78 | if(strncmp(size_lst[i] , fmt+local_i , strlen(size_lst[i])) == 0) {
79 | local_i += strlen(size_lst[i]);
80 | return i+1;
81 | }
82 | }
83 | return NONE;
84 | }
85 |
86 | char get_type(const char *fmt , int &local_i) {
87 | return fmt[local_i];
88 | }
89 |
90 | template int get_integer_digits(T value) {
91 | int c = 0;
92 | for(; value != 0; c++) {
93 | value /= 10;
94 | }
95 | return c;
96 | }
97 |
98 | void process_added_string_d_i(struct FormatData fd , char *added_string , va_list ap) {
99 | if(fd.size == NONE) {
100 | int value = va_arg(ap , int);
101 | itoa_variation(value , added_string , 10);
102 | }
103 | else if(fd.size == FMT_SIZE_l) {
104 | long int value = va_arg(ap , long int);
105 | itoa_variation(value , added_string , 10);
106 | }
107 | else if(fd.size == FMT_SIZE_ll) {
108 | long long int value = va_arg(ap , long long int);
109 | itoa_variation(value , added_string , 10);
110 | }
111 | }
112 |
113 | void process_added_string_u_o(struct FormatData fd , char *added_string , va_list ap) {
114 | int base = 10;
115 | base = (fd.type == 'u') ? 10 : 8;
116 | if(fd.size == NONE) {
117 | unsigned int value = va_arg(ap , unsigned int);
118 | itoa_variation(value , added_string , base);
119 | }
120 | else if(fd.size == FMT_SIZE_l) {
121 | unsigned long int value = va_arg(ap , unsigned long);
122 | itoa_variation(value , added_string , base);
123 | }
124 | else if(fd.size == FMT_SIZE_ll) {
125 | unsigned long long int value = va_arg(ap , unsigned long long int);
126 | itoa_variation(value , added_string , base);
127 | }
128 | }
129 |
130 | void process_added_string_x_X(struct FormatData fd , char *added_string , va_list ap) {
131 | bool lowercase = (fd.type == 'x') ? true : false;
132 |
133 | if(fd.size == NONE) {
134 | unsigned int value = va_arg(ap , unsigned int);
135 | itoa_variation(value , added_string , 16 , lowercase);
136 | }
137 | else if(fd.size == FMT_SIZE_l) {
138 | unsigned long value = va_arg(ap , unsigned long);
139 | itoa_variation(value , added_string , 16 , lowercase);
140 | }
141 | else if(fd.size == FMT_SIZE_ll) {
142 | unsigned long long int value = va_arg(ap , unsigned long long int);
143 | itoa_variation(value , added_string , 16 , lowercase);
144 | }
145 | }
146 |
147 | void process_format(char *buf , struct FormatData fd , int &buf_i , va_list ap) {
148 | char temp_buffer[512] = {0 , };
149 |
150 | char *added_string = temp_buffer;
151 | char width_fill = ' ';
152 | if(fd.type == 'd'||fd.type == 'i') {
153 | process_added_string_d_i(fd , added_string , ap);
154 | width_fill = (fd.flag == '0') ? fd.flag : ' ';
155 | }
156 | else if(fd.type == 'u'||fd.type == 'o') {
157 | process_added_string_u_o(fd , added_string , ap);
158 | width_fill = (fd.flag == '0') ? fd.flag : ' ';
159 | }
160 | else if(fd.type == 'x'||fd.type == 'X') {
161 | process_added_string_x_X(fd , added_string , ap);
162 | width_fill = (fd.flag == '0') ? fd.flag : ' ';
163 | }
164 | else if(fd.type == 'c') {
165 | added_string[0] = va_arg(ap , int);
166 | added_string[1] = 0;
167 | }
168 | else if(fd.type == 's') {
169 | added_string = va_arg(ap , char*);
170 | }
171 |
172 | if(fd.flag == '-') { // sort to left
173 | strcat(buf , added_string);
174 | if(fd.width != NONE && fd.width > strlen(added_string)) {
175 | int c = fd.width-strlen(added_string);
176 | char flag[2] = {width_fill , 0};
177 | for(int i = 0; i < c; i++) {
178 | strcat(buf , flag);
179 | }
180 | buf_i += c;
181 | }
182 | buf_i += strlen(added_string);
183 | }
184 | else {
185 | if(fd.width != NONE && fd.width > strlen(added_string)) {
186 | int c = fd.width-strlen(added_string);
187 | char flag[2] = {width_fill , 0};
188 | for(int i = 0; i < c; i++) {
189 | strcat(buf , flag);
190 | }
191 | buf_i += c;
192 | }
193 | strcat(buf , added_string);
194 | buf_i += strlen(added_string);
195 | }
196 | }
197 |
198 | // %[flags][width][.precision][size]type
199 |
200 | int vsprintf(char *buf , const char *fmt , va_list ap) {
201 | int buf_i = 0;
202 | struct FormatData fd = {0 , 0 , 0 , 0 , 0};
203 | buf[0] = 0;
204 | for(int i = 0; fmt[i] != 0; i++) {
205 | if(fmt[i] == '%') {
206 | int local_i = i+1;
207 |
208 | fd.flag = get_flag(fmt , local_i);
209 | fd.width = get_width(fmt , local_i , ap);
210 | fd.precision = get_precision(fmt , local_i , ap);
211 | fd.size = get_size(fmt , local_i);
212 | fd.type = get_type(fmt , local_i);
213 | process_format(buf , fd , buf_i , ap);
214 | i = local_i;
215 | }
216 | else {
217 | buf[buf_i++] = fmt[i];
218 | buf[buf_i] = 0;
219 | }
220 | }
221 | return buf_i;
222 | }
223 |
224 | int sprintf(char *buf , const char *fmt , ...) {
225 | va_list ap;
226 | va_start(ap , fmt);
227 | int ret = vsprintf(buf , fmt , ap);
228 | va_end(ap);
229 | return ret;
230 | }
231 |
232 | template char* itoa_variation(T value, char* result, int base , bool lowercase) {
233 | // check that the base if valid
234 | char sample_str_low[] = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz";
235 | char sample_str_high[] = "ZYXWVUTSRQPONMLKJIHGFEDCBA9876543210123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
236 | char *sample_str = (lowercase) ? sample_str_low : sample_str_high;
237 | if (base < 2 || base > 36) { *result = '\0'; return result; }
238 | char* ptr = result, *ptr1 = result, tmp_char;
239 | T tmp_value;
240 | do {
241 | tmp_value = value;
242 | value /= base;
243 | *ptr++ = sample_str[35 + (tmp_value - value * base)];
244 | } while ( value );
245 | // Apply negative sign
246 | if (tmp_value < 0) *ptr++ = '-';
247 | *ptr-- = '\0';
248 | while(ptr1 < ptr) {
249 | tmp_char = *ptr;
250 | *ptr--= *ptr1;
251 | *ptr1++ = tmp_char;
252 | }
253 | return result;
254 | }
--------------------------------------------------------------------------------
/loader/build_common.mk:
--------------------------------------------------------------------------------
1 | # build_common.mk
2 |
3 | # Required arguments :
4 | # LOADER_CC : gcc(or g++) compiler for the loader
5 | # LOADER_LD : the ld compiler for the loader
6 | # LOADER_AS : the assembler "
7 | # LOADER_CCOPTIONS : gcc(or g++) compiler options
8 | # LOADER_ASOPTIONS : assembler options
9 | # LOADER_LDOPTIONS : ld compiler options
10 | # LOADER_LINKERSCRIPT : path to the linker script
11 | # LOADER_LD_OUT : output file name for the ld compiler
12 | # C_EXTENSION : C/C++ source file's extension
13 | # ASM_EXTENSION : assembly source file's extension
14 |
15 | # SOURCESFOLDER : the path to the source folder
16 | # INCLUDEPATHS : includepaths for the C/C++ sources
17 |
18 | # LINK_OBJECTS[yes/no] : select whether the compiled C/C++ objects will be linked
19 | # If this options is set to "yes," compiled objects are linked using the ld options.
20 |
21 | include $(ROOTDIR)/configurations.mk
22 | include $(ROOTDIR)/global_variables.mk
23 |
24 | BINARYFOLDER = $(ROOTDIR)/$(ROOTBINARYFOLDER)/$(LOADERFOLDER)/$(ARCH)/$(IMAGE)
25 |
26 | clean: remove_target
27 | rm -rf $(BINARYFOLDER)
28 |
29 | AUTO_CC_TARGETS = $(subst .$(C_EXTENSION),.obj,$(wildcard $(SOURCESFOLDER)/*.$(C_EXTENSION)))
30 | AUTO_AS_TARGETS = $(subst .$(AS_EXTENSION),.aobj,$(wildcard $(SOURCESFOLDER)/*.$(AS_EXTENSION)))
31 |
32 | ifeq ($(LINK_OBJECTS),yes)
33 | all: prepare build_bootloader $(AUTO_CC_TARGETS) $(AUTO_AS_TARGETS) build_objects build_final_image
34 | else
35 | all: prepare build_bootloader $(AUTO_CC_TARGETS) $(AUTO_AS_TARGETS) build_final_image
36 | endif
37 |
38 | prepare:
39 | mkdir -p $(BINARYFOLDER)
40 |
41 | build_objects:
42 | $(LOADER_LD) $(wildcard $(BINARYFOLDER)/*.obj) $(wildcard $(BINARYFOLDER)/*.aobj) -T $(LOADER_LINKERSCRIPT) -o $(LOADER_LD_OUT) $(LOADER_LDOPTIONS)
43 |
44 | %.obj: %.$(C_EXTENSION)
45 | $(LOADER_CC) -c $< -o $(subst $(SOURCESFOLDER),$(BINARYFOLDER),$@) $(LOADER_CCOPTIONS)\
46 | $(addprefix -I,$(INCLUDEPATHS)) -I$(ROOTDIR)/$(ARCH_CONFIGURATION_FILE_LOC)
47 |
48 | %.aobj: %.$(AS_EXTENSION)
49 | $(LOADER_AS) $< -o $(subst $(SOURCESFOLDER),$(BINARYFOLDER),$@) $(LOADER_ASOPTIONS)
50 |
--------------------------------------------------------------------------------
/loader/x86_64/img/Makefile:
--------------------------------------------------------------------------------
1 | # Required arguments :
2 | # TARGET_DIR : Location to the directory of the argument
3 | # KERNEL_ELF : Location to the kernel elf file
4 | # KERNEL_IMG : Location to the kernel binary file
5 |
6 | include $(ROOTDIR)/configurations.mk
7 |
8 | LOADER_CC = gcc
9 | LOADER_LD = ld
10 | LOADER_AS = nasm
11 | LOADER_OBJCOPY = objcopy
12 |
13 | LOADER_CCOPTIONS = -m32 -Os -masm=intel -fno-builtin -fpack-struct=1 -fno-stack-protector \
14 | -Wno-implicit-function-declaration \
15 | -Wno-int-to-pointer-cast \
16 | -W -Wall
17 | LOADER_ASOPTIONS = -f elf32
18 | LOADER_LDOPTIONS = -m elf_i386 -z noexecstack
19 | LOADER_LINKERSCRIPT = linker.ld
20 | LOADER_LD_OUT = $(BINARYFOLDER)/loader32.elf
21 |
22 | C_EXTENSION = c
23 | AS_EXTENSION = asm
24 |
25 | SOURCESFOLDER = src
26 | INCLUDEPATHS = include
27 |
28 | LINK_OBJECTS = yes
29 |
30 | TARGET_DIR=$(ROOTDIR)/output/$(ARCH)/$(IMAGE)
31 | TARGET = $(OUTPUT_FILENAME).img
32 |
33 | remove_target:
34 | rm -rf $(TARGET_DIR)/$(TARGET)
35 |
36 | build_bootloader:
37 | $(LOADER_AS) bootloader.asm -f bin -o $(BINARYFOLDER)/bootloader.bin
38 |
39 | build_final_image:
40 | $(LOADER_OBJCOPY) -O binary $(LOADER_LD_OUT) $(BINARYFOLDER)/loader32.bin
41 |
42 | ./imgmaker $(TARGET_DIR)/$(TARGET) $(BINARYFOLDER)/bootloader.bin $(BINARYFOLDER)/loader32.bin 8 $(KERNEL_IMG) 48
43 |
44 | run_os: $(TARGET_DIR)/$(TARGET)
45 | qemu-system-x86_64 -drive format=raw,file=$(TARGET_DIR)/$(TARGET)
46 |
47 | include ../../build_common.mk
48 |
--------------------------------------------------------------------------------
/loader/x86_64/img/bootloader.asm:
--------------------------------------------------------------------------------
1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 | ;; Compact bootloader for x86_64 architecture ;;
3 | ;; Load the 32-bit Kernel Loader to designated location ;;
4 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5 |
6 | [ORG 0x7C00]
7 | [BITS 16]
8 |
9 | jmp start
10 |
11 | boot_drive: db 0x00
12 | kernel_loader_location: dw 0x1000
13 | kernel_loader_size: dd 8
14 | kernel_location: dw 0x00
15 | kernel_location_seg: dw 0x1000
16 | kernel_size: dw 48
17 |
18 | dap_address: dw 0x700
19 |
20 | start:
21 | mov ax , 0x00
22 | mov ds , ax
23 |
24 | xor ax , ax
25 | mov ss , ax
26 | mov sp , 0xFFF8
27 | mov bp , 0xFFF8
28 |
29 | ; Enable A20 gate
30 | mov eax , 0x2401
31 | int 0x15
32 |
33 | xor ecx , ecx
34 |
35 | mov [boot_drive] , dl
36 |
37 | ; read the disk content (sector #2)
38 | xor ax , ax
39 | mov es , ax
40 | mov bx , [kernel_loader_location]
41 |
42 | mov ah , 0x02
43 | mov al , byte[kernel_loader_size]
44 | mov ch , 0x00
45 | mov dh , 0x00
46 | mov cl , 2 ; sector location of kernel loader
47 | mov dl , [boot_drive]
48 |
49 | int 0x13
50 |
51 | jc failed
52 |
53 | xor ch , ch
54 | add cx , word[kernel_loader_size]
55 | dec cx
56 |
57 | ; use LBA
58 | mov ah , 0x42
59 | mov dl , [boot_drive]
60 | mov si , [dap_address]
61 | mov byte[es:si] , 0x10 ; DAP structure size
62 | mov byte[es:si+1] , 0x00
63 | mov di , [kernel_size]
64 | mov word[es:si+2] , di
65 | mov di , word[kernel_location]
66 | mov word[es:si+4] , di
67 | mov di , word[kernel_location_seg]
68 | mov word[es:si+6] , di
69 | mov dword[es:si+8] , ecx ; sector location
70 | mov dword[es:si+12] , 0x00 ; (empty qword field)
71 |
72 | int 0x13
73 |
74 | jc failed
75 |
76 | cli
77 |
78 | ; switch to protect mode
79 |
80 | mov eax , cr0
81 | or eax , 0x01
82 | mov cr0 , eax
83 |
84 | lgdt [pmode_gdtr]
85 |
86 | ; store the kernel's location and size to the registers
87 | mov di , word[kernel_location]
88 | mov dx , word[kernel_location_seg]
89 | mov si , word[kernel_size]
90 |
91 | jmp 0x08:0x1000
92 |
93 | failed:
94 | mov ax , 0xB800
95 | mov ds , ax
96 |
97 | mov byte[0x00] , 'E'
98 | mov byte[0x01] , 0x04
99 | mov byte[0x02] , 'r'
100 | mov byte[0x03] , 0x04
101 | mov byte[0x04] , 'r'
102 | mov byte[0x05] , 0x04
103 | mov byte[0x06] , 'o'
104 | mov byte[0x07] , 0x04
105 | mov byte[0x08] , 'r'
106 | mov byte[0x09] , 0x04
107 | mov byte[0x0A] , '!'
108 | mov byte[0x0B] , 0x04
109 | jmp $
110 |
111 | pmode_gdt:
112 | dw 0x0000
113 | dw 0x0000
114 | db 0x00
115 | db 0x00
116 | db 0x00
117 | db 0x00
118 |
119 | ; code segment
120 | dw 0xFFFF
121 | dw 0x0000
122 | db 0x00
123 | db 0x9A
124 | db 0xCF
125 | db 0x00
126 |
127 | ; data segment
128 | dw 0xFFFF
129 | dw 0x0000
130 | db 0x00
131 | db 0x92
132 | db 0xCF
133 | db 0x00
134 | pmode_gdt_end:
135 |
136 | pmode_gdtr:
137 | .size: dw pmode_gdt_end-pmode_gdt
138 | .offset: dd pmode_gdt
139 |
140 | times (510-($-$$)) db 0x00
141 | dw 0xAA55
--------------------------------------------------------------------------------
/loader/x86_64/img/imgmaker:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fosd-project/FOSD/8daa0134ce7c0bc8c2fefd62a5b7d07c5339a3f9/loader/x86_64/img/imgmaker
--------------------------------------------------------------------------------
/loader/x86_64/img/imgmaker.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #define BYTES_PER_SECTOR 512
5 | #define FIXED_BOOTLOADER_SIZE 1*BYTES_PER_SECTOR
6 |
7 | int main(int argc , char **argv) {
8 | if(argc != 7) {
9 | printf("Usage : imgmaker [output file] [bootloader] [kernel loader] [kernel loader sector size] [kernel] [kernel sector size]\n");
10 | return -1;
11 | }
12 | FILE *out = fopen(argv[1] , "wb");
13 | FILE *bootloader = fopen(argv[2] , "rb");
14 | FILE *kernel_loader = fopen(argv[3] , "rb");
15 | FILE *kernel = fopen(argv[5] , "rb");
16 |
17 | int kernel_loader_sector_size = atoi(argv[4]);
18 | int kernel_sector_size = atoi(argv[6]);
19 |
20 | if(bootloader == 0x00) {
21 | printf("bootloader not found\n");
22 | return -1;
23 | }
24 | if(kernel_loader == 0x00) {
25 | printf("kernel loader not found\n");
26 | return -1;
27 | }
28 | if(kernel == 0x00) {
29 | printf("kernel not found\n");
30 | return -1;
31 | }
32 |
33 | fseek(kernel_loader , 0 , SEEK_END);
34 | fseek(kernel , 0 , SEEK_END);
35 | unsigned long kernel_loader_size = ftell(kernel_loader);
36 | unsigned long aligned_kernel_loader_size = kernel_loader_sector_size*BYTES_PER_SECTOR;
37 | unsigned long kernel_size = ftell(kernel);
38 | unsigned long aligned_kernel_size = kernel_sector_size*BYTES_PER_SECTOR;
39 | printf("kernel_loader_size = %ld(aligned : %ld)\n" , kernel_loader_size , aligned_kernel_loader_size);
40 | printf("kernel_size = %ld(aligned : %ld)\n" , kernel_size , aligned_kernel_size);
41 | fseek(kernel_loader , 0 , SEEK_SET);
42 | fseek(kernel , 0 , SEEK_SET);
43 |
44 | unsigned long i = 0;
45 | for(; i < FIXED_BOOTLOADER_SIZE; i++) {
46 | if(feof(bootloader)) break;
47 | unsigned char c = fgetc(bootloader);
48 | fputc(c , out);
49 | }
50 | for(i = 0; i < kernel_loader_size; i++) { fputc(fgetc(kernel_loader) , out); }
51 | for(; i < aligned_kernel_loader_size; i++) { fputc(0 , out); }
52 | for(i = 0; i < kernel_size; i++) { fputc(fgetc(kernel) , out); }
53 | for(; i < aligned_kernel_size; i++) { fputc(0 , out); }
54 |
55 | fclose(out);
56 | fclose(bootloader);
57 | fclose(kernel_loader);
58 | fclose(kernel);
59 | return 0;
60 | }
--------------------------------------------------------------------------------
/loader/x86_64/img/include/basicstring.h:
--------------------------------------------------------------------------------
1 | #ifndef _PSEUDOSTRING_H_
2 | #define _PSEUDOSTRING_H_
3 |
4 | #include
5 |
6 | unsigned int memset(void *Destination , int Data , unsigned int Size);
7 | unsigned int memcpy(void *Destination , const void *Source , unsigned int Size);
8 | int strlen(const char *Destination);
9 | char *strcpy(char *Destination , const char *Source);
10 | char *strncpy(char *Destination , const char *Source , int Length);
11 | char *strcat(char *Destination , const char *Source);
12 | char *strncat(char *Destination , const char *Source , int Length);
13 | int strcmp(const char *Destination , const char *Source);
14 | int strncmp(const char *Destination , const char *Source , int Length);
15 |
16 | unsigned long atoi(const char *String);
17 | unsigned long atol(const char *String);
18 | char *itoa(unsigned long Number , char *String , int radix);
19 |
20 | void vsprintf(char *Destination , const char *Format , va_list ap);
21 | void sprintf(char *Destination , const char *Format , ...);
22 |
23 | #endif
--------------------------------------------------------------------------------
/loader/x86_64/img/include/intel_paging.h:
--------------------------------------------------------------------------------
1 | #ifndef _PAGING_H_
2 | #define _PAGING_H_
3 |
4 |
5 | #define PAGE_SIZE 0x200000
6 |
7 | #define PAGE_MAX_ENTRY_COUNT 512
8 | #define PAGE_PML4ENTRY_FLAGS_P 0b000000000001
9 | #define PAGE_PML4ENTRY_FLAGS_RW 0b000000000010
10 | #define PAGE_PML4ENTRY_FLAGS_US 0b000000000100
11 | #define PAGE_PML4ENTRY_FLAGS_PWT 0b000000001000
12 | #define PAGE_PML4ENTRY_FLAGS_PCD 0b000000010000
13 | #define PAGE_PML4ENTRY_FLAGS_A 0b000000100000
14 | #define PAGE_PML4ENTRY_FLAGS_EXB 0b100000000000
15 |
16 | #define PAGE_PDPTENTRY_FLAGS_P 0b00000000000001
17 | #define PAGE_PDPTENTRY_FLAGS_RW 0b00000000000010
18 | #define PAGE_PDPTENTRY_FLAGS_US 0b00000000000100
19 | #define PAGE_PDPTENTRY_FLAGS_PWT 0b00000000001000
20 | #define PAGE_PDPTENTRY_FLAGS_PCD 0b00000000010000
21 | #define PAGE_PDPTENTRY_FLAGS_A 0b00000000100000
22 | #define PAGE_PDPTENTRY_FLAGS_D 0b00000001000000 // Ignored when PDPTE references Page Directory
23 | #define PAGE_PDPTENTRY_FLAGS_PS 0b00000010000000 // Page size, 1 = 1GB page, 0 = 2MB or 4KB page.
24 | #define PAGE_PDPTENTRY_FLAGS_G 0b00000100000000 //
25 | #define PAGE_PDPTENTRY_FLAGS_PAT 0b01000000000000
26 | #define PAGE_PDPTENTRY_FLAGS_EXB 0b10000000000000
27 |
28 | #define PAGE_PDENTRY_FLAGS_P 0b00000000000001
29 | #define PAGE_PDENTRY_FLAGS_RW 0b00000000000010
30 | #define PAGE_PDENTRY_FLAGS_US 0b00000000000100
31 | #define PAGE_PDENTRY_FLAGS_PWT 0b00000000001000
32 | #define PAGE_PDENTRY_FLAGS_PCD 0b00000000010000
33 | #define PAGE_PDENTRY_FLAGS_A 0b00000000100000
34 | #define PAGE_PDENTRY_FLAGS_D 0b00000001000000
35 | #define PAGE_PDENTRY_FLAGS_PS 0b00000010000000
36 | #define PAGE_PDENTRY_FLAGS_G 0b00000100000000
37 | #define PAGE_PDENTRY_FLAGS_EXB 0b10000000000000
38 |
39 | #define PAGE_GET_PML4ENTRY_NUM(addr) (((addr) >> 39) & 0x1FF)
40 | #define PAGE_GET_PDPTENTRY_NUM(addr) (((addr) >> 30) & 0x1FF)
41 | #define PAGE_GET_PDENTRY_NUM(addr) (((addr) >> 21) & 0x1FF)
42 | #define PAGE_GET_OFFSET(addr) ((addr) & 0x1FFFFF)
43 |
44 | typedef struct {
45 | unsigned int baseaddress_low_flags;
46 | unsigned int baseaddress_high;
47 | }page_entry_t;
48 |
49 | void set_page_entry(page_entry_t *page_entry , unsigned int baseaddr_low , unsigned int baseaddr_high , unsigned short flags);
50 | void setup_pml4(unsigned long pml4_table_address , int pdpt_entry_count);
51 |
52 | #endif
--------------------------------------------------------------------------------
/loader/x86_64/img/linker.ld:
--------------------------------------------------------------------------------
1 | OUTPUT_FORMAT(elf32-i386)
2 | ENTRY(entry)
3 |
4 | SECTIONS {
5 | . = 0x1000;
6 | .text 0x1000 : {
7 | *(.entry)
8 |
9 | *(.text .stub .text.* .gnu.linkonce.t.*)
10 | }
11 | .data : {
12 | *(.data .data.* .gnu.linkonce.d.*)
13 | }
14 | .rodata : {
15 | *(.rodata .rodata.* .gnu.linkonce.r.*)
16 | }
17 | .rodata1 : {
18 | *(.rodata1)
19 | }
20 | .bss : {
21 | *(.bss .bss.* .gnu.linkonce.b.*)
22 | }
23 | }
--------------------------------------------------------------------------------
/loader/x86_64/img/src/basicstring.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | unsigned int memset(void *dest , int d , unsigned int size) {
4 | int i;
5 | for(i = 0; i < size; i++) {
6 | ((unsigned char*)dest)[i] = d;
7 | }
8 | return size;
9 | }
10 |
11 | unsigned int memcpy(void *dest , const void *src , unsigned int size) {
12 | int i;
13 | for(i = 0; i < size; i++) {
14 | ((unsigned char*)dest)[i] = ((unsigned char*)src)[i];
15 | }
16 | return size;
17 | }
18 |
19 | int strlen(const char *dest) {
20 | int i = 0;
21 | for(; dest[i] != '\0'; i++) {}
22 | return i;
23 | }
24 |
25 | char *strcpy(char *dest , const char *src) {
26 | int i;
27 | memset(dest , 0 , sizeof(dest));
28 | for(i = 0; (dest[i] != '\0')||(src[i] != '\0'); i++) {
29 | dest[i] = src[i];
30 | }
31 | return dest;
32 | }
33 |
34 | char *strncpy(char *dest , const char *src , int len) {
35 | int i;
36 | memset(dest , 0 , sizeof(dest));
37 | for(i = 0; i < len; i++) {
38 | dest[i] = src[i];
39 | }
40 | return dest;
41 | }
42 |
43 | char *strcat(char *dest , const char *src) {
44 | int i = 0;
45 | int j = 0;
46 | while(dest[i] != '\0') {
47 | i++;
48 | }
49 | while(src[j] != '\0') {
50 | dest[i++] = src[j++];
51 | }
52 | dest[i] = '\0';
53 | return dest;
54 | }
55 |
56 | char *strncat(char *dest , const char *src , int len) {
57 | int i = 0;
58 | int j;
59 | while(dest[i] != '\0') {
60 | i++;
61 | }
62 | for(j = 0; j < len; j++) {
63 | dest[i++] = src[j++];
64 | }
65 | dest[i] = '\0';
66 | return dest;
67 | }
68 |
69 | int strcmp(const char *dest , const char *src) {
70 | int i;
71 | int not_equal = 0;
72 | for(i = 0; (dest[i] != '\0')||(src[i] != '\0'); i++) {
73 | if(dest[i] != src[i]) {
74 | not_equal++;
75 | }
76 | }
77 | return not_equal;
78 | }
79 |
80 | int strncmp(const char *dest , const char *src , int len) {
81 | int i;
82 | int not_equal = 0;
83 | for(i = 0; i < len; i++) {
84 | if(dest[i] != src[i]) {
85 | not_equal++;
86 | }
87 | }
88 | return not_equal;
89 | }
90 |
91 | unsigned long atoi(const char *str) {
92 | unsigned long num = 0;
93 | int positive = 1;
94 | if(*str == '-') {
95 | positive = -1;
96 | str++;
97 | }
98 | if(*str == '+') {
99 | positive = 1;
100 | str++;
101 | }
102 | if(*str == '\0') {
103 | return 0;
104 | }
105 | while(*str != 0x00) {
106 | if((*str >= '0') && (*str <= '9')) {
107 | num = num*10+(*str)-'0';
108 | str++;
109 | }
110 | }
111 | num *= positive;
112 | return num;
113 | }
114 |
115 | unsigned long atol(const char *str) {
116 | unsigned long num = 0;
117 | int positive = 1;
118 | if(*str == '-') {
119 | positive = -1;
120 | str++;
121 | }
122 | if(*str == '+') {
123 | positive = 1;
124 | str++;
125 | }
126 | if(*str == '\0') {
127 | return 0;
128 | }
129 | while(*str != 0x00) {
130 | num *= 16;
131 | if(((*str >= 'A') && (*str <= 'Z'))) {
132 | num += ((*str)-'A')+10;
133 | str++;
134 | }
135 | else if(((*str >= 'a') && (*str <= 'z'))) {
136 | num += ((*str)-'a')+10;
137 | str++;
138 | }
139 | else {
140 | num += ((*str)-'0');
141 | str++;
142 | }
143 | }
144 | num *= positive;
145 | return num;
146 | }
147 |
148 | char *itoa(unsigned long num , char *str , int Radix) {
149 | int i = 0;
150 | int len;
151 | unsigned long TempBuffer;
152 | char tmp;
153 | if(num == 0) {
154 | str[0] = '0';
155 | str[1] = '\0';
156 | return str;
157 | }
158 | while(1) {
159 | if(num == 0) {
160 | break;
161 | }
162 | if(Radix <= 10) {
163 | str[i++] = (num%Radix)+'0';
164 | }
165 | else {
166 | TempBuffer = num%Radix;
167 | if(TempBuffer <= 9) {
168 | str[i++] = TempBuffer+'0';
169 | }
170 | else {
171 | str[i++] = TempBuffer-10+'A';
172 | }
173 | }
174 | num /= Radix;
175 | }
176 | str[i] = 0x00;
177 | len = i;
178 | for(i = 0; i < len/2; i++) {
179 | tmp = str[i];
180 | str[i] = str[strlen(str)-i-1];
181 | str[strlen(str)-i-1] = tmp;
182 | }
183 | return str;
184 | }
185 |
186 | void vsprintf(char *dest , const char *fmt , va_list ap) {
187 | int i;
188 | int j = 0;
189 | for(i = 0; i < strlen(fmt); i++) {
190 | switch(fmt[i]) {
191 | case '%':
192 | switch(fmt[i+1]) {
193 | case 'c': {
194 | unsigned char buffer = va_arg(ap , int);
195 | dest[j++] = buffer;
196 | i++;
197 | break;
198 | }
199 | case 's': {
200 | static char buffer[4096];
201 | memset(buffer , 0 , 4096);
202 | strcpy(buffer , va_arg(ap , char*));
203 | strcpy(dest+j , buffer);
204 | j += strlen(buffer);
205 | i++;
206 | break;
207 | }
208 | case 'd':
209 | case 'i': {
210 | unsigned long value = va_arg(ap , unsigned long);
211 | static char buffer[128];
212 | memset(buffer , 0 , 128);
213 | itoa(value , buffer , 10);
214 | strcpy(dest+j , buffer);
215 | j += strlen(buffer);
216 | i++;
217 | break;
218 | }
219 | case 'X': {
220 | unsigned long value = va_arg(ap , unsigned long);
221 | static char buffer[128];
222 | memset(buffer , 0 , 128);
223 | itoa(value , buffer , 16);
224 | strcpy(dest+j , buffer);
225 | j += strlen(buffer);
226 | i++;
227 | break;
228 | }
229 | case 'f': {
230 | break;
231 | }
232 | case '%': {
233 | dest[j++] = '%';
234 | i++;
235 | break;
236 | }
237 | default: {
238 | i++;
239 | break;
240 | }
241 | }
242 | break;
243 | default:
244 | dest[j++] = fmt[i];
245 | break;
246 | }
247 | }
248 | dest[j] = '\0';
249 | }
250 |
251 | void sprintf(char *dest , const char *fmt , ...) {
252 | va_list ap;
253 | va_start(ap , fmt);
254 | vsprintf(dest , fmt , ap);
255 | va_end(ap);
256 | }
257 |
--------------------------------------------------------------------------------
/loader/x86_64/img/src/entry.asm:
--------------------------------------------------------------------------------
1 | [BITS 32]
2 |
3 | ; section entry
4 | SECTION .entry
5 |
6 | global entry
7 |
8 | extern loader_main
9 |
10 | entry:
11 | mov ax , 0x10
12 | mov ds , ax
13 | mov es , ax
14 | mov fs , ax
15 | mov gs , ax
16 | mov ss , ax
17 |
18 | mov esp , 0x9FF8
19 | mov ebp , 0x9FF8
20 |
21 | ; convert the 16bit segment addressing to the physical address
22 | imul edx , 16
23 | add edi , edx
24 |
25 | push esi
26 | push edi
27 | call loader_main
28 |
29 | jmp $
--------------------------------------------------------------------------------
/loader/x86_64/img/src/intel_paging.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | void set_page_entry(page_entry_t *page_entry , unsigned int baseaddr_low , unsigned int baseaddr_high , unsigned short flags) {
4 | page_entry->baseaddress_low_flags = (baseaddr_low & 0xFFFFF000)|(flags & 0xFFF);
5 | page_entry->baseaddress_high = baseaddr_high;
6 | }
7 |
8 | // setup the PML4 entries
9 | void setup_pml4(unsigned long pml4_table_address , int pdpt_entry_count) {
10 | page_entry_t *pml4_entry = (page_entry_t *)pml4_table_address;
11 | page_entry_t *pdpt_entry = (page_entry_t *)(pml4_table_address+(PAGE_MAX_ENTRY_COUNT*sizeof(page_entry_t)));
12 | page_entry_t *pde_entry = (page_entry_t *)((pml4_table_address+(PAGE_MAX_ENTRY_COUNT*sizeof(page_entry_t)))+(PAGE_MAX_ENTRY_COUNT*sizeof(page_entry_t)));
13 | /* overall structure of the PML4 entry :
14 | *
15 | * pml4_table_address
16 | * V
17 | * +------------------+----------------------+-------------------+
18 | * | | | |
19 | * | PML4 Entry | PDPT Entry | PDE Entry |
20 | * | | | |
21 | * +------------------+----------------------+-------------------+
22 | * entry count : 1 entry count : entry_count :
23 | * pdpt_entry_count 512 x pdpt_entry_count
24 | * x 1 x 1
25 | * (2MB PML4)
26 | *
27 | * This page entry are linearly wired to their corresponding physical address.
28 | * Linear address of each page exactly corresponds to the physical address.
29 | */
30 |
31 | for(unsigned int i = 0; i < PAGE_MAX_ENTRY_COUNT; i++) {
32 | set_page_entry(&(pml4_entry[i]) , 0x00 , 0x00 , 0x00);
33 | }
34 | set_page_entry(pml4_entry , pdpt_entry , 0 , PAGE_PML4ENTRY_FLAGS_P|PAGE_PML4ENTRY_FLAGS_RW);
35 |
36 | for(unsigned int i_pdpt = 0; i_pdpt < pdpt_entry_count; i_pdpt++) {
37 | set_page_entry(&(pdpt_entry[i_pdpt]) , pde_entry , 0 , PAGE_PDPTENTRY_FLAGS_P|PAGE_PDPTENTRY_FLAGS_RW);
38 | for(unsigned int i_pde = 0; i_pde < PAGE_MAX_ENTRY_COUNT; i_pde++) {
39 | /* The linear address is consisted of following structure :
40 | *
41 | * 63 47 39 38 30 29 21 20 0
42 | * +-------------+--------------+--------------+------------+-------------------+
43 | * | Sign extend | PML4E offset | PDPTE offset | PDE offset | page offset |
44 | * +-------------+--------------+--------------+------------+-------------------+
45 | *
46 | * One PDE page covers 2MBs of the memory, and one PDPT page covers 2MB*512 = 1GB of the memory
47 | * Set the physical address that PDE is pointing exactly to the linear address(according to the structure above.)
48 | */
49 |
50 | unsigned int base_low = (i_pde << 21)|((i_pdpt & 0b11) << 30);
51 | unsigned int base_high = (i_pdpt >> 2);
52 | set_page_entry(&(pde_entry[i_pde]) , base_low , base_high , PAGE_PDENTRY_FLAGS_P|PAGE_PDENTRY_FLAGS_RW|PAGE_PDENTRY_FLAGS_PS);
53 | }
54 | pde_entry += PAGE_MAX_ENTRY_COUNT*sizeof(page_entry_t);
55 | }
56 | }
--------------------------------------------------------------------------------
/loader/x86_64/img/src/longmode.asm:
--------------------------------------------------------------------------------
1 | [BITS 32]
2 |
3 | SECTION .text
4 |
5 | global jump_to_longmode
6 |
7 | jump_to_longmode:
8 | push ebp
9 | mov ebp , esp
10 |
11 | mov edi , dword[ebp+8] ; kernel jump address
12 | mov ebx , dword[ebp+12] ; pml4 table location
13 |
14 | cli
15 | xor edx , edx
16 | ; Switch to Long Mode
17 | mov eax , cr4 ; 1. Set PAE(Physical Address Extension) bit to 1 (5th bit)
18 | ; If you set both PAE bit and PS bit, page size is set to 2MB.
19 | or eax , 0b1000100000 ; Also set OSFXSR to 1
20 | mov cr4 , eax
21 |
22 | mov eax , ebx
23 | mov cr3 , eax ; 2. Set the location of the PML4 Entry (0x10000, check 140th line in current code)
24 |
25 | mov ecx , 0xC0000080
26 | rdmsr ; Access 0xC0000080 of MSR(Model Specific Register)
27 |
28 | or eax , 0b100000001 ; 3. Set LME(Long Mode Enable) bit and SCE(System Call Enable) bit (8th bit , 0th bit respectively)
29 | ; - which both exist in MSR register
30 | ; (System Call will be featured in this Operating System,
31 | ; that's why I'm currently setting SCE bit to 1)
32 | wrmsr
33 |
34 | mov eax , cr0
35 | or eax , 0x80000000 ; Set PG(Paging Enable) bit to 1
36 | mov cr0 , eax
37 | lgdt [longmode_gdtr] ; Load long mode GDT so that we can use Data and Code segments without an issue
38 |
39 | mov ax , 0x10
40 | mov ds , ax
41 | mov es , ax
42 | mov fs , ax
43 | mov gs , ax
44 | mov ss , ax
45 |
46 | jmp 0x08:0x200000 ; Finally jump to long mode kernel (Main Kernel)
47 |
48 | SECTION .data
49 |
50 | longmode_gdt:
51 | dw 0x0000
52 | dw 0x0000
53 | db 0x00
54 | db 0x00
55 | db 0x00
56 | db 0x00
57 |
58 | dw 0xFFFF
59 | dw 0x0000
60 | db 0x00
61 | db 0x9A
62 | db 0xAF
63 | db 0x00
64 |
65 | dw 0xFFFF
66 | dw 0x0000
67 | db 0x00
68 | db 0x92
69 | db 0xAF ; Don't forget to set the L flag!!
70 | db 0x00
71 | longmode_gdt_end:
72 |
73 | longmode_gdtr:
74 | dw longmode_gdt_end-longmode_gdt
75 | dd longmode_gdt
76 |
77 | longmode_idtr:
78 | dw 0x00
79 | dd 0x00
--------------------------------------------------------------------------------
/loader/x86_64/img/src/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | // The purpose of the kernel loader is copying the kernel to the proper location and switch the system mode to 64-bit.
6 | // The kernel loader first copies the kernel image, constructs the page table for 64-bit mode, and finally switches into 64-bit long mode.
7 |
8 | #define PAGE_TABLE_LOCATION 0x100000
9 | #define BYTES_PER_SECTOR 512
10 |
11 | void clear_screen(int color);
12 | void print_debug_str(int x , int y , int color , const char *str);
13 | void debug_printf(int x , int y , int color , const char *fmt , ...);
14 | void jump_to_longmode(unsigned int kernel_location , unsigned int pml4_location);
15 |
16 | void loader_main(unsigned int kernel_address , unsigned int kernel_sector_size) {
17 | clear_screen(0x07);
18 | print_debug_str(0 , 0 , 0x07 , "Loading the kernel..");
19 |
20 | // copy the kernel into the destination
21 | unsigned int kernel_size = kernel_sector_size*BYTES_PER_SECTOR;
22 | unsigned char *kernel_dest_ptr = (unsigned char *)KERNEL_LOAD_LOCATION;
23 | unsigned char *kernel_source_ptr = (unsigned char *)kernel_address;
24 | for(unsigned int i = 0; i < kernel_size; i++) {
25 | *kernel_dest_ptr = *kernel_source_ptr;
26 | kernel_dest_ptr++; kernel_source_ptr++;
27 | }
28 | // setup PML4 table for long mode
29 | setup_pml4(PAGE_TABLE_LOCATION , 32); // 16GB max for now
30 | jump_to_longmode(KERNEL_LOAD_LOCATION , PAGE_TABLE_LOCATION);
31 | while(1) {
32 | ;
33 | }
34 | }
35 |
36 | void clear_screen(int color) {
37 | int i;
38 | unsigned char *vmem = (unsigned char *)0xB8000;
39 | for(i = 0; i < 80*25; i++) {
40 | *(vmem++) = 0x00;
41 | *(vmem++) = color;
42 | }
43 | }
44 |
45 | void print_debug_str(int x , int y , int color , const char *str) {
46 | unsigned char *vmem = (unsigned char *)0xB8000;
47 | vmem += 2*((80*y)+x);
48 | for(int i = 0; str[i] != 0; i++) {
49 | *(vmem++) = str[i];
50 | *(vmem++) = color;
51 | }
52 | }
53 |
54 | void debug_printf(int x , int y , int color , const char *fmt , ...) {
55 | char string[2048];
56 | va_list ap;
57 | va_start(ap , fmt);
58 | vsprintf(string , fmt , ap);
59 | print_debug_str(x , y , color , string);
60 | va_end(ap);
61 | }
62 |
--------------------------------------------------------------------------------