├── .vscode └── settings.json ├── LICENSE ├── Makefile ├── README.md ├── bin └── core ├── build.sh ├── build ├── .keep ├── disk │ └── .keep ├── fs │ ├── .keep │ └── fat │ │ └── .keep ├── gdt │ └── .keep ├── idt │ └── .keep ├── io │ └── .keep ├── isr80h │ └── .keep ├── keyboard │ └── .keep ├── loader │ └── formats │ │ └── .keep ├── memory │ ├── .keep │ ├── heap │ │ └── .keep │ └── paging │ │ └── .keep └── task │ └── .keep ├── hello.txt ├── programs ├── blank │ ├── Makefile │ ├── blank.c │ ├── build │ │ └── .keep │ └── linker.ld ├── shell │ ├── Makefile │ ├── build │ │ └── .keep │ ├── linker.ld │ └── src │ │ ├── shell.c │ │ └── shell.h └── stdlib │ ├── Makefile │ ├── build │ └── .keep │ └── src │ ├── memory.c │ ├── memory.h │ ├── peachos.asm │ ├── peachos.c │ ├── peachos.h │ ├── start.asm │ ├── start.c │ ├── stdio.c │ ├── stdio.h │ ├── stdlib.c │ ├── stdlib.h │ ├── string.c │ └── string.h └── src ├── boot └── boot.asm ├── config.h ├── disk ├── disk.c ├── disk.h ├── streamer.c └── streamer.h ├── fs ├── fat │ ├── fat16.c │ └── fat16.h ├── file.c ├── file.h ├── pparser.c └── pparser.h ├── gdt ├── gdt.asm ├── gdt.c └── gdt.h ├── idt ├── idt.asm ├── idt.c └── idt.h ├── io ├── io.asm └── io.h ├── isr80h ├── heap.c ├── heap.h ├── io.c ├── io.h ├── isr80h.c ├── isr80h.h ├── misc.c ├── misc.h ├── process.c └── process.h ├── kernel.asm ├── kernel.c ├── kernel.h ├── keyboard ├── classic.c ├── classic.h ├── keyboard.c └── keyboard.h ├── linker.ld ├── loader └── formats │ ├── elf.c │ ├── elf.h │ ├── elfloader.c │ └── elfloader.h ├── memory ├── heap │ ├── heap.c │ ├── heap.h │ ├── kheap.c │ └── kheap.h ├── memory.c ├── memory.h └── paging │ ├── paging.asm │ ├── paging.c │ └── paging.h ├── status.h ├── string ├── string.c └── string.h └── task ├── process.c ├── process.h ├── task.asm ├── task.c ├── task.h ├── tss.asm └── tss.h /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.tcc": "c", 4 | "algorithm": "c", 5 | "fstream": "c" 6 | } 7 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | FILES = ./build/kernel.asm.o ./build/kernel.o ./build/loader/formats/elf.o ./build/loader/formats/elfloader.o ./build/isr80h/isr80h.o ./build/isr80h/process.o ./build/isr80h/heap.o ./build/keyboard/keyboard.o ./build/keyboard/classic.o ./build/isr80h/io.o ./build/isr80h/misc.o ./build/disk/disk.o ./build/disk/streamer.o ./build/task/process.o ./build/task/task.o ./build/task/task.asm.o ./build/task/tss.asm.o ./build/fs/pparser.o ./build/fs/file.o ./build/fs/fat/fat16.o ./build/string/string.o ./build/idt/idt.asm.o ./build/idt/idt.o ./build/memory/memory.o ./build/io/io.asm.o ./build/gdt/gdt.o ./build/gdt/gdt.asm.o ./build/memory/heap/heap.o ./build/memory/heap/kheap.o ./build/memory/paging/paging.o ./build/memory/paging/paging.asm.o 2 | INCLUDES = -I./src 3 | FLAGS = -g -ffreestanding -falign-jumps -falign-functions -falign-labels -falign-loops -fstrength-reduce -fomit-frame-pointer -finline-functions -Wno-unused-function -fno-builtin -Werror -Wno-unused-label -Wno-cpp -Wno-unused-parameter -nostdlib -nostartfiles -nodefaultlibs -Wall -O0 -Iinc 4 | 5 | all: ./bin/boot.bin ./bin/kernel.bin user_programs 6 | rm -rf ./bin/os.bin 7 | dd if=./bin/boot.bin >> ./bin/os.bin 8 | dd if=./bin/kernel.bin >> ./bin/os.bin 9 | dd if=/dev/zero bs=1048576 count=16 >> ./bin/os.bin 10 | sudo mount -t vfat ./bin/os.bin /mnt/d 11 | # Copy a file over 12 | sudo cp ./hello.txt /mnt/d 13 | sudo cp ./programs/blank/blank.elf /mnt/d 14 | sudo cp ./programs/shell/shell.elf /mnt/d 15 | 16 | sudo umount /mnt/d 17 | ./bin/kernel.bin: $(FILES) 18 | i686-elf-ld -g -relocatable $(FILES) -o ./build/kernelfull.o 19 | i686-elf-gcc $(FLAGS) -T ./src/linker.ld -o ./bin/kernel.bin -ffreestanding -O0 -nostdlib ./build/kernelfull.o 20 | 21 | ./bin/boot.bin: ./src/boot/boot.asm 22 | nasm -f bin ./src/boot/boot.asm -o ./bin/boot.bin 23 | 24 | ./build/kernel.asm.o: ./src/kernel.asm 25 | nasm -f elf -g ./src/kernel.asm -o ./build/kernel.asm.o 26 | 27 | ./build/kernel.o: ./src/kernel.c 28 | i686-elf-gcc $(INCLUDES) $(FLAGS) -std=gnu99 -c ./src/kernel.c -o ./build/kernel.o 29 | 30 | ./build/idt/idt.asm.o: ./src/idt/idt.asm 31 | nasm -f elf -g ./src/idt/idt.asm -o ./build/idt/idt.asm.o 32 | 33 | ./build/loader/formats/elf.o: ./src/loader/formats/elf.c 34 | i686-elf-gcc $(INCLUDES) -I./src/loader/formats $(FLAGS) -std=gnu99 -c ./src/loader/formats/elf.c -o ./build/loader/formats/elf.o 35 | 36 | ./build/loader/formats/elfloader.o: ./src/loader/formats/elfloader.c 37 | i686-elf-gcc $(INCLUDES) -I./src/loader/formats $(FLAGS) -std=gnu99 -c ./src/loader/formats/elfloader.c -o ./build/loader/formats/elfloader.o 38 | 39 | ./build/gdt/gdt.o: ./src/gdt/gdt.c 40 | i686-elf-gcc $(INCLUDES) -I./src/gdt $(FLAGS) -std=gnu99 -c ./src/gdt/gdt.c -o ./build/gdt/gdt.o 41 | 42 | ./build/gdt/gdt.asm.o: ./src/gdt/gdt.asm 43 | nasm -f elf -g ./src/gdt/gdt.asm -o ./build/gdt/gdt.asm.o 44 | 45 | ./build/isr80h/isr80h.o: ./src/isr80h/isr80h.c 46 | i686-elf-gcc $(INCLUDES) -I./src/isr80h $(FLAGS) -std=gnu99 -c ./src/isr80h/isr80h.c -o ./build/isr80h/isr80h.o 47 | 48 | ./build/isr80h/heap.o: ./src/isr80h/heap.c 49 | i686-elf-gcc $(INCLUDES) -I./src/isr80h $(FLAGS) -std=gnu99 -c ./src/isr80h/heap.c -o ./build/isr80h/heap.o 50 | 51 | ./build/isr80h/misc.o: ./src/isr80h/misc.c 52 | i686-elf-gcc $(INCLUDES) -I./src/isr80h $(FLAGS) -std=gnu99 -c ./src/isr80h/misc.c -o ./build/isr80h/misc.o 53 | 54 | ./build/isr80h/io.o: ./src/isr80h/io.c 55 | i686-elf-gcc $(INCLUDES) -I./src/isr80h $(FLAGS) -std=gnu99 -c ./src/isr80h/io.c -o ./build/isr80h/io.o 56 | 57 | ./build/isr80h/process.o: ./src/isr80h/process.c 58 | i686-elf-gcc $(INCLUDES) -I./src/isr80h $(FLAGS) -std=gnu99 -c ./src/isr80h/process.c -o ./build/isr80h/process.o 59 | 60 | 61 | ./build/keyboard/keyboard.o: ./src/keyboard/keyboard.c 62 | i686-elf-gcc $(INCLUDES) -I./src/keyboard $(FLAGS) -std=gnu99 -c ./src/keyboard/keyboard.c -o ./build/keyboard/keyboard.o 63 | 64 | 65 | ./build/keyboard/classic.o: ./src/keyboard/classic.c 66 | i686-elf-gcc $(INCLUDES) -I./src/keyboard $(FLAGS) -std=gnu99 -c ./src/keyboard/classic.c -o ./build/keyboard/classic.o 67 | 68 | 69 | ./build/idt/idt.o: ./src/idt/idt.c 70 | i686-elf-gcc $(INCLUDES) -I./src/idt $(FLAGS) -std=gnu99 -c ./src/idt/idt.c -o ./build/idt/idt.o 71 | 72 | ./build/memory/memory.o: ./src/memory/memory.c 73 | i686-elf-gcc $(INCLUDES) -I./src/memory $(FLAGS) -std=gnu99 -c ./src/memory/memory.c -o ./build/memory/memory.o 74 | 75 | 76 | ./build/task/process.o: ./src/task/process.c 77 | i686-elf-gcc $(INCLUDES) -I./src/task $(FLAGS) -std=gnu99 -c ./src/task/process.c -o ./build/task/process.o 78 | 79 | 80 | ./build/task/task.o: ./src/task/task.c 81 | i686-elf-gcc $(INCLUDES) -I./src/task $(FLAGS) -std=gnu99 -c ./src/task/task.c -o ./build/task/task.o 82 | 83 | ./build/task/task.asm.o: ./src/task/task.asm 84 | nasm -f elf -g ./src/task/task.asm -o ./build/task/task.asm.o 85 | 86 | ./build/task/tss.asm.o: ./src/task/tss.asm 87 | nasm -f elf -g ./src/task/tss.asm -o ./build/task/tss.asm.o 88 | 89 | ./build/io/io.asm.o: ./src/io/io.asm 90 | nasm -f elf -g ./src/io/io.asm -o ./build/io/io.asm.o 91 | 92 | ./build/memory/heap/heap.o: ./src/memory/heap/heap.c 93 | i686-elf-gcc $(INCLUDES) -I./src/memory/heap $(FLAGS) -std=gnu99 -c ./src/memory/heap/heap.c -o ./build/memory/heap/heap.o 94 | 95 | ./build/memory/heap/kheap.o: ./src/memory/heap/kheap.c 96 | i686-elf-gcc $(INCLUDES) -I./src/memory/heap $(FLAGS) -std=gnu99 -c ./src/memory/heap/kheap.c -o ./build/memory/heap/kheap.o 97 | 98 | ./build/memory/paging/paging.o: ./src/memory/paging/paging.c 99 | i686-elf-gcc $(INCLUDES) -I./src/memory/paging $(FLAGS) -std=gnu99 -c ./src/memory/paging/paging.c -o ./build/memory/paging/paging.o 100 | 101 | ./build/memory/paging/paging.asm.o: ./src/memory/paging/paging.asm 102 | nasm -f elf -g ./src/memory/paging/paging.asm -o ./build/memory/paging/paging.asm.o 103 | 104 | ./build/disk/disk.o: ./src/disk/disk.c 105 | i686-elf-gcc $(INCLUDES) -I./src/disk $(FLAGS) -std=gnu99 -c ./src/disk/disk.c -o ./build/disk/disk.o 106 | 107 | ./build/disk/streamer.o: ./src/disk/streamer.c 108 | i686-elf-gcc $(INCLUDES) -I./src/disk $(FLAGS) -std=gnu99 -c ./src/disk/streamer.c -o ./build/disk/streamer.o 109 | 110 | ./build/fs/fat/fat16.o: ./src/fs/fat/fat16.c 111 | i686-elf-gcc $(INCLUDES) -I./src/fs -I./src/fat $(FLAGS) -std=gnu99 -c ./src/fs/fat/fat16.c -o ./build/fs/fat/fat16.o 112 | 113 | 114 | ./build/fs/file.o: ./src/fs/file.c 115 | i686-elf-gcc $(INCLUDES) -I./src/fs $(FLAGS) -std=gnu99 -c ./src/fs/file.c -o ./build/fs/file.o 116 | 117 | ./build/fs/pparser.o: ./src/fs/pparser.c 118 | i686-elf-gcc $(INCLUDES) -I./src/fs $(FLAGS) -std=gnu99 -c ./src/fs/pparser.c -o ./build/fs/pparser.o 119 | 120 | ./build/string/string.o: ./src/string/string.c 121 | i686-elf-gcc $(INCLUDES) -I./src/string $(FLAGS) -std=gnu99 -c ./src/string/string.c -o ./build/string/string.o 122 | 123 | user_programs: 124 | cd ./programs/stdlib && $(MAKE) all 125 | cd ./programs/blank && $(MAKE) all 126 | cd ./programs/shell && $(MAKE) all 127 | 128 | user_programs_clean: 129 | cd ./programs/stdlib && $(MAKE) clean 130 | cd ./programs/blank && $(MAKE) clean 131 | cd ./programs/shell && $(MAKE) clean 132 | 133 | clean: user_programs_clean 134 | rm -rf ./bin/boot.bin 135 | rm -rf ./bin/kernel.bin 136 | rm -rf ./bin/os.bin 137 | rm -rf ${FILES} 138 | rm -rf ./build/kernelfull.o -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Developing a Multithreaded Kernel from Scratch 2 | 3 | Welcome to our comprehensive kernel development course, meticulously designed for learners who are interested in creating a multitasking operating system and kernel from the ground up. This course assumes no previous experience in kernel programming, ensuring a complete understanding of concepts starting from the basics. This is the code repository you will build from scratch when learning kernel development in our kernel course. 4 | 5 | [![Get the Course](https://img.shields.io/badge/Get%20the%20Course-Discount%20Link-blue?style=for-the-badge&logo=appveyor)](https://dragonzap.com/course/developing-a-multithreaded-kernel-from-scratch?coupon=GITHUBKERNELDISCOUNT) 6 | 7 | ## About this Course 8 | 9 | The course is divided into several main sections: 10 | 11 | - **Real Mode Development** 12 | - **Protected Mode Development** 13 | - **Assembly Language Bonus** 14 | 15 | Each section offers a unique perspective on kernel development and is designed to build your skills incrementally. 16 | 17 | ### Real Mode Development 18 | 19 | This is your introduction to kernel development, here we cover: 20 | 21 | - The boot process and how memory works 22 | - Writing a boot loader in assembly language 23 | - Working with interrupts in real mode 24 | - Reading a sector (512 bytes) from the hard disk 25 | 26 | ### Protected Mode Development 27 | 28 | Delve deep into the creation of a 32-bit multi-tasking kernel featuring: 29 | 30 | - FAT16 filesystem implementation 31 | - Memory management and virtualization techniques 32 | - Keyboard driver implementation 33 | - ELF file loader creation 34 | - Design of a virtual filesystem layer (inspired by Linux kernel) 35 | - Process and task functionality 36 | 37 | ### Assembly Language Bonus 38 | 39 | If you struggle with assembly language, this bonus section aims to bring your skills up to speed. 40 | 41 | ## Instructor 42 | 43 | This course is taught by an experienced instructor who has developed Linux kernel modules professionally. 44 | 45 | ## Prerequisites 46 | 47 | - Understanding of the C programming language 48 | - Understanding of Assembly Language 49 | 50 | ## Who is this course for? 51 | 52 | This course is ideal for individuals interested in developing a kernel from scratch. 53 | 54 | ## What you'll learn 55 | 56 | By the end of the course, you will acquire skills in: 57 | 58 | - Creating a kernel from scratch 59 | - Developing a multi-tasking kernel 60 | - Handling problematic programs in your operating system 61 | - Understanding how memory works in computers 62 | - Differentiating between kernel land, user land, and the protection rings 63 | - Learning kernel design patterns used by Linux 64 | - Understanding and implementing virtual memory 65 | - Developing processes and tasks in the kernel 66 | - Loading ELF files 67 | - Debugging disassembled machine code 68 | - Debugging your kernel in an emulator with GDB 69 | 70 | Ready to begin your kernel development journey? [Enroll in the course now](https://dragonzap.com/course/developing-a-multithreaded-kernel-from-scratch?coupon=GITHUBKERNELDISCOUNT) with a special discount! 71 | -------------------------------------------------------------------------------- /bin/core: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/bin/core -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | export PREFIX="$HOME/opt/cross" 3 | export TARGET=i686-elf 4 | export PATH="$PREFIX/bin:$PATH" 5 | make all 6 | -------------------------------------------------------------------------------- /build/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/.keep -------------------------------------------------------------------------------- /build/disk/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/disk/.keep -------------------------------------------------------------------------------- /build/fs/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/fs/.keep -------------------------------------------------------------------------------- /build/fs/fat/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/fs/fat/.keep -------------------------------------------------------------------------------- /build/gdt/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/gdt/.keep -------------------------------------------------------------------------------- /build/idt/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/idt/.keep -------------------------------------------------------------------------------- /build/io/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/io/.keep -------------------------------------------------------------------------------- /build/isr80h/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/isr80h/.keep -------------------------------------------------------------------------------- /build/keyboard/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/keyboard/.keep -------------------------------------------------------------------------------- /build/loader/formats/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/loader/formats/.keep -------------------------------------------------------------------------------- /build/memory/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/memory/.keep -------------------------------------------------------------------------------- /build/memory/heap/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/memory/heap/.keep -------------------------------------------------------------------------------- /build/memory/paging/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/memory/paging/.keep -------------------------------------------------------------------------------- /build/task/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/build/task/.keep -------------------------------------------------------------------------------- /hello.txt: -------------------------------------------------------------------------------- 1 | Testo world! -------------------------------------------------------------------------------- /programs/blank/Makefile: -------------------------------------------------------------------------------- 1 | FILES=./build/blank.o 2 | INCLUDES= -I../stdlib/src 3 | FLAGS= -g -ffreestanding -falign-jumps -falign-functions -falign-labels -falign-loops -fstrength-reduce -fomit-frame-pointer -finline-functions -Wno-unused-function -fno-builtin -Werror -Wno-unused-label -Wno-cpp -Wno-unused-parameter -nostdlib -nostartfiles -nodefaultlibs -Wall -O0 -Iinc 4 | all: ${FILES} 5 | i686-elf-gcc -g -T ./linker.ld -o ./blank.elf -ffreestanding -O0 -nostdlib -fpic -g ${FILES} ../stdlib/stdlib.elf 6 | 7 | ./build/blank.o: ./blank.c 8 | i686-elf-gcc ${INCLUDES} -I./ $(FLAGS) -std=gnu99 -c ./blank.c -o ./build/blank.o 9 | 10 | clean: 11 | rm -rf ${FILES} 12 | rm ./blank.elf -------------------------------------------------------------------------------- /programs/blank/blank.c: -------------------------------------------------------------------------------- 1 | #include "peachos.h" 2 | #include "stdlib.h" 3 | #include "stdio.h" 4 | #include "string.h" 5 | int main(int argc, char** argv) 6 | { 7 | while(1) 8 | { 9 | print(argv[0]); 10 | for (int i = 0; i < 1000000; i++) 11 | { 12 | 13 | } 14 | } 15 | return 0; 16 | } -------------------------------------------------------------------------------- /programs/blank/build/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/programs/blank/build/.keep -------------------------------------------------------------------------------- /programs/blank/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | OUTPUT_FORMAT(elf32-i386) 3 | SECTIONS 4 | { 5 | . = 0x400000; 6 | .text : ALIGN(4096) 7 | { 8 | *(.text) 9 | } 10 | 11 | .asm : ALIGN(4096) 12 | { 13 | *(.asm) 14 | } 15 | 16 | .rodata : ALIGN(4096) 17 | { 18 | *(.rodata) 19 | } 20 | 21 | .data : ALIGN(4096) 22 | { 23 | *(.data) 24 | } 25 | 26 | .bss : ALIGN(4096) 27 | { 28 | *(COMMON) 29 | *(.bss) 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /programs/shell/Makefile: -------------------------------------------------------------------------------- 1 | FILES=./build/shell.o 2 | INCLUDES= -I../stdlib/src 3 | FLAGS= -g -ffreestanding -falign-jumps -falign-functions -falign-labels -falign-loops -fstrength-reduce -fomit-frame-pointer -finline-functions -Wno-unused-function -fno-builtin -Werror -Wno-unused-label -Wno-cpp -Wno-unused-parameter -nostdlib -nostartfiles -nodefaultlibs -Wall -O0 -Iinc 4 | all: ${FILES} 5 | i686-elf-gcc -g -T ./linker.ld -o ./shell.elf -ffreestanding -O0 -nostdlib -fpic -g ${FILES} ../stdlib/stdlib.elf 6 | 7 | ./build/shell.o: ./src/shell.c 8 | i686-elf-gcc ${INCLUDES} -I./ $(FLAGS) -std=gnu99 -c ./src/shell.c -o ./build/shell.o 9 | 10 | clean: 11 | rm -rf ${FILES} 12 | rm ./shell.elf -------------------------------------------------------------------------------- /programs/shell/build/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/programs/shell/build/.keep -------------------------------------------------------------------------------- /programs/shell/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | OUTPUT_FORMAT(elf32-i386) 3 | SECTIONS 4 | { 5 | . = 0x400000; 6 | .text : ALIGN(4096) 7 | { 8 | *(.text) 9 | } 10 | 11 | .asm : ALIGN(4096) 12 | { 13 | *(.asm) 14 | } 15 | 16 | .rodata : ALIGN(4096) 17 | { 18 | *(.rodata) 19 | } 20 | 21 | .data : ALIGN(4096) 22 | { 23 | *(.data) 24 | } 25 | 26 | .bss : ALIGN(4096) 27 | { 28 | *(COMMON) 29 | *(.bss) 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /programs/shell/src/shell.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | #include "stdio.h" 3 | #include "stdlib.h" 4 | #include "peachos.h" 5 | int main(int argc, char** argv) 6 | { 7 | print("PeachOS v1.0.0\n"); 8 | while(1) 9 | { 10 | print("> "); 11 | char buf[1024]; 12 | peachos_terminal_readline(buf, sizeof(buf), true); 13 | print("\n"); 14 | peachos_system_run(buf); 15 | 16 | print("\n"); 17 | } 18 | return 0; 19 | } -------------------------------------------------------------------------------- /programs/shell/src/shell.h: -------------------------------------------------------------------------------- 1 | #ifndef SHELL_H 2 | #define SHELL_H 3 | 4 | #endif -------------------------------------------------------------------------------- /programs/stdlib/Makefile: -------------------------------------------------------------------------------- 1 | FILES=./build/start.asm.o ./build/start.o ./build/peachos.asm.o ./build/peachos.o ./build/stdlib.o ./build/stdio.o ./build/string.o ./build/memory.o 2 | INCLUDES=-I./src 3 | FLAGS= -g -ffreestanding -falign-jumps -falign-functions -falign-labels -falign-loops -fstrength-reduce -fomit-frame-pointer -finline-functions -Wno-unused-function -fno-builtin -Werror -Wno-unused-label -Wno-cpp -Wno-unused-parameter -nostdlib -nostartfiles -nodefaultlibs -Wall -O0 -Iinc 4 | 5 | all: ${FILES} 6 | i686-elf-ld -m elf_i386 -relocatable ${FILES} -o ./stdlib.elf 7 | 8 | ./build/start.asm.o: ./src/start.asm 9 | nasm -f elf ./src/start.asm -o ./build/start.asm.o 10 | 11 | ./build/peachos.asm.o: ./src/peachos.asm 12 | nasm -f elf ./src/peachos.asm -o ./build/peachos.asm.o 13 | 14 | ./build/peachos.o: ./src/peachos.c 15 | i686-elf-gcc ${INCLUDES} $(FLAGS) -std=gnu99 -c ./src/peachos.c -o ./build/peachos.o 16 | 17 | ./build/stdlib.o: ./src/stdlib.c 18 | i686-elf-gcc ${INCLUDES} $(FLAGS) -std=gnu99 -c ./src/stdlib.c -o ./build/stdlib.o 19 | 20 | ./build/stdio.o: ./src/stdio.c 21 | i686-elf-gcc ${INCLUDES} $(FLAGS) -std=gnu99 -c ./src/stdio.c -o ./build/stdio.o 22 | 23 | 24 | ./build/string.o: ./src/string.c 25 | i686-elf-gcc ${INCLUDES} $(FLAGS) -std=gnu99 -c ./src/string.c -o ./build/string.o 26 | 27 | ./build/memory.o: ./src/memory.c 28 | i686-elf-gcc ${INCLUDES} $(FLAGS) -std=gnu99 -c ./src/memory.c -o ./build/memory.o 29 | 30 | ./build/start.o: ./src/start.c 31 | i686-elf-gcc ${INCLUDES} $(FLAGS) -std=gnu99 -c ./src/start.c -o ./build/start.o 32 | 33 | 34 | clean: 35 | rm -rf ${FILES} 36 | rm ./stdlib.elf -------------------------------------------------------------------------------- /programs/stdlib/build/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nibblebits/PeachOS/a3b2b23f59efd70fc7b522daa45f3052cc9b96dc/programs/stdlib/build/.keep -------------------------------------------------------------------------------- /programs/stdlib/src/memory.c: -------------------------------------------------------------------------------- 1 | #include "memory.h" 2 | 3 | void* memset(void* ptr, int c, size_t size) 4 | { 5 | char* c_ptr = (char*) ptr; 6 | for (int i = 0; i < size; i++) 7 | { 8 | c_ptr[i] = (char) c; 9 | } 10 | return ptr; 11 | } 12 | 13 | int memcmp(void* s1, void* s2, int count) 14 | { 15 | char* c1 = s1; 16 | char* c2 = s2; 17 | while(count-- > 0) 18 | { 19 | if (*c1++ != *c2++) 20 | { 21 | return c1[-1] < c2[-1] ? -1 : 1; 22 | } 23 | } 24 | 25 | return 0; 26 | } 27 | 28 | void* memcpy(void* dest, void* src, int len) 29 | { 30 | char *d = dest; 31 | char *s = src; 32 | while(len--) 33 | { 34 | *d++ = *s++; 35 | } 36 | return dest; 37 | } -------------------------------------------------------------------------------- /programs/stdlib/src/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef PEACHOS_MEMORY_H 2 | #define PEACHOS_MEMORY_H 3 | 4 | #include 5 | void* memset(void* ptr, int c, size_t size); 6 | int memcmp(void* s1, void* s2, int count); 7 | void* memcpy(void* dest, void* src, int len); 8 | #endif -------------------------------------------------------------------------------- /programs/stdlib/src/peachos.asm: -------------------------------------------------------------------------------- 1 | [BITS 32] 2 | 3 | section .asm 4 | 5 | global print:function 6 | global peachos_getkey:function 7 | global peachos_malloc:function 8 | global peachos_free:function 9 | global peachos_putchar:function 10 | global peachos_process_load_start:function 11 | global peachos_process_get_arguments:function 12 | global peachos_system:function 13 | global peachos_exit:function 14 | 15 | ; void print(const char* filename) 16 | print: 17 | push ebp 18 | mov ebp, esp 19 | push dword[ebp+8] 20 | mov eax, 1 ; Command print 21 | int 0x80 22 | add esp, 4 23 | pop ebp 24 | ret 25 | 26 | ; int peachos_getkey() 27 | peachos_getkey: 28 | push ebp 29 | mov ebp, esp 30 | mov eax, 2 ; Command getkey 31 | int 0x80 32 | pop ebp 33 | ret 34 | 35 | ; void peachos_putchar(char c) 36 | peachos_putchar: 37 | push ebp 38 | mov ebp, esp 39 | mov eax, 3 ; Command putchar 40 | push dword [ebp+8] ; Variable "c" 41 | int 0x80 42 | add esp, 4 43 | pop ebp 44 | ret 45 | 46 | ; void* peachos_malloc(size_t size) 47 | peachos_malloc: 48 | push ebp 49 | mov ebp, esp 50 | mov eax, 4 ; Command malloc (Allocates memory for the process) 51 | push dword[ebp+8] ; Variable "size" 52 | int 0x80 53 | add esp, 4 54 | pop ebp 55 | ret 56 | 57 | ; void peachos_free(void* ptr) 58 | peachos_free: 59 | push ebp 60 | mov ebp, esp 61 | mov eax, 5 ; Command 5 free (Frees the allocated memory for this process) 62 | push dword[ebp+8] ; Variable "ptr" 63 | int 0x80 64 | add esp, 4 65 | pop ebp 66 | ret 67 | 68 | ; void peachos_process_load_start(const char* filename) 69 | peachos_process_load_start: 70 | push ebp 71 | mov ebp, esp 72 | mov eax, 6 ; Command 6 process load start ( stars a process ) 73 | push dword[ebp+8] ; Variable "filename" 74 | int 0x80 75 | add esp, 4 76 | pop ebp 77 | ret 78 | 79 | ; int peachos_system(struct command_argument* arguments) 80 | peachos_system: 81 | push ebp 82 | mov ebp, esp 83 | mov eax, 7 ; Command 7 process_system ( runs a system command based on the arguments) 84 | push dword[ebp+8] ; Variable "arguments" 85 | int 0x80 86 | add esp, 4 87 | pop ebp 88 | ret 89 | 90 | 91 | ; void peachos_process_get_arguments(struct process_arguments* arguments) 92 | peachos_process_get_arguments: 93 | push ebp 94 | mov ebp, esp 95 | mov eax, 8 ; Command 8 Gets the process arguments 96 | push dword[ebp+8] ; Variable arguments 97 | int 0x80 98 | add esp, 4 99 | pop ebp 100 | ret 101 | 102 | ; void peachos_exit() 103 | peachos_exit: 104 | push ebp 105 | mov ebp, esp 106 | mov eax, 9 ; Command 9 process exit 107 | int 0x80 108 | pop ebp 109 | ret -------------------------------------------------------------------------------- /programs/stdlib/src/peachos.c: -------------------------------------------------------------------------------- 1 | #include "peachos.h" 2 | #include "string.h" 3 | 4 | struct command_argument* peachos_parse_command(const char* command, int max) 5 | { 6 | struct command_argument* root_command = 0; 7 | char scommand[1025]; 8 | if (max >= (int) sizeof(scommand)) 9 | { 10 | return 0; 11 | } 12 | 13 | 14 | strncpy(scommand, command, sizeof(scommand)); 15 | char* token = strtok(scommand, " "); 16 | if (!token) 17 | { 18 | goto out; 19 | } 20 | 21 | root_command = peachos_malloc(sizeof(struct command_argument)); 22 | if (!root_command) 23 | { 24 | goto out; 25 | } 26 | 27 | strncpy(root_command->argument, token, sizeof(root_command->argument)); 28 | root_command->next = 0; 29 | 30 | 31 | struct command_argument* current = root_command; 32 | token = strtok(NULL, " "); 33 | while(token != 0) 34 | { 35 | struct command_argument* new_command = peachos_malloc(sizeof(struct command_argument)); 36 | if (!new_command) 37 | { 38 | break; 39 | } 40 | 41 | strncpy(new_command->argument, token, sizeof(new_command->argument)); 42 | new_command->next = 0x00; 43 | current->next = new_command; 44 | current = new_command; 45 | token = strtok(NULL, " "); 46 | } 47 | out: 48 | return root_command; 49 | } 50 | int peachos_getkeyblock() 51 | { 52 | int val = 0; 53 | do 54 | { 55 | val = peachos_getkey(); 56 | } 57 | while(val == 0); 58 | return val; 59 | } 60 | 61 | void peachos_terminal_readline(char* out, int max, bool output_while_typing) 62 | { 63 | int i = 0; 64 | for (i = 0; i < max -1; i++) 65 | { 66 | char key = peachos_getkeyblock(); 67 | 68 | // Carriage return means we have read the line 69 | if (key == 13) 70 | { 71 | break; 72 | } 73 | 74 | if (output_while_typing) 75 | { 76 | peachos_putchar(key); 77 | } 78 | 79 | // Backspace 80 | if (key == 0x08 && i >= 1) 81 | { 82 | out[i-1] = 0x00; 83 | // -2 because we will +1 when we go to the continue 84 | i -= 2; 85 | continue; 86 | } 87 | 88 | out[i] = key; 89 | } 90 | 91 | // Add the null terminator 92 | out[i] = 0x00; 93 | } 94 | 95 | int peachos_system_run(const char* command) 96 | { 97 | char buf[1024]; 98 | strncpy(buf, command, sizeof(buf)); 99 | struct command_argument* root_command_argument = peachos_parse_command(buf, sizeof(buf)); 100 | if (!root_command_argument) 101 | { 102 | return -1; 103 | } 104 | 105 | return peachos_system(root_command_argument); 106 | } -------------------------------------------------------------------------------- /programs/stdlib/src/peachos.h: -------------------------------------------------------------------------------- 1 | #ifndef PEACHOS_H 2 | #define PEACHOS_H 3 | #include 4 | #include 5 | 6 | 7 | struct command_argument 8 | { 9 | char argument[512]; 10 | struct command_argument* next; 11 | }; 12 | 13 | struct process_arguments 14 | { 15 | int argc; 16 | char** argv; 17 | }; 18 | 19 | 20 | void print(const char* filename); 21 | int peachos_getkey(); 22 | 23 | void* peachos_malloc(size_t size); 24 | void peachos_free(void* ptr); 25 | void peachos_putchar(char c); 26 | int peachos_getkeyblock(); 27 | void peachos_terminal_readline(char* out, int max, bool output_while_typing); 28 | void peachos_process_load_start(const char* filename); 29 | struct command_argument* peachos_parse_command(const char* command, int max); 30 | void peachos_process_get_arguments(struct process_arguments* arguments); 31 | int peachos_system(struct command_argument* arguments); 32 | int peachos_system_run(const char* command); 33 | void peachos_exit(); 34 | #endif -------------------------------------------------------------------------------- /programs/stdlib/src/start.asm: -------------------------------------------------------------------------------- 1 | [BITS 32] 2 | 3 | global _start 4 | extern c_start 5 | extern peachos_exit 6 | 7 | section .asm 8 | 9 | _start: 10 | call c_start 11 | call peachos_exit 12 | ret -------------------------------------------------------------------------------- /programs/stdlib/src/start.c: -------------------------------------------------------------------------------- 1 | #include "peachos.h" 2 | 3 | extern int main(int argc, char** argv); 4 | 5 | void c_start() 6 | { 7 | struct process_arguments arguments; 8 | peachos_process_get_arguments(&arguments); 9 | 10 | int res = main(arguments.argc, arguments.argv); 11 | if (res == 0) 12 | { 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /programs/stdlib/src/stdio.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "peachos.h" 3 | #include "stdlib.h" 4 | #include 5 | int putchar(int c) 6 | { 7 | peachos_putchar((char)c); 8 | return 0; 9 | } 10 | 11 | int printf(const char *fmt, ...) 12 | { 13 | va_list ap; 14 | const char *p; 15 | char* sval; 16 | int ival; 17 | 18 | va_start(ap, fmt); 19 | for (p = fmt; *p; p++) 20 | { 21 | if (*p != '%') 22 | { 23 | putchar(*p); 24 | continue; 25 | } 26 | 27 | switch (*++p) 28 | { 29 | case 'i': 30 | ival = va_arg(ap, int); 31 | print(itoa(ival)); 32 | break; 33 | 34 | case 's': 35 | sval = va_arg(ap, char *); 36 | print(sval); 37 | break; 38 | 39 | default: 40 | putchar(*p); 41 | break; 42 | } 43 | } 44 | 45 | va_end(ap); 46 | 47 | return 0; 48 | } -------------------------------------------------------------------------------- /programs/stdlib/src/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef PEACHOS_STDIO 2 | #define PEACHOS_STDIO 3 | 4 | int putchar(int c); 5 | int printf(const char *fmt, ...); 6 | 7 | #endif -------------------------------------------------------------------------------- /programs/stdlib/src/stdlib.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "peachos.h" 3 | 4 | char* itoa(int i) 5 | { 6 | static char text[12]; 7 | int loc = 11; 8 | text[11] = 0; 9 | char neg = 1; 10 | if (i >= 0) 11 | { 12 | neg = 0; 13 | i = -i; 14 | } 15 | 16 | while(i) 17 | { 18 | text[--loc] = '0' - (i % 10); 19 | i /= 10; 20 | } 21 | 22 | if (loc == 11) 23 | text[--loc] = '0'; 24 | 25 | if (neg) 26 | text[--loc] = '-'; 27 | 28 | return &text[loc]; 29 | } 30 | 31 | void* malloc(size_t size) 32 | { 33 | return peachos_malloc(size); 34 | } 35 | 36 | void free(void* ptr) 37 | { 38 | peachos_free(ptr); 39 | } -------------------------------------------------------------------------------- /programs/stdlib/src/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef PEACHOS_STDLIB_H 2 | #define PEACHOS_STDLIB_H 3 | #include 4 | 5 | void* malloc(size_t size); 6 | void free(void* ptr); 7 | char* itoa(int i); 8 | #endif -------------------------------------------------------------------------------- /programs/stdlib/src/string.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char tolower(char s1) 4 | { 5 | if (s1 >= 65 && s1 <= 90) 6 | { 7 | s1 += 32; 8 | } 9 | 10 | return s1; 11 | } 12 | 13 | int strlen(const char* ptr) 14 | { 15 | int i = 0; 16 | while(*ptr != 0) 17 | { 18 | i++; 19 | ptr += 1; 20 | } 21 | 22 | return i; 23 | } 24 | 25 | int strnlen(const char* ptr, int max) 26 | { 27 | int i = 0; 28 | for (i = 0; i < max; i++) 29 | { 30 | if (ptr[i] == 0) 31 | break; 32 | } 33 | 34 | return i; 35 | } 36 | 37 | int strnlen_terminator(const char* str, int max, char terminator) 38 | { 39 | int i = 0; 40 | for(i = 0; i < max; i++) 41 | { 42 | if (str[i] == '\0' || str[i] == terminator) 43 | break; 44 | } 45 | 46 | return i; 47 | } 48 | 49 | int istrncmp(const char* s1, const char* s2, int n) 50 | { 51 | unsigned char u1, u2; 52 | while(n-- > 0) 53 | { 54 | u1 = (unsigned char)*s1++; 55 | u2 = (unsigned char)*s2++; 56 | if (u1 != u2 && tolower(u1) != tolower(u2)) 57 | return u1 - u2; 58 | if (u1 == '\0') 59 | return 0; 60 | } 61 | 62 | return 0; 63 | } 64 | int strncmp(const char* str1, const char* str2, int n) 65 | { 66 | unsigned char u1, u2; 67 | 68 | while(n-- > 0) 69 | { 70 | u1 = (unsigned char)*str1++; 71 | u2 = (unsigned char)*str2++; 72 | if (u1 != u2) 73 | return u1 - u2; 74 | if (u1 == '\0') 75 | return 0; 76 | } 77 | 78 | return 0; 79 | } 80 | 81 | char* strcpy(char* dest, const char* src) 82 | { 83 | char* res = dest; 84 | while(*src != 0) 85 | { 86 | *dest = *src; 87 | src += 1; 88 | dest += 1; 89 | } 90 | 91 | *dest = 0x00; 92 | 93 | return res; 94 | } 95 | 96 | char* strncpy(char* dest, const char* src, int count) 97 | { 98 | int i = 0; 99 | for (i = 0; i < count-1; i++) 100 | { 101 | if (src[i] == 0x00) 102 | break; 103 | 104 | dest[i] = src[i]; 105 | } 106 | 107 | dest[i] = 0x00; 108 | return dest; 109 | } 110 | 111 | bool isdigit(char c) 112 | { 113 | return c >= 48 && c <= 57; 114 | } 115 | int tonumericdigit(char c) 116 | { 117 | return c - 48; 118 | } 119 | 120 | char* sp = 0; 121 | char* strtok(char* str, const char* delimiters) 122 | { 123 | int i = 0; 124 | int len = strlen(delimiters); 125 | if (!str && !sp) 126 | return 0; 127 | 128 | if (str && !sp) 129 | { 130 | sp = str; 131 | } 132 | 133 | char* p_start = sp; 134 | while(1) 135 | { 136 | for (i = 0; i < len; i++) 137 | { 138 | if(*p_start == delimiters[i]) 139 | { 140 | p_start++; 141 | break; 142 | } 143 | } 144 | 145 | if (i == len) 146 | { 147 | sp = p_start; 148 | break; 149 | } 150 | } 151 | 152 | if (*sp == '\0') 153 | { 154 | sp = 0; 155 | return sp; 156 | } 157 | 158 | // Find end of substring 159 | while(*sp != '\0') 160 | { 161 | for (i = 0; i < len; i++) 162 | { 163 | if (*sp == delimiters[i]) 164 | { 165 | *sp = '\0'; 166 | break; 167 | } 168 | } 169 | 170 | sp++; 171 | if (i < len) 172 | break; 173 | } 174 | 175 | return p_start; 176 | } -------------------------------------------------------------------------------- /programs/stdlib/src/string.h: -------------------------------------------------------------------------------- 1 | #ifndef PEACHOS_STRING_H 2 | #define PEACHOS_STRING_H 3 | 4 | #include 5 | 6 | char tolower(char s1); 7 | int strlen(const char* ptr); 8 | int strnlen(const char* ptr, int max); 9 | int strnlen_terminator(const char* str, int max, char terminator); 10 | int istrncmp(const char* s1, const char* s2, int n); 11 | int strncmp(const char* str1, const char* str2, int n); 12 | char* strcpy(char* dest, const char* src); 13 | char* strncpy(char* dest, const char* src, int count); 14 | bool isdigit(char c); 15 | int tonumericdigit(char c); 16 | char* strtok(char* str, const char* delimiters); 17 | 18 | #endif -------------------------------------------------------------------------------- /src/boot/boot.asm: -------------------------------------------------------------------------------- 1 | ORG 0x7c00 2 | BITS 16 3 | 4 | CODE_SEG equ gdt_code - gdt_start 5 | DATA_SEG equ gdt_data - gdt_start 6 | 7 | jmp short start 8 | nop 9 | 10 | ; FAT16 Header 11 | OEMIdentifier db 'PEACHOS ' 12 | BytesPerSector dw 0x200 13 | SectorsPerCluster db 0x80 14 | ReservedSectors dw 200 15 | FATCopies db 0x02 16 | RootDirEntries dw 0x40 17 | NumSectors dw 0x00 18 | MediaType db 0xF8 19 | SectorsPerFat dw 0x100 20 | SectorsPerTrack dw 0x20 21 | NumberOfHeads dw 0x40 22 | HiddenSectors dd 0x00 23 | SectorsBig dd 0x773594 24 | 25 | ; Extended BPB (Dos 4.0) 26 | DriveNumber db 0x80 27 | WinNTBit db 0x00 28 | Signature db 0x29 29 | VolumeID dd 0xD105 30 | VolumeIDString db 'PEACHOS BOO' 31 | SystemIDString db 'FAT16 ' 32 | 33 | 34 | start: 35 | jmp 0:step2 36 | 37 | step2: 38 | cli ; Clear Interrupts 39 | mov ax, 0x00 40 | mov ds, ax 41 | mov es, ax 42 | mov ss, ax 43 | mov fs, ax 44 | mov es, ax 45 | 46 | mov sp, 0x7c00 47 | sti ; Enables Interrupts 48 | 49 | .load_protected: 50 | cli 51 | lgdt[gdt_descriptor] 52 | mov eax, cr0 53 | or eax, 0x1 54 | mov cr0, eax 55 | jmp CODE_SEG:load32 56 | 57 | ; GDT 58 | gdt_start: 59 | gdt_null: 60 | dd 0x0 61 | dd 0x0 62 | 63 | ; offset 0x8 64 | gdt_code: ; CS SHOULD POINT TO THIS 65 | dw 0xffff ; Segment limit first 0-15 bits 66 | dw 0 ; Base first 0-15 bits 67 | db 0 ; Base 16-23 bits 68 | db 0x9a ; Access byte 69 | db 11001111b ; High 4 bit flags and the low 4 bit flags 70 | db 0 ; Base 24-31 bits 71 | 72 | ; offset 0x10 73 | gdt_data: ; DS, SS, ES, FS, GS 74 | dw 0xffff ; Segment limit first 0-15 bits 75 | dw 0 ; Base first 0-15 bits 76 | db 0 ; Base 16-23 bits 77 | db 0x92 ; Access byte 78 | db 11001111b ; High 4 bit flags and the low 4 bit flags 79 | db 0 ; Base 24-31 bits 80 | 81 | gdt_end: 82 | 83 | gdt_descriptor: 84 | dw gdt_end - gdt_start-1 85 | dd gdt_start 86 | 87 | [BITS 32] 88 | load32: 89 | mov ax, DATA_SEG 90 | mov ds, ax 91 | mov es, ax 92 | mov fs, ax 93 | mov gs, ax 94 | mov ss, ax 95 | 96 | ; Enable the A20 line 97 | in al, 0x92 98 | or al, 2 99 | out 0x92, al 100 | 101 | ; For the loading... 102 | mov eax, 1 103 | mov ecx, 100 104 | mov edi, 0x0100000 105 | 106 | 107 | call ata_lba_read 108 | jmp CODE_SEG:0x0100000 109 | 110 | ata_lba_read: 111 | mov ebx, eax, ; Backup the LBA 112 | ; Send the highest 8 bits of the lba to hard disk controller 113 | shr eax, 24 114 | or eax, 0xE0 ; Select the master drive 115 | mov dx, 0x1F6 116 | out dx, al 117 | ; Finished sending the highest 8 bits of the lba 118 | 119 | ; Send the total sectors to read 120 | mov eax, ecx 121 | mov dx, 0x1F2 122 | out dx, al 123 | ; Finished sending the total sectors to read 124 | 125 | ; Send more bits of the LBA 126 | mov eax, ebx ; Restore the backup LBA 127 | mov dx, 0x1F3 128 | out dx, al 129 | ; Finished sending more bits of the LBA 130 | 131 | ; Send more bits of the LBA 132 | mov dx, 0x1F4 133 | mov eax, ebx ; Restore the backup LBA 134 | shr eax, 8 135 | out dx, al 136 | ; Finished sending more bits of the LBA 137 | 138 | ; Send upper 16 bits of the LBA 139 | mov dx, 0x1F5 140 | mov eax, ebx ; Restore the backup LBA 141 | shr eax, 16 142 | out dx, al 143 | ; Finished sending upper 16 bits of the LBA 144 | 145 | mov dx, 0x1f7 146 | mov al, 0x20 147 | out dx, al 148 | 149 | ; Read all sectors into memory 150 | .next_sector: 151 | push ecx 152 | 153 | ; Checking if we need to read 154 | .try_again: 155 | mov dx, 0x1f7 156 | in al, dx 157 | test al, 8 158 | jz .try_again 159 | 160 | ; We need to read 256 words at a time 161 | mov ecx, 256 162 | mov dx, 0x1F0 163 | rep insw 164 | pop ecx 165 | loop .next_sector 166 | ; End of reading sectors into memory 167 | ret 168 | 169 | times 510-($ - $$) db 0 170 | dw 0xAA55 171 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #define KERNEL_CODE_SELECTOR 0x08 5 | #define KERNEL_DATA_SELECTOR 0x10 6 | 7 | 8 | #define PEACHOS_TOTAL_INTERRUPTS 512 9 | 10 | // 100MB heap size 11 | #define PEACHOS_HEAP_SIZE_BYTES 104857600 12 | #define PEACHOS_HEAP_BLOCK_SIZE 4096 13 | #define PEACHOS_HEAP_ADDRESS 0x01000000 14 | #define PEACHOS_HEAP_TABLE_ADDRESS 0x00007E00 15 | 16 | #define PEACHOS_SECTOR_SIZE 512 17 | 18 | #define PEACHOS_MAX_FILESYSTEMS 12 19 | #define PEACHOS_MAX_FILE_DESCRIPTORS 512 20 | 21 | #define PEACHOS_MAX_PATH 108 22 | 23 | #define PEACHOS_TOTAL_GDT_SEGMENTS 6 24 | 25 | #define PEACHOS_PROGRAM_VIRTUAL_ADDRESS 0x400000 26 | #define PEACHOS_USER_PROGRAM_STACK_SIZE 1024 * 16 27 | #define PEACHOS_PROGRAM_VIRTUAL_STACK_ADDRESS_START 0x3FF000 28 | #define PEACHOS_PROGRAM_VIRTUAL_STACK_ADDRESS_END PEACHOS_PROGRAM_VIRTUAL_STACK_ADDRESS_START - PEACHOS_USER_PROGRAM_STACK_SIZE 29 | 30 | #define PEACHOS_MAX_PROGRAM_ALLOCATIONS 1024 31 | #define PEACHOS_MAX_PROCESSES 12 32 | 33 | #define USER_DATA_SEGMENT 0x23 34 | #define USER_CODE_SEGMENT 0x1b 35 | 36 | #define PEACHOS_MAX_ISR80H_COMMANDS 1024 37 | 38 | #define PEACHOS_KEYBOARD_BUFFER_SIZE 1024 39 | 40 | #endif -------------------------------------------------------------------------------- /src/disk/disk.c: -------------------------------------------------------------------------------- 1 | #include "disk.h" 2 | #include "io/io.h" 3 | #include "config.h" 4 | #include "status.h" 5 | #include "memory/memory.h" 6 | 7 | struct disk disk; 8 | 9 | int disk_read_sector(int lba, int total, void* buf) 10 | { 11 | outb(0x1F6, (lba >> 24) | 0xE0); 12 | outb(0x1F2, total); 13 | outb(0x1F3, (unsigned char)(lba & 0xff)); 14 | outb(0x1F4, (unsigned char)(lba >> 8)); 15 | outb(0x1F5, (unsigned char)(lba >> 16)); 16 | outb(0x1F7, 0x20); 17 | 18 | unsigned short* ptr = (unsigned short*) buf; 19 | for (int b = 0; b < total; b++) 20 | { 21 | // Wait for the buffer to be ready 22 | char c = insb(0x1F7); 23 | while(!(c & 0x08)) 24 | { 25 | c = insb(0x1F7); 26 | } 27 | 28 | // Copy from hard disk to memory 29 | for (int i = 0; i < 256; i++) 30 | { 31 | *ptr = insw(0x1F0); 32 | ptr++; 33 | } 34 | 35 | } 36 | return 0; 37 | } 38 | 39 | void disk_search_and_init() 40 | { 41 | memset(&disk, 0, sizeof(disk)); 42 | disk.type = PEACHOS_DISK_TYPE_REAL; 43 | disk.sector_size = PEACHOS_SECTOR_SIZE; 44 | disk.id = 0; 45 | disk.filesystem = fs_resolve(&disk); 46 | } 47 | 48 | struct disk* disk_get(int index) 49 | { 50 | if (index != 0) 51 | return 0; 52 | 53 | return &disk; 54 | } 55 | 56 | int disk_read_block(struct disk* idisk, unsigned int lba, int total, void* buf) 57 | { 58 | if (idisk != &disk) 59 | { 60 | return -EIO; 61 | } 62 | 63 | return disk_read_sector(lba, total, buf); 64 | } -------------------------------------------------------------------------------- /src/disk/disk.h: -------------------------------------------------------------------------------- 1 | #ifndef DISK_H 2 | #define DISK_H 3 | 4 | #include "fs/file.h" 5 | 6 | typedef unsigned int PEACHOS_DISK_TYPE; 7 | 8 | 9 | // Represents a real physical hard disk 10 | #define PEACHOS_DISK_TYPE_REAL 0 11 | 12 | struct disk 13 | { 14 | PEACHOS_DISK_TYPE type; 15 | int sector_size; 16 | 17 | // The id of the disk 18 | int id; 19 | 20 | struct filesystem* filesystem; 21 | 22 | // The private data of our filesystem 23 | void* fs_private; 24 | }; 25 | 26 | void disk_search_and_init(); 27 | struct disk* disk_get(int index); 28 | int disk_read_block(struct disk* idisk, unsigned int lba, int total, void* buf); 29 | 30 | #endif -------------------------------------------------------------------------------- /src/disk/streamer.c: -------------------------------------------------------------------------------- 1 | #include "streamer.h" 2 | #include "memory/heap/kheap.h" 3 | #include "config.h" 4 | 5 | #include 6 | struct disk_stream* diskstreamer_new(int disk_id) 7 | { 8 | struct disk* disk = disk_get(disk_id); 9 | if (!disk) 10 | { 11 | return 0; 12 | } 13 | 14 | struct disk_stream* streamer = kzalloc(sizeof(struct disk_stream)); 15 | streamer->pos = 0; 16 | streamer->disk = disk; 17 | return streamer; 18 | } 19 | 20 | int diskstreamer_seek(struct disk_stream* stream, int pos) 21 | { 22 | stream->pos = pos; 23 | return 0; 24 | } 25 | 26 | int diskstreamer_read(struct disk_stream* stream, void* out, int total) 27 | { 28 | int sector = stream->pos / PEACHOS_SECTOR_SIZE; 29 | int offset = stream->pos % PEACHOS_SECTOR_SIZE; 30 | int total_to_read = total; 31 | bool overflow = (offset+total_to_read) >= PEACHOS_SECTOR_SIZE; 32 | char buf[PEACHOS_SECTOR_SIZE]; 33 | 34 | if (overflow) 35 | { 36 | total_to_read -= (offset+total_to_read) - PEACHOS_SECTOR_SIZE; 37 | } 38 | 39 | int res = disk_read_block(stream->disk, sector, 1, buf); 40 | if (res < 0) 41 | { 42 | goto out; 43 | } 44 | 45 | 46 | for (int i = 0; i < total_to_read; i++) 47 | { 48 | *(char*)out++ = buf[offset+i]; 49 | } 50 | 51 | // Adjust the stream 52 | stream->pos += total_to_read; 53 | if (overflow) 54 | { 55 | res = diskstreamer_read(stream, out, total-total_to_read); 56 | } 57 | out: 58 | return res; 59 | } 60 | 61 | void diskstreamer_close(struct disk_stream* stream) 62 | { 63 | kfree(stream); 64 | } -------------------------------------------------------------------------------- /src/disk/streamer.h: -------------------------------------------------------------------------------- 1 | #ifndef DISKSTREAMER_H 2 | #define DISKSTREAMER_H 3 | 4 | #include "disk.h" 5 | 6 | struct disk_stream 7 | { 8 | int pos; 9 | struct disk* disk; 10 | }; 11 | 12 | struct disk_stream* diskstreamer_new(int disk_id); 13 | int diskstreamer_seek(struct disk_stream* stream, int pos); 14 | int diskstreamer_read(struct disk_stream* stream, void* out, int total); 15 | void diskstreamer_close(struct disk_stream* stream); 16 | 17 | #endif -------------------------------------------------------------------------------- /src/fs/fat/fat16.c: -------------------------------------------------------------------------------- 1 | #include "fat16.h" 2 | #include "string/string.h" 3 | #include "disk/disk.h" 4 | #include "disk/streamer.h" 5 | #include "memory/heap/kheap.h" 6 | #include "memory/memory.h" 7 | #include "status.h" 8 | #include "kernel.h" 9 | #include 10 | 11 | #define PEACHOS_FAT16_SIGNATURE 0x29 12 | #define PEACHOS_FAT16_FAT_ENTRY_SIZE 0x02 13 | #define PEACHOS_FAT16_BAD_SECTOR 0xFF7 14 | #define PEACHOS_FAT16_UNUSED 0x00 15 | 16 | typedef unsigned int FAT_ITEM_TYPE; 17 | #define FAT_ITEM_TYPE_DIRECTORY 0 18 | #define FAT_ITEM_TYPE_FILE 1 19 | 20 | // Fat directory entry attributes bitmask 21 | #define FAT_FILE_READ_ONLY 0x01 22 | #define FAT_FILE_HIDDEN 0x02 23 | #define FAT_FILE_SYSTEM 0x04 24 | #define FAT_FILE_VOLUME_LABEL 0x08 25 | #define FAT_FILE_SUBDIRECTORY 0x10 26 | #define FAT_FILE_ARCHIVED 0x20 27 | #define FAT_FILE_DEVICE 0x40 28 | #define FAT_FILE_RESERVED 0x80 29 | 30 | struct fat_header_extended 31 | { 32 | uint8_t drive_number; 33 | uint8_t win_nt_bit; 34 | uint8_t signature; 35 | uint32_t volume_id; 36 | uint8_t volume_id_string[11]; 37 | uint8_t system_id_string[8]; 38 | } __attribute__((packed)); 39 | 40 | struct fat_header 41 | { 42 | uint8_t short_jmp_ins[3]; 43 | uint8_t oem_identifier[8]; 44 | uint16_t bytes_per_sector; 45 | uint8_t sectors_per_cluster; 46 | uint16_t reserved_sectors; 47 | uint8_t fat_copies; 48 | uint16_t root_dir_entries; 49 | uint16_t number_of_sectors; 50 | uint8_t media_type; 51 | uint16_t sectors_per_fat; 52 | uint16_t sectors_per_track; 53 | uint16_t number_of_heads; 54 | uint32_t hidden_setors; 55 | uint32_t sectors_big; 56 | } __attribute__((packed)); 57 | 58 | struct fat_h 59 | { 60 | struct fat_header primary_header; 61 | union fat_h_e { 62 | struct fat_header_extended extended_header; 63 | } shared; 64 | }; 65 | 66 | struct fat_directory_item 67 | { 68 | uint8_t filename[8]; 69 | uint8_t ext[3]; 70 | uint8_t attribute; 71 | uint8_t reserved; 72 | uint8_t creation_time_tenths_of_a_sec; 73 | uint16_t creation_time; 74 | uint16_t creation_date; 75 | uint16_t last_access; 76 | uint16_t high_16_bits_first_cluster; 77 | uint16_t last_mod_time; 78 | uint16_t last_mod_date; 79 | uint16_t low_16_bits_first_cluster; 80 | uint32_t filesize; 81 | } __attribute__((packed)); 82 | 83 | struct fat_directory 84 | { 85 | struct fat_directory_item *item; 86 | int total; 87 | int sector_pos; 88 | int ending_sector_pos; 89 | }; 90 | 91 | struct fat_item 92 | { 93 | union { 94 | struct fat_directory_item *item; 95 | struct fat_directory *directory; 96 | }; 97 | 98 | FAT_ITEM_TYPE type; 99 | }; 100 | 101 | struct fat_file_descriptor 102 | { 103 | struct fat_item *item; 104 | uint32_t pos; 105 | }; 106 | 107 | struct fat_private 108 | { 109 | struct fat_h header; 110 | struct fat_directory root_directory; 111 | 112 | // Used to stream data clusters 113 | struct disk_stream *cluster_read_stream; 114 | // Used to stream the file allocation table 115 | struct disk_stream *fat_read_stream; 116 | 117 | // Used in situations where we stream the directory 118 | struct disk_stream *directory_stream; 119 | }; 120 | 121 | int fat16_resolve(struct disk *disk); 122 | void *fat16_open(struct disk *disk, struct path_part *path, FILE_MODE mode); 123 | int fat16_read(struct disk *disk, void *descriptor, uint32_t size, uint32_t nmemb, char *out_ptr); 124 | int fat16_seek(void *private, uint32_t offset, FILE_SEEK_MODE seek_mode); 125 | int fat16_stat(struct disk* disk, void* private, struct file_stat* stat); 126 | int fat16_close(void* private); 127 | 128 | struct filesystem fat16_fs = 129 | { 130 | .resolve = fat16_resolve, 131 | .open = fat16_open, 132 | .read = fat16_read, 133 | .seek = fat16_seek, 134 | .stat = fat16_stat, 135 | .close = fat16_close 136 | }; 137 | 138 | struct filesystem *fat16_init() 139 | { 140 | strcpy(fat16_fs.name, "FAT16"); 141 | return &fat16_fs; 142 | } 143 | 144 | static void fat16_init_private(struct disk *disk, struct fat_private *private) 145 | { 146 | memset(private, 0, sizeof(struct fat_private)); 147 | private 148 | ->cluster_read_stream = diskstreamer_new(disk->id); 149 | private 150 | ->fat_read_stream = diskstreamer_new(disk->id); 151 | private 152 | ->directory_stream = diskstreamer_new(disk->id); 153 | } 154 | 155 | int fat16_sector_to_absolute(struct disk *disk, int sector) 156 | { 157 | return sector * disk->sector_size; 158 | } 159 | 160 | int fat16_get_total_items_for_directory(struct disk *disk, uint32_t directory_start_sector) 161 | { 162 | struct fat_directory_item item; 163 | struct fat_directory_item empty_item; 164 | memset(&empty_item, 0, sizeof(empty_item)); 165 | 166 | struct fat_private *fat_private = disk->fs_private; 167 | 168 | int res = 0; 169 | int i = 0; 170 | int directory_start_pos = directory_start_sector * disk->sector_size; 171 | struct disk_stream *stream = fat_private->directory_stream; 172 | if (diskstreamer_seek(stream, directory_start_pos) != PEACHOS_ALL_OK) 173 | { 174 | res = -EIO; 175 | goto out; 176 | } 177 | 178 | while (1) 179 | { 180 | if (diskstreamer_read(stream, &item, sizeof(item)) != PEACHOS_ALL_OK) 181 | { 182 | res = -EIO; 183 | goto out; 184 | } 185 | 186 | if (item.filename[0] == 0x00) 187 | { 188 | // We are done 189 | break; 190 | } 191 | 192 | // Is the item unused 193 | if (item.filename[0] == 0xE5) 194 | { 195 | continue; 196 | } 197 | 198 | i++; 199 | } 200 | 201 | res = i; 202 | 203 | out: 204 | return res; 205 | } 206 | 207 | int fat16_get_root_directory(struct disk *disk, struct fat_private *fat_private, struct fat_directory *directory) 208 | { 209 | int res = 0; 210 | struct fat_directory_item *dir = 0x00; 211 | struct fat_header *primary_header = &fat_private->header.primary_header; 212 | int root_dir_sector_pos = (primary_header->fat_copies * primary_header->sectors_per_fat) + primary_header->reserved_sectors; 213 | int root_dir_entries = fat_private->header.primary_header.root_dir_entries; 214 | int root_dir_size = (root_dir_entries * sizeof(struct fat_directory_item)); 215 | int total_sectors = root_dir_size / disk->sector_size; 216 | if (root_dir_size % disk->sector_size) 217 | { 218 | total_sectors += 1; 219 | } 220 | 221 | int total_items = fat16_get_total_items_for_directory(disk, root_dir_sector_pos); 222 | 223 | dir = kzalloc(root_dir_size); 224 | if (!dir) 225 | { 226 | res = -ENOMEM; 227 | goto err_out; 228 | } 229 | 230 | struct disk_stream *stream = fat_private->directory_stream; 231 | if (diskstreamer_seek(stream, fat16_sector_to_absolute(disk, root_dir_sector_pos)) != PEACHOS_ALL_OK) 232 | { 233 | res = -EIO; 234 | goto err_out; 235 | } 236 | 237 | if (diskstreamer_read(stream, dir, root_dir_size) != PEACHOS_ALL_OK) 238 | { 239 | res = -EIO; 240 | goto err_out; 241 | } 242 | 243 | directory->item = dir; 244 | directory->total = total_items; 245 | directory->sector_pos = root_dir_sector_pos; 246 | directory->ending_sector_pos = root_dir_sector_pos + total_sectors; 247 | out: 248 | return res; 249 | 250 | err_out: 251 | if (dir) 252 | { 253 | kfree(dir); 254 | } 255 | 256 | return res; 257 | } 258 | int fat16_resolve(struct disk *disk) 259 | { 260 | int res = 0; 261 | struct fat_private *fat_private = kzalloc(sizeof(struct fat_private)); 262 | fat16_init_private(disk, fat_private); 263 | 264 | disk->fs_private = fat_private; 265 | disk->filesystem = &fat16_fs; 266 | 267 | struct disk_stream *stream = diskstreamer_new(disk->id); 268 | if (!stream) 269 | { 270 | res = -ENOMEM; 271 | goto out; 272 | } 273 | 274 | if (diskstreamer_read(stream, &fat_private->header, sizeof(fat_private->header)) != PEACHOS_ALL_OK) 275 | { 276 | res = -EIO; 277 | goto out; 278 | } 279 | 280 | if (fat_private->header.shared.extended_header.signature != 0x29) 281 | { 282 | res = -EFSNOTUS; 283 | goto out; 284 | } 285 | 286 | if (fat16_get_root_directory(disk, fat_private, &fat_private->root_directory) != PEACHOS_ALL_OK) 287 | { 288 | res = -EIO; 289 | goto out; 290 | } 291 | 292 | out: 293 | if (stream) 294 | { 295 | diskstreamer_close(stream); 296 | } 297 | 298 | if (res < 0) 299 | { 300 | kfree(fat_private); 301 | disk->fs_private = 0; 302 | } 303 | return res; 304 | } 305 | 306 | void fat16_to_proper_string(char **out, const char *in, size_t size) 307 | { 308 | int i = 0; 309 | while (*in != 0x00 && *in != 0x20) 310 | { 311 | **out = *in; 312 | *out += 1; 313 | in += 1; 314 | // We cant process anymore since we have exceeded the input buffer size 315 | if (i >= size-1) 316 | { 317 | break; 318 | } 319 | i++; 320 | } 321 | 322 | **out = 0x00; 323 | } 324 | 325 | void fat16_get_full_relative_filename(struct fat_directory_item *item, char *out, int max_len) 326 | { 327 | memset(out, 0x00, max_len); 328 | char *out_tmp = out; 329 | fat16_to_proper_string(&out_tmp, (const char *)item->filename, sizeof(item->filename)); 330 | if (item->ext[0] != 0x00 && item->ext[0] != 0x20) 331 | { 332 | *out_tmp++ = '.'; 333 | fat16_to_proper_string(&out_tmp, (const char *)item->ext, sizeof(item->ext)); 334 | } 335 | } 336 | 337 | struct fat_directory_item *fat16_clone_directory_item(struct fat_directory_item *item, int size) 338 | { 339 | struct fat_directory_item *item_copy = 0; 340 | if (size < sizeof(struct fat_directory_item)) 341 | { 342 | return 0; 343 | } 344 | 345 | item_copy = kzalloc(size); 346 | if (!item_copy) 347 | { 348 | return 0; 349 | } 350 | 351 | memcpy(item_copy, item, size); 352 | return item_copy; 353 | } 354 | 355 | static uint32_t fat16_get_first_cluster(struct fat_directory_item *item) 356 | { 357 | return (item->high_16_bits_first_cluster << 16) | item->low_16_bits_first_cluster; 358 | }; 359 | 360 | static int fat16_cluster_to_sector(struct fat_private *private, int cluster) 361 | { 362 | return private->root_directory.ending_sector_pos + ((cluster - 2) * private->header.primary_header.sectors_per_cluster); 363 | } 364 | 365 | static uint32_t fat16_get_first_fat_sector(struct fat_private *private) 366 | { 367 | return private->header.primary_header.reserved_sectors; 368 | } 369 | 370 | static int fat16_get_fat_entry(struct disk *disk, int cluster) 371 | { 372 | int res = -1; 373 | struct fat_private *private = disk->fs_private; 374 | struct disk_stream *stream = private->fat_read_stream; 375 | if (!stream) 376 | { 377 | goto out; 378 | } 379 | 380 | uint32_t fat_table_position = fat16_get_first_fat_sector(private) * disk->sector_size; 381 | res = diskstreamer_seek(stream, fat_table_position + (cluster * PEACHOS_FAT16_FAT_ENTRY_SIZE)); 382 | if (res < 0) 383 | { 384 | goto out; 385 | } 386 | 387 | uint16_t result = 0; 388 | res = diskstreamer_read(stream, &result, sizeof(result)); 389 | if (res < 0) 390 | { 391 | goto out; 392 | } 393 | 394 | res = result; 395 | out: 396 | return res; 397 | } 398 | /** 399 | * Gets the correct cluster to use based on the starting cluster and the offset 400 | */ 401 | static int fat16_get_cluster_for_offset(struct disk *disk, int starting_cluster, int offset) 402 | { 403 | int res = 0; 404 | struct fat_private *private = disk->fs_private; 405 | int size_of_cluster_bytes = private->header.primary_header.sectors_per_cluster * disk->sector_size; 406 | int cluster_to_use = starting_cluster; 407 | int clusters_ahead = offset / size_of_cluster_bytes; 408 | for (int i = 0; i < clusters_ahead; i++) 409 | { 410 | int entry = fat16_get_fat_entry(disk, cluster_to_use); 411 | if (entry == 0xFFf8 || entry == 0xFFFF) 412 | { 413 | // We are at the last entry in the file 414 | res = -EIO; 415 | goto out; 416 | } 417 | 418 | // Sector is marked as bad? 419 | if (entry == PEACHOS_FAT16_BAD_SECTOR) 420 | { 421 | res = -EIO; 422 | goto out; 423 | } 424 | 425 | // Reserved sector? 426 | if (entry == 0xFF0 || entry == 0xFF6) 427 | { 428 | res = -EIO; 429 | goto out; 430 | } 431 | 432 | if (entry == 0x00) 433 | { 434 | res = -EIO; 435 | goto out; 436 | } 437 | 438 | cluster_to_use = entry; 439 | } 440 | 441 | res = cluster_to_use; 442 | out: 443 | return res; 444 | } 445 | static int fat16_read_internal_from_stream(struct disk *disk, struct disk_stream *stream, int cluster, int offset, int total, void *out) 446 | { 447 | int res = 0; 448 | struct fat_private *private = disk->fs_private; 449 | int size_of_cluster_bytes = private->header.primary_header.sectors_per_cluster * disk->sector_size; 450 | int cluster_to_use = fat16_get_cluster_for_offset(disk, cluster, offset); 451 | if (cluster_to_use < 0) 452 | { 453 | res = cluster_to_use; 454 | goto out; 455 | } 456 | 457 | int offset_from_cluster = offset % size_of_cluster_bytes; 458 | 459 | int starting_sector = fat16_cluster_to_sector(private, cluster_to_use); 460 | int starting_pos = (starting_sector * disk->sector_size) + offset_from_cluster; 461 | int total_to_read = total > size_of_cluster_bytes ? size_of_cluster_bytes : total; 462 | res = diskstreamer_seek(stream, starting_pos); 463 | if (res != PEACHOS_ALL_OK) 464 | { 465 | goto out; 466 | } 467 | 468 | res = diskstreamer_read(stream, out, total_to_read); 469 | if (res != PEACHOS_ALL_OK) 470 | { 471 | goto out; 472 | } 473 | 474 | total -= total_to_read; 475 | if (total > 0) 476 | { 477 | // We still have more to read 478 | res = fat16_read_internal_from_stream(disk, stream, cluster, offset + total_to_read, total, out + total_to_read); 479 | } 480 | 481 | out: 482 | return res; 483 | } 484 | 485 | static int fat16_read_internal(struct disk *disk, int starting_cluster, int offset, int total, void *out) 486 | { 487 | struct fat_private *fs_private = disk->fs_private; 488 | struct disk_stream *stream = fs_private->cluster_read_stream; 489 | return fat16_read_internal_from_stream(disk, stream, starting_cluster, offset, total, out); 490 | } 491 | 492 | void fat16_free_directory(struct fat_directory *directory) 493 | { 494 | if (!directory) 495 | { 496 | return; 497 | } 498 | 499 | if (directory->item) 500 | { 501 | kfree(directory->item); 502 | } 503 | 504 | kfree(directory); 505 | } 506 | 507 | void fat16_fat_item_free(struct fat_item *item) 508 | { 509 | if (item->type == FAT_ITEM_TYPE_DIRECTORY) 510 | { 511 | fat16_free_directory(item->directory); 512 | } 513 | else if (item->type == FAT_ITEM_TYPE_FILE) 514 | { 515 | kfree(item->item); 516 | } 517 | 518 | kfree(item); 519 | } 520 | 521 | struct fat_directory *fat16_load_fat_directory(struct disk *disk, struct fat_directory_item *item) 522 | { 523 | int res = 0; 524 | struct fat_directory *directory = 0; 525 | struct fat_private *fat_private = disk->fs_private; 526 | if (!(item->attribute & FAT_FILE_SUBDIRECTORY)) 527 | { 528 | res = -EINVARG; 529 | goto out; 530 | } 531 | 532 | directory = kzalloc(sizeof(struct fat_directory)); 533 | if (!directory) 534 | { 535 | res = -ENOMEM; 536 | goto out; 537 | } 538 | 539 | int cluster = fat16_get_first_cluster(item); 540 | int cluster_sector = fat16_cluster_to_sector(fat_private, cluster); 541 | int total_items = fat16_get_total_items_for_directory(disk, cluster_sector); 542 | directory->total = total_items; 543 | int directory_size = directory->total * sizeof(struct fat_directory_item); 544 | directory->item = kzalloc(directory_size); 545 | if (!directory->item) 546 | { 547 | res = -ENOMEM; 548 | goto out; 549 | } 550 | 551 | res = fat16_read_internal(disk, cluster, 0x00, directory_size, directory->item); 552 | if (res != PEACHOS_ALL_OK) 553 | { 554 | goto out; 555 | } 556 | 557 | out: 558 | if (res != PEACHOS_ALL_OK) 559 | { 560 | fat16_free_directory(directory); 561 | } 562 | return directory; 563 | } 564 | struct fat_item *fat16_new_fat_item_for_directory_item(struct disk *disk, struct fat_directory_item *item) 565 | { 566 | struct fat_item *f_item = kzalloc(sizeof(struct fat_item)); 567 | if (!f_item) 568 | { 569 | return 0; 570 | } 571 | 572 | if (item->attribute & FAT_FILE_SUBDIRECTORY) 573 | { 574 | f_item->directory = fat16_load_fat_directory(disk, item); 575 | f_item->type = FAT_ITEM_TYPE_DIRECTORY; 576 | return f_item; 577 | } 578 | 579 | f_item->type = FAT_ITEM_TYPE_FILE; 580 | f_item->item = fat16_clone_directory_item(item, sizeof(struct fat_directory_item)); 581 | return f_item; 582 | } 583 | 584 | struct fat_item *fat16_find_item_in_directory(struct disk *disk, struct fat_directory *directory, const char *name) 585 | { 586 | struct fat_item *f_item = 0; 587 | char tmp_filename[PEACHOS_MAX_PATH]; 588 | for (int i = 0; i < directory->total; i++) 589 | { 590 | fat16_get_full_relative_filename(&directory->item[i], tmp_filename, sizeof(tmp_filename)); 591 | if (istrncmp(tmp_filename, name, sizeof(tmp_filename)) == 0) 592 | { 593 | // Found it let's create a new fat_item 594 | f_item = fat16_new_fat_item_for_directory_item(disk, &directory->item[i]); 595 | } 596 | } 597 | 598 | return f_item; 599 | } 600 | struct fat_item *fat16_get_directory_entry(struct disk *disk, struct path_part *path) 601 | { 602 | struct fat_private *fat_private = disk->fs_private; 603 | struct fat_item *current_item = 0; 604 | struct fat_item *root_item = fat16_find_item_in_directory(disk, &fat_private->root_directory, path->part); 605 | if (!root_item) 606 | { 607 | goto out; 608 | } 609 | 610 | struct path_part *next_part = path->next; 611 | current_item = root_item; 612 | while (next_part != 0) 613 | { 614 | if (current_item->type != FAT_ITEM_TYPE_DIRECTORY) 615 | { 616 | current_item = 0; 617 | break; 618 | } 619 | 620 | struct fat_item *tmp_item = fat16_find_item_in_directory(disk, current_item->directory, next_part->part); 621 | fat16_fat_item_free(current_item); 622 | current_item = tmp_item; 623 | next_part = next_part->next; 624 | } 625 | out: 626 | return current_item; 627 | } 628 | 629 | void *fat16_open(struct disk *disk, struct path_part *path, FILE_MODE mode) 630 | { 631 | struct fat_file_descriptor *descriptor = 0; 632 | int err_code = 0; 633 | if (mode != FILE_MODE_READ) 634 | { 635 | err_code = -ERDONLY; 636 | goto err_out; 637 | } 638 | 639 | descriptor = kzalloc(sizeof(struct fat_file_descriptor)); 640 | if (!descriptor) 641 | { 642 | err_code = -ENOMEM; 643 | goto err_out; 644 | } 645 | 646 | descriptor->item = fat16_get_directory_entry(disk, path); 647 | if (!descriptor->item) 648 | { 649 | err_code = -EIO; 650 | goto err_out; 651 | } 652 | 653 | descriptor->pos = 0; 654 | return descriptor; 655 | 656 | err_out: 657 | if(descriptor) 658 | kfree(descriptor); 659 | 660 | return ERROR(err_code); 661 | } 662 | 663 | static void fat16_free_file_descriptor(struct fat_file_descriptor* desc) 664 | { 665 | fat16_fat_item_free(desc->item); 666 | kfree(desc); 667 | } 668 | 669 | 670 | int fat16_close(void* private) 671 | { 672 | fat16_free_file_descriptor((struct fat_file_descriptor*) private); 673 | return 0; 674 | } 675 | 676 | int fat16_stat(struct disk* disk, void* private, struct file_stat* stat) 677 | { 678 | int res = 0; 679 | struct fat_file_descriptor* descriptor = (struct fat_file_descriptor*) private; 680 | struct fat_item* desc_item = descriptor->item; 681 | if (desc_item->type != FAT_ITEM_TYPE_FILE) 682 | { 683 | res = -EINVARG; 684 | goto out; 685 | } 686 | 687 | struct fat_directory_item* ritem = desc_item->item; 688 | stat->filesize = ritem->filesize; 689 | stat->flags = 0x00; 690 | 691 | if (ritem->attribute & FAT_FILE_READ_ONLY) 692 | { 693 | stat->flags |= FILE_STAT_READ_ONLY; 694 | } 695 | out: 696 | return res; 697 | } 698 | 699 | int fat16_read(struct disk *disk, void *descriptor, uint32_t size, uint32_t nmemb, char *out_ptr) 700 | { 701 | int res = 0; 702 | struct fat_file_descriptor *fat_desc = descriptor; 703 | struct fat_directory_item *item = fat_desc->item->item; 704 | int offset = fat_desc->pos; 705 | for (uint32_t i = 0; i < nmemb; i++) 706 | { 707 | res = fat16_read_internal(disk, fat16_get_first_cluster(item), offset, size, out_ptr); 708 | if (ISERR(res)) 709 | { 710 | goto out; 711 | } 712 | 713 | out_ptr += size; 714 | offset += size; 715 | } 716 | fat_desc->pos = offset; 717 | res = nmemb; 718 | out: 719 | return res; 720 | } 721 | 722 | int fat16_seek(void *private, uint32_t offset, FILE_SEEK_MODE seek_mode) 723 | { 724 | int res = 0; 725 | struct fat_file_descriptor *desc = private; 726 | struct fat_item *desc_item = desc->item; 727 | if (desc_item->type != FAT_ITEM_TYPE_FILE) 728 | { 729 | res = -EINVARG; 730 | goto out; 731 | } 732 | 733 | struct fat_directory_item *ritem = desc_item->item; 734 | if (offset >= ritem->filesize) 735 | { 736 | res = -EIO; 737 | goto out; 738 | } 739 | 740 | switch (seek_mode) 741 | { 742 | case SEEK_SET: 743 | desc->pos = offset; 744 | break; 745 | 746 | case SEEK_END: 747 | res = -EUNIMP; 748 | break; 749 | 750 | case SEEK_CUR: 751 | desc->pos += offset; 752 | break; 753 | 754 | default: 755 | res = -EINVARG; 756 | break; 757 | } 758 | out: 759 | return res; 760 | } -------------------------------------------------------------------------------- /src/fs/fat/fat16.h: -------------------------------------------------------------------------------- 1 | #ifndef FAT16_H 2 | #define FAT16_H 3 | 4 | #include "file.h" 5 | struct filesystem* fat16_init(); 6 | #endif -------------------------------------------------------------------------------- /src/fs/file.c: -------------------------------------------------------------------------------- 1 | #include "file.h" 2 | #include "config.h" 3 | #include "memory/memory.h" 4 | #include "memory/heap/kheap.h" 5 | #include "string/string.h" 6 | #include "disk/disk.h" 7 | #include "fat/fat16.h" 8 | #include "status.h" 9 | #include "kernel.h" 10 | struct filesystem* filesystems[PEACHOS_MAX_FILESYSTEMS]; 11 | struct file_descriptor* file_descriptors[PEACHOS_MAX_FILE_DESCRIPTORS]; 12 | 13 | static struct filesystem** fs_get_free_filesystem() 14 | { 15 | int i = 0; 16 | for (i = 0; i < PEACHOS_MAX_FILESYSTEMS; i++) 17 | { 18 | if (filesystems[i] == 0) 19 | { 20 | return &filesystems[i]; 21 | } 22 | } 23 | 24 | return 0; 25 | } 26 | 27 | void fs_insert_filesystem(struct filesystem* filesystem) 28 | { 29 | struct filesystem** fs; 30 | fs = fs_get_free_filesystem(); 31 | if (!fs) 32 | { 33 | print("Problem inserting filesystem"); 34 | while(1) {} 35 | } 36 | 37 | *fs = filesystem; 38 | } 39 | 40 | static void fs_static_load() 41 | { 42 | fs_insert_filesystem(fat16_init()); 43 | } 44 | 45 | void fs_load() 46 | { 47 | memset(filesystems, 0, sizeof(filesystems)); 48 | fs_static_load(); 49 | } 50 | 51 | void fs_init() 52 | { 53 | memset(file_descriptors, 0, sizeof(file_descriptors)); 54 | fs_load(); 55 | } 56 | 57 | static void file_free_descriptor(struct file_descriptor* desc) 58 | { 59 | file_descriptors[desc->index-1] = 0x00; 60 | kfree(desc); 61 | } 62 | 63 | static int file_new_descriptor(struct file_descriptor** desc_out) 64 | { 65 | int res = -ENOMEM; 66 | for (int i = 0; i < PEACHOS_MAX_FILE_DESCRIPTORS; i++) 67 | { 68 | if (file_descriptors[i] == 0) 69 | { 70 | struct file_descriptor* desc = kzalloc(sizeof(struct file_descriptor)); 71 | // Descriptors start at 1 72 | desc->index = i + 1; 73 | file_descriptors[i] = desc; 74 | *desc_out = desc; 75 | res = 0; 76 | break; 77 | } 78 | } 79 | 80 | return res; 81 | } 82 | 83 | static struct file_descriptor* file_get_descriptor(int fd) 84 | { 85 | if (fd <= 0 || fd >= PEACHOS_MAX_FILE_DESCRIPTORS) 86 | { 87 | return 0; 88 | } 89 | 90 | // Descriptors start at 1 91 | int index = fd - 1; 92 | return file_descriptors[index]; 93 | } 94 | 95 | struct filesystem* fs_resolve(struct disk* disk) 96 | { 97 | struct filesystem* fs = 0; 98 | for (int i = 0; i < PEACHOS_MAX_FILESYSTEMS; i++) 99 | { 100 | if (filesystems[i] != 0 && filesystems[i]->resolve(disk) == 0) 101 | { 102 | fs = filesystems[i]; 103 | break; 104 | } 105 | } 106 | 107 | return fs; 108 | } 109 | 110 | FILE_MODE file_get_mode_by_string(const char* str) 111 | { 112 | FILE_MODE mode = FILE_MODE_INVALID; 113 | if (strncmp(str, "r", 1) == 0) 114 | { 115 | mode = FILE_MODE_READ; 116 | } 117 | else if(strncmp(str, "w", 1) == 0) 118 | { 119 | mode = FILE_MODE_WRITE; 120 | } 121 | else if(strncmp(str, "a", 1) == 0) 122 | { 123 | mode = FILE_MODE_APPEND; 124 | } 125 | return mode; 126 | } 127 | 128 | int fopen(const char* filename, const char* mode_str) 129 | { 130 | int res = 0; 131 | struct disk* disk = NULL; 132 | FILE_MODE mode = FILE_MODE_INVALID; 133 | void* descriptor_private_data = NULL; 134 | struct file_descriptor* desc = 0; 135 | struct path_root* root_path = pathparser_parse(filename, NULL); 136 | if (!root_path) 137 | { 138 | res = -EINVARG; 139 | goto out; 140 | } 141 | 142 | // We cannot have just a root path 0:/ 0:/test.txt 143 | if (!root_path->first) 144 | { 145 | res = -EINVARG; 146 | goto out; 147 | } 148 | 149 | // Ensure the disk we are reading from exists 150 | disk = disk_get(root_path->drive_no); 151 | if (!disk) 152 | { 153 | res = -EIO; 154 | goto out; 155 | } 156 | 157 | if (!disk->filesystem) 158 | { 159 | res = -EIO; 160 | goto out; 161 | } 162 | 163 | mode = file_get_mode_by_string(mode_str); 164 | if (mode == FILE_MODE_INVALID) 165 | { 166 | res = -EINVARG; 167 | goto out; 168 | } 169 | 170 | descriptor_private_data = disk->filesystem->open(disk, root_path->first, mode); 171 | if (ISERR(descriptor_private_data)) 172 | { 173 | res = ERROR_I(descriptor_private_data); 174 | goto out; 175 | } 176 | 177 | 178 | res = file_new_descriptor(&desc); 179 | if (res < 0) 180 | { 181 | goto out; 182 | } 183 | desc->filesystem = disk->filesystem; 184 | desc->private = descriptor_private_data; 185 | desc->disk = disk; 186 | res = desc->index; 187 | 188 | out: 189 | 190 | if (res < 0) 191 | { 192 | // ERROR 193 | if (root_path) 194 | { 195 | pathparser_free(root_path); 196 | root_path = NULL; 197 | } 198 | 199 | if (disk && descriptor_private_data) 200 | { 201 | disk->filesystem->close(descriptor_private_data); 202 | descriptor_private_data = NULL; 203 | } 204 | 205 | if (desc) 206 | { 207 | file_free_descriptor(desc); 208 | desc = NULL; 209 | } 210 | 211 | 212 | // fopen shouldnt return negative values 213 | res = 0; 214 | } 215 | 216 | return res; 217 | } 218 | 219 | int fstat(int fd, struct file_stat* stat) 220 | { 221 | int res = 0; 222 | struct file_descriptor* desc = file_get_descriptor(fd); 223 | if (!desc) 224 | { 225 | res = -EIO; 226 | goto out; 227 | } 228 | 229 | res = desc->filesystem->stat(desc->disk, desc->private, stat); 230 | out: 231 | return res; 232 | } 233 | 234 | int fclose(int fd) 235 | { 236 | int res = 0; 237 | struct file_descriptor* desc = file_get_descriptor(fd); 238 | if (!desc) 239 | { 240 | res = -EIO; 241 | goto out; 242 | } 243 | 244 | res = desc->filesystem->close(desc->private); 245 | if (res == PEACHOS_ALL_OK) 246 | { 247 | file_free_descriptor(desc); 248 | } 249 | out: 250 | return res; 251 | } 252 | 253 | int fseek(int fd, int offset, FILE_SEEK_MODE whence) 254 | { 255 | int res = 0; 256 | struct file_descriptor* desc = file_get_descriptor(fd); 257 | if (!desc) 258 | { 259 | res = -EIO; 260 | goto out; 261 | } 262 | 263 | res = desc->filesystem->seek(desc->private, offset, whence); 264 | out: 265 | return res; 266 | } 267 | int fread(void* ptr, uint32_t size, uint32_t nmemb, int fd) 268 | { 269 | int res = 0; 270 | if (size == 0 || nmemb == 0 || fd < 1) 271 | { 272 | res = -EINVARG; 273 | goto out; 274 | } 275 | 276 | struct file_descriptor* desc = file_get_descriptor(fd); 277 | if (!desc) 278 | { 279 | res = -EINVARG; 280 | goto out; 281 | } 282 | 283 | res = desc->filesystem->read(desc->disk, desc->private, size, nmemb, (char*) ptr); 284 | out: 285 | return res; 286 | } -------------------------------------------------------------------------------- /src/fs/file.h: -------------------------------------------------------------------------------- 1 | #ifndef FILE_H 2 | #define FILE_H 3 | 4 | #include "pparser.h" 5 | #include 6 | 7 | typedef unsigned int FILE_SEEK_MODE; 8 | enum 9 | { 10 | SEEK_SET, 11 | SEEK_CUR, 12 | SEEK_END 13 | }; 14 | 15 | 16 | typedef unsigned int FILE_MODE; 17 | enum 18 | { 19 | FILE_MODE_READ, 20 | FILE_MODE_WRITE, 21 | FILE_MODE_APPEND, 22 | FILE_MODE_INVALID 23 | }; 24 | 25 | enum 26 | { 27 | FILE_STAT_READ_ONLY = 0b00000001 28 | }; 29 | 30 | typedef unsigned int FILE_STAT_FLAGS; 31 | 32 | struct disk; 33 | typedef void*(*FS_OPEN_FUNCTION)(struct disk* disk, struct path_part* path, FILE_MODE mode); 34 | typedef int (*FS_READ_FUNCTION)(struct disk* disk, void* private, uint32_t size, uint32_t nmemb, char* out); 35 | typedef int (*FS_RESOLVE_FUNCTION)(struct disk* disk); 36 | 37 | typedef int (*FS_CLOSE_FUNCTION)(void* private); 38 | 39 | typedef int (*FS_SEEK_FUNCTION)(void* private, uint32_t offset, FILE_SEEK_MODE seek_mode); 40 | 41 | 42 | struct file_stat 43 | { 44 | FILE_STAT_FLAGS flags; 45 | uint32_t filesize; 46 | }; 47 | 48 | typedef int (*FS_STAT_FUNCTION)(struct disk* disk, void* private, struct file_stat* stat); 49 | 50 | struct filesystem 51 | { 52 | // Filesystem should return zero from resolve if the provided disk is using its filesystem 53 | FS_RESOLVE_FUNCTION resolve; 54 | FS_OPEN_FUNCTION open; 55 | FS_READ_FUNCTION read; 56 | FS_SEEK_FUNCTION seek; 57 | FS_STAT_FUNCTION stat; 58 | FS_CLOSE_FUNCTION close; 59 | char name[20]; 60 | }; 61 | 62 | struct file_descriptor 63 | { 64 | // The descriptor index 65 | int index; 66 | struct filesystem* filesystem; 67 | 68 | // Private data for internal file descriptor 69 | void* private; 70 | 71 | // The disk that the file descriptor should be used on 72 | struct disk* disk; 73 | }; 74 | 75 | 76 | 77 | void fs_init(); 78 | int fopen(const char* filename, const char* mode_str); 79 | int fseek(int fd, int offset, FILE_SEEK_MODE whence); 80 | int fread(void* ptr, uint32_t size, uint32_t nmemb, int fd); 81 | int fstat(int fd, struct file_stat* stat); 82 | int fclose(int fd); 83 | 84 | void fs_insert_filesystem(struct filesystem* filesystem); 85 | struct filesystem* fs_resolve(struct disk* disk); 86 | #endif -------------------------------------------------------------------------------- /src/fs/pparser.c: -------------------------------------------------------------------------------- 1 | #include "pparser.h" 2 | #include "kernel.h" 3 | #include "string/string.h" 4 | #include "memory/heap/kheap.h" 5 | #include "memory/memory.h" 6 | #include "status.h" 7 | 8 | static int pathparser_path_valid_format(const char* filename) 9 | { 10 | int len = strnlen(filename, PEACHOS_MAX_PATH); 11 | return (len >= 3 && isdigit(filename[0]) && memcmp((void*)&filename[1], ":/", 2) == 0); 12 | } 13 | 14 | static int pathparser_get_drive_by_path(const char** path) 15 | { 16 | if(!pathparser_path_valid_format(*path)) 17 | { 18 | return -EBADPATH; 19 | } 20 | 21 | int drive_no = tonumericdigit(*path[0]); 22 | 23 | // Add 3 bytes to skip drive number 0:/ 1:/ 2:/ 24 | *path += 3; 25 | return drive_no; 26 | } 27 | 28 | static struct path_root* pathparser_create_root(int drive_number) 29 | { 30 | struct path_root* path_r = kzalloc(sizeof(struct path_root)); 31 | if (!path_r) 32 | { 33 | return NULL; 34 | } 35 | 36 | path_r->drive_no = drive_number; 37 | path_r->first = 0; 38 | return path_r; 39 | } 40 | 41 | 42 | static const char* pathparser_get_path_part(const char** path) 43 | { 44 | char* result_path_part = kzalloc(PEACHOS_MAX_PATH); 45 | if (!result_path_part) 46 | { 47 | return NULL; 48 | } 49 | 50 | int i = 0; 51 | while(**path != '/' && **path != 0x00) 52 | { 53 | result_path_part[i] = **path; 54 | *path += 1; 55 | i++; 56 | } 57 | 58 | if (**path == '/') 59 | { 60 | // Skip the forward slash to avoid problems 61 | *path += 1; 62 | } 63 | 64 | if(i == 0) 65 | { 66 | kfree(result_path_part); 67 | result_path_part = 0; 68 | } 69 | 70 | return result_path_part; 71 | } 72 | 73 | struct path_part* pathparser_parse_path_part(struct path_part* last_part, const char** path) 74 | { 75 | const char* path_part_str = pathparser_get_path_part(path); 76 | if (!path_part_str) 77 | { 78 | return 0; 79 | } 80 | 81 | struct path_part* part = kzalloc(sizeof(struct path_part)); 82 | if (!part) 83 | { 84 | kfree((void*)path_part_str); 85 | return 0; 86 | } 87 | part->part = path_part_str; 88 | part->next = 0x00; 89 | 90 | if (last_part) 91 | { 92 | last_part->next = part; 93 | } 94 | 95 | return part; 96 | } 97 | 98 | void pathparser_free(struct path_root* root) 99 | { 100 | struct path_part* part = root->first; 101 | while(part) 102 | { 103 | struct path_part* next_part = part->next; 104 | kfree((void*) part->part); 105 | kfree(part); 106 | part = next_part; 107 | } 108 | 109 | kfree(root); 110 | } 111 | 112 | struct path_root* pathparser_parse(const char* path, const char* current_directory_path) 113 | { 114 | int res = 0; 115 | const char* tmp_path = path; 116 | struct path_root* path_root = NULL; 117 | struct path_part* first_part = NULL; 118 | struct path_part* part = NULL; 119 | 120 | if (strlen(path) > PEACHOS_MAX_PATH) 121 | { 122 | res = -1; 123 | goto out; 124 | } 125 | 126 | res = pathparser_get_drive_by_path(&tmp_path); 127 | if (res < 0) 128 | { 129 | res = -1; 130 | goto out; 131 | } 132 | 133 | path_root = pathparser_create_root(res); 134 | if (!path_root) 135 | { 136 | res = -1; 137 | goto out; 138 | } 139 | 140 | first_part = pathparser_parse_path_part(NULL, &tmp_path); 141 | if (!first_part) 142 | { 143 | res = -1; 144 | goto out; 145 | } 146 | 147 | path_root->first = first_part; 148 | part = pathparser_parse_path_part(first_part, &tmp_path); 149 | while(part) 150 | { 151 | part = pathparser_parse_path_part(part, &tmp_path); 152 | } 153 | 154 | out: 155 | if (res < 0) 156 | { 157 | if (path_root) 158 | { 159 | kfree(path_root); 160 | path_root = NULL; 161 | } 162 | if (first_part) 163 | { 164 | kfree(first_part); 165 | } 166 | } 167 | return path_root; 168 | } -------------------------------------------------------------------------------- /src/fs/pparser.h: -------------------------------------------------------------------------------- 1 | #ifndef PATHPARSER_H 2 | #define PATHPARSER_H 3 | 4 | struct path_root 5 | { 6 | int drive_no; 7 | struct path_part* first; 8 | }; 9 | 10 | struct path_part 11 | { 12 | const char* part; 13 | struct path_part* next; 14 | }; 15 | 16 | struct path_root* pathparser_parse(const char* path, const char* current_directory_path); 17 | void pathparser_free(struct path_root* root); 18 | 19 | #endif -------------------------------------------------------------------------------- /src/gdt/gdt.asm: -------------------------------------------------------------------------------- 1 | section .asm 2 | global gdt_load 3 | 4 | gdt_load: 5 | mov eax, [esp+4] 6 | mov [gdt_descriptor + 2], eax 7 | mov ax, [esp+8] 8 | mov [gdt_descriptor], ax 9 | lgdt [gdt_descriptor] 10 | ret 11 | 12 | 13 | section .data 14 | gdt_descriptor: 15 | dw 0x00 ; Size 16 | dd 0x00 ; GDT Start Address -------------------------------------------------------------------------------- /src/gdt/gdt.c: -------------------------------------------------------------------------------- 1 | #include "gdt.h" 2 | #include "kernel.h" 3 | 4 | void encodeGdtEntry(uint8_t* target, struct gdt_structured source) 5 | { 6 | if ((source.limit > 65536) && ((source.limit & 0xFFF) != 0xFFF)) 7 | { 8 | panic("encodeGdtEntry: Invalid argument\n"); 9 | } 10 | 11 | target[6] = 0x40; 12 | if (source.limit > 65536) 13 | { 14 | source.limit = source.limit >> 12; 15 | target[6] = 0xC0; 16 | } 17 | 18 | // Encodes the limit 19 | target[0] = source.limit & 0xFF; 20 | target[1] = (source.limit >> 8) & 0xFF; 21 | target[6] |= (source.limit >> 16) & 0x0F; 22 | 23 | // Encode the base 24 | target[2] = source.base & 0xFF; 25 | target[3] = (source.base >> 8) & 0xFF; 26 | target[4] = (source.base >> 16) & 0xFF; 27 | target[7] = (source.base >> 24) & 0xFF; 28 | 29 | // Set the type 30 | target[5] = source.type; 31 | 32 | } 33 | 34 | void gdt_structured_to_gdt(struct gdt* gdt, struct gdt_structured* structured_gdt, int total_entires) 35 | { 36 | for (int i = 0; i < total_entires; i++) 37 | { 38 | encodeGdtEntry((uint8_t*)&gdt[i], structured_gdt[i]); 39 | } 40 | } -------------------------------------------------------------------------------- /src/gdt/gdt.h: -------------------------------------------------------------------------------- 1 | #ifndef GDT_H 2 | #define GDT_H 3 | #include 4 | struct gdt 5 | { 6 | uint16_t segment; 7 | uint16_t base_first; 8 | uint8_t base; 9 | uint8_t access; 10 | uint8_t high_flags; 11 | uint8_t base_24_31_bits; 12 | } __attribute__((packed)); 13 | 14 | struct gdt_structured 15 | { 16 | uint32_t base; 17 | uint32_t limit; 18 | uint8_t type; 19 | }; 20 | 21 | void gdt_load(struct gdt* gdt, int size); 22 | void gdt_structured_to_gdt(struct gdt* gdt, struct gdt_structured* structured_gdt, int total_entires); 23 | #endif -------------------------------------------------------------------------------- /src/idt/idt.asm: -------------------------------------------------------------------------------- 1 | section .asm 2 | 3 | extern int21h_handler 4 | extern no_interrupt_handler 5 | extern isr80h_handler 6 | extern interrupt_handler 7 | 8 | global idt_load 9 | global no_interrupt 10 | global enable_interrupts 11 | global disable_interrupts 12 | global isr80h_wrapper 13 | global interrupt_pointer_table 14 | 15 | enable_interrupts: 16 | sti 17 | ret 18 | 19 | disable_interrupts: 20 | cli 21 | ret 22 | 23 | 24 | idt_load: 25 | push ebp 26 | mov ebp, esp 27 | 28 | mov ebx, [ebp+8] 29 | lidt [ebx] 30 | pop ebp 31 | ret 32 | 33 | 34 | no_interrupt: 35 | pushad 36 | call no_interrupt_handler 37 | popad 38 | iret 39 | 40 | %macro interrupt 1 41 | global int%1 42 | int%1: 43 | ; INTERRUPT FRAME START 44 | ; ALREADY PUSHED TO US BY THE PROCESSOR UPON ENTRY TO THIS INTERRUPT 45 | ; uint32_t ip 46 | ; uint32_t cs; 47 | ; uint32_t flags 48 | ; uint32_t sp; 49 | ; uint32_t ss; 50 | ; Pushes the general purpose registers to the stack 51 | pushad 52 | ; Interrupt frame end 53 | push esp 54 | push dword %1 55 | call interrupt_handler 56 | add esp, 8 57 | popad 58 | iret 59 | %endmacro 60 | 61 | %assign i 0 62 | %rep 512 63 | interrupt i 64 | %assign i i+1 65 | %endrep 66 | 67 | isr80h_wrapper: 68 | ; INTERRUPT FRAME START 69 | ; ALREADY PUSHED TO US BY THE PROCESSOR UPON ENTRY TO THIS INTERRUPT 70 | ; uint32_t ip 71 | ; uint32_t cs; 72 | ; uint32_t flags 73 | ; uint32_t sp; 74 | ; uint32_t ss; 75 | ; Pushes the general purpose registers to the stack 76 | pushad 77 | 78 | ; INTERRUPT FRAME END 79 | 80 | ; Push the stack pointer so that we are pointing to the interrupt frame 81 | push esp 82 | 83 | ; EAX holds our command lets push it to the stack for isr80h_handler 84 | push eax 85 | call isr80h_handler 86 | mov dword[tmp_res], eax 87 | add esp, 8 88 | 89 | ; Restore general purpose registers for user land 90 | popad 91 | mov eax, [tmp_res] 92 | iretd 93 | 94 | section .data 95 | ; Inside here is stored the return result from isr80h_handler 96 | tmp_res: dd 0 97 | 98 | 99 | %macro interrupt_array_entry 1 100 | dd int%1 101 | %endmacro 102 | 103 | interrupt_pointer_table: 104 | %assign i 0 105 | %rep 512 106 | interrupt_array_entry i 107 | %assign i i+1 108 | %endrep -------------------------------------------------------------------------------- /src/idt/idt.c: -------------------------------------------------------------------------------- 1 | #include "idt.h" 2 | #include "config.h" 3 | #include "kernel.h" 4 | #include "memory/memory.h" 5 | #include "task/task.h" 6 | #include "task/process.h" 7 | #include "io/io.h" 8 | #include "status.h" 9 | struct idt_desc idt_descriptors[PEACHOS_TOTAL_INTERRUPTS]; 10 | struct idtr_desc idtr_descriptor; 11 | 12 | extern void* interrupt_pointer_table[PEACHOS_TOTAL_INTERRUPTS]; 13 | 14 | static INTERRUPT_CALLBACK_FUNCTION interrupt_callbacks[PEACHOS_TOTAL_INTERRUPTS]; 15 | 16 | static ISR80H_COMMAND isr80h_commands[PEACHOS_MAX_ISR80H_COMMANDS]; 17 | 18 | extern void idt_load(struct idtr_desc* ptr); 19 | extern void int21h(); 20 | extern void no_interrupt(); 21 | extern void isr80h_wrapper(); 22 | 23 | void no_interrupt_handler() 24 | { 25 | outb(0x20, 0x20); 26 | } 27 | 28 | void interrupt_handler(int interrupt, struct interrupt_frame* frame) 29 | { 30 | kernel_page(); 31 | if (interrupt_callbacks[interrupt] != 0) 32 | { 33 | task_current_save_state(frame); 34 | interrupt_callbacks[interrupt](frame); 35 | } 36 | 37 | task_page(); 38 | outb(0x20, 0x20); 39 | } 40 | 41 | void idt_zero() 42 | { 43 | print("Divide by zero error\n"); 44 | } 45 | 46 | void idt_set(int interrupt_no, void* address) 47 | { 48 | struct idt_desc* desc = &idt_descriptors[interrupt_no]; 49 | desc->offset_1 = (uint32_t) address & 0x0000ffff; 50 | desc->selector = KERNEL_CODE_SELECTOR; 51 | desc->zero = 0x00; 52 | desc->type_attr = 0xEE; 53 | desc->offset_2 = (uint32_t) address >> 16; 54 | } 55 | 56 | void idt_handle_exception() 57 | { 58 | process_terminate(task_current()->process); 59 | task_next(); 60 | } 61 | 62 | void idt_clock() 63 | { 64 | outb(0x20, 0x20); 65 | 66 | // Switch to the next task 67 | task_next(); 68 | } 69 | 70 | void idt_init() 71 | { 72 | memset(idt_descriptors, 0, sizeof(idt_descriptors)); 73 | idtr_descriptor.limit = sizeof(idt_descriptors) -1; 74 | idtr_descriptor.base = (uint32_t) idt_descriptors; 75 | 76 | for (int i = 0; i < PEACHOS_TOTAL_INTERRUPTS; i++) 77 | { 78 | idt_set(i, interrupt_pointer_table[i]); 79 | } 80 | 81 | idt_set(0, idt_zero); 82 | idt_set(0x80, isr80h_wrapper); 83 | 84 | 85 | for (int i = 0; i < 0x20; i++) 86 | { 87 | idt_register_interrupt_callback(i, idt_handle_exception); 88 | } 89 | 90 | 91 | idt_register_interrupt_callback(0x20, idt_clock); 92 | 93 | // Load the interrupt descriptor table 94 | idt_load(&idtr_descriptor); 95 | } 96 | 97 | int idt_register_interrupt_callback(int interrupt, INTERRUPT_CALLBACK_FUNCTION interrupt_callback) 98 | { 99 | if (interrupt < 0 || interrupt >= PEACHOS_TOTAL_INTERRUPTS) 100 | { 101 | return -EINVARG; 102 | } 103 | 104 | interrupt_callbacks[interrupt] = interrupt_callback; 105 | return 0; 106 | } 107 | 108 | void isr80h_register_command(int command_id, ISR80H_COMMAND command) 109 | { 110 | if (command_id < 0 || command_id >= PEACHOS_MAX_ISR80H_COMMANDS) 111 | { 112 | panic("The command is out of bounds\n"); 113 | } 114 | 115 | if (isr80h_commands[command_id]) 116 | { 117 | panic("Your attempting to overwrite an existing command\n"); 118 | } 119 | 120 | isr80h_commands[command_id] = command; 121 | } 122 | 123 | void* isr80h_handle_command(int command, struct interrupt_frame* frame) 124 | { 125 | void* result = 0; 126 | 127 | if(command < 0 || command >= PEACHOS_MAX_ISR80H_COMMANDS) 128 | { 129 | // Invalid command 130 | return 0; 131 | } 132 | 133 | ISR80H_COMMAND command_func = isr80h_commands[command]; 134 | if (!command_func) 135 | { 136 | return 0; 137 | } 138 | 139 | result = command_func(frame); 140 | return result; 141 | } 142 | 143 | void* isr80h_handler(int command, struct interrupt_frame* frame) 144 | { 145 | void* res = 0; 146 | kernel_page(); 147 | task_current_save_state(frame); 148 | res = isr80h_handle_command(command, frame); 149 | task_page(); 150 | return res; 151 | } -------------------------------------------------------------------------------- /src/idt/idt.h: -------------------------------------------------------------------------------- 1 | #ifndef IDT_H 2 | #define IDT_H 3 | 4 | #include 5 | 6 | struct interrupt_frame; 7 | typedef void*(*ISR80H_COMMAND)(struct interrupt_frame* frame); 8 | typedef void(*INTERRUPT_CALLBACK_FUNCTION)(struct interrupt_frame* frame); 9 | 10 | 11 | struct idt_desc 12 | { 13 | uint16_t offset_1; // Offset bits 0 - 15 14 | uint16_t selector; // Selector thats in our GDT 15 | uint8_t zero; // Does nothing, unused set to zero 16 | uint8_t type_attr; // Descriptor type and attributes 17 | uint16_t offset_2; // Offset bits 16-31 18 | } __attribute__((packed)); 19 | 20 | struct idtr_desc 21 | { 22 | uint16_t limit; // Size of descriptor table -1 23 | uint32_t base; // Base address of the start of the interrupt descriptor table 24 | } __attribute__((packed)); 25 | 26 | struct interrupt_frame 27 | { 28 | uint32_t edi; 29 | uint32_t esi; 30 | uint32_t ebp; 31 | uint32_t reserved; 32 | uint32_t ebx; 33 | uint32_t edx; 34 | uint32_t ecx; 35 | uint32_t eax; 36 | uint32_t ip; 37 | uint32_t cs; 38 | uint32_t flags; 39 | uint32_t esp; 40 | uint32_t ss; 41 | } __attribute__((packed)); 42 | 43 | void idt_init(); 44 | void enable_interrupts(); 45 | void disable_interrupts(); 46 | void isr80h_register_command(int command_id, ISR80H_COMMAND command); 47 | int idt_register_interrupt_callback(int interrupt, INTERRUPT_CALLBACK_FUNCTION interrupt_callback); 48 | 49 | #endif -------------------------------------------------------------------------------- /src/io/io.asm: -------------------------------------------------------------------------------- 1 | section .asm 2 | 3 | global insb 4 | global insw 5 | global outb 6 | global outw 7 | 8 | insb: 9 | push ebp 10 | mov ebp, esp 11 | 12 | xor eax, eax 13 | mov edx, [ebp+8] 14 | in al, dx 15 | 16 | pop ebp 17 | ret 18 | 19 | insw: 20 | push ebp 21 | mov ebp, esp 22 | 23 | xor eax, eax 24 | mov edx, [ebp+8] 25 | in ax, dx 26 | 27 | pop ebp 28 | ret 29 | 30 | outb: 31 | push ebp 32 | mov ebp, esp 33 | 34 | mov eax, [ebp+12] 35 | mov edx, [ebp+8] 36 | out dx, al 37 | 38 | pop ebp 39 | ret 40 | 41 | outw: 42 | push ebp 43 | mov ebp, esp 44 | 45 | mov eax, [ebp+12] 46 | mov edx, [ebp+8] 47 | out dx, ax 48 | 49 | pop ebp 50 | ret -------------------------------------------------------------------------------- /src/io/io.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_H 2 | #define IO_H 3 | 4 | unsigned char insb(unsigned short port); 5 | unsigned short insw(unsigned short port); 6 | 7 | void outb(unsigned short port, unsigned char val); 8 | void outw(unsigned short port, unsigned short val); 9 | 10 | #endif -------------------------------------------------------------------------------- /src/isr80h/heap.c: -------------------------------------------------------------------------------- 1 | #include "heap.h" 2 | #include "task/task.h" 3 | #include "task/process.h" 4 | #include 5 | void* isr80h_command4_malloc(struct interrupt_frame* frame) 6 | { 7 | size_t size = (int)task_get_stack_item(task_current(), 0); 8 | return process_malloc(task_current()->process, size); 9 | } 10 | 11 | 12 | void* isr80h_command5_free(struct interrupt_frame* frame) 13 | { 14 | void* ptr_to_free = task_get_stack_item(task_current(), 0); 15 | process_free(task_current()->process, ptr_to_free); 16 | return 0; 17 | } -------------------------------------------------------------------------------- /src/isr80h/heap.h: -------------------------------------------------------------------------------- 1 | #ifndef ISR80H_HEAP_H 2 | #define ISR80H_HEAP_H 3 | 4 | struct interrupt_frame; 5 | void* isr80h_command4_malloc(struct interrupt_frame* frame); 6 | void* isr80h_command5_free(struct interrupt_frame* frame); 7 | 8 | #endif -------------------------------------------------------------------------------- /src/isr80h/io.c: -------------------------------------------------------------------------------- 1 | #include "io.h" 2 | #include "task/task.h" 3 | #include "keyboard/keyboard.h" 4 | #include "kernel.h" 5 | void* isr80h_command1_print(struct interrupt_frame* frame) 6 | { 7 | void* user_space_msg_buffer = task_get_stack_item(task_current(), 0); 8 | char buf[1024]; 9 | copy_string_from_task(task_current(), user_space_msg_buffer, buf, sizeof(buf)); 10 | 11 | print(buf); 12 | return 0; 13 | } 14 | 15 | 16 | void* isr80h_command2_getkey(struct interrupt_frame* frame) 17 | { 18 | char c = keyboard_pop(); 19 | return (void*)((int)c); 20 | } 21 | 22 | void* isr80h_command3_putchar(struct interrupt_frame* frame) 23 | { 24 | char c = (char)(int) task_get_stack_item(task_current(), 0); 25 | terminal_writechar(c, 15); 26 | return 0; 27 | } -------------------------------------------------------------------------------- /src/isr80h/io.h: -------------------------------------------------------------------------------- 1 | #ifndef ISR80H_IO_H 2 | #define ISR80H_IO_H 3 | 4 | struct interrupt_frame; 5 | void* isr80h_command1_print(struct interrupt_frame* frame); 6 | void* isr80h_command2_getkey(struct interrupt_frame* frame); 7 | void* isr80h_command3_putchar(struct interrupt_frame* frame); 8 | #endif -------------------------------------------------------------------------------- /src/isr80h/isr80h.c: -------------------------------------------------------------------------------- 1 | #include "isr80h.h" 2 | #include "idt/idt.h" 3 | #include "misc.h" 4 | #include "io.h" 5 | #include "heap.h" 6 | #include "process.h" 7 | void isr80h_register_commands() 8 | { 9 | isr80h_register_command(SYSTEM_COMMAND0_SUM, isr80h_command0_sum); 10 | isr80h_register_command(SYSTEM_COMMAND1_PRINT, isr80h_command1_print); 11 | isr80h_register_command(SYSTEM_COMMAND2_GETKEY, isr80h_command2_getkey); 12 | isr80h_register_command(SYSTEM_COMMAND3_PUTCHAR, isr80h_command3_putchar); 13 | isr80h_register_command(SYSTEM_COMMAND4_MALLOC, isr80h_command4_malloc); 14 | isr80h_register_command(SYSTEM_COMMAND5_FREE, isr80h_command5_free); 15 | isr80h_register_command(SYSTEM_COMMAND6_PROCESS_LOAD_START, isr80h_command6_process_load_start); 16 | isr80h_register_command(SYSTEM_COMMAND7_INVOKE_SYSTEM_COMMAND, isr80h_command7_invoke_system_command); 17 | isr80h_register_command(SYSTEM_COMMAND8_GET_PROGRAM_ARGUMENTS, isr80h_command8_get_program_arguments); 18 | isr80h_register_command(SYSTEM_COMMAND9_EXIT, isr80h_command9_exit); 19 | } -------------------------------------------------------------------------------- /src/isr80h/isr80h.h: -------------------------------------------------------------------------------- 1 | #ifndef ISR80H_H 2 | #define ISR80H_H 3 | 4 | enum SystemCommands 5 | { 6 | SYSTEM_COMMAND0_SUM, 7 | SYSTEM_COMMAND1_PRINT, 8 | SYSTEM_COMMAND2_GETKEY, 9 | SYSTEM_COMMAND3_PUTCHAR, 10 | SYSTEM_COMMAND4_MALLOC, 11 | SYSTEM_COMMAND5_FREE, 12 | SYSTEM_COMMAND6_PROCESS_LOAD_START, 13 | SYSTEM_COMMAND7_INVOKE_SYSTEM_COMMAND, 14 | SYSTEM_COMMAND8_GET_PROGRAM_ARGUMENTS, 15 | SYSTEM_COMMAND9_EXIT 16 | }; 17 | 18 | void isr80h_register_commands(); 19 | 20 | #endif -------------------------------------------------------------------------------- /src/isr80h/misc.c: -------------------------------------------------------------------------------- 1 | #include "misc.h" 2 | #include "idt/idt.h" 3 | #include "task/task.h" 4 | 5 | void* isr80h_command0_sum(struct interrupt_frame* frame) 6 | { 7 | int v2 = (int) task_get_stack_item(task_current(), 1); 8 | int v1 = (int) task_get_stack_item(task_current(), 0); 9 | return (void*)(v1 + v2); 10 | } -------------------------------------------------------------------------------- /src/isr80h/misc.h: -------------------------------------------------------------------------------- 1 | #ifndef ISR80H_MISC_H 2 | #define ISR80H_MISC_H 3 | 4 | struct interrupt_frame; 5 | void* isr80h_command0_sum(struct interrupt_frame* frame); 6 | #endif -------------------------------------------------------------------------------- /src/isr80h/process.c: -------------------------------------------------------------------------------- 1 | #include "process.h" 2 | #include "task/task.h" 3 | #include "task/process.h" 4 | #include "string/string.h" 5 | #include "status.h" 6 | #include "config.h" 7 | #include "kernel.h" 8 | 9 | 10 | void* isr80h_command6_process_load_start(struct interrupt_frame* frame) 11 | { 12 | void* filename_user_ptr = task_get_stack_item(task_current(), 0); 13 | char filename[PEACHOS_MAX_PATH]; 14 | int res = copy_string_from_task(task_current(), filename_user_ptr, filename, sizeof(filename)); 15 | if (res < 0) 16 | { 17 | goto out; 18 | } 19 | 20 | char path[PEACHOS_MAX_PATH]; 21 | strcpy(path, "0:/"); 22 | strcpy(path+3, filename); 23 | 24 | struct process* process = 0; 25 | res = process_load_switch(path, &process); 26 | if (res < 0) 27 | { 28 | goto out; 29 | } 30 | 31 | task_switch(process->task); 32 | task_return(&process->task->registers); 33 | 34 | out: 35 | return 0; 36 | } 37 | 38 | void* isr80h_command7_invoke_system_command(struct interrupt_frame* frame) 39 | { 40 | struct command_argument* arguments = task_virtual_address_to_physical(task_current(), task_get_stack_item(task_current(), 0)); 41 | if (!arguments || strlen(arguments[0].argument) == 0) 42 | { 43 | return ERROR(-EINVARG); 44 | } 45 | 46 | struct command_argument* root_command_argument = &arguments[0]; 47 | const char* program_name = root_command_argument->argument; 48 | 49 | char path[PEACHOS_MAX_PATH]; 50 | strcpy(path, "0:/"); 51 | strncpy(path+3, program_name, sizeof(path)); 52 | 53 | struct process* process = 0; 54 | int res = process_load_switch(path, &process); 55 | if (res < 0) 56 | { 57 | return ERROR(res); 58 | } 59 | 60 | res = process_inject_arguments(process, root_command_argument); 61 | if (res < 0) 62 | { 63 | return ERROR(res); 64 | } 65 | 66 | task_switch(process->task); 67 | task_return(&process->task->registers); 68 | 69 | return 0; 70 | } 71 | 72 | void* isr80h_command8_get_program_arguments(struct interrupt_frame* frame) 73 | { 74 | struct process* process = task_current()->process; 75 | struct process_arguments* arguments = task_virtual_address_to_physical(task_current(), task_get_stack_item(task_current(), 0)); 76 | 77 | process_get_arguments(process, &arguments->argc, &arguments->argv); 78 | return 0; 79 | } 80 | 81 | void* isr80h_command9_exit(struct interrupt_frame* frame) 82 | { 83 | struct process* process = task_current()->process; 84 | process_terminate(process); 85 | task_next(); 86 | return 0; 87 | } -------------------------------------------------------------------------------- /src/isr80h/process.h: -------------------------------------------------------------------------------- 1 | #ifndef ISR80H_PROCESS_H 2 | #define ISR80H_PROCESS_H 3 | 4 | struct interrupt_frame; 5 | void* isr80h_command6_process_load_start(struct interrupt_frame* frame); 6 | void* isr80h_command7_invoke_system_command(struct interrupt_frame* frame); 7 | void* isr80h_command8_get_program_arguments(struct interrupt_frame* frame); 8 | void* isr80h_command9_exit(struct interrupt_frame* frame); 9 | 10 | #endif -------------------------------------------------------------------------------- /src/kernel.asm: -------------------------------------------------------------------------------- 1 | [BITS 32] 2 | 3 | global _start 4 | global kernel_registers 5 | extern kernel_main 6 | 7 | CODE_SEG equ 0x08 8 | DATA_SEG equ 0x10 9 | 10 | _start: 11 | mov ax, DATA_SEG 12 | mov ds, ax 13 | mov es, ax 14 | mov fs, ax 15 | mov gs, ax 16 | mov ss, ax 17 | mov ebp, 0x00200000 18 | mov esp, ebp 19 | 20 | 21 | ; Remap the master PIC 22 | mov al, 00010001b 23 | out 0x20, al ; Tell master PIC 24 | 25 | mov al, 0x20 ; Interrupt 0x20 is where master ISR should start 26 | out 0x21, al 27 | 28 | mov al, 0x04 ; ICW3 29 | out 0x21, al 30 | 31 | mov al, 00000001b 32 | out 0x21, al 33 | ; End remap of the master PIC 34 | 35 | call kernel_main 36 | 37 | jmp $ 38 | 39 | kernel_registers: 40 | mov ax, 0x10 41 | mov ds, ax 42 | mov es, ax 43 | mov gs, ax 44 | mov fs, ax 45 | ret 46 | 47 | 48 | times 512-($ - $$) db 0 49 | -------------------------------------------------------------------------------- /src/kernel.c: -------------------------------------------------------------------------------- 1 | #include "kernel.h" 2 | #include 3 | #include 4 | #include "idt/idt.h" 5 | #include "memory/heap/kheap.h" 6 | #include "memory/paging/paging.h" 7 | #include "memory/memory.h" 8 | #include "keyboard/keyboard.h" 9 | #include "string/string.h" 10 | #include "isr80h/isr80h.h" 11 | #include "task/task.h" 12 | #include "task/process.h" 13 | #include "fs/file.h" 14 | #include "disk/disk.h" 15 | #include "fs/pparser.h" 16 | #include "disk/streamer.h" 17 | #include "task/tss.h" 18 | #include "gdt/gdt.h" 19 | #include "config.h" 20 | #include "status.h" 21 | 22 | uint16_t* video_mem = 0; 23 | uint16_t terminal_row = 0; 24 | uint16_t terminal_col = 0; 25 | 26 | uint16_t terminal_make_char(char c, char colour) 27 | { 28 | return (colour << 8) | c; 29 | } 30 | 31 | void terminal_putchar(int x, int y, char c, char colour) 32 | { 33 | video_mem[(y * VGA_WIDTH) + x] = terminal_make_char(c, colour); 34 | } 35 | 36 | void terminal_backspace() 37 | { 38 | if (terminal_row == 0 && terminal_col == 0) 39 | { 40 | return; 41 | } 42 | 43 | if (terminal_col == 0) 44 | { 45 | terminal_row -= 1; 46 | terminal_col = VGA_WIDTH; 47 | } 48 | 49 | terminal_col -=1; 50 | terminal_writechar(' ', 15); 51 | terminal_col -=1; 52 | } 53 | 54 | void terminal_writechar(char c, char colour) 55 | { 56 | if (c == '\n') 57 | { 58 | terminal_row += 1; 59 | terminal_col = 0; 60 | return; 61 | } 62 | 63 | if (c == 0x08) 64 | { 65 | terminal_backspace(); 66 | return; 67 | } 68 | 69 | terminal_putchar(terminal_col, terminal_row, c, colour); 70 | terminal_col += 1; 71 | if (terminal_col >= VGA_WIDTH) 72 | { 73 | terminal_col = 0; 74 | terminal_row += 1; 75 | } 76 | } 77 | void terminal_initialize() 78 | { 79 | video_mem = (uint16_t*)(0xB8000); 80 | terminal_row = 0; 81 | terminal_col = 0; 82 | for (int y = 0; y < VGA_HEIGHT; y++) 83 | { 84 | for (int x = 0; x < VGA_WIDTH; x++) 85 | { 86 | terminal_putchar(x, y, ' ', 0); 87 | } 88 | } 89 | } 90 | 91 | 92 | 93 | void print(const char* str) 94 | { 95 | size_t len = strlen(str); 96 | for (int i = 0; i < len; i++) 97 | { 98 | terminal_writechar(str[i], 15); 99 | } 100 | } 101 | 102 | 103 | static struct paging_4gb_chunk* kernel_chunk = 0; 104 | 105 | void panic(const char* msg) 106 | { 107 | print(msg); 108 | while(1) {} 109 | } 110 | 111 | void kernel_page() 112 | { 113 | kernel_registers(); 114 | paging_switch(kernel_chunk); 115 | } 116 | 117 | struct tss tss; 118 | struct gdt gdt_real[PEACHOS_TOTAL_GDT_SEGMENTS]; 119 | struct gdt_structured gdt_structured[PEACHOS_TOTAL_GDT_SEGMENTS] = { 120 | {.base = 0x00, .limit = 0x00, .type = 0x00}, // NULL Segment 121 | {.base = 0x00, .limit = 0xffffffff, .type = 0x9a}, // Kernel code segment 122 | {.base = 0x00, .limit = 0xffffffff, .type = 0x92}, // Kernel data segment 123 | {.base = 0x00, .limit = 0xffffffff, .type = 0xf8}, // User code segment 124 | {.base = 0x00, .limit = 0xffffffff, .type = 0xf2}, // User data segment 125 | {.base = (uint32_t)&tss, .limit=sizeof(tss), .type = 0xE9} // TSS Segment 126 | }; 127 | 128 | void kernel_main() 129 | { 130 | terminal_initialize(); 131 | memset(gdt_real, 0x00, sizeof(gdt_real)); 132 | gdt_structured_to_gdt(gdt_real, gdt_structured, PEACHOS_TOTAL_GDT_SEGMENTS); 133 | 134 | // Load the gdt 135 | gdt_load(gdt_real, sizeof(gdt_real)-1); 136 | 137 | // Initialize the heap 138 | kheap_init(); 139 | 140 | // Initialize filesystems 141 | fs_init(); 142 | 143 | // Search and initialize the disks 144 | disk_search_and_init(); 145 | 146 | // Initialize the interrupt descriptor table 147 | idt_init(); 148 | 149 | // Setup the TSS 150 | memset(&tss, 0x00, sizeof(tss)); 151 | tss.esp0 = 0x600000; 152 | tss.ss0 = KERNEL_DATA_SELECTOR; 153 | 154 | // Load the TSS 155 | tss_load(0x28); 156 | 157 | // Setup paging 158 | kernel_chunk = paging_new_4gb(PAGING_IS_WRITEABLE | PAGING_IS_PRESENT | PAGING_ACCESS_FROM_ALL); 159 | 160 | // Switch to kernel paging chunk 161 | paging_switch(kernel_chunk); 162 | 163 | // Enable paging 164 | enable_paging(); 165 | 166 | // Register the kernel commands 167 | isr80h_register_commands(); 168 | 169 | // Initialize all the system keyboards 170 | keyboard_init(); 171 | 172 | struct process* process = 0; 173 | int res = process_load_switch("0:/blank.elf", &process); 174 | if (res != PEACHOS_ALL_OK) 175 | { 176 | panic("Failed to load blank.elf\n"); 177 | } 178 | 179 | 180 | struct command_argument argument; 181 | strcpy(argument.argument, "Testing!"); 182 | argument.next = 0x00; 183 | 184 | process_inject_arguments(process, &argument); 185 | 186 | res = process_load_switch("0:/blank.elf", &process); 187 | if (res != PEACHOS_ALL_OK) 188 | { 189 | panic("Failed to load blank.elf\n"); 190 | } 191 | 192 | strcpy(argument.argument, "Abc!"); 193 | argument.next = 0x00; 194 | process_inject_arguments(process, &argument); 195 | 196 | task_run_first_ever_task(); 197 | 198 | while(1) {} 199 | } -------------------------------------------------------------------------------- /src/kernel.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_H 2 | #define KERNEL_H 3 | 4 | #define VGA_WIDTH 80 5 | #define VGA_HEIGHT 20 6 | 7 | #define PEACHOS_MAX_PATH 108 8 | 9 | void kernel_main(); 10 | void print(const char* str); 11 | void terminal_writechar(char c, char colour); 12 | 13 | void panic(const char* msg); 14 | void kernel_page(); 15 | void kernel_registers(); 16 | 17 | 18 | #define ERROR(value) (void*)(value) 19 | #define ERROR_I(value) (int)(value) 20 | #define ISERR(value) ((int)value < 0) 21 | #endif -------------------------------------------------------------------------------- /src/keyboard/classic.c: -------------------------------------------------------------------------------- 1 | #include "classic.h" 2 | #include "keyboard.h" 3 | #include "io/io.h" 4 | #include "kernel.h" 5 | #include "idt/idt.h" 6 | #include "task/task.h" 7 | 8 | #include 9 | #include 10 | 11 | #define CLASSIC_KEYBOARD_CAPSLOCK 0x3A 12 | 13 | int classic_keyboard_init(); 14 | 15 | static uint8_t keyboard_scan_set_one[] = { 16 | 0x00, 0x1B, '1', '2', '3', '4', '5', 17 | '6', '7', '8', '9', '0', '-', '=', 18 | 0x08, '\t', 'Q', 'W', 'E', 'R', 'T', 19 | 'Y', 'U', 'I', 'O', 'P', '[', ']', 20 | 0x0d, 0x00, 'A', 'S', 'D', 'F', 'G', 21 | 'H', 'J', 'K', 'L', ';', '\'', '`', 22 | 0x00, '\\', 'Z', 'X', 'C', 'V', 'B', 23 | 'N', 'M', ',', '.', '/', 0x00, '*', 24 | 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 25 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 26 | 0x00, '7', '8', '9', '-', '4', '5', 27 | '6', '+', '1', '2', '3', '0', '.' 28 | }; 29 | 30 | struct keyboard classic_keyboard = { 31 | .name = {"Classic"}, 32 | .init = classic_keyboard_init 33 | }; 34 | 35 | 36 | void classic_keyboard_handle_interrupt(); 37 | 38 | int classic_keyboard_init() 39 | { 40 | idt_register_interrupt_callback(ISR_KEYBOARD_INTERRUPT, classic_keyboard_handle_interrupt); 41 | 42 | keyboard_set_capslock(&classic_keyboard, KEYBOARD_CAPS_LOCK_OFF); 43 | 44 | outb(PS2_PORT, PS2_COMMAND_ENABLE_FIRST_PORT); 45 | return 0; 46 | } 47 | 48 | uint8_t classic_keyboard_scancode_to_char(uint8_t scancode) 49 | { 50 | size_t size_of_keyboard_set_one = sizeof(keyboard_scan_set_one) / sizeof(uint8_t); 51 | if (scancode > size_of_keyboard_set_one) 52 | { 53 | return 0; 54 | } 55 | 56 | char c = keyboard_scan_set_one[scancode]; 57 | if (keyboard_get_capslock(&classic_keyboard) == KEYBOARD_CAPS_LOCK_OFF) 58 | { 59 | if (c >= 'A' && c <= 'Z') 60 | { 61 | c += 32; 62 | } 63 | } 64 | return c; 65 | } 66 | 67 | 68 | void classic_keyboard_handle_interrupt() 69 | { 70 | kernel_page(); 71 | uint8_t scancode = 0; 72 | scancode = insb(KEYBOARD_INPUT_PORT); 73 | insb(KEYBOARD_INPUT_PORT); 74 | 75 | if(scancode & CLASSIC_KEYBOARD_KEY_RELEASED) 76 | { 77 | return; 78 | } 79 | 80 | if (scancode == CLASSIC_KEYBOARD_CAPSLOCK) 81 | { 82 | KEYBOARD_CAPS_LOCK_STATE old_state = keyboard_get_capslock(&classic_keyboard); 83 | keyboard_set_capslock(&classic_keyboard, old_state == KEYBOARD_CAPS_LOCK_ON ? KEYBOARD_CAPS_LOCK_OFF : KEYBOARD_CAPS_LOCK_ON); 84 | } 85 | 86 | uint8_t c = classic_keyboard_scancode_to_char(scancode); 87 | if (c != 0) 88 | { 89 | keyboard_push(c); 90 | } 91 | 92 | task_page(); 93 | 94 | } 95 | 96 | struct keyboard* classic_init() 97 | { 98 | return &classic_keyboard; 99 | } -------------------------------------------------------------------------------- /src/keyboard/classic.h: -------------------------------------------------------------------------------- 1 | #ifndef CLASSIC_KEYBOARD_H 2 | #define CLASSIC_KEYBOARD_H 3 | 4 | #define PS2_PORT 0x64 5 | #define PS2_COMMAND_ENABLE_FIRST_PORT 0xAE 6 | 7 | #define CLASSIC_KEYBOARD_KEY_RELEASED 0x80 8 | #define ISR_KEYBOARD_INTERRUPT 0x21 9 | #define KEYBOARD_INPUT_PORT 0x60 10 | 11 | struct keyboard* classic_init(); 12 | 13 | #endif -------------------------------------------------------------------------------- /src/keyboard/keyboard.c: -------------------------------------------------------------------------------- 1 | #include "keyboard.h" 2 | #include "status.h" 3 | #include "kernel.h" 4 | #include "task/process.h" 5 | #include "task/task.h" 6 | #include "classic.h" 7 | 8 | static struct keyboard* keyboard_list_head = 0; 9 | static struct keyboard* keyboard_list_last = 0; 10 | 11 | void keyboard_init() 12 | { 13 | keyboard_insert(classic_init()); 14 | } 15 | 16 | int keyboard_insert(struct keyboard* keyboard) 17 | { 18 | int res = 0; 19 | if (keyboard->init == 0) 20 | { 21 | res = -EINVARG; 22 | goto out; 23 | } 24 | 25 | if (keyboard_list_last) 26 | { 27 | keyboard_list_last->next = keyboard; 28 | keyboard_list_last = keyboard; 29 | 30 | } 31 | else 32 | { 33 | keyboard_list_head = keyboard; 34 | keyboard_list_last = keyboard; 35 | } 36 | 37 | res = keyboard->init(); 38 | out: 39 | return res; 40 | } 41 | 42 | static int keyboard_get_tail_index(struct process* process) 43 | { 44 | return process->keyboard.tail % sizeof(process->keyboard.buffer); 45 | } 46 | 47 | void keyboard_backspace(struct process* process) 48 | { 49 | process->keyboard.tail -=1 ; 50 | int real_index = keyboard_get_tail_index(process); 51 | process->keyboard.buffer[real_index] = 0x00; 52 | } 53 | 54 | void keyboard_set_capslock(struct keyboard* keyboard, KEYBOARD_CAPS_LOCK_STATE state) 55 | { 56 | keyboard->capslock_state = state; 57 | } 58 | 59 | KEYBOARD_CAPS_LOCK_STATE keyboard_get_capslock(struct keyboard* keyboard) 60 | { 61 | return keyboard->capslock_state; 62 | } 63 | 64 | void keyboard_push(char c) 65 | { 66 | struct process* process = process_current(); 67 | if (!process) 68 | { 69 | return; 70 | } 71 | 72 | if(c == 0) 73 | { 74 | return; 75 | } 76 | 77 | int real_index = keyboard_get_tail_index(process); 78 | process->keyboard.buffer[real_index] = c; 79 | process->keyboard.tail++; 80 | } 81 | 82 | char keyboard_pop() 83 | { 84 | if (!task_current()) 85 | { 86 | return 0; 87 | } 88 | 89 | struct process* process = task_current()->process; 90 | int real_index = process->keyboard.head % sizeof(process->keyboard.buffer); 91 | char c = process->keyboard.buffer[real_index]; 92 | if (c == 0x00) 93 | { 94 | // Nothing to pop return zero. 95 | return 0; 96 | } 97 | 98 | process->keyboard.buffer[real_index] = 0; 99 | process->keyboard.head++; 100 | return c; 101 | } -------------------------------------------------------------------------------- /src/keyboard/keyboard.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYBOARD_H 2 | #define KEYBOARD_H 3 | 4 | #define KEYBOARD_CAPS_LOCK_ON 1 5 | #define KEYBOARD_CAPS_LOCK_OFF 0 6 | 7 | typedef int KEYBOARD_CAPS_LOCK_STATE; 8 | 9 | struct process; 10 | 11 | typedef int (*KEYBOARD_INIT_FUNCTION)(); 12 | struct keyboard 13 | { 14 | KEYBOARD_INIT_FUNCTION init; 15 | char name[20]; 16 | 17 | KEYBOARD_CAPS_LOCK_STATE capslock_state; 18 | 19 | struct keyboard* next; 20 | }; 21 | 22 | void keyboard_init(); 23 | void keyboard_backspace(struct process* process); 24 | void keyboard_push(char c); 25 | char keyboard_pop(); 26 | int keyboard_insert(struct keyboard* keyboard); 27 | void keyboard_set_capslock(struct keyboard* keyboard, KEYBOARD_CAPS_LOCK_STATE state); 28 | KEYBOARD_CAPS_LOCK_STATE keyboard_get_capslock(struct keyboard* keyboard); 29 | 30 | #endif -------------------------------------------------------------------------------- /src/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | OUTPUT_FORMAT(binary) 3 | SECTIONS 4 | { 5 | . = 1M; 6 | .text : ALIGN(4096) 7 | { 8 | *(.text) 9 | } 10 | 11 | .asm : ALIGN(4096) 12 | { 13 | *(.asm) 14 | } 15 | 16 | .rodata : ALIGN(4096) 17 | { 18 | *(.rodata) 19 | } 20 | 21 | .data : ALIGN(4096) 22 | { 23 | *(.data) 24 | } 25 | 26 | .bss : ALIGN(4096) 27 | { 28 | *(COMMON) 29 | *(.bss) 30 | } 31 | } -------------------------------------------------------------------------------- /src/loader/formats/elf.c: -------------------------------------------------------------------------------- 1 | #include "elf.h" 2 | 3 | void* elf_get_entry_ptr(struct elf_header* elf_header) 4 | { 5 | return (void*) elf_header->e_entry; 6 | } 7 | 8 | uint32_t elf_get_entry(struct elf_header* elf_header) 9 | { 10 | return elf_header->e_entry; 11 | } -------------------------------------------------------------------------------- /src/loader/formats/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef ELF_H 2 | #define ELF_H 3 | 4 | #include 5 | #include 6 | 7 | #define PF_X 0x01 8 | #define PF_W 0x02 9 | #define PF_R 0x04 10 | 11 | #define PT_NULL 0 12 | #define PT_LOAD 1 13 | #define PT_DYNAMIC 2 14 | #define PT_INTERP 3 15 | #define PT_NOTE 4 16 | #define PT_SHLIB 5 17 | #define PT_PHDR 6 18 | 19 | #define SHT_NULL 0 20 | #define SHT_PROGBITS 1 21 | #define SHT_SYMTAB 2 22 | #define SHT_STRTAB 3 23 | #define SHT_RELA 4 24 | #define SHT_HASH 5 25 | #define SHT_DYNAMIC 6 26 | #define SHT_NOTE 7 27 | #define SHT_NOBITS 8 28 | #define SHT_REL 9 29 | #define SHT_SHLIB 10 30 | #define SHT_DYNSYM 11 31 | #define SHT_LOPROC 12 32 | #define SHT_HIPROC 13 33 | #define SHT_LOUSER 14 34 | #define SHT_HIUSER 15 35 | 36 | #define ET_NONE 0 37 | #define ET_REL 1 38 | #define ET_EXEC 2 39 | #define ET_DYN 3 40 | #define ET_CORE 4 41 | 42 | #define EI_NIDENT 16 43 | #define EI_CLASS 4 44 | #define EI_DATA 5 45 | 46 | #define ELFCLASSNONE 0 47 | #define ELFCLASS32 1 48 | #define ELFCLASS64 2 49 | 50 | #define ELFDATANONE 0 51 | #define ELFDATA2LSB 1 52 | #define ELFDATA2MSB 2 53 | 54 | #define SHN_UNDEF 0 55 | 56 | typedef uint16_t elf32_half; 57 | typedef uint32_t elf32_word; 58 | typedef int32_t elf32_sword; 59 | typedef uint32_t elf32_addr; 60 | typedef uint32_t elf32_off; 61 | 62 | struct elf32_phdr 63 | { 64 | elf32_word p_type; 65 | elf32_off p_offset; 66 | elf32_addr p_vaddr; 67 | elf32_addr p_paddr; 68 | elf32_word p_filesz; 69 | elf32_word p_memsz; 70 | elf32_word p_flags; 71 | elf32_word p_align; 72 | } __attribute__((packed)); 73 | 74 | struct elf32_shdr 75 | { 76 | elf32_word sh_name; 77 | elf32_word sh_type; 78 | elf32_word sh_flags; 79 | elf32_addr sh_addr; 80 | elf32_off sh_offset; 81 | elf32_word sh_size; 82 | elf32_word sh_link; 83 | elf32_word sh_info; 84 | elf32_word sh_addralign; 85 | elf32_word sh_entsize; 86 | } __attribute__((packed)); 87 | 88 | struct elf_header 89 | { 90 | unsigned char e_ident[EI_NIDENT]; 91 | elf32_half e_type; 92 | elf32_half e_machine; 93 | elf32_word e_version; 94 | elf32_addr e_entry; 95 | elf32_off e_phoff; 96 | elf32_off e_shoff; 97 | elf32_word e_flags; 98 | elf32_half e_ehsize; 99 | elf32_half e_phentsize; 100 | elf32_half e_phnum; 101 | elf32_half e_shentsize; 102 | elf32_half e_shnum; 103 | elf32_half e_shstrndx; 104 | } __attribute__((packed)); 105 | 106 | struct elf32_dyn 107 | { 108 | elf32_sword d_tag; 109 | union 110 | { 111 | elf32_word d_val; 112 | elf32_addr d_ptr; 113 | } d_un; 114 | 115 | } __attribute__((packed)); 116 | 117 | struct elf32_sym 118 | { 119 | elf32_word st_name; 120 | elf32_addr st_value; 121 | elf32_word st_size; 122 | unsigned char st_info; 123 | unsigned char st_other; 124 | elf32_half st_shndx; 125 | } __attribute__((packed)); 126 | 127 | void* elf_get_entry_ptr(struct elf_header* elf_header); 128 | uint32_t elf_get_entry(struct elf_header* elf_header); 129 | 130 | #endif -------------------------------------------------------------------------------- /src/loader/formats/elfloader.c: -------------------------------------------------------------------------------- 1 | #include "elfloader.h" 2 | #include "fs/file.h" 3 | #include "status.h" 4 | #include 5 | #include "memory/memory.h" 6 | #include "memory/heap/kheap.h" 7 | #include "string/string.h" 8 | #include "memory/paging/paging.h" 9 | #include "kernel.h" 10 | #include "config.h" 11 | 12 | 13 | const char elf_signature[] = {0x7f, 'E', 'L', 'F'}; 14 | 15 | static bool elf_valid_signature(void* buffer) 16 | { 17 | return memcmp(buffer, (void*) elf_signature, sizeof(elf_signature)) == 0; 18 | } 19 | 20 | static bool elf_valid_class(struct elf_header* header) 21 | { 22 | // We only support 32 bit binaries. 23 | return header->e_ident[EI_CLASS] == ELFCLASSNONE || header->e_ident[EI_CLASS] == ELFCLASS32; 24 | } 25 | 26 | static bool elf_valid_encoding(struct elf_header* header) 27 | { 28 | return header->e_ident[EI_DATA] == ELFDATANONE || header->e_ident[EI_DATA] == ELFDATA2LSB; 29 | } 30 | 31 | static bool elf_is_executable(struct elf_header* header) 32 | { 33 | return header->e_type == ET_EXEC && header->e_entry >= PEACHOS_PROGRAM_VIRTUAL_ADDRESS; 34 | } 35 | 36 | static bool elf_has_program_header(struct elf_header* header) 37 | { 38 | return header->e_phoff != 0; 39 | } 40 | 41 | void* elf_memory(struct elf_file* file) 42 | { 43 | return file->elf_memory; 44 | } 45 | 46 | struct elf_header* elf_header(struct elf_file* file) 47 | { 48 | return file->elf_memory; 49 | } 50 | 51 | struct elf32_shdr* elf_sheader(struct elf_header* header) 52 | { 53 | return (struct elf32_shdr*)((int)header+header->e_shoff); 54 | } 55 | 56 | struct elf32_phdr* elf_pheader(struct elf_header* header) 57 | { 58 | if(header->e_phoff == 0) 59 | { 60 | return 0; 61 | } 62 | 63 | return (struct elf32_phdr*)((int)header + header->e_phoff); 64 | } 65 | 66 | struct elf32_phdr* elf_program_header(struct elf_header* header, int index) 67 | { 68 | return &elf_pheader(header)[index]; 69 | } 70 | 71 | struct elf32_shdr* elf_section(struct elf_header* header, int index) 72 | { 73 | return &elf_sheader(header)[index]; 74 | } 75 | 76 | 77 | void* elf_phdr_phys_address(struct elf_file* file, struct elf32_phdr* phdr) 78 | { 79 | return elf_memory(file)+phdr->p_offset; 80 | } 81 | 82 | char* elf_str_table(struct elf_header* header) 83 | { 84 | return (char*) header + elf_section(header, header->e_shstrndx)->sh_offset; 85 | } 86 | 87 | void* elf_virtual_base(struct elf_file* file) 88 | { 89 | return file->virtual_base_address; 90 | } 91 | 92 | void* elf_virtual_end(struct elf_file* file) 93 | { 94 | return file->virtual_end_address; 95 | } 96 | 97 | void* elf_phys_base(struct elf_file* file) 98 | { 99 | return file->physical_base_address; 100 | } 101 | 102 | void* elf_phys_end(struct elf_file* file) 103 | { 104 | return file->physical_end_address; 105 | } 106 | 107 | int elf_validate_loaded(struct elf_header* header) 108 | { 109 | return (elf_valid_signature(header) && elf_valid_class(header) && elf_valid_encoding(header) && elf_has_program_header(header) && elf_is_executable(header)) ? PEACHOS_ALL_OK : -EINFORMAT; 110 | } 111 | 112 | int elf_process_phdr_pt_load(struct elf_file* elf_file, struct elf32_phdr* phdr) 113 | { 114 | if (elf_file->virtual_base_address >= (void*) phdr->p_vaddr || elf_file->virtual_base_address == 0x00) 115 | { 116 | elf_file->virtual_base_address = (void*) phdr->p_vaddr; 117 | elf_file->physical_base_address = elf_memory(elf_file)+phdr->p_offset; 118 | } 119 | 120 | unsigned int end_virtual_address = phdr->p_vaddr + phdr->p_filesz; 121 | if (elf_file->virtual_end_address <= (void*)(end_virtual_address) || elf_file->virtual_end_address == 0x00) 122 | { 123 | elf_file->virtual_end_address = (void*) end_virtual_address; 124 | elf_file->physical_end_address = elf_memory(elf_file)+phdr->p_offset+phdr->p_filesz; 125 | } 126 | return 0; 127 | } 128 | int elf_process_pheader(struct elf_file* elf_file, struct elf32_phdr* phdr) 129 | { 130 | int res = 0; 131 | switch(phdr->p_type) 132 | { 133 | case PT_LOAD: 134 | res = elf_process_phdr_pt_load(elf_file, phdr); 135 | break; 136 | } 137 | return res; 138 | } 139 | int elf_process_pheaders(struct elf_file* elf_file) 140 | { 141 | int res = 0; 142 | struct elf_header* header = elf_header(elf_file); 143 | for(int i = 0; i < header->e_phnum; i++) 144 | { 145 | struct elf32_phdr* phdr = elf_program_header(header, i); 146 | res = elf_process_pheader(elf_file, phdr); 147 | if (res < 0) 148 | { 149 | break; 150 | } 151 | 152 | } 153 | return res; 154 | } 155 | 156 | int elf_process_loaded(struct elf_file* elf_file) 157 | { 158 | int res = 0; 159 | struct elf_header* header = elf_header(elf_file); 160 | res = elf_validate_loaded(header); 161 | if (res < 0) 162 | { 163 | goto out; 164 | } 165 | 166 | res = elf_process_pheaders(elf_file); 167 | if (res < 0) 168 | { 169 | goto out; 170 | } 171 | 172 | out: 173 | return res; 174 | } 175 | 176 | void elf_file_free(struct elf_file* elf_file) 177 | { 178 | if (elf_file->elf_memory) 179 | { 180 | kfree(elf_file->elf_memory); 181 | } 182 | 183 | kfree(elf_file); 184 | } 185 | struct elf_file* elf_file_new() 186 | { 187 | return (struct elf_file*)kzalloc(sizeof(struct elf_file)); 188 | } 189 | 190 | int elf_load(const char* filename, struct elf_file** file_out) 191 | { 192 | struct elf_file* elf_file = elf_file_new(); 193 | int fd = 0; 194 | int res = fopen(filename, "r"); 195 | if (res <= 0) 196 | { 197 | res = -EIO; 198 | goto out; 199 | } 200 | 201 | fd = res; 202 | struct file_stat stat; 203 | res = fstat(fd, &stat); 204 | if (res < 0) 205 | { 206 | goto out; 207 | } 208 | 209 | elf_file->elf_memory = kzalloc(stat.filesize); 210 | res = fread(elf_file->elf_memory, stat.filesize, 1, fd); 211 | if (res < 0) 212 | { 213 | goto out; 214 | } 215 | 216 | res = elf_process_loaded(elf_file); 217 | if(res < 0) 218 | { 219 | goto out; 220 | } 221 | 222 | *file_out = elf_file; 223 | out: 224 | if (res < 0) 225 | { 226 | elf_file_free(elf_file); 227 | } 228 | fclose(fd); 229 | return res; 230 | } 231 | 232 | void elf_close(struct elf_file* file) 233 | { 234 | if (!file) 235 | return; 236 | 237 | kfree(file->elf_memory); 238 | kfree(file); 239 | } -------------------------------------------------------------------------------- /src/loader/formats/elfloader.h: -------------------------------------------------------------------------------- 1 | #ifndef ELFLOADER_H 2 | #define ELFLOADER_H 3 | 4 | #include 5 | #include 6 | 7 | #include "elf.h" 8 | #include "config.h" 9 | 10 | struct elf_file 11 | { 12 | char filename[PEACHOS_MAX_PATH]; 13 | 14 | int in_memory_size; 15 | 16 | /** 17 | * The physical memory address that this elf file is loaded at 18 | */ 19 | void* elf_memory; 20 | 21 | /** 22 | * The virtual base address of this binary 23 | */ 24 | void* virtual_base_address; 25 | 26 | /** 27 | * The ending virtual address 28 | */ 29 | void* virtual_end_address; 30 | 31 | /** 32 | * The physical base address of this binary 33 | */ 34 | void* physical_base_address; 35 | 36 | /** 37 | * The physical end address of this bunary 38 | */ 39 | void* physical_end_address; 40 | 41 | 42 | }; 43 | 44 | int elf_load(const char* filename, struct elf_file** file_out); 45 | struct elf_file* elf_file_new(); 46 | void elf_file_free(struct elf_file* file); 47 | 48 | void elf_close(struct elf_file* file); 49 | void* elf_virtual_base(struct elf_file* file); 50 | void* elf_virtual_end(struct elf_file* file); 51 | void* elf_phys_base(struct elf_file* file); 52 | void* elf_phys_end(struct elf_file* file); 53 | 54 | struct elf_header* elf_header(struct elf_file* file); 55 | struct elf32_shdr* elf_sheader(struct elf_header* header); 56 | void* elf_memory(struct elf_file* file); 57 | struct elf32_phdr* elf_pheader(struct elf_header* header); 58 | struct elf32_phdr* elf_program_header(struct elf_header* header, int index); 59 | struct elf32_shdr* elf_section(struct elf_header* header, int index); 60 | void* elf_phdr_phys_address(struct elf_file* file, struct elf32_phdr* phdr); 61 | 62 | #endif -------------------------------------------------------------------------------- /src/memory/heap/heap.c: -------------------------------------------------------------------------------- 1 | #include "heap.h" 2 | #include "kernel.h" 3 | #include "status.h" 4 | #include "memory/memory.h" 5 | #include 6 | 7 | static int heap_validate_table(void* ptr, void* end, struct heap_table* table) 8 | { 9 | int res = 0; 10 | 11 | size_t table_size = (size_t)(end - ptr); 12 | size_t total_blocks = table_size / PEACHOS_HEAP_BLOCK_SIZE; 13 | if (table->total != total_blocks) 14 | { 15 | res = -EINVARG; 16 | goto out; 17 | } 18 | 19 | out: 20 | return res; 21 | } 22 | 23 | static bool heap_validate_alignment(void* ptr) 24 | { 25 | return ((unsigned int)ptr % PEACHOS_HEAP_BLOCK_SIZE) == 0; 26 | } 27 | 28 | int heap_create(struct heap* heap, void* ptr, void* end, struct heap_table* table) 29 | { 30 | int res = 0; 31 | 32 | if (!heap_validate_alignment(ptr) || !heap_validate_alignment(end)) 33 | { 34 | res = -EINVARG; 35 | goto out; 36 | } 37 | 38 | memset(heap, 0, sizeof(struct heap)); 39 | heap->saddr = ptr; 40 | heap->table = table; 41 | 42 | res = heap_validate_table(ptr, end, table); 43 | if (res < 0) 44 | { 45 | goto out; 46 | } 47 | 48 | size_t table_size = sizeof(HEAP_BLOCK_TABLE_ENTRY) * table->total; 49 | memset(table->entries, HEAP_BLOCK_TABLE_ENTRY_FREE, table_size); 50 | 51 | out: 52 | return res; 53 | } 54 | 55 | static uint32_t heap_align_value_to_upper(uint32_t val) 56 | { 57 | if ((val % PEACHOS_HEAP_BLOCK_SIZE) == 0) 58 | { 59 | return val; 60 | } 61 | 62 | val = (val - ( val % PEACHOS_HEAP_BLOCK_SIZE)); 63 | val += PEACHOS_HEAP_BLOCK_SIZE; 64 | return val; 65 | } 66 | 67 | static int heap_get_entry_type(HEAP_BLOCK_TABLE_ENTRY entry) 68 | { 69 | return entry & 0x0f; 70 | } 71 | 72 | int heap_get_start_block(struct heap* heap, uint32_t total_blocks) 73 | { 74 | struct heap_table* table = heap->table; 75 | int bc = 0; 76 | int bs = -1; 77 | 78 | for (size_t i = 0; i < table->total; i++) 79 | { 80 | if (heap_get_entry_type(table->entries[i]) != HEAP_BLOCK_TABLE_ENTRY_FREE) 81 | { 82 | bc = 0; 83 | bs = -1; 84 | continue; 85 | } 86 | 87 | // If this is the first block 88 | if (bs == -1) 89 | { 90 | bs = i; 91 | } 92 | bc++; 93 | if (bc == total_blocks) 94 | { 95 | break; 96 | } 97 | } 98 | 99 | if (bs == -1) 100 | { 101 | return -ENOMEM; 102 | } 103 | 104 | return bs; 105 | 106 | } 107 | 108 | void* heap_block_to_address(struct heap* heap, int block) 109 | { 110 | return heap->saddr + (block * PEACHOS_HEAP_BLOCK_SIZE); 111 | } 112 | 113 | void heap_mark_blocks_taken(struct heap* heap, int start_block, int total_blocks) 114 | { 115 | int end_block = (start_block + total_blocks)-1; 116 | 117 | HEAP_BLOCK_TABLE_ENTRY entry = HEAP_BLOCK_TABLE_ENTRY_TAKEN | HEAP_BLOCK_IS_FIRST; 118 | if (total_blocks > 1) 119 | { 120 | entry |= HEAP_BLOCK_HAS_NEXT; 121 | } 122 | 123 | for (int i = start_block; i <= end_block; i++) 124 | { 125 | heap->table->entries[i] = entry; 126 | entry = HEAP_BLOCK_TABLE_ENTRY_TAKEN; 127 | if (i != end_block -1) 128 | { 129 | entry |= HEAP_BLOCK_HAS_NEXT; 130 | } 131 | } 132 | } 133 | 134 | void* heap_malloc_blocks(struct heap* heap, uint32_t total_blocks) 135 | { 136 | void* address = 0; 137 | 138 | int start_block = heap_get_start_block(heap, total_blocks); 139 | if (start_block < 0) 140 | { 141 | goto out; 142 | } 143 | 144 | address = heap_block_to_address(heap, start_block); 145 | 146 | // Mark the blocks as taken 147 | heap_mark_blocks_taken(heap, start_block, total_blocks); 148 | 149 | out: 150 | return address; 151 | } 152 | 153 | void heap_mark_blocks_free(struct heap* heap, int starting_block) 154 | { 155 | struct heap_table* table = heap->table; 156 | for (int i = starting_block; i < (int)table->total; i++) 157 | { 158 | HEAP_BLOCK_TABLE_ENTRY entry = table->entries[i]; 159 | table->entries[i] = HEAP_BLOCK_TABLE_ENTRY_FREE; 160 | if (!(entry & HEAP_BLOCK_HAS_NEXT)) 161 | { 162 | break; 163 | } 164 | } 165 | } 166 | 167 | int heap_address_to_block(struct heap* heap, void* address) 168 | { 169 | return ((int)(address - heap->saddr)) / PEACHOS_HEAP_BLOCK_SIZE; 170 | } 171 | 172 | void* heap_malloc(struct heap* heap, size_t size) 173 | { 174 | size_t aligned_size = heap_align_value_to_upper(size); 175 | uint32_t total_blocks = aligned_size / PEACHOS_HEAP_BLOCK_SIZE; 176 | return heap_malloc_blocks(heap, total_blocks); 177 | } 178 | 179 | void heap_free(struct heap* heap, void* ptr) 180 | { 181 | heap_mark_blocks_free(heap, heap_address_to_block(heap, ptr)); 182 | } -------------------------------------------------------------------------------- /src/memory/heap/heap.h: -------------------------------------------------------------------------------- 1 | #ifndef HEAP_H 2 | #define HEAP_H 3 | #include "config.h" 4 | #include 5 | #include 6 | 7 | #define HEAP_BLOCK_TABLE_ENTRY_TAKEN 0x01 8 | #define HEAP_BLOCK_TABLE_ENTRY_FREE 0x00 9 | 10 | #define HEAP_BLOCK_HAS_NEXT 0b10000000 11 | #define HEAP_BLOCK_IS_FIRST 0b01000000 12 | 13 | 14 | typedef unsigned char HEAP_BLOCK_TABLE_ENTRY; 15 | 16 | struct heap_table 17 | { 18 | HEAP_BLOCK_TABLE_ENTRY* entries; 19 | size_t total; 20 | }; 21 | 22 | 23 | struct heap 24 | { 25 | struct heap_table* table; 26 | 27 | // Start address of the heap data pool 28 | void* saddr; 29 | }; 30 | 31 | int heap_create(struct heap* heap, void* ptr, void* end, struct heap_table* table); 32 | void* heap_malloc(struct heap* heap, size_t size); 33 | void heap_free(struct heap* heap, void* ptr); 34 | #endif -------------------------------------------------------------------------------- /src/memory/heap/kheap.c: -------------------------------------------------------------------------------- 1 | #include "kheap.h" 2 | #include "heap.h" 3 | #include "config.h" 4 | #include "kernel.h" 5 | #include "memory/memory.h" 6 | 7 | struct heap kernel_heap; 8 | struct heap_table kernel_heap_table; 9 | 10 | void kheap_init() 11 | { 12 | int total_table_entries = PEACHOS_HEAP_SIZE_BYTES / PEACHOS_HEAP_BLOCK_SIZE; 13 | kernel_heap_table.entries = (HEAP_BLOCK_TABLE_ENTRY*)(PEACHOS_HEAP_TABLE_ADDRESS); 14 | kernel_heap_table.total = total_table_entries; 15 | 16 | void* end = (void*)(PEACHOS_HEAP_ADDRESS + PEACHOS_HEAP_SIZE_BYTES); 17 | int res = heap_create(&kernel_heap, (void*)(PEACHOS_HEAP_ADDRESS), end, &kernel_heap_table); 18 | if (res < 0) 19 | { 20 | print("Failed to create heap\n"); 21 | } 22 | 23 | } 24 | 25 | void* kmalloc(size_t size) 26 | { 27 | return heap_malloc(&kernel_heap, size); 28 | } 29 | 30 | void* kzalloc(size_t size) 31 | { 32 | void* ptr = kmalloc(size); 33 | if (!ptr) 34 | return 0; 35 | 36 | memset(ptr, 0x00, size); 37 | return ptr; 38 | } 39 | 40 | void kfree(void* ptr) 41 | { 42 | heap_free(&kernel_heap, ptr); 43 | } -------------------------------------------------------------------------------- /src/memory/heap/kheap.h: -------------------------------------------------------------------------------- 1 | #ifndef KHEAP_H 2 | #define KHEAP_H 3 | 4 | #include 5 | #include 6 | 7 | void kheap_init(); 8 | void* kmalloc(size_t size); 9 | void* kzalloc(size_t size); 10 | void kfree(void* ptr); 11 | 12 | #endif -------------------------------------------------------------------------------- /src/memory/memory.c: -------------------------------------------------------------------------------- 1 | #include "memory.h" 2 | 3 | void* memset(void* ptr, int c, size_t size) 4 | { 5 | char* c_ptr = (char*) ptr; 6 | for (int i = 0; i < size; i++) 7 | { 8 | c_ptr[i] = (char) c; 9 | } 10 | return ptr; 11 | } 12 | 13 | int memcmp(void* s1, void* s2, int count) 14 | { 15 | char* c1 = s1; 16 | char* c2 = s2; 17 | while(count-- > 0) 18 | { 19 | if (*c1++ != *c2++) 20 | { 21 | return c1[-1] < c2[-1] ? -1 : 1; 22 | } 23 | } 24 | 25 | return 0; 26 | } 27 | 28 | void* memcpy(void* dest, void* src, int len) 29 | { 30 | char *d = dest; 31 | char *s = src; 32 | while(len--) 33 | { 34 | *d++ = *s++; 35 | } 36 | return dest; 37 | } -------------------------------------------------------------------------------- /src/memory/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_H 2 | #define MEMORY_H 3 | 4 | #include 5 | 6 | void* memset(void* ptr, int c, size_t size); 7 | int memcmp(void* s1, void* s2, int count); 8 | void* memcpy(void* dest, void* src, int len); 9 | 10 | #endif -------------------------------------------------------------------------------- /src/memory/paging/paging.asm: -------------------------------------------------------------------------------- 1 | [BITS 32] 2 | 3 | section .asm 4 | 5 | global paging_load_directory 6 | global enable_paging 7 | 8 | paging_load_directory: 9 | push ebp 10 | mov ebp, esp 11 | mov eax, [ebp+8] 12 | mov cr3, eax 13 | pop ebp 14 | ret 15 | 16 | enable_paging: 17 | push ebp 18 | mov ebp, esp 19 | mov eax, cr0 20 | or eax, 0x80000000 21 | mov cr0, eax 22 | pop ebp 23 | ret 24 | -------------------------------------------------------------------------------- /src/memory/paging/paging.c: -------------------------------------------------------------------------------- 1 | #include "paging.h" 2 | #include "memory/heap/kheap.h" 3 | #include "status.h" 4 | void paging_load_directory(uint32_t *directory); 5 | 6 | static uint32_t *current_directory = 0; 7 | struct paging_4gb_chunk *paging_new_4gb(uint8_t flags) 8 | { 9 | uint32_t *directory = kzalloc(sizeof(uint32_t) * PAGING_TOTAL_ENTRIES_PER_TABLE); 10 | int offset = 0; 11 | for (int i = 0; i < PAGING_TOTAL_ENTRIES_PER_TABLE; i++) 12 | { 13 | uint32_t *entry = kzalloc(sizeof(uint32_t) * PAGING_TOTAL_ENTRIES_PER_TABLE); 14 | for (int b = 0; b < PAGING_TOTAL_ENTRIES_PER_TABLE; b++) 15 | { 16 | entry[b] = (offset + (b * PAGING_PAGE_SIZE)) | flags; 17 | } 18 | offset += (PAGING_TOTAL_ENTRIES_PER_TABLE * PAGING_PAGE_SIZE); 19 | directory[i] = (uint32_t)entry | flags | PAGING_IS_WRITEABLE; 20 | } 21 | 22 | struct paging_4gb_chunk *chunk_4gb = kzalloc(sizeof(struct paging_4gb_chunk)); 23 | chunk_4gb->directory_entry = directory; 24 | return chunk_4gb; 25 | } 26 | 27 | void paging_switch(struct paging_4gb_chunk *directory) 28 | { 29 | paging_load_directory(directory->directory_entry); 30 | current_directory = directory->directory_entry; 31 | } 32 | 33 | void paging_free_4gb(struct paging_4gb_chunk *chunk) 34 | { 35 | for (int i = 0; i < 1024; i++) 36 | { 37 | uint32_t entry = chunk->directory_entry[i]; 38 | uint32_t *table = (uint32_t *)(entry & 0xfffff000); 39 | kfree(table); 40 | } 41 | 42 | kfree(chunk->directory_entry); 43 | kfree(chunk); 44 | } 45 | 46 | uint32_t *paging_4gb_chunk_get_directory(struct paging_4gb_chunk *chunk) 47 | { 48 | return chunk->directory_entry; 49 | } 50 | 51 | bool paging_is_aligned(void *addr) 52 | { 53 | return ((uint32_t)addr % PAGING_PAGE_SIZE) == 0; 54 | } 55 | 56 | int paging_get_indexes(void *virtual_address, uint32_t *directory_index_out, uint32_t *table_index_out) 57 | { 58 | int res = 0; 59 | if (!paging_is_aligned(virtual_address)) 60 | { 61 | res = -EINVARG; 62 | goto out; 63 | } 64 | 65 | *directory_index_out = ((uint32_t)virtual_address / (PAGING_TOTAL_ENTRIES_PER_TABLE * PAGING_PAGE_SIZE)); 66 | *table_index_out = ((uint32_t)virtual_address % (PAGING_TOTAL_ENTRIES_PER_TABLE * PAGING_PAGE_SIZE) / PAGING_PAGE_SIZE); 67 | out: 68 | return res; 69 | } 70 | 71 | void* paging_align_address(void* ptr) 72 | { 73 | if ((uint32_t)ptr % PAGING_PAGE_SIZE) 74 | { 75 | return (void*)((uint32_t)ptr + PAGING_PAGE_SIZE - ((uint32_t)ptr % PAGING_PAGE_SIZE)); 76 | } 77 | 78 | return ptr; 79 | } 80 | 81 | void* paging_align_to_lower_page(void* addr) 82 | { 83 | uint32_t _addr = (uint32_t) addr; 84 | _addr -= (_addr % PAGING_PAGE_SIZE); 85 | return (void*) _addr; 86 | } 87 | 88 | int paging_map(struct paging_4gb_chunk* directory, void* virt, void* phys, int flags) 89 | { 90 | if (((unsigned int)virt % PAGING_PAGE_SIZE) || ((unsigned int) phys % PAGING_PAGE_SIZE)) 91 | { 92 | return -EINVARG; 93 | } 94 | 95 | return paging_set(directory->directory_entry, virt, (uint32_t) phys | flags); 96 | } 97 | 98 | int paging_map_range(struct paging_4gb_chunk* directory, void* virt, void* phys, int count, int flags) 99 | { 100 | int res = 0; 101 | for (int i = 0; i < count; i++) 102 | { 103 | res = paging_map(directory, virt, phys, flags); 104 | if (res < 0) 105 | break; 106 | virt += PAGING_PAGE_SIZE; 107 | phys += PAGING_PAGE_SIZE; 108 | } 109 | 110 | return res; 111 | } 112 | 113 | int paging_map_to(struct paging_4gb_chunk *directory, void *virt, void *phys, void *phys_end, int flags) 114 | { 115 | int res = 0; 116 | if ((uint32_t)virt % PAGING_PAGE_SIZE) 117 | { 118 | res = -EINVARG; 119 | goto out; 120 | } 121 | if ((uint32_t)phys % PAGING_PAGE_SIZE) 122 | { 123 | res = -EINVARG; 124 | goto out; 125 | } 126 | if ((uint32_t)phys_end % PAGING_PAGE_SIZE) 127 | { 128 | res = -EINVARG; 129 | goto out; 130 | } 131 | 132 | if ((uint32_t)phys_end < (uint32_t)phys) 133 | { 134 | res = -EINVARG; 135 | goto out; 136 | } 137 | 138 | uint32_t total_bytes = phys_end - phys; 139 | int total_pages = total_bytes / PAGING_PAGE_SIZE; 140 | res = paging_map_range(directory, virt, phys, total_pages, flags); 141 | out: 142 | return res; 143 | } 144 | int paging_set(uint32_t *directory, void *virt, uint32_t val) 145 | { 146 | if (!paging_is_aligned(virt)) 147 | { 148 | return -EINVARG; 149 | } 150 | 151 | uint32_t directory_index = 0; 152 | uint32_t table_index = 0; 153 | int res = paging_get_indexes(virt, &directory_index, &table_index); 154 | if (res < 0) 155 | { 156 | return res; 157 | } 158 | 159 | uint32_t entry = directory[directory_index]; 160 | uint32_t *table = (uint32_t *)(entry & 0xfffff000); 161 | table[table_index] = val; 162 | 163 | return 0; 164 | } 165 | 166 | void* paging_get_physical_address(uint32_t* directory, void* virt) 167 | { 168 | void* virt_addr_new = (void*) paging_align_to_lower_page(virt); 169 | void* difference = (void*)((uint32_t) virt - (uint32_t) virt_addr_new); 170 | return (void*)((paging_get(directory, virt_addr_new) & 0xfffff000) + difference); 171 | } 172 | 173 | uint32_t paging_get(uint32_t* directory, void* virt) 174 | { 175 | uint32_t directory_index = 0; 176 | uint32_t table_index = 0; 177 | paging_get_indexes(virt, &directory_index, &table_index); 178 | 179 | uint32_t entry = directory[directory_index]; 180 | uint32_t* table = (uint32_t*)(entry & 0xfffff000); 181 | return table[table_index]; 182 | } -------------------------------------------------------------------------------- /src/memory/paging/paging.h: -------------------------------------------------------------------------------- 1 | #ifndef PAGING_H 2 | #define PAGING_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define PAGING_CACHE_DISABLED 0b00010000 9 | #define PAGING_WRITE_THROUGH 0b00001000 10 | #define PAGING_ACCESS_FROM_ALL 0b00000100 11 | #define PAGING_IS_WRITEABLE 0b00000010 12 | #define PAGING_IS_PRESENT 0b00000001 13 | 14 | 15 | #define PAGING_TOTAL_ENTRIES_PER_TABLE 1024 16 | #define PAGING_PAGE_SIZE 4096 17 | 18 | 19 | struct paging_4gb_chunk 20 | { 21 | uint32_t* directory_entry; 22 | }; 23 | 24 | struct paging_4gb_chunk* paging_new_4gb(uint8_t flags); 25 | void paging_switch(struct paging_4gb_chunk* directory); 26 | void enable_paging(); 27 | 28 | int paging_set(uint32_t* directory, void* virt, uint32_t val); 29 | bool paging_is_aligned(void* addr); 30 | 31 | uint32_t* paging_4gb_chunk_get_directory(struct paging_4gb_chunk* chunk); 32 | void paging_free_4gb(struct paging_4gb_chunk* chunk); 33 | 34 | int paging_map_to(struct paging_4gb_chunk *directory, void *virt, void *phys, void *phys_end, int flags); 35 | int paging_map_range(struct paging_4gb_chunk* directory, void* virt, void* phys, int count, int flags); 36 | int paging_map(struct paging_4gb_chunk* directory, void* virt, void* phys, int flags); 37 | void* paging_align_address(void* ptr); 38 | uint32_t paging_get(uint32_t* directory, void* virt); 39 | void* paging_align_to_lower_page(void* addr); 40 | void* paging_get_physical_address(uint32_t* directory, void* virt); 41 | 42 | #endif -------------------------------------------------------------------------------- /src/status.h: -------------------------------------------------------------------------------- 1 | #ifndef STATUS_H 2 | #define STATUS_H 3 | 4 | #define PEACHOS_ALL_OK 0 5 | #define EIO 1 6 | #define EINVARG 2 7 | #define ENOMEM 3 8 | #define EBADPATH 4 9 | #define EFSNOTUS 5 10 | #define ERDONLY 6 11 | #define EUNIMP 7 12 | #define EISTKN 8 13 | #define EINFORMAT 9 14 | 15 | #endif -------------------------------------------------------------------------------- /src/string/string.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char tolower(char s1) 4 | { 5 | if (s1 >= 65 && s1 <= 90) 6 | { 7 | s1 += 32; 8 | } 9 | 10 | return s1; 11 | } 12 | 13 | int strlen(const char* ptr) 14 | { 15 | int i = 0; 16 | while(*ptr != 0) 17 | { 18 | i++; 19 | ptr += 1; 20 | } 21 | 22 | return i; 23 | } 24 | 25 | int strnlen(const char* ptr, int max) 26 | { 27 | int i = 0; 28 | for (i = 0; i < max; i++) 29 | { 30 | if (ptr[i] == 0) 31 | break; 32 | } 33 | 34 | return i; 35 | } 36 | 37 | int strnlen_terminator(const char* str, int max, char terminator) 38 | { 39 | int i = 0; 40 | for(i = 0; i < max; i++) 41 | { 42 | if (str[i] == '\0' || str[i] == terminator) 43 | break; 44 | } 45 | 46 | return i; 47 | } 48 | 49 | int istrncmp(const char* s1, const char* s2, int n) 50 | { 51 | unsigned char u1, u2; 52 | while(n-- > 0) 53 | { 54 | u1 = (unsigned char)*s1++; 55 | u2 = (unsigned char)*s2++; 56 | if (u1 != u2 && tolower(u1) != tolower(u2)) 57 | return u1 - u2; 58 | if (u1 == '\0') 59 | return 0; 60 | } 61 | 62 | return 0; 63 | } 64 | int strncmp(const char* str1, const char* str2, int n) 65 | { 66 | unsigned char u1, u2; 67 | 68 | while(n-- > 0) 69 | { 70 | u1 = (unsigned char)*str1++; 71 | u2 = (unsigned char)*str2++; 72 | if (u1 != u2) 73 | return u1 - u2; 74 | if (u1 == '\0') 75 | return 0; 76 | } 77 | 78 | return 0; 79 | } 80 | 81 | char* strcpy(char* dest, const char* src) 82 | { 83 | char* res = dest; 84 | while(*src != 0) 85 | { 86 | *dest = *src; 87 | src += 1; 88 | dest += 1; 89 | } 90 | 91 | *dest = 0x00; 92 | 93 | return res; 94 | } 95 | 96 | char* strncpy(char* dest, const char* src, int count) 97 | { 98 | int i = 0; 99 | for (i = 0; i < count-1; i++) 100 | { 101 | if (src[i] == 0x00) 102 | break; 103 | 104 | dest[i] = src[i]; 105 | } 106 | 107 | dest[i] = 0x00; 108 | return dest; 109 | } 110 | 111 | bool isdigit(char c) 112 | { 113 | return c >= 48 && c <= 57; 114 | } 115 | int tonumericdigit(char c) 116 | { 117 | return c - 48; 118 | } -------------------------------------------------------------------------------- /src/string/string.h: -------------------------------------------------------------------------------- 1 | #ifndef STRING_H 2 | #define STRING_H 3 | #include 4 | int strlen(const char* ptr); 5 | int strnlen(const char* ptr, int max); 6 | bool isdigit(char c); 7 | int tonumericdigit(char c); 8 | char* strcpy(char* dest, const char* src); 9 | char* strncpy(char* dest, const char* src, int count); 10 | int strncmp(const char* str1, const char* str2, int n); 11 | int istrncmp(const char* s1, const char* s2, int n); 12 | int strnlen_terminator(const char* str, int max, char terminator); 13 | char tolower(char s1); 14 | #endif -------------------------------------------------------------------------------- /src/task/process.c: -------------------------------------------------------------------------------- 1 | #include "process.h" 2 | #include "config.h" 3 | #include "status.h" 4 | #include "task/task.h" 5 | #include "memory/memory.h" 6 | #include "string/string.h" 7 | #include "fs/file.h" 8 | #include "memory/heap/kheap.h" 9 | #include "memory/paging/paging.h" 10 | #include "loader/formats/elfloader.h" 11 | #include "kernel.h" 12 | 13 | // The current process that is running 14 | struct process* current_process = 0; 15 | 16 | static struct process* processes[PEACHOS_MAX_PROCESSES] = {}; 17 | 18 | int process_free_process(struct process* process); 19 | 20 | 21 | static void process_init(struct process* process) 22 | { 23 | memset(process, 0, sizeof(struct process)); 24 | } 25 | 26 | struct process* process_current() 27 | { 28 | return current_process; 29 | } 30 | 31 | struct process* process_get(int process_id) 32 | { 33 | if (process_id < 0 || process_id >= PEACHOS_MAX_PROCESSES) 34 | { 35 | return NULL; 36 | } 37 | 38 | return processes[process_id]; 39 | } 40 | 41 | int process_switch(struct process* process) 42 | { 43 | current_process = process; 44 | return 0; 45 | } 46 | 47 | static int process_find_free_allocation_index(struct process* process) 48 | { 49 | int res = -ENOMEM; 50 | for (int i = 0; i < PEACHOS_MAX_PROGRAM_ALLOCATIONS; i++) 51 | { 52 | if (process->allocations[i].ptr == 0) 53 | { 54 | res = i; 55 | break; 56 | } 57 | } 58 | 59 | return res; 60 | } 61 | 62 | void* process_malloc(struct process* process, size_t size) 63 | { 64 | void* ptr = kzalloc(size); 65 | if (!ptr) 66 | { 67 | goto out_err; 68 | } 69 | 70 | int index = process_find_free_allocation_index(process); 71 | if (index < 0) 72 | { 73 | goto out_err; 74 | } 75 | 76 | int res = paging_map_to(process->task->page_directory, ptr, ptr, paging_align_address(ptr+size), PAGING_IS_WRITEABLE | PAGING_IS_PRESENT | PAGING_ACCESS_FROM_ALL); 77 | if (res < 0) 78 | { 79 | goto out_err; 80 | } 81 | 82 | process->allocations[index].ptr = ptr; 83 | process->allocations[index].size = size; 84 | return ptr; 85 | 86 | out_err: 87 | if(ptr) 88 | { 89 | kfree(ptr); 90 | } 91 | return 0; 92 | } 93 | 94 | static bool process_is_process_pointer(struct process* process, void* ptr) 95 | { 96 | for (int i = 0; i < PEACHOS_MAX_PROGRAM_ALLOCATIONS; i++) 97 | { 98 | if (process->allocations[i].ptr == ptr) 99 | return true; 100 | } 101 | 102 | return false; 103 | } 104 | 105 | static void process_allocation_unjoin(struct process* process, void* ptr) 106 | { 107 | for (int i = 0; i < PEACHOS_MAX_PROGRAM_ALLOCATIONS; i++) 108 | { 109 | if (process->allocations[i].ptr == ptr) 110 | { 111 | process->allocations[i].ptr = 0x00; 112 | process->allocations[i].size = 0; 113 | } 114 | } 115 | } 116 | 117 | static struct process_allocation* process_get_allocation_by_addr(struct process* process, void* addr) 118 | { 119 | for (int i = 0; i < PEACHOS_MAX_PROGRAM_ALLOCATIONS; i++) 120 | { 121 | if (process->allocations[i].ptr == addr) 122 | return &process->allocations[i]; 123 | } 124 | 125 | return 0; 126 | } 127 | 128 | 129 | int process_terminate_allocations(struct process* process) 130 | { 131 | for (int i = 0; i < PEACHOS_MAX_PROGRAM_ALLOCATIONS; i++) 132 | { 133 | if (process->allocations[i].ptr) 134 | { 135 | process_free(process, process->allocations[i].ptr); 136 | } 137 | } 138 | 139 | return 0; 140 | } 141 | 142 | int process_free_binary_data(struct process* process) 143 | { 144 | if (process->ptr) 145 | { 146 | kfree(process->ptr); 147 | } 148 | return 0; 149 | } 150 | 151 | int process_free_elf_data(struct process* process) 152 | { 153 | if (process->elf_file) 154 | { 155 | elf_close(process->elf_file); 156 | } 157 | 158 | return 0; 159 | } 160 | int process_free_program_data(struct process* process) 161 | { 162 | int res = 0; 163 | switch(process->filetype) 164 | { 165 | case PROCESS_FILETYPE_BINARY: 166 | res = process_free_binary_data(process); 167 | break; 168 | 169 | case PROCESS_FILETYPE_ELF: 170 | res = process_free_elf_data(process); 171 | break; 172 | 173 | default: 174 | res = -EINVARG; 175 | } 176 | return res; 177 | } 178 | 179 | void process_switch_to_any() 180 | { 181 | for (int i = 0; i < PEACHOS_MAX_PROCESSES; i++) 182 | { 183 | if (processes[i]) 184 | { 185 | process_switch(processes[i]); 186 | return; 187 | } 188 | } 189 | 190 | 191 | panic("No processes to switch too\n"); 192 | } 193 | 194 | static void process_unlink(struct process* process) 195 | { 196 | processes[process->id] = 0x00; 197 | 198 | if (current_process == process) 199 | { 200 | process_switch_to_any(); 201 | } 202 | } 203 | 204 | int process_free_process(struct process* process) 205 | { 206 | int res = 0; 207 | process_terminate_allocations(process); 208 | process_free_program_data(process); 209 | 210 | // Free the process stack memory. 211 | if (process->stack) 212 | { 213 | kfree(process->stack); 214 | process->stack = NULL; 215 | } 216 | // Free the task 217 | if (process->task) 218 | { 219 | task_free(process->task); 220 | process->task = NULL; 221 | } 222 | 223 | kfree(process); 224 | 225 | out: 226 | return res; 227 | } 228 | 229 | int process_terminate(struct process* process) 230 | { 231 | // Unlink the process from the process array. 232 | process_unlink(process); 233 | 234 | int res = process_free_process(process); 235 | if (res < 0) 236 | { 237 | goto out; 238 | } 239 | 240 | 241 | out: 242 | return res; 243 | } 244 | 245 | void process_get_arguments(struct process* process, int* argc, char*** argv) 246 | { 247 | *argc = process->arguments.argc; 248 | *argv = process->arguments.argv; 249 | } 250 | 251 | int process_count_command_arguments(struct command_argument* root_argument) 252 | { 253 | struct command_argument* current = root_argument; 254 | int i = 0; 255 | while(current) 256 | { 257 | i++; 258 | current = current->next; 259 | } 260 | 261 | return i; 262 | } 263 | 264 | 265 | int process_inject_arguments(struct process* process, struct command_argument* root_argument) 266 | { 267 | int res = 0; 268 | struct command_argument* current = root_argument; 269 | int i = 0; 270 | int argc = process_count_command_arguments(root_argument); 271 | if (argc == 0) 272 | { 273 | res = -EIO; 274 | goto out; 275 | } 276 | 277 | char **argv = process_malloc(process, sizeof(const char*) * argc); 278 | if (!argv) 279 | { 280 | res = -ENOMEM; 281 | goto out; 282 | } 283 | 284 | 285 | while(current) 286 | { 287 | char* argument_str = process_malloc(process, sizeof(current->argument)); 288 | if (!argument_str) 289 | { 290 | res = -ENOMEM; 291 | goto out; 292 | } 293 | 294 | strncpy(argument_str, current->argument, sizeof(current->argument)); 295 | argv[i] = argument_str; 296 | current = current->next; 297 | i++; 298 | } 299 | 300 | process->arguments.argc = argc; 301 | process->arguments.argv = argv; 302 | out: 303 | return res; 304 | } 305 | void process_free(struct process* process, void* ptr) 306 | { 307 | // Unlink the pages from the process for the given address 308 | struct process_allocation* allocation = process_get_allocation_by_addr(process, ptr); 309 | if (!allocation) 310 | { 311 | // Oops its not our pointer. 312 | return; 313 | } 314 | 315 | int res = paging_map_to(process->task->page_directory, allocation->ptr, allocation->ptr, paging_align_address(allocation->ptr+allocation->size), 0x00); 316 | if (res < 0) 317 | { 318 | return; 319 | } 320 | 321 | // Unjoin the allocation 322 | process_allocation_unjoin(process, ptr); 323 | 324 | // We can now free the memory. 325 | kfree(ptr); 326 | } 327 | 328 | static int process_load_binary(const char* filename, struct process* process) 329 | { 330 | void* program_data_ptr = 0x00; 331 | int res = 0; 332 | int fd = fopen(filename, "r"); 333 | if (!fd) 334 | { 335 | res = -EIO; 336 | goto out; 337 | } 338 | 339 | struct file_stat stat; 340 | res = fstat(fd, &stat); 341 | if (res != PEACHOS_ALL_OK) 342 | { 343 | goto out; 344 | } 345 | 346 | program_data_ptr = kzalloc(stat.filesize); 347 | if (!program_data_ptr) 348 | { 349 | res = -ENOMEM; 350 | goto out; 351 | } 352 | 353 | if (fread(program_data_ptr, stat.filesize, 1, fd) != 1) 354 | { 355 | res = -EIO; 356 | goto out; 357 | } 358 | 359 | process->filetype = PROCESS_FILETYPE_BINARY; 360 | process->ptr = program_data_ptr; 361 | process->size = stat.filesize; 362 | 363 | out: 364 | if (res < 0) 365 | { 366 | if (program_data_ptr) 367 | { 368 | kfree(program_data_ptr); 369 | } 370 | } 371 | fclose(fd); 372 | return res; 373 | } 374 | 375 | static int process_load_elf(const char* filename, struct process* process) 376 | { 377 | int res = 0; 378 | struct elf_file* elf_file = 0; 379 | res = elf_load(filename, &elf_file); 380 | if (ISERR(res)) 381 | { 382 | goto out; 383 | } 384 | 385 | process->filetype = PROCESS_FILETYPE_ELF; 386 | process->elf_file = elf_file; 387 | out: 388 | return res; 389 | } 390 | static int process_load_data(const char* filename, struct process* process) 391 | { 392 | int res = 0; 393 | res = process_load_elf(filename, process); 394 | if (res == -EINFORMAT) 395 | { 396 | res = process_load_binary(filename, process); 397 | } 398 | 399 | return res; 400 | } 401 | 402 | int process_map_binary(struct process* process) 403 | { 404 | int res = 0; 405 | paging_map_to(process->task->page_directory, (void*) PEACHOS_PROGRAM_VIRTUAL_ADDRESS, process->ptr, paging_align_address(process->ptr + process->size), PAGING_IS_PRESENT | PAGING_ACCESS_FROM_ALL | PAGING_IS_WRITEABLE); 406 | return res; 407 | } 408 | 409 | static int process_map_elf(struct process* process) 410 | { 411 | int res = 0; 412 | 413 | struct elf_file* elf_file = process->elf_file; 414 | struct elf_header* header = elf_header(elf_file); 415 | struct elf32_phdr* phdrs = elf_pheader(header); 416 | for (int i = 0; i < header->e_phnum; i++) 417 | { 418 | struct elf32_phdr* phdr = &phdrs[i]; 419 | void* phdr_phys_address = elf_phdr_phys_address(elf_file, phdr); 420 | int flags = PAGING_IS_PRESENT | PAGING_ACCESS_FROM_ALL; 421 | if (phdr->p_flags & PF_W) 422 | { 423 | flags |= PAGING_IS_WRITEABLE; 424 | } 425 | res = paging_map_to(process->task->page_directory, paging_align_to_lower_page((void*)phdr->p_vaddr), paging_align_to_lower_page(phdr_phys_address), paging_align_address(phdr_phys_address+phdr->p_memsz), flags); 426 | if (ISERR(res)) 427 | { 428 | break; 429 | } 430 | } 431 | return res; 432 | } 433 | int process_map_memory(struct process* process) 434 | { 435 | int res = 0; 436 | 437 | switch(process->filetype) 438 | { 439 | case PROCESS_FILETYPE_ELF: 440 | res = process_map_elf(process); 441 | break; 442 | 443 | case PROCESS_FILETYPE_BINARY: 444 | res = process_map_binary(process); 445 | break; 446 | 447 | default: 448 | panic("process_map_memory: Invalid filetype\n"); 449 | } 450 | 451 | if (res < 0) 452 | { 453 | goto out; 454 | } 455 | 456 | // Finally map the stack 457 | paging_map_to(process->task->page_directory, (void*)PEACHOS_PROGRAM_VIRTUAL_STACK_ADDRESS_END, process->stack, paging_align_address(process->stack+PEACHOS_USER_PROGRAM_STACK_SIZE), PAGING_IS_PRESENT | PAGING_ACCESS_FROM_ALL | PAGING_IS_WRITEABLE); 458 | out: 459 | return res; 460 | } 461 | 462 | int process_get_free_slot() 463 | { 464 | for (int i = 0; i < PEACHOS_MAX_PROCESSES; i++) 465 | { 466 | if (processes[i] == 0) 467 | return i; 468 | } 469 | 470 | return -EISTKN; 471 | } 472 | 473 | int process_load(const char* filename, struct process** process) 474 | { 475 | int res = 0; 476 | int process_slot = process_get_free_slot(); 477 | if (process_slot < 0) 478 | { 479 | res = -EISTKN; 480 | goto out; 481 | } 482 | 483 | res = process_load_for_slot(filename, process, process_slot); 484 | out: 485 | return res; 486 | } 487 | 488 | int process_load_switch(const char* filename, struct process** process) 489 | { 490 | int res = process_load(filename, process); 491 | if (res == 0) 492 | { 493 | process_switch(*process); 494 | } 495 | 496 | return res; 497 | } 498 | 499 | int process_load_for_slot(const char* filename, struct process** process, int process_slot) 500 | { 501 | int res = 0; 502 | struct process* _process; 503 | 504 | if (process_get(process_slot) != 0) 505 | { 506 | res = -EISTKN; 507 | goto out; 508 | } 509 | 510 | _process = kzalloc(sizeof(struct process)); 511 | if (!_process) 512 | { 513 | res = -ENOMEM; 514 | goto out; 515 | } 516 | 517 | process_init(_process); 518 | res = process_load_data(filename, _process); 519 | if (res < 0) 520 | { 521 | goto out; 522 | } 523 | 524 | _process->stack = kzalloc(PEACHOS_USER_PROGRAM_STACK_SIZE); 525 | if (!_process->stack) 526 | { 527 | res = -ENOMEM; 528 | goto out; 529 | } 530 | 531 | strncpy(_process->filename, filename, sizeof(_process->filename)); 532 | _process->id = process_slot; 533 | 534 | // Create a task 535 | _process->task = task_new(_process); 536 | if (ERROR_I(_process->task) == 0) 537 | { 538 | res = ERROR_I(_process->task); 539 | 540 | // Task is NULL due to error code being returned in task_new. 541 | _process->task = NULL; 542 | goto out; 543 | } 544 | 545 | 546 | res = process_map_memory(_process); 547 | if (res < 0) 548 | { 549 | goto out; 550 | } 551 | 552 | *process = _process; 553 | 554 | // Add the process to the array 555 | processes[process_slot] = _process; 556 | 557 | out: 558 | if (ISERR(res)) 559 | { 560 | if (_process) 561 | { 562 | process_free_process(_process); 563 | _process = NULL; 564 | *process = NULL; 565 | } 566 | 567 | // Free the process data 568 | } 569 | return res; 570 | } -------------------------------------------------------------------------------- /src/task/process.h: -------------------------------------------------------------------------------- 1 | #ifndef PROCESS_H 2 | #define PROCESS_H 3 | #include 4 | #include 5 | 6 | #include "task.h" 7 | #include "config.h" 8 | 9 | #define PROCESS_FILETYPE_ELF 0 10 | #define PROCESS_FILETYPE_BINARY 1 11 | 12 | typedef unsigned char PROCESS_FILETYPE; 13 | 14 | struct process_allocation 15 | { 16 | void* ptr; 17 | size_t size; 18 | }; 19 | 20 | struct command_argument 21 | { 22 | char argument[512]; 23 | struct command_argument* next; 24 | }; 25 | 26 | struct process_arguments 27 | { 28 | int argc; 29 | char** argv; 30 | }; 31 | 32 | struct process 33 | { 34 | // The process id 35 | uint16_t id; 36 | 37 | char filename[PEACHOS_MAX_PATH]; 38 | 39 | // The main process task 40 | struct task* task; 41 | 42 | // The memory (malloc) allocations of the process 43 | struct process_allocation allocations[PEACHOS_MAX_PROGRAM_ALLOCATIONS]; 44 | 45 | PROCESS_FILETYPE filetype; 46 | 47 | union 48 | { 49 | // The physical pointer to the process memory. 50 | void* ptr; 51 | struct elf_file* elf_file; 52 | }; 53 | 54 | 55 | // The physical pointer to the stack memory 56 | void* stack; 57 | 58 | // The size of the data pointed to by "ptr" 59 | uint32_t size; 60 | 61 | struct keyboard_buffer 62 | { 63 | char buffer[PEACHOS_KEYBOARD_BUFFER_SIZE]; 64 | int tail; 65 | int head; 66 | } keyboard; 67 | 68 | // The arguments of the process. 69 | struct process_arguments arguments; 70 | }; 71 | 72 | int process_switch(struct process* process); 73 | int process_load_switch(const char* filename, struct process** process); 74 | int process_load(const char* filename, struct process** process); 75 | int process_load_for_slot(const char* filename, struct process** process, int process_slot); 76 | struct process* process_current(); 77 | struct process* process_get(int process_id); 78 | void* process_malloc(struct process* process, size_t size); 79 | void process_free(struct process* process, void* ptr); 80 | 81 | void process_get_arguments(struct process* process, int* argc, char*** argv); 82 | int process_inject_arguments(struct process* process, struct command_argument* root_argument); 83 | int process_terminate(struct process* process); 84 | 85 | #endif -------------------------------------------------------------------------------- /src/task/task.asm: -------------------------------------------------------------------------------- 1 | [BITS 32] 2 | section .asm 3 | 4 | global restore_general_purpose_registers 5 | global task_return 6 | global user_registers 7 | 8 | ; void task_return(struct registers* regs); 9 | task_return: 10 | mov ebp, esp 11 | ; PUSH THE DATA SEGMENT (SS WILL BE FINE) 12 | ; PUSH THE STACK ADDRESS 13 | ; PUSH THE FLAGS 14 | ; PUSH THE CODE SEGMENT 15 | ; PUSH IP 16 | 17 | ; Let's access the structure passed to us 18 | mov ebx, [ebp+4] 19 | ; push the data/stack selector 20 | push dword [ebx+44] 21 | ; Push the stack pointer 22 | push dword [ebx+40] 23 | 24 | ; Push the flags 25 | mov eax, [ebx+36] 26 | or eax, 0x200 ; interrupt enable flag set 27 | push eax 28 | 29 | ; Push the code segment 30 | push dword [ebx+32] 31 | 32 | ; Push the IP to execute 33 | push dword [ebx+28] 34 | 35 | ; Setup some segment registers 36 | mov ax, [ebx+44] 37 | mov ds, ax 38 | mov es, ax 39 | mov fs, ax 40 | mov gs, ax 41 | 42 | push dword [ebp+4] 43 | call restore_general_purpose_registers 44 | add esp, 4 45 | 46 | ; Let's leave kernel land and execute in user land! 47 | iretd 48 | 49 | ; void restore_general_purpose_registers(struct registers* regs); 50 | restore_general_purpose_registers: 51 | push ebp 52 | mov ebp, esp 53 | mov ebx, [ebp+8] 54 | mov edi, [ebx] 55 | mov esi, [ebx+4] 56 | mov ebp, [ebx+8] 57 | mov edx, [ebx+16] 58 | mov ecx, [ebx+20] 59 | mov eax, [ebx+24] 60 | mov ebx, [ebx+12] 61 | add esp, 4 62 | ret 63 | 64 | ; void user_registers() 65 | user_registers: 66 | mov ax, 0x23 67 | mov ds, ax 68 | mov es, ax 69 | mov fs, ax 70 | mov gs, ax 71 | ret -------------------------------------------------------------------------------- /src/task/task.c: -------------------------------------------------------------------------------- 1 | #include "task.h" 2 | #include "kernel.h" 3 | #include "status.h" 4 | #include "process.h" 5 | #include "memory/heap/kheap.h" 6 | #include "memory/memory.h" 7 | #include "string/string.h" 8 | #include "memory/paging/paging.h" 9 | #include "loader/formats/elfloader.h" 10 | #include "idt/idt.h" 11 | 12 | // The current task that is running 13 | struct task *current_task = 0; 14 | 15 | // Task linked list 16 | struct task *task_tail = 0; 17 | struct task *task_head = 0; 18 | 19 | int task_init(struct task *task, struct process *process); 20 | 21 | struct task *task_current() 22 | { 23 | return current_task; 24 | } 25 | 26 | struct task *task_new(struct process *process) 27 | { 28 | int res = 0; 29 | struct task *task = kzalloc(sizeof(struct task)); 30 | if (!task) 31 | { 32 | res = -ENOMEM; 33 | goto out; 34 | } 35 | 36 | res = task_init(task, process); 37 | if (res != PEACHOS_ALL_OK) 38 | { 39 | goto out; 40 | } 41 | 42 | if (task_head == 0) 43 | { 44 | task_head = task; 45 | task_tail = task; 46 | current_task = task; 47 | goto out; 48 | } 49 | 50 | task_tail->next = task; 51 | task->prev = task_tail; 52 | task_tail = task; 53 | 54 | out: 55 | if (ISERR(res)) 56 | { 57 | task_free(task); 58 | return ERROR(res); 59 | } 60 | 61 | return task; 62 | } 63 | 64 | struct task *task_get_next() 65 | { 66 | if (!current_task->next) 67 | { 68 | return task_head; 69 | } 70 | 71 | return current_task->next; 72 | } 73 | 74 | static void task_list_remove(struct task *task) 75 | { 76 | if (task->prev) 77 | { 78 | task->prev->next = task->next; 79 | } 80 | 81 | if (task == task_head) 82 | { 83 | task_head = task->next; 84 | } 85 | 86 | if (task == task_tail) 87 | { 88 | task_tail = task->prev; 89 | } 90 | 91 | if (task == current_task) 92 | { 93 | current_task = task_get_next(); 94 | } 95 | } 96 | 97 | int task_free(struct task *task) 98 | { 99 | paging_free_4gb(task->page_directory); 100 | task_list_remove(task); 101 | 102 | // Finally free the task data 103 | kfree(task); 104 | return 0; 105 | } 106 | 107 | void task_next() 108 | { 109 | struct task* next_task = task_get_next(); 110 | if (!next_task) 111 | { 112 | panic("No more tasks!\n"); 113 | } 114 | 115 | task_switch(next_task); 116 | task_return(&next_task->registers); 117 | } 118 | 119 | int task_switch(struct task *task) 120 | { 121 | current_task = task; 122 | paging_switch(task->page_directory); 123 | return 0; 124 | } 125 | 126 | void task_save_state(struct task *task, struct interrupt_frame *frame) 127 | { 128 | task->registers.ip = frame->ip; 129 | task->registers.cs = frame->cs; 130 | task->registers.flags = frame->flags; 131 | task->registers.esp = frame->esp; 132 | task->registers.ss = frame->ss; 133 | task->registers.eax = frame->eax; 134 | task->registers.ebp = frame->ebp; 135 | task->registers.ebx = frame->ebx; 136 | task->registers.ecx = frame->ecx; 137 | task->registers.edi = frame->edi; 138 | task->registers.edx = frame->edx; 139 | task->registers.esi = frame->esi; 140 | } 141 | int copy_string_from_task(struct task* task, void* virtual, void* phys, int max) 142 | { 143 | if (max >= PAGING_PAGE_SIZE) 144 | { 145 | return -EINVARG; 146 | } 147 | 148 | int res = 0; 149 | char* tmp = kzalloc(max); 150 | if (!tmp) 151 | { 152 | res = -ENOMEM; 153 | goto out; 154 | } 155 | 156 | uint32_t* task_directory = task->page_directory->directory_entry; 157 | uint32_t old_entry = paging_get(task_directory, tmp); 158 | paging_map(task->page_directory, tmp, tmp, PAGING_IS_WRITEABLE | PAGING_IS_PRESENT | PAGING_ACCESS_FROM_ALL); 159 | paging_switch(task->page_directory); 160 | strncpy(tmp, virtual, max); 161 | kernel_page(); 162 | 163 | res = paging_set(task_directory, tmp, old_entry); 164 | if (res < 0) 165 | { 166 | res = -EIO; 167 | goto out_free; 168 | } 169 | 170 | strncpy(phys, tmp, max); 171 | 172 | out_free: 173 | kfree(tmp); 174 | out: 175 | return res; 176 | } 177 | void task_current_save_state(struct interrupt_frame *frame) 178 | { 179 | if (!task_current()) 180 | { 181 | panic("No current task to save\n"); 182 | } 183 | 184 | struct task *task = task_current(); 185 | task_save_state(task, frame); 186 | } 187 | 188 | int task_page() 189 | { 190 | user_registers(); 191 | task_switch(current_task); 192 | return 0; 193 | } 194 | 195 | int task_page_task(struct task* task) 196 | { 197 | user_registers(); 198 | paging_switch(task->page_directory); 199 | return 0; 200 | } 201 | 202 | void task_run_first_ever_task() 203 | { 204 | if (!current_task) 205 | { 206 | panic("task_run_first_ever_task(): No current task exists!\n"); 207 | } 208 | 209 | task_switch(task_head); 210 | task_return(&task_head->registers); 211 | } 212 | 213 | int task_init(struct task *task, struct process *process) 214 | { 215 | memset(task, 0, sizeof(struct task)); 216 | // Map the entire 4GB address space to its self 217 | task->page_directory = paging_new_4gb(PAGING_IS_PRESENT | PAGING_ACCESS_FROM_ALL); 218 | if (!task->page_directory) 219 | { 220 | return -EIO; 221 | } 222 | 223 | task->registers.ip = PEACHOS_PROGRAM_VIRTUAL_ADDRESS; 224 | if (process->filetype == PROCESS_FILETYPE_ELF) 225 | { 226 | task->registers.ip = elf_header(process->elf_file)->e_entry; 227 | } 228 | 229 | task->registers.ss = USER_DATA_SEGMENT; 230 | task->registers.cs = USER_CODE_SEGMENT; 231 | task->registers.esp = PEACHOS_PROGRAM_VIRTUAL_STACK_ADDRESS_START; 232 | 233 | task->process = process; 234 | 235 | return 0; 236 | } 237 | 238 | void* task_get_stack_item(struct task* task, int index) 239 | { 240 | void* result = 0; 241 | 242 | uint32_t* sp_ptr = (uint32_t*) task->registers.esp; 243 | 244 | // Switch to the given tasks page 245 | task_page_task(task); 246 | 247 | result = (void*) sp_ptr[index]; 248 | 249 | // Switch back to the kernel page 250 | kernel_page(); 251 | 252 | return result; 253 | } 254 | 255 | void* task_virtual_address_to_physical(struct task* task, void* virtual_address) 256 | { 257 | return paging_get_physical_address(task->page_directory->directory_entry, virtual_address); 258 | } -------------------------------------------------------------------------------- /src/task/task.h: -------------------------------------------------------------------------------- 1 | #ifndef TASK_H 2 | #define TASK_H 3 | 4 | #include "config.h" 5 | #include "memory/paging/paging.h" 6 | 7 | struct interrupt_frame; 8 | struct registers 9 | { 10 | uint32_t edi; 11 | uint32_t esi; 12 | uint32_t ebp; 13 | uint32_t ebx; 14 | uint32_t edx; 15 | uint32_t ecx; 16 | uint32_t eax; 17 | 18 | uint32_t ip; 19 | uint32_t cs; 20 | uint32_t flags; 21 | uint32_t esp; 22 | uint32_t ss; 23 | }; 24 | 25 | 26 | struct process; 27 | struct task 28 | { 29 | /** 30 | * The page directory of the task 31 | */ 32 | struct paging_4gb_chunk* page_directory; 33 | 34 | // The registers of the task when the task is not running 35 | struct registers registers; 36 | 37 | // The process of the task 38 | struct process* process; 39 | 40 | // The next task in the linked list 41 | struct task* next; 42 | 43 | // Previous task in the linked list 44 | struct task* prev; 45 | }; 46 | 47 | struct task* task_new(struct process* process); 48 | struct task* task_current(); 49 | struct task* task_get_next(); 50 | int task_free(struct task* task); 51 | 52 | int task_switch(struct task* task); 53 | int task_page(); 54 | int task_page_task(struct task* task); 55 | 56 | void task_run_first_ever_task(); 57 | 58 | void task_return(struct registers* regs); 59 | void restore_general_purpose_registers(struct registers* regs); 60 | void user_registers(); 61 | 62 | void task_current_save_state(struct interrupt_frame *frame); 63 | int copy_string_from_task(struct task* task, void* virtual, void* phys, int max); 64 | void* task_get_stack_item(struct task* task, int index); 65 | void* task_virtual_address_to_physical(struct task* task, void* virtual_address); 66 | void task_next(); 67 | 68 | #endif -------------------------------------------------------------------------------- /src/task/tss.asm: -------------------------------------------------------------------------------- 1 | section .asm 2 | 3 | global tss_load 4 | 5 | tss_load: 6 | push ebp 7 | mov ebp, esp 8 | mov ax, [ebp+8] ; TSS Segment 9 | ltr ax 10 | pop ebp 11 | ret -------------------------------------------------------------------------------- /src/task/tss.h: -------------------------------------------------------------------------------- 1 | #ifndef TASKSWITCHSEGMENT_H 2 | #define TASKSWITCHSEGMENT_H 3 | 4 | #include 5 | struct tss 6 | { 7 | uint32_t link; 8 | uint32_t esp0; // Kernel stack pointer 9 | uint32_t ss0; // Kernel stack segment 10 | uint32_t esp1; 11 | uint32_t ss1; 12 | uint32_t esp2; 13 | uint32_t ss2; 14 | uint32_t sr3; 15 | uint32_t eip; 16 | uint32_t eflags; 17 | uint32_t eax; 18 | uint32_t ecx; 19 | uint32_t edx; 20 | uint32_t ebx; 21 | uint32_t esp; 22 | uint32_t ebp; 23 | uint32_t esi; 24 | uint32_t edi; 25 | uint32_t es; 26 | uint32_t cs; 27 | uint32_t ss; 28 | uint32_t ds; 29 | uint32_t fs; 30 | uint32_t gs; 31 | uint32_t ldtr; 32 | uint32_t iopb; 33 | uint32_t ssp; 34 | } __attribute__((packed)); 35 | 36 | void tss_load(int tss_segment); 37 | #endif --------------------------------------------------------------------------------