373 Commits

Author SHA1 Message Date
a047edc97d fix(kernel/std): handle empty list case in begin() and cbegin() methods in foward_list
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
Build OS / Upload Nightly Build to GitHub Releases (push) Has been cancelled
2025-06-13 19:09:03 +00:00
2c1d6c2608 fix(workflow): add GH_TOKEN environment variable for GitHub CLI
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
Build OS / Upload Nightly Build to GitHub Releases (push) Has been cancelled
2025-06-13 14:49:59 +00:00
97a892d114 fix(workflow): ensure nightly build upload runs unconditionally 2025-06-13 14:44:19 +00:00
3be150da53 fix(workflow): fix xhost error 2025-06-13 13:24:49 +00:00
455224ceb4 fix(workflow): fix issues with packages 2025-06-13 13:15:14 +00:00
e01f1dc97c fix(workflow): add installation step for Dev Container 2025-06-13 13:06:41 +00:00
76113df5a9 ci: upload nightly builds to GitHub Releases 2025-06-13 13:01:32 +00:00
1addd310ad fix(kernel/std): remove unnecessary algorithm include from utility 2025-06-11 03:49:50 +00:00
3d92a87bef fix(kernel/std): cast lhs and rhs to __UINTPTR_TYPE__ 2025-06-11 03:45:34 +00:00
f7177f92cf test(kernel): add tests for std::foward_list and std::is_sorted 2025-06-10 02:02:58 +00:00
6a6c3bfc67 feat(kernel/std): complete the std::foward_list implementation 2025-06-10 02:00:23 +00:00
8dbeee4d9a fix(kernel/std): 🎨 reorder is_sorted_until function declaration 2025-06-10 01:52:58 +00:00
5d5b674aed feat(kernel/std): 🎨 add stub std::foward_list 2025-06-09 07:41:49 +00:00
31bbc29c9f feat(kernel/std): add is_sorted and is_sorted_until functions 2025-06-09 07:41:13 +00:00
f5c8ae9323 fix(devcontainer): use xhost to allow qemu to run inside the container
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
I did this because on every reboot xauth directory was changing, and had to rebuild the container.
2025-05-30 01:50:05 +00:00
154d857c2e refactor(kernel): remove debug log from Sleep function 2025-05-28 02:15:11 +00:00
12ae5a83da feat(kernel): 🎨 add whileto macro for conditional looping with timeout 2025-05-28 02:05:16 +00:00
13ce994edf fix(kernel): 🐛 interrupt handler was broken for PCI 2025-05-28 00:43:21 +00:00
814175ddaf fix(kernel/pci): 🔥 do not map I/O BARs 2025-05-24 17:24:32 +00:00
43e7ddb9de fix(kernel): remove redundant HPET counter test loop 2025-05-24 00:39:20 +00:00
0187fa5b66 feat(kernel): 🎨 add the logo to the kernel as a png resource 2025-05-23 23:32:37 +00:00
33c284091d refactor(kernel): ♻️ rewrite time manager 2025-05-23 23:30:04 +00:00
9538589c11 feat(kernel): add kvm cpuid structures 2025-05-23 20:52:29 +00:00
905b6933c9 fix(kernel/std): 🎨 implementation for <chrono>, <ratio> & <thread> were broken 2025-05-23 15:16:04 +00:00
07d0ca0438 fix(kernel/efi): 🐛 check if ImageHandle and SystemTable has valid, pointers
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
2025-05-19 23:39:29 +00:00
7d37f8a8a1 feat(kernel): 🎨 update BGRT header
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Deploy Website / Deploy Website to GitHub Pages (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
2025-05-18 19:45:09 +00:00
8103caa52c feat(kernel): ⬆️ update stb headers 2025-05-18 19:42:50 +00:00
4929b76c7c fix(kernel/std): 🐛 correct bucket assignment inside [] operator in std::unordered_map 2025-05-18 19:39:20 +00:00
d20d4f7bf9 feat(kernel): 🎨 show stack on panic screen by default
This is good if the PS/2 keyboard doesn't work. It clearly needs a rework tho.
2025-05-18 19:37:18 +00:00
f06c0b19fa fix(kernel/vfs): fully implement ustar driver implementation + mounting system 2025-05-18 11:38:42 +00:00
70a08e46bd fix(rootfs): 🐛 fix subsystem tar to not use PaxHeader 2025-05-17 12:05:45 +00:00
2349610e47 test(kernel): add debug playground functions for testing purposes 2025-05-16 17:23:41 +00:00
fda5ede37f fix(drivers): 🐛 prevent unnecessary recompilation by leaving trusted.c unchanged if no updates are detected 2025-05-14 11:11:35 +00:00
81da8dd989 refactor(kernel/drivers): 🎨 rename filesystem name to "devfs" 2025-05-13 16:28:37 +00:00
557c7e6235 fix(kernel/vfs): 🎉 a complete rewrite of the vfs
This is the fourth time re-writing the VFS, hope this will be the last. Tried to make it as modular as possible so this won't be necessary in the future. 🙏

This change required the entire kernel code to be modified.
2025-05-13 15:59:12 +00:00
83a7f83f81 feat(kernel): 🎨 always include the uptime in KPrint output 2025-05-13 15:54:05 +00:00
6592db3f4e build(kernel): fix compiling in release mode 2025-05-13 15:11:32 +00:00
d7abd36717 feat(kernel/std): add iterator_traits specialization for pointer types 2025-05-11 16:31:33 +00:00
7873d0e724 revert(kernel/std): 🔥 std::set is too hard to implement for now 2025-05-11 16:31:12 +00:00
9626ec4662 feat(kernel/std): add three way compare for std::basic_string and std::vector 2025-05-10 16:32:54 +00:00
dbb5a483e0 feat(kernel/std): implement std::compare 2025-05-10 15:02:37 +00:00
aca55f993f feat(kernel/std): implement std::less specializations for pointer types and void 2025-05-10 15:00:47 +00:00
41fe55fd1f feat(kernel/std): implement lexicographical_compare* functions 2025-05-10 14:59:57 +00:00
c491351fd0 feat(kernel/std): add is_floating_point type trait 2025-05-10 14:58:16 +00:00
75d51fb9d9 feat(kernel/std): add stub std::set implementation 2025-05-10 06:45:42 +00:00
21db83b943 refactor(kernel/std): ♻️ rename test function to test_stl_shared_ptr 2025-05-10 06:03:58 +00:00
fa2e37f603 feat(kernel/std): add stub lexicographical_compare and lexicographical_compare_three_way functions 2025-05-10 04:34:50 +00:00
fab3be67ee refactor(kernel/std): ♻️ rename pragma regions from "Member Functions" to "Constructors" 2025-05-10 04:17:19 +00:00
6e26184a04 test(kernel/std): 🧪 add tests for std::shared_ptr 2025-05-09 07:34:28 +00:00
6b6028434d feat(kernel/std): implement std::shared_ptr 2025-05-09 07:06:25 +00:00
ca02557df4 fix(kernel/std): 🐛 handle empty string case in append and resize methods 2025-05-09 07:05:08 +00:00
527ad803d3 chore(kernel): add custom pretty printer for std::string 2025-05-07 09:32:29 +00:00
2791a602b5 fix(kernel): ✏️ correct ReturnLogError macro structure
Missing "do".
2025-04-27 04:24:24 +00:00
3404bbc3bc feat(rootfs): update subsystem configs 2025-04-23 17:54:38 +00:00
c254b96256 fix(kernel/bootstrap): enable SSE
This shouldn't be an issue, I guess all 64-bit CPU's support SSE anyway...
2025-04-22 21:24:51 +00:00
1e4d404a43 refactor(kernel/efi): rename main efi file 2025-04-20 00:58:19 +00:00
16ec6cbdb6 feat(kernel/efi): add more efi tables 2025-04-20 00:52:32 +00:00
ba99275700 fix(kernel): reset color even on serial output 2025-04-19 19:19:26 +00:00
80c313b02d refactor(kernel/efi): improve code and add more debug messages 2025-04-19 19:18:45 +00:00
fe8682aa85 feat(kernel): use efi in kernel for smbios and rsdp info 2025-04-19 12:27:28 +00:00
cd23c59c46 fix(userspace/libc): interpreter didn't worked at all 2025-04-18 12:38:21 +00:00
f5c9b561a9 fix(kernel/elf): check if vector is empty before calling .front() 2025-04-18 12:36:33 +00:00
366fd97c0a refactor(kernel/elf): simplify dynamic tag and section handling in ELF parsing 2025-04-18 12:35:44 +00:00
d3fd61c068 refactor(kernel/drivers): update trusted drivers hash 2025-04-17 16:04:10 +00:00
0a037f1ae1 test(kernel): add more memory allocator tests 2025-04-17 16:03:03 +00:00
292bfa362a refactor(kernel): change IDT debug message color from blue to green when debugger is attached 2025-04-17 16:02:22 +00:00
bcc2c9d0ab refactor(kernel): change color arrays to static 2025-04-17 16:01:40 +00:00
e270c9f35b refactor(kernel): update debug messages 2025-04-17 16:01:03 +00:00
7902726239 fix(kernel/tty): wrong calculation of cell index
Instead of ws_row, now it's ws_col.
2025-04-17 15:56:16 +00:00
abb7899a9d fix(kernel/std): improve capacity growth strategy in std::vector operations
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
2025-04-15 16:48:23 +00:00
8c4c8d36de fix(kernel/std): ensure null termination after removing elements in std::string::erase 2025-04-15 15:38:20 +00:00
0fffc6c914 build: fix "limine.h: No such file or directory" error 2025-04-14 01:29:25 +00:00
34e24df7c9 build: add __ci-prepare-archive 2025-04-14 01:27:20 +00:00
550e98e87c ci: fix job names 2025-04-14 01:26:18 +00:00
4ff6790072 ci: add separate build steps in workflow 2025-04-14 01:20:57 +00:00
205ddb1e49 ci: ensure artifact upload occurs regardless of previous steps 2025-04-13 13:50:02 +00:00
0735743f44 build: fix kernel build on different architectures
Userspace still fails to compile on non-x86!!!
2025-04-13 13:47:59 +00:00
33eee9c628 feat(kernel/syscalls): implement stub linux_poll 2025-04-13 10:18:15 +00:00
ef5d61df9d build(kernel/tty): fix vtable linking error 2025-04-13 10:08:49 +00:00
11d326b693 feat(kernel/tty): implement processing control characters (^C, ^D, etc) 2025-04-13 09:49:09 +00:00
5293bb2039 feat(kernel/tty): implement blinking cursor 2025-04-12 10:55:01 +00:00
bc84c406d9 build: update Linux Subsystem boot configuration to use compressed rootfs 2025-04-12 04:39:30 +00:00
ed1f4f3c1b test: reduce debug qemu memory allocation for amd64 architecture 2025-04-12 04:38:24 +00:00
ec04e5abe9 build: update rootfs tar command to use gzip compression 2025-04-12 04:37:48 +00:00
5ecfffc049 build: create mnt directory in root filesystem setup 2025-04-12 04:37:23 +00:00
c7d501b466 build: add support for quiet build mode in CMakeLists 2025-04-12 04:36:16 +00:00
1f646d6826 fix(kernel): improve error message for failed init program startup 2025-04-12 04:33:10 +00:00
3315d79742 fix(kernel/vfs): support multiple roots 2025-04-08 05:04:04 +00:00
a1b58bacd8 refactor(kernel): remove unused assert_allow_continue macro 2025-04-08 03:37:32 +00:00
69122746de refactor(kernel): change NIF to nif 2025-04-08 03:25:38 +00:00
764dfe67a5 refactor(kernel): replace manual sorting with std::sort 2025-04-08 02:37:22 +00:00
3d87345a51 fix(kernel/memory): correct bitmap address calculation 2025-04-08 02:31:40 +00:00
eb89b060f6 fix(kernel/vfs): accessing null pointer 2025-04-07 07:42:27 +00:00
25713e0f13 refactor(kernel): improve code readability and formatting 2025-04-07 07:30:48 +00:00
03147b532c fix(kernel/memory): correct loop control in ReservePages function 2025-04-07 07:25:11 +00:00
d8cd27196d feat(kernel/std): add std::sort implementations 2025-04-07 06:32:25 +00:00
832833a56f fix(kernel/vfs): forgot ';' inside ramfs.hpp 2025-04-07 05:38:24 +00:00
a4e5f4785c refactor(kernel): clean up KPrint formatting and fix memory reporting 2025-04-07 05:37:45 +00:00
a268f8dc2f feat(kernel/vfs): implement RAMFS filesystem 2025-04-07 05:37:23 +00:00
a16a88b5f9 fix(kernel): validate symbol entries to prevent processing of invalid symbols 2025-04-07 05:35:17 +00:00
2d2d28689c fix(kernel/vfs): correct root assignment logic in filesystem 2025-04-07 05:31:13 +00:00
d4346202ca refactor(kernel): ramfs loading 2025-04-07 05:04:23 +00:00
b1a30059ed feat(kernel): add initial subsystem implementation files 2025-04-07 04:51:05 +00:00
58accf8acf feat(kernel): add initial security implementation files 2025-04-07 04:02:02 +00:00
24c0848797 refactor(workspace): remove useless settings in vscode workspaces 2025-04-05 17:20:34 +00:00
b232dc6b40 feat(kernel/vfs): add AddRootAt, SetRootAt, RemoveRoot & RootExists functions
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-04 11:51:47 +00:00
120d67fb1a refactor(kernel): remove unnecessary type casting in Execute::Spawn call
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-04 11:01:40 +00:00
f6eb4bd3dc test(kernel/std): add <array> header tests
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-04 10:58:13 +00:00
7e7e475dac feat(kernel/std): implement <array> header
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-04 10:57:40 +00:00
23d0056098 feat(kernel/std): implement std::is_pointer_v
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-04 10:57:10 +00:00
3edb4b4761 feat(kernel/std): implement std::reverse_iterator
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-04 10:56:46 +00:00
fd24431eea feat(kernel/std): implement std::runtime_error and std::length_error
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-04 10:55:44 +00:00
5c1c26b135 refactor(kernel): use default constructor for std::exception class
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-04 10:54:33 +00:00
a333d8aa7c refactor(kernel): change Spawn function parameter type from char* to const char*
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-04 10:53:40 +00:00
f054e9976a build: increase qemu debug RAM to 1GB
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-04 10:50:39 +00:00
f87c3d7e11 feat(kernel/tty): add TCSETS
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-04 04:14:19 +00:00
0041300a00 style(kernel/elf): change code style
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Deploy Website / Deploy Website to GitHub Pages (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 12:06:23 +00:00
fe6d7f4b08 fix(kernel/syscalls): remove unused variable 'vma' in linux_fchmod
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 11:01:57 +00:00
a1622cc885 ci: fix 'tmp_rootfs/sys/drv/': No such file or directory
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 10:53:38 +00:00
bd32020876 revert: last commit
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 10:53:07 +00:00
44323c85a3 ci: rootfs structure was not created
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 10:48:53 +00:00
027d77ed66 fix(devcontainer): move installation of autoconf and automake
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 09:15:39 +00:00
bbb70eb621 feat: add advanced options for Fennix boot menu in grub.cfg
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 07:13:13 +00:00
1593e3107d fix(kernel/syscalls): convert error codes in linux_getdents64 to Linux
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 07:12:11 +00:00
1a48d05042 feat(kernel/syscalls): implement semi-stub linux_sysinfo
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 06:46:26 +00:00
75dd958316 feat(kernel/syscalls): implemented stub linux_syslog
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 06:32:51 +00:00
cccbfd2c95 build: add libstdc++ target
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 06:17:34 +00:00
bf20bd89ed build(kernel): add -fdiagnostics-all-candidates flag
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 06:16:23 +00:00
c3fd55bb00 fix(devcontainer): set network mode to host
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 06:15:32 +00:00
c660a7fe4f fix(kernel/elf): interpreter loading is now correctly implemented
ref: linux @ fs/binfmt_elf.c
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 06:15:12 +00:00
91ad0e14df test(kernel): expand coroutine tests
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-31 09:39:22 +00:00
a6ca98987e fix(kernel/scheduler): threads were skipped if one has affinity for other core
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-30 19:08:18 +00:00
f8f08a11db refactor: add SYS_DEBUG_REPORT
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-30 18:42:04 +00:00
5d64c05446 feat(kernel): enhance chrono and thread
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-30 18:41:05 +00:00
a1064d8978 feat(kernel): add std::terminate() function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-30 18:07:26 +00:00
6d01cf4e69 refactor(kernel): check for __cpp_impl_coroutine in <coroutine>
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-30 17:36:24 +00:00
ffd992cd74 refactor(kernel): improve future implementation
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-29 23:39:44 +00:00
8d71ed0ad5 refactor(kernel): remove 'foreach' macro
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-29 22:43:07 +00:00
93d897e95c feat(kernel): update stl headers
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-29 18:27:57 +00:00
31181d5b5d refactor(kernel/syscalls): improve linux_execve implementation
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 18:45:25 +00:00
2f18d390e4 fix(kernel/tty): add stub implementation for TIOCSCTTY ioctl
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 16:46:55 +00:00
5ffb0e704d refactor(kernel/syscalls): add fixme comments for Ctrl+Alt+Del reboot commands
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 16:42:59 +00:00
ad0c1e15e0 fix(kernel/syscalls): add null check for argp in linux_ioctl function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 16:41:58 +00:00
b74d4db23b fix(kernel): update device file references from 'kcon' to 'console'
Feels more right to be 'console'.

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 16:09:16 +00:00
022d99f795 refactor(kernel): remove unused kernel argument from SpawnInit()
There is no reason to use this

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 16:04:46 +00:00
3482131b3f fix(kernel/scheduler): use GetKernelProcess() for idle threads
This will make the init process to be pid 1

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 16:00:22 +00:00
0a32c19923 refactor(kernel): comment out printf declarations in <stdio.h> and include <printf.h> instead
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 15:56:09 +00:00
36c5c8ad67 fix(kernel/elf): segment mapping and handling of program headers were wrongly implemented
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 15:55:29 +00:00
6240d6638f feat(kernel/syscalls): implement linux_chmod and linux_fchmod
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 15:52:50 +00:00
7491f19f9a feat(kernel): implement handling symbolic links in paths
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 14:33:29 +00:00
13d52897b8 feat(kernel): update configuration
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 14:31:22 +00:00
4cc058ab42 feat(kernel/elf): add OS-specific segment types and GNU properties
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 02:09:00 +00:00
a7f754c5e8 fix(kernel): options were not properly parsed
Had to set the context.index to 0 because here argv[0] is not the program name.

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 01:07:27 +00:00
9304cafe0c feat(kernel): update cargs to v1.2.0
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 00:46:34 +00:00
7b42b46942 style(kernel): tab spaces in cargs.c
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 00:13:03 +00:00
2ce0e0ed79 feat(kernel/syscalls): add SYS_DEBUG_REPORT syscall
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 23:25:16 +00:00
d69eb73a59 chore: update CHANGELOG.md
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 23:24:24 +00:00
aa8f415b98 ci: set fetch-depth to 0 for submodule checkout
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 23:24:01 +00:00
ec792f1fe2 docs: update contributing guidelines for commit messages and versioning
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 23:18:11 +00:00
4c31568329 fix(devcontainer): update XAUTHORITY source to use localEnv
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 23:00:29 +00:00
e9dd70c6c4 feat(kernel): add <utf8.h> header
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 23:00:10 +00:00
4e9d25143e fix(kernel): add LD_LIBRARY_PATH
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 02:33:03 +00:00
92fe4bdd81 feat(kernel): add KERNEL_HHDM_OFFSET macro
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-25 19:43:50 +00:00
0b21c57ee5 fix(vscode): problem matcher lagging the interface
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-25 19:43:30 +00:00
c412a75f91 feat(kernel): update limine
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-25 18:15:45 +00:00
0cc4d5096b fix: accidentally hit CTRL+Z
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Deploy Website / Deploy Website to GitHub Pages (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-25 15:20:57 +00:00
34bd348f25 fix(devcontainer): qemu cannot access /dev/kvm "failed to initialize kvm: Permission denied"
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-25 15:18:43 +00:00
d251d9d03f refactor(rootfs): reorganize file structure and remove unnecessary .gitkeep files
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-24 15:33:07 +00:00
8f88d9028e feat(devcontainer): add libtool and libltdl-dev packages
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-24 15:32:42 +00:00
fcdc26c1f7 refactor(tools): update boot configurations
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-24 15:07:22 +00:00
fc588f10bc feat(kernel): enable SIMD by default
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-24 15:05:14 +00:00
527e1708ce refactor(rootfs): change "initrd" to "rootfs"
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-24 00:51:00 +00:00
1286c4cd90 feat(userspace/libs): add libexpat, libffi and libxml2
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-24 00:42:47 +00:00
0d8c65e44b feat(userspace/libc): implement functions for porting apps
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-24 00:40:07 +00:00
27356b7826 fix(userspace/libc): mark ABI and build ID notes as used to prevent optimization removal
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-24 00:38:03 +00:00
d06b6d3270 feat(kernel): add hot and cold attributes to optimize function performance
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-22 03:04:23 +00:00
f9476d8c57 fix(kernel/syscalls): cast syscall arguments to scarg type for call_time
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-22 01:44:46 +00:00
79f2faf55b feat(devcontainer): install meson in Dockerfile
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 22:59:58 +00:00
2d0245f2ac feat(kernel): move kernel note to a separate file
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Deploy Website / Deploy Website to GitHub Pages (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 03:29:40 +00:00
79e55140e3 feat(kernel/driver): implement driver sha512 verification
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 03:23:25 +00:00
ae7f39d0de feat(kernel/drivers): add trusted drivers list
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 03:22:40 +00:00
be72d2dc06 fix(kernel/driver): filter out non-.drv files in driver loading
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 03:21:32 +00:00
a8e4dd08bb feat(kernel): add SHA-512 implementation
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 03:15:57 +00:00
c2e31827d8 refactor(kernel): remove unused TaskingPanic() function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 02:19:01 +00:00
7087ce7ec5 feat(userspace/libc): implement brk(), chdir() and getcwd()
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 02:01:57 +00:00
36bb7b7a88 refactor: sync headers
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 02:00:10 +00:00
2080d1f2b7 feat(kernel/syscalls): add fcntl() syscall
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 01:58:14 +00:00
b05a6a14e8 fix(kernel): compilation issues due to header changes
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 01:57:51 +00:00
c4225f7bdf feat(userspace/coreutils): improve fennix shell implementation
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 01:27:09 +00:00
76b3d30db9 build(userspace/libc): correctly detect linux in cmake
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 01:17:44 +00:00
e89e984ccb feat(userspace/libc): implement access()
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 01:17:21 +00:00
dd1ffe0d17 fix(userspace/libc): add .gitkeep to arch directories
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 01:16:58 +00:00
3feb4e72aa refactor(userspace/coreutils): change code style
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 01:16:21 +00:00
a43fac0c2d feat(kernel/api): add fcntl.h
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-21 01:12:08 +00:00
67a3527e29 fix(userspace): change version of libc and coreutils
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-20 00:10:06 +00:00
f4a96e0b2e docs: add note in echo.c PrintHelp()
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-17 23:22:00 +00:00
7e69b8f82a feat(userspace/libc): support for linux target
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-17 23:18:54 +00:00
8258d40115 feat(userspace/coreutils): add stub "sh" command
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-17 02:26:47 +00:00
568dffbca1 feat(userspace/libc): add <getopt.h> header
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-16 03:14:14 +00:00
9a82d812d6 feat(userspace/libc): add <regex.h> header
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-16 01:43:57 +00:00
49ee634822 feat(userspace/coreutils): add alias command
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-16 00:54:59 +00:00
babf792c30 feat(userspace/coreutils): add stub "admin" command
https://pubs.opengroup.org/onlinepubs/9799919799/utilities/admin.html
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-16 00:47:56 +00:00
65f9a805e2 build(userspace/coreutils): generate symlink "[" on install
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-16 00:25:04 +00:00
6e077acc66 fix(userspace/coreutils): fix test command to correctly detect the bracket
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-16 00:15:51 +00:00
5af9c9b0a2 feat(userspace/coreutils): add test command
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-16 00:00:09 +00:00
201ace7eec refactor(userspace): build using cmake
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-15 23:05:17 +00:00
40f46312f8 fix(userspace/apps/test): make gcc shut up about "infinite recursion detected"
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-13 23:25:52 +00:00
a53d41008c fix(userspace/coreutils): handle combined uname options (-sv, -np, etc.)
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-11 15:38:07 +00:00
8a6910bf04 refactor(userspace/coreutils): improve uname command
The IEEE Std 1003.1-2024 specifies this for output:

    By default, the output shall be a single line of the following form:

    "%s\n", <sysname>

    If the -a option is specified, the output shall be a single line of the following form:

    "%s %s %s %s %s\n", <sysname>, <nodename>, <release>,
        <version>, <machine>

    Additional implementation-defined symbols may be written; all such symbols shall be written at the end of the line of output before the <newline>.

    If options are specified to select different combinations of the symbols, only those symbols shall be written, in the order shown above for the -a option. If a symbol is not selected for writing, its corresponding trailing <blank> characters also shall not be written.

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-11 15:33:08 +00:00
1d7a9edd46 feat(userspace/coreutils): implement arch command
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-11 15:29:17 +00:00
58477bae6a refactor(userspace): move uname program to coreutils
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-11 00:53:36 +00:00
cbc6238d9d fix(userspace/libc): implement uname()
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 22:39:26 +00:00
9f393754f6 feat(kernel/syscalls): implement uname syscall
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 22:38:52 +00:00
fc43512c75 feat: add /etc/hostname file
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 22:05:54 +00:00
551853c5d6 fix(userspace/libc): implement gethostname()
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 22:05:28 +00:00
6b4faf9f78 fix(userspace/libc): remove stub macros in termios.c
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 21:04:53 +00:00
4a6cf4f2e5 chore(userspace/coreutils): update .gitignore
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 19:34:35 +00:00
b008b8089c fix(userspace/libc): missing include <sys/ioctl.h>
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 19:32:16 +00:00
2f33ea4dfd build(devcontainer): install cmake too
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 13:48:23 +00:00
87540ab0b9 feat(coreutils): implement coreutils and compile it using cmake
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 02:29:14 +00:00
88a3b0912b feat(userspace): add dummy libstdc++ library
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 02:20:32 +00:00
7ec85e67df style(kernel): format document
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 01:14:47 +00:00
67692f2cef feat(userspace/libc): define TIOC*WINSZ constants in <sys/ioctl.h>
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 01:14:18 +00:00
cc81facf50 feat(userspace/apps/usr): stub implementation for mdview
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 01:12:10 +00:00
95cc190b54 build(devcontainer): potential fix for "failed to initialize kvm: Permission denied"
qemu-system-x86_64: Could not access KVM kernel module: Permission denied
qemu-system-x86_64: failed to initialize kvm: Permission denied

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-10 01:07:56 +00:00
1c842ef3d1 docs: update build instructions
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-08 00:47:43 +00:00
27ad61fa17 chore(devcontainer): cleanup devcontainer.json file
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-07 22:58:04 +00:00
45d34c688f fix(userspace/libc): fix puts() in interpreter
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-07 02:09:16 +00:00
1ff62e22bf feat(kernel/syscalls): implement sys_fork()
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-07 01:31:50 +00:00
2c02da7eaf build: add Clean, Build & Run tasks for vscode
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-06 15:19:21 +00:00
8ef7a25728 ci: separate github pages deploy workflow
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-06 13:46:52 +00:00
b4cc1d9e66 fix(kernel): crash on ACPI shutdown/reboot
The deletion of DriverManager invalidates "DriverManager->GlobalKeyboardInputReports" which results in a crash if other processes are waiting for keyboard input.

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-06 13:38:42 +00:00
793ccfd5ba ci: add CHANGELOG.md in artifacts
Some checks failed
Build OS / Deploy Documentation to GitHub Pages (push) Has been cancelled
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-06 03:22:30 +00:00
66362ed387 chore: add git-cliff
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-06 03:17:00 +00:00
11e7d8c2dd ci: add "push: never" to devcontainers/ci
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-06 02:26:13 +00:00
e1e9ce050d ci: fix limine in ci build
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-06 02:00:47 +00:00
92610b6678 ci: fix ci
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-06 01:55:00 +00:00
15a9a21448 ci: fix "touch: cannot touch '/run/user/1000/pulse/native': No such file or directory"
Some checks failed
Build OS / Deploy Documentation to GitHub Pages (push) Has been cancelled
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-06 00:37:57 +00:00
d4c4016c7c ci: potential fix for Dev Container issues
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-06 00:35:44 +00:00
19055409cd ci: experimental change to workflows to use dev container
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-06 00:26:30 +00:00
839dfb74b2 build(kernel): fix i386 build
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 23:34:20 +00:00
0bfb45020f build(kernel): fix compiling issues on arm
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 23:19:02 +00:00
9e746c52bc feat(kernel/api): implement arm syscall wrappers
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 23:18:18 +00:00
3740b65263 fix(userspace/libc): add libgcc link to fix softfloat
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 23:17:15 +00:00
77e51a6f2c feat(userspace/libc): add experimental __aeabi_dcmpun() function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 18:58:32 +00:00
42b8b6895f fix(userspace/libc): fix wrong implementation of ioctl()
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 18:54:18 +00:00
9da2650486 build(kernel): fix compiling issues on i386
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 17:39:42 +00:00
e01f488768 feat(kernel/api): implement i386 syscall wrappers
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 17:38:59 +00:00
958a3ed263 feat(userspace/apps/test): update utest
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Build OS / Deploy Documentation to GitHub Pages (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build amd64 (push) Has been cancelled
Build OS / Build i386 (push) Has been cancelled
Build OS / Build aarch64 (push) Has been cancelled
Build OS / Build arm (push) Has been cancelled
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 04:23:19 +00:00
a0e3993a3f feat(userspace/libc): implement <math.h> header
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 04:21:06 +00:00
edeecf7831 fix(userspace/apps/test): adjust fflush(stdout) calls for better output control
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 04:19:34 +00:00
90fb9c7952 test(userspace/apps/test): expand math function tests for accuracy
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 04:18:40 +00:00
0a52ef4f68 fix(userspace/apps/test): update expected results for rounding and special functions
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 03:53:59 +00:00
5e0a80fa1c feat(userspace/libc): implementation <fenv.h> header
FIXME: testing required!
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 03:23:19 +00:00
784f3c3df9 chore: standardize indentation for CMake files
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-05 01:22:45 +02:00
68acf428a2 fix(userspace/libc): disable debug info in memory allocation functions
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-03 18:26:00 +00:00
9105c63465 refactor(userspace/apps/test): ♻️ move all functions in one file
it's just too much...

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-03 18:25:05 +00:00
659805960b fix(userspace/libc): wrong puts() implementation
The implementation didn't fully followed the POSIX.1-2024 standard "The puts() function shall write the string pointed to by s, followed by a <newline>, to the standard output stream stdout. The terminating null byte shall not be written."

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-03 12:08:39 +00:00
451c5405e0 fix(userspace/apps/test): fix noreturn compiler warning
fix "warning: 'noreturn' function does return"

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-03 00:58:19 +00:00
bd02b976a2 fix(kernel/tty): temporal removal of ICANON checking
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 23:57:46 +00:00
9bffe3e013 chore(vscode): rename preLaunchTask from launch-qemu to QEMU
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 23:33:28 +00:00
84298fc4eb fix(kernel/driver): set unused file system operation pointers to nullptr
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 23:31:30 +00:00
87a2dc9444 fix(kernel/driver): node device & offset were not set for new created files under /dev
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 23:29:13 +00:00
426a84a1a9 docs(kernel): short doc for __check_op macro
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 23:14:40 +00:00
8eed8909da chore(vscode): update launch configuration to include libc_test
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 22:47:43 +00:00
09d0af1ea6 refactor(userspace/libs): rename libdemo to libexample
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 22:02:02 +00:00
7b85636f8f fix(drivers): remove drivers that are now in kernel
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 21:37:52 +00:00
95585fce5f fix(kernel/driver): remove unused device handling code in daemon
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 21:37:10 +00:00
bf1e3432d7 feat(kernel/drivers): migrate drivers to the kernel
make the drivers builtin

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 21:37:01 +00:00
f824df9aad feat(kernel/driver): implement built-in driver support
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 21:34:16 +00:00
426499090e feat(kernel/driver): add CreateDeviceFile function in the API
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 21:32:00 +00:00
1af2cf657d feat(kernel/driver): add CreateDeviceFile method
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 21:30:15 +00:00
f31d11f7ad fix(kernel/pci): fix MapPCIAddresses when BAR size of zero
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 21:28:28 +00:00
851a8c140f feat(kernel/driver): add ReloadDriver method to manage driver reloading
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 21:27:20 +00:00
ae2617dca2 refactor(driver/api): delegate memory allocation and deallocation to DriverManager
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 21:26:00 +00:00
adba9cc348 refactor(driver/api): fix formatting
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-01 23:33:55 +00:00
232e06f8f3 refactor(kernel/pci): simplify PCI device initialization by delegating to PCIManager
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-01 23:32:54 +00:00
aea8a7bb08 feat(kernel/pci): add device initialization method for PCI devices
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-01 23:32:14 +00:00
65ab83b42b fix(kernel/pci): map BAR address using PWT and PCD flags
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-01 23:31:31 +00:00
d3f6d51ed2 build(vscode): add separated tasks for building bootloader, kernel, drivers, userspace, and image
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-28 00:41:17 +00:00
ca8dc6429b fix(kernel): fix empty initialization of std::string (str = "")
_size is 0 which fails the memcpy checks

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-27 18:13:51 +00:00
cfb5d9a0f4 build(tools): fix gdb error 'Scripting in the "Python" language is not supported in this copy of GDB.'
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-26 23:20:10 +00:00
8dab45ecfd build(devcontainer): improve Dev Container development
The toolchain and qemu can be built inside the container + running the qemu inside the container

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-26 23:10:17 +00:00
88a5f06325 build(tools): rewrite makefile to be more efficient and easy to understand
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-26 23:07:36 +00:00
aab84cd3ab chore(devcontainer): rename dev container (libc_test)
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-26 23:04:57 +00:00
a3719eef3e feat(initrd): add /etc/hosts file
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-26 15:21:54 +00:00
0769a82f4b feat(userspace/libc): update math functions
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-26 02:10:06 +00:00
f978f2487e feat(userspace/libc): add math stub functions
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-25 16:17:37 +00:00
8859bfc438 chore(vscode): add Dev Container
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-25 16:16:41 +00:00
5202601c4f feat(userspace/libs/libm): add stub libm
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-25 16:13:42 +00:00
78141b28c7 feat(userspace/apps/test/libc_test): rewrite a lot of the code and improve debugging with vscode using .devcontainer
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-25 14:10:12 +00:00
3f2584ac09 chore(vscode): add 'kernel' scope to conventional commits
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-24 02:10:14 +02:00
a2ce579a61 fix(userspace/libc): update vscode stub macro with improved formatting
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-24 02:09:31 +02:00
0958cdf7f8 fix(kernel): add TZ environment variable to init process
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-24 02:08:42 +02:00
7f3b2b4dbb fix(userspace/libc): fix tzset() function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-22 03:26:49 +02:00
f6f46d1bbe fix(userspace/libc): fix gmtime_r, localtime_r and mktime implementation
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-22 03:22:47 +02:00
c12ee67592 fix(userspace/libc): handle NULL input in getenv function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-22 02:52:11 +02:00
74ff9579f3 fix(userspace/libc): fopen should set buffer_pos to -1
This change is a fix for fread() because it needs to pass the if statement: "if (stream->buffer_pos >= stream->buffer_size)"

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-22 02:43:06 +02:00
d7cbeb9eba fix(userspace/libc): modify __libc_init and crt0 to initialize "environ"
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-22 02:41:41 +02:00
4d333f94bc feat(userspace/apps/test/utest): add TestProcess function for executing test programs
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:58:30 +02:00
e003af38ff chore(vscode): add userspace/apps/sys/init to conventional commit scopes
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:56:09 +02:00
d1c504f9a6 feat(userspace/apps/sys/init): handle termination signals for graceful shutdown
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:55:29 +02:00
d46ed57dd7 chore(vscode): add more conventional commit scopes for userspace
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:54:45 +02:00
a6d372aaad feat(userspace/libs/libdemo): add template library
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:53:41 +02:00
b3e0b30147 refactor(tests): remove obsolete SIMD and web test files
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:47:12 +02:00
93e57f5dbe feat(userspace/libc): add stub termios implementation
Stub implementation! This needs a rewrite!

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:45:20 +02:00
db5a42289a feat(userspace/libc): implement feof() and ferror() functions
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:43:00 +02:00
77136acccd feat(userspace/libc): implement <time.h> header
Not tested enough!

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:42:33 +02:00
258ac6e2f6 chore(vscode): add recommended extensions for improved development experience
ms-vscode.cpptools maziac.asm-code-lens editorconfig.editorconfig vivaxy.vscode-conventional-commits ms-vscode.hexeditor webfreak.debug ibm.output-colorizer gruntfuggly.todo-tree naumovs.color-highlight seven1bit.vscode-ext-ansi-color-highlight jeff-hykin.better-cpp-syntax aaron-bond.better-comments

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:40:21 +02:00
fbe4b94805 chore(vscode): add conventional commit scopes for kernel
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:38:52 +02:00
2c2e7d9de3 build(userspace): update vscode launch configuration and Makefiles for utest and libc_test
Easier to debug

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:37:48 +02:00
9dfa750444 refactor(kernel/syscalls): simplify argument handling in HandleNativeSyscalls
Easier to debug

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:35:57 +02:00
4240183fa1 fix(userspace/libc): cast status to int in __check_errno for proper error handling
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-21 02:33:40 +02:00
42f26787fb feat(userspace/libc): implement getdelim and getline functions
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-20 02:20:26 +02:00
8d08ab933a feat(userspace/libc): implement fstatat, lstat & stat
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-20 02:17:19 +02:00
c83c542f5b feat(userspace/libc): implement fstat()
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-20 02:12:02 +02:00
08319ef4c7 docs(syscalls): add documentation for FBIOGET_SCREEN_INFO ioctl
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-20 02:09:09 +02:00
f4168e2815 refactor(userspace/libc): implement pthread_sigmask, sigaddset, sigfillset & sigprocmask
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-20 02:07:40 +02:00
123d11e4e3 feat(userspace/libc): implement system() function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-20 02:07:04 +02:00
b1a107fb65 refactor(userspace/libc): replace syscall2 with call_kill in kill function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-20 02:00:26 +02:00
d375acd0ec fix(userspace/libc): include <ctype.h> in stdlib.c
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-20 01:53:21 +02:00
5e6e63ab1a feat(userspace/libc): implement <ctype.h> header
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-20 01:52:37 +02:00
ab4bc55270 feat(userspace/libc): implement atoi, strtol, and strtoll functions in <stdlib.h>
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-20 01:49:41 +02:00
e5acf4a99e feat(userspace/libc): implement getpid, getppid & getuid
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-20 01:49:12 +02:00
5089cfa81b feat(userspace/libc): implement <pwd.h> header
Implemented everything except endpwent() and setpwent()

NOT TESTED!

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-20 01:45:04 +02:00
b5fce27037 feat(userspace/libc): implement getchar() and getc()
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-19 21:57:51 +02:00
0238f62894 fix(userspace/libc): fix error handling in ioctl function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-19 21:03:53 +02:00
ce59b6ea03 feat(userspace/libc): extend termios header with input/output speed and winsize structure
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-19 20:59:48 +02:00
9dcb5abe89 feat(userspace/libc): add termios header file for terminal I/O control
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-19 20:43:37 +02:00
4ac29bbce1 feat(userspace/libc): define file descriptor macros for standard input/output
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-19 20:42:56 +02:00
155f3bfab5 docs(kernel/api): add documentation for FBIOGET_SCREEN_INFO
Add documentation for FBIOGET_SCREEN_INFO macro

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-19 19:47:10 +02:00
e960f9fcc8 chore(userspace/libc): update vscode workspace config
Add conventionalCommits.scopes with "userspace/libc"

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-19 18:55:28 +02:00
4bb8ce6d00 feat(userspace/libc): complete <string.h> implementation
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-19 18:54:20 +02:00
2ae18af9a0 feat(userspace/apps/test/libc_test): add more tests
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-19 18:53:54 +02:00
e61b5824db refactor(userspace/apps/test/libc_test): remove deprecated string test files
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-15 15:35:28 +02:00
0f9a1915d1 feat(userspace/libc): implement all <string.h> functions
Implement all string.h functions except some which require locale which is not implemented yet

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-14 22:15:20 +02:00
6dfefc90c4 feat(userspace/libc): implement strcpy function
Add strcpy implementation in string.c

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-14 20:07:20 +02:00
c688bd7a97 feat: synchronize syscalls.h
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-14 19:59:59 +02:00
e927d93a48 feat(kernel): add stub device /dev/fb0
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-14 19:57:29 +02:00
d9235c6f90 userspace/libc: implement qsort, realloc and reallocarray functions in stdlib
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-14 02:19:14 +02:00
afa87ec5f3 userspace/libc: implement strcoll()
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-14 02:18:40 +02:00
22d01c7a51 userspace/libc: add <sys/socket.h> for socket programming support
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-14 02:18:15 +02:00
dfe9bbdbfa userspace/libc: implement read, pread, write & pwrite
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-14 02:17:47 +02:00
92ef18b412 userspace/libc: implement alphasort, fdopendir, opendir, posix_getdents, readdir & scandir
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-14 02:17:06 +02:00
d0a8d9dd62 userspace/libc: add <sys/uio.h> header for vector I/O operations
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-14 02:15:40 +02:00
f3e145e6f7 userspace/libc: add <netinet/in.h> header for IPv4 and IPv6 support
FIXME: not sure if this is implemented correctly

ref: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/netinet_in.h.html
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-14 02:15:18 +02:00
d9433256ab userspace/libc: add <arpa/inet.h>
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-14 02:13:48 +02:00
ade1c77361 userspace/test: add web server test program
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-14 02:11:30 +02:00
3e656854bc userspace/test: implement more tests in libc_test
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-13 01:14:11 +02:00
6c3eefa85d userspace/libc: add stub uname function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-12 02:53:44 +02:00
2384791793 userspace/libc: add stub gethostname function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-12 02:53:13 +02:00
97af4d855f userspace/libc: implement <sys/fcntl>
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-12 02:52:39 +02:00
b0f0982fd4 userspace/libc: update function signatures in fcntl.h
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-12 02:52:01 +02:00
bd1d117283 userspace/libc: add ioctl function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-12 02:51:14 +02:00
a1b040360c userspace/apps/sys: add uname command
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-12 02:50:27 +02:00
8f7938a1e5 userspace/libc: implement vfprintf function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-12 02:47:45 +02:00
b05868d120 userspace/libc: implement fprintf function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-12 02:43:43 +02:00
24fd486764 userspace/libc: implement strncpy function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-02-12 02:42:51 +02:00
23a17fae00 userspace/init: dummy code
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Successful in 1h46m32s
Build OS / Deploy Documentation to GitHub Pages (push) Failing after 4m27s
Build OS / Analyze (${{ matrix.language }}) (manual, c-cpp) (push) Failing after 6m13s
Build OS / Build amd64 (push) Failing after 14m44s
Build OS / Build i386 (push) Failing after 16m28s
Build OS / Build aarch64 (push) Failing after 11m17s
Build OS / Build arm (push) Failing after 15m17s
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-28 12:26:53 +02:00
d7bccb6948 userspace: add sh program
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-28 12:25:36 +02:00
833d8d497a userspace/libc: implement sigaction(), sigemptyset(), signal() & strcspn()
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-28 12:25:05 +02:00
1b55332027 userspace/libc_test: add test functions for various libc components
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-28 11:42:28 +02:00
cbe651d2da userspace/libc_test: add native build target and default toolchain configuration
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-28 11:37:45 +02:00
9c9f5549d7 userspace/libc_test: add VSCode snippets and workspace configuration
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-28 11:37:10 +02:00
655a2d88f5 chore: add newline at end of c_boilerplates.code-snippets
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-28 11:36:54 +02:00
cd49a219df userspace/libc: include stdio.h in dirent.c
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-27 23:59:29 +02:00
48067d8f58 userspace/libc: implement close() & dirfd()
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-27 23:58:54 +02:00
c2412fe710 userspace/libc_test: add return statement to main function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-27 23:31:34 +02:00
2f71bccef2 userspace/libc: implement std more functions
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-27 23:30:07 +02:00
f5a813380b userspace/utest: comment out build and linking commands in Makefile
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-27 23:28:22 +02:00
b54a32ba7a userspace: add stub libc test program
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-27 23:20:54 +02:00
1c5c0b524e userspace: update Makefiles
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-26 23:28:10 +02:00
62e482facb fix: correct project name references in license headers
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-01-25 00:20:34 +02:00
518 changed files with 63299 additions and 25379 deletions

127
.devcontainer/Dockerfile Normal file
View File

@ -0,0 +1,127 @@
FROM mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04
ARG REINSTALL_CMAKE_VERSION_FROM_SOURCE="none"
COPY ./reinstall-cmake.sh /tmp/
RUN <<EOF
if [ "${REINSTALL_CMAKE_VERSION_FROM_SOURCE}" != "none" ]; then
chmod +x /tmp/reinstall-cmake.sh && /tmp/reinstall-cmake.sh ${REINSTALL_CMAKE_VERSION_FROM_SOURCE};
fi
rm -f /tmp/reinstall-cmake.sh
EOF
# Update system and set noninteractive env
RUN export DEBIAN_FRONTEND=noninteractive && apt-get update
# Required packages for building gcc & binutils
RUN apt-get -y install --no-install-recommends \
build-essential \
bison \
flex \
libgmp-dev \
libmpfr-dev \
texinfo \
file \
python3-dev
# Required packages for building qemu
RUN apt-get -y install --no-install-recommends \
git \
libglib2.0-dev \
libfdt-dev \
libpixman-1-dev \
zlib1g-dev \
ninja-build \
libaio-dev \
libbluetooth-dev \
libcapstone-dev \
libbrlapi-dev \
libbz2-dev \
libcap-ng-dev \
libcurl4-gnutls-dev \
libgtk-3-dev \
libibverbs-dev \
libjpeg8-dev \
libncurses5-dev \
libnuma-dev \
librbd-dev \
librdmacm-dev \
libsasl2-dev \
libsdl2-dev \
libseccomp-dev \
libsnappy-dev \
libssh-dev \
libvde-dev \
libvdeplug-dev \
libvte-2.91-dev \
libxen-dev \
liblzo2-dev \
valgrind \
xfslibs-dev \
libnfs-dev \
libiscsi-dev \
python3-venv \
libslirp-dev \
ovmf
# Required packages for building test apps in userspace
RUN apt-get -y install --no-install-recommends \
mingw-w64 \
libtool \
libltdl-dev
# Required packages for building the OS and misc
RUN apt-get -y install --no-install-recommends \
grub2-common \
xorriso \
mtools \
grub-common \
grub-efi-amd64-bin \
grub-efi-amd64-signed \
grub-gfxpayload-lists \
grub-pc-bin \
grub-pc \
grub2-common \
pip \
cmake
# Install git-cliff
RUN pip install git-cliff --break-system-packages
# Install meson
RUN pip install meson --break-system-packages
# Configure git
RUN <<EOF
git config --global advice.detachedHead false
git config --global core.autocrlf input
git config --global init.defaultbranch master
EOF
# Set display environment variable for QEMU
ENV DISPLAY=:0
ENV NO_AT_BRIDGE=1
# Set PATH
RUN <<EOF
echo PATH=$PATH:/workspaces/Fennix/cross/bin >> /etc/profile
EOF
ENV CHMOD_KVM=1
# Remove autoconf & automake
RUN sudo apt-get -y remove autoconf automake
# Required packages for building gcc & binutils
RUN <<EOF
wget https://launchpad.net/ubuntu/+archive/primary/+files/autoconf_2.69-11.1_all.deb -O /tmp/autoconf.deb
sudo dpkg --force-all -i /tmp/autoconf.deb
EOF
# Required packages for building gcc & binutils
RUN <<EOF
wget https://ftp.gnu.org/gnu/automake/automake-1.15.1.tar.gz -O /tmp/automake.tar.gz
tar -xzf /tmp/automake.tar.gz -C /tmp
cd /tmp/automake-1.15.1
./configure && make && sudo make install
EOF

View File

@ -0,0 +1,45 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/cpp
{
"name": "Fennix",
"build": {
"dockerfile": "Dockerfile"
},
"customizations": {
"vscode": {
"extensions": [
"ms-azuretools.vscode-docker",
"eamodio.gitlens",
"EditorConfig.EditorConfig",
"naumovs.color-highlight",
"Gruntfuggly.todo-tree",
"ms-vscode.hexeditor",
"vivaxy.vscode-conventional-commits",
"webfreak.debug",
"maziac.asm-code-lens",
"Seven1bit.vscode-ext-ansi-color-highlight",
"ms-vsliveshare.vsliveshare",
"maziac.hex-hover-converter",
"ms-vscode.makefile-tools"
]
}
},
// From this line below are for qemu, so not that important.
"initializeCommand": "[ -x \"$(command -v xhost)\" ] && xhost +local:docker || true", // "xhost -local:docker" to disable
"mounts": [
{
"source": "/tmp/.X11-unix",
"target": "/tmp/.X11-unix",
"type": "bind"
},
{
"source": "/run/user/1000/pulse/native",
"target": "/run/user/1000/pulse/native",
"type": "bind"
}
],
"runArgs": [
"--privileged",
"--network=host"
]
}

View File

@ -0,0 +1,59 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
#
set -e
CMAKE_VERSION=${1:-"none"}
if [ "${CMAKE_VERSION}" = "none" ]; then
echo "No CMake version specified, skipping CMake reinstallation"
exit 0
fi
# Cleanup temporary directory and associated files when exiting the script.
cleanup() {
EXIT_CODE=$?
set +e
if [[ -n "${TMP_DIR}" ]]; then
echo "Executing cleanup of tmp files"
rm -Rf "${TMP_DIR}"
fi
exit $EXIT_CODE
}
trap cleanup EXIT
echo "Installing CMake..."
apt-get -y purge --auto-remove cmake
mkdir -p /opt/cmake
architecture=$(dpkg --print-architecture)
case "${architecture}" in
arm64)
ARCH=aarch64 ;;
amd64)
ARCH=x86_64 ;;
*)
echo "Unsupported architecture ${architecture}."
exit 1
;;
esac
CMAKE_BINARY_NAME="cmake-${CMAKE_VERSION}-linux-${ARCH}.sh"
CMAKE_CHECKSUM_NAME="cmake-${CMAKE_VERSION}-SHA-256.txt"
TMP_DIR=$(mktemp -d -t cmake-XXXXXXXXXX)
echo "${TMP_DIR}"
cd "${TMP_DIR}"
curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_BINARY_NAME}" -O
curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_CHECKSUM_NAME}" -O
sha256sum -c --ignore-missing "${CMAKE_CHECKSUM_NAME}"
sh "${TMP_DIR}/${CMAKE_BINARY_NAME}" --prefix=/opt/cmake --skip-license
ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake
ln -s /opt/cmake/bin/ctest /usr/local/bin/ctest

View File

@ -15,3 +15,12 @@ indent_style = tab
[.github/**] [.github/**]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
[{CMakeLists.txt,*.cmake}]
indent_size = 2
indent_style = space
[*.md]
indent_style = space
indent_size = 4
trim_trailing_whitespace = false

View File

@ -22,53 +22,19 @@ jobs:
path: tools/cross path: tools/cross
key: ${{ runner.os }}-cross-${{ hashFiles('tools/Makefile') }} key: ${{ runner.os }}-cross-${{ hashFiles('tools/Makefile') }}
- name: Update System - name: Prepare Environment for Dev Container
if: steps.cache-cross.outputs.cache-hit != 'true'
run: sudo apt update
- name: Install GCC Dependencies
if: steps.cache-cross.outputs.cache-hit != 'true'
run: sudo apt --no-install-recommends -y install build-essential bison flex libgmp3-dev libmpc-dev libmpfr-dev texinfo libzstd-dev libisl-dev m4 automake gettext gperf dejagnu guile-3.0 guile-3.0-dev expect tcl autogen tex-common sphinx-common git ssh diffutils patch autoconf2.69 libtool wget dpkg
- name: Check autoconf
if: steps.cache-cross.outputs.cache-hit != 'true'
run: | run: |
if [ "$(autoconf --version | head -n 1 | awk '{print $NF}')" != "2.69" ]; then sudo mkdir -p /tmp/.X11-unix
echo "Autoconf version is not 2.69, performing additional steps..." sudo mkdir -p /run/user/1000/pulse
wget https://launchpad.net/ubuntu/+archive/primary/+files/autoconf_2.69-11.1_all.deb sudo touch /run/user/1000/pulse/native
sudo dpkg --force-all -i ./autoconf_2.69-11.1_all.deb
fi
- name: Check automake - name: Run make ci-setup in dev container
if: steps.cache-cross.outputs.cache-hit != 'true' if: steps.cache-cross.outputs.cache-hit != 'true'
run: | uses: devcontainers/ci@v0.3
if [ "$(automake --version | head -n 1 | awk '{print $NF}')" != "1.15.1" ]; then with:
echo "Automake version is not 1.15.1, performing additional steps..." push: never
wget https://ftp.gnu.org/gnu/automake/automake-1.15.1.tar.gz runCmd: |
tar -xzf automake-1.15.1.tar.gz /usr/bin/make ci-setup
cd automake-1.15.1
./configure
make
sudo make install
fi
- name: Clone All
if: steps.cache-cross.outputs.cache-hit != 'true'
run: make --quiet -C tools __clone_all_no_qemu
- name: Compile Binutils
if: steps.cache-cross.outputs.cache-hit != 'true'
run: make --quiet -C tools do_binutils
- name: Compile GCC
if: steps.cache-cross.outputs.cache-hit != 'true'
run: make --quiet -C tools do_gcc
- name: Clean Up
if: steps.cache-cross.outputs.cache-hit != 'true'
run: |
cd tools
rm -rf binutils-gdb gcc
analyze: analyze:
name: Analyze (${{ matrix.language }}) name: Analyze (${{ matrix.language }})
@ -145,47 +111,15 @@ jobs:
with: with:
category: "/language:${{matrix.language}}" category: "/language:${{matrix.language}}"
deploydoc: compile:
name: Deploy Documentation to GitHub Pages name: Build OS
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Update System
run: sudo apt update
- name: Install Doxygen
run: sudo apt --no-install-recommends -y install doxygen make
- name: Generate Documentation
run: make doxygen
- name: Copy GitHub Pages Website
run: cp -r tools/website/* doxygen-doc/
- name: Deploy documentation
uses: JamesIves/github-pages-deploy-action@v4
with:
folder: doxygen-doc
compile_amd64:
name: Build amd64
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [buildcompiler] needs: [buildcompiler]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
fetch-depth: 0
- name: Update & Install Required Packages
run: |
sudo apt update
sudo apt --no-install-recommends -y install rustc xorriso mtools genisoimage ovmf nasm doxygen make meson gcc-10 g++-10 gcc-mingw-w64-x86-64 gcc-mingw-w64-i686 mingw-w64
make --quiet -C tools do_limine
make --quiet prepare
- name: Cache cross Folder - name: Cache cross Folder
id: cache-cross id: cache-cross
@ -194,167 +128,98 @@ jobs:
path: tools/cross path: tools/cross
key: ${{ runner.os }}-cross-${{ hashFiles('tools/Makefile') }} key: ${{ runner.os }}-cross-${{ hashFiles('tools/Makefile') }}
- name: Configure config.mk - name: Prepare Environment for Dev Container
run: sed -i 's/.*OSARCH = .*/OSARCH = amd64/' ./config.mk && cat config.mk | grep OSARCH
- name: Compile Debug and Release ISO
run: | run: |
make build sudo mkdir -p /tmp/.X11-unix
mv Fennix.iso Fennix-debug.iso sudo mkdir -p /run/user/1000/pulse
make clean sudo touch /run/user/1000/pulse/native
sed -i 's/.*DEBUG = .*/DEBUG = 0/' ./config.mk && cat config.mk | grep DEBUG
make build
mv Fennix.iso Fennix-release.iso
- name: Upload Artifact (Fennix-debug.iso) - name: Build AMD64 Debug
if: always()
uses: devcontainers/ci@v0.3
with:
push: never
runCmd: /usr/bin/make __ci-amd64-debug
- name: Build AMD64 Release
if: always()
uses: devcontainers/ci@v0.3
with:
push: never
runCmd: /usr/bin/make __ci-amd64-release
- name: Build i386 Debug
if: always()
uses: devcontainers/ci@v0.3
with:
push: never
runCmd: /usr/bin/make __ci-i386-debug
- name: Build i386 Release
if: always()
uses: devcontainers/ci@v0.3
with:
push: never
runCmd: /usr/bin/make __ci-i386-release
- name: Build ARM Debug
if: always()
uses: devcontainers/ci@v0.3
with:
push: never
runCmd: /usr/bin/make __ci-arm-debug
- name: Build ARM Release
if: always()
uses: devcontainers/ci@v0.3
with:
push: never
runCmd: /usr/bin/make __ci-arm-release
- name: Build AArch64 Debug
if: always()
uses: devcontainers/ci@v0.3
with:
push: never
runCmd: /usr/bin/make __ci-aarch64-debug
- name: Build AArch64 Release
if: always()
uses: devcontainers/ci@v0.3
with:
push: never
runCmd: /usr/bin/make __ci-aarch64-release
- name: Build Prepare Archive
if: always()
uses: devcontainers/ci@v0.3
with:
push: never
runCmd: /usr/bin/make __ci-prepare-archive
- name: Upload Artifact
if: always()
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: Fennix-amd64-debug name: artifacts
path: Fennix-debug.iso path: artifacts/
- name: Upload Artifact (Fennix-release.iso) nightly:
uses: actions/upload-artifact@v4 if: always()
with: name: Upload Nightly Build to GitHub Releases
name: Fennix-amd64-release
path: Fennix-release.iso
compile_i386:
name: Build i386
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [buildcompiler] needs: [compile]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
fetch-depth: 0
- name: Update & Install Required Packages - name: Download All Builds
run: | uses: actions/download-artifact@v4
sudo apt update
sudo apt --no-install-recommends -y install rustc xorriso mtools genisoimage ovmf nasm doxygen make meson gcc-10 g++-10 gcc-mingw-w64-x86-64 gcc-mingw-w64-i686 mingw-w64
make --quiet -C tools do_limine
make --quiet prepare
- name: Cache cross Folder - name: Update Nightly
id: cache-cross run: gh release upload nightly artifacts/* -R ${{github.repository}} --clobber
uses: actions/cache@v4
with:
path: tools/cross
key: ${{ runner.os }}-cross-${{ hashFiles('tools/Makefile') }}
- name: Configure config.mk env:
run: sed -i 's/.*OSARCH = .*/OSARCH = i386/' ./config.mk && cat config.mk | grep OSARCH GH_TOKEN: ${{ github.token }}
- name: Compile Debug and Release ISO
run: |
make build
mv Fennix.iso Fennix-debug.iso
make clean
sed -i 's/.*DEBUG = .*/DEBUG = 0/' ./config.mk && cat config.mk | grep DEBUG
make build
mv Fennix.iso Fennix-release.iso
- name: Upload Artifact (Fennix-debug.iso)
uses: actions/upload-artifact@v4
with:
name: Fennix-i386-debug
path: Fennix-debug.iso
- name: Upload Artifact (Fennix-release.iso)
uses: actions/upload-artifact@v4
with:
name: Fennix-i386-release
path: Fennix-release.iso
compile_aarch64:
name: Build aarch64
runs-on: ubuntu-latest
needs: [buildcompiler]
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Update & Install Required Packages
run: |
sudo apt update
sudo apt --no-install-recommends -y install rustc xorriso mtools genisoimage ovmf nasm doxygen make meson gcc-10 g++-10 gcc-mingw-w64-x86-64 gcc-mingw-w64-i686 mingw-w64
make --quiet -C tools do_limine
make --quiet prepare
- name: Cache cross Folder
id: cache-cross
uses: actions/cache@v4
with:
path: tools/cross
key: ${{ runner.os }}-cross-${{ hashFiles('tools/Makefile') }}
- name: Configure config.mk
run: sed -i 's/.*OSARCH = .*/OSARCH = aarch64/' ./config.mk && cat config.mk | grep OSARCH
- name: Compile Debug and Release ISO
run: |
make build
mv Fennix.iso Fennix-debug.iso
make clean
sed -i 's/.*DEBUG = .*/DEBUG = 0/' ./config.mk && cat config.mk | grep DEBUG
make build
mv Fennix.iso Fennix-release.iso
- name: Upload Artifact (Fennix-debug.iso)
uses: actions/upload-artifact@v4
with:
name: Fennix-aarch64-debug
path: Fennix-debug.iso
- name: Upload Artifact (Fennix-release.iso)
uses: actions/upload-artifact@v4
with:
name: Fennix-aarch64-release
path: Fennix-release.iso
compile_arm:
name: Build arm
runs-on: ubuntu-latest
needs: [buildcompiler]
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Update & Install Required Packages
run: |
sudo apt update
sudo apt --no-install-recommends -y install rustc xorriso mtools genisoimage ovmf nasm doxygen make meson gcc-10 g++-10 gcc-mingw-w64-x86-64 gcc-mingw-w64-i686 mingw-w64
make --quiet -C tools do_limine
make --quiet prepare
- name: Cache cross Folder
id: cache-cross
uses: actions/cache@v4
with:
path: tools/cross
key: ${{ runner.os }}-cross-${{ hashFiles('tools/Makefile') }}
- name: Configure config.mk
run: sed -i 's/.*OSARCH = .*/OSARCH = arm/' ./config.mk && cat config.mk | grep OSARCH
- name: Compile Debug and Release ISO
run: |
make build
mv Fennix.iso Fennix-debug.iso
make clean
sed -i 's/.*DEBUG = .*/DEBUG = 0/' ./config.mk && cat config.mk | grep DEBUG
make build
mv Fennix.iso Fennix-release.iso
- name: Upload Artifact (Fennix-debug.iso)
uses: actions/upload-artifact@v4
with:
name: Fennix-arm-debug
path: Fennix-debug.iso
- name: Upload Artifact (Fennix-release.iso)
uses: actions/upload-artifact@v4
with:
name: Fennix-arm-release
path: Fennix-release.iso

33
.github/workflows/website.yml vendored Normal file
View File

@ -0,0 +1,33 @@
name: Deploy Website
on:
push:
branches: [ master ]
paths:
- tools/website/**
- Kernel/include/interface/**
- Doxyfile
jobs:
deploydoc:
name: Deploy Website to GitHub Pages
runs-on: ubuntu-latest
steps:
- name: Checkout code 🛎️
uses: actions/checkout@v4
- name: Install Doxygen 📦
run: |
sudo apt update
sudo apt --no-install-recommends -y install doxygen make
- name: Generate Documentation 📚
run: make doxygen
- name: Copy GitHub Pages Website 📁
run: cp -r tools/website/* doxygen-doc/
- name: Deploy documentation 🚀
uses: JamesIves/github-pages-deploy-action@v4
with:
folder: doxygen-doc

9
.gitignore vendored
View File

@ -1,9 +1,10 @@
iso_tmp_data iso_tmp_data
initrd_tmp_data artifacts
initrd/usr/include/* tmp_rootfs
!initrd/usr/include/.gitkeep rootfs/usr/include/*
!rootfs/usr/include/.gitkeep
doxygen-doc doxygen-doc
initrd.tar rootfs.tar.gz
.dccache .dccache
*.log *.log
*.log.* *.log.*

46
.vscode/launch.json vendored
View File

@ -19,15 +19,20 @@
"description": "Make breakpoint pending on future shared library load." "description": "Make breakpoint pending on future shared library load."
}, },
{ {
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest", "text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/utest",
"description": "Load /bin/utest", "description": "/bin/utest (0x00400000)",
"ignoreFailures": true
},
{
"text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/libc_test",
"description": "/bin/libc_test (0x00600000)",
"ignoreFailures": true "ignoreFailures": true
}, },
{ {
"text": "source ${workspaceFolder}/../tools/.gdbinit" "text": "source ${workspaceFolder}/../tools/.gdbinit"
} }
], ],
"preLaunchTask": "launch-qemu" "preLaunchTask": "QEMU"
}, },
{ {
"name": "Debug Kernel (x86)", "name": "Debug Kernel (x86)",
@ -47,15 +52,20 @@
"description": "Make breakpoint pending on future shared library load." "description": "Make breakpoint pending on future shared library load."
}, },
{ {
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest", "text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/utest",
"description": "Load /bin/utest", "description": "/bin/utest (0x00400000)",
"ignoreFailures": true
},
{
"text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/libc_test",
"description": "/bin/libc_test (0x00600000)",
"ignoreFailures": true "ignoreFailures": true
}, },
{ {
"text": "source ${workspaceFolder}/../tools/.gdbinit" "text": "source ${workspaceFolder}/../tools/.gdbinit"
} }
], ],
"preLaunchTask": "launch-qemu" "preLaunchTask": "QEMU"
}, },
{ {
"name": "Debug Kernel (arm64)", "name": "Debug Kernel (arm64)",
@ -75,15 +85,20 @@
"description": "Make breakpoint pending on future shared library load." "description": "Make breakpoint pending on future shared library load."
}, },
{ {
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest", "text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/utest",
"description": "Load /bin/utest", "description": "/bin/utest (0x00400000)",
"ignoreFailures": true
},
{
"text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/libc_test",
"description": "/bin/libc_test (0x00600000)",
"ignoreFailures": true "ignoreFailures": true
}, },
{ {
"text": "source ${workspaceFolder}/../tools/.gdbinit" "text": "source ${workspaceFolder}/../tools/.gdbinit"
} }
], ],
"preLaunchTask": "launch-qemu" "preLaunchTask": "QEMU"
}, },
{ {
"name": "Debug Kernel (arm)", "name": "Debug Kernel (arm)",
@ -103,15 +118,20 @@
"description": "Make breakpoint pending on future shared library load." "description": "Make breakpoint pending on future shared library load."
}, },
{ {
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest", "text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/utest",
"description": "Load /bin/utest", "description": "/bin/utest (0x00400000)",
"ignoreFailures": true
},
{
"text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/libc_test",
"description": "/bin/libc_test (0x00600000)",
"ignoreFailures": true "ignoreFailures": true
}, },
{ {
"text": "source ${workspaceFolder}/../tools/.gdbinit" "text": "source ${workspaceFolder}/../tools/.gdbinit"
} }
], ],
"preLaunchTask": "launch-qemu" "preLaunchTask": "QEMU"
}, },
{ {
"type": "gdb", "type": "gdb",
@ -129,7 +149,7 @@
], ],
"internalConsoleOptions": "neverOpen", "internalConsoleOptions": "neverOpen",
"printCalls": false, "printCalls": false,
"preLaunchTask": "launch-qemu" "preLaunchTask": "QEMU"
}, },
] ]
} }

View File

@ -16,5 +16,6 @@
"**/tools/qemu/**": true, "**/tools/qemu/**": true,
"**/tools/cross/**": true, "**/tools/cross/**": true,
"**/doxygen-doc/**": true, "**/doxygen-doc/**": true,
} },
"cmake.ignoreCMakeListsMissing": true
} }

478
.vscode/tasks.json vendored
View File

@ -2,13 +2,240 @@
"version": "2.0.0", "version": "2.0.0",
"tasks": [ "tasks": [
{ {
"label": "launch-qemu", "label": "Clean",
"type": "shell", "type": "shell",
"command": "make -C ../ build && make -C ../ vscode_debug_only", "command": "make clean",
"isBackground": true, "isBackground": false,
"problemMatcher": [], "hide": false,
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "never",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}/../",
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "Build",
"type": "shell",
"command": "make build",
"isBackground": false,
"hide": false,
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}/../",
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "Run",
"type": "shell",
"command": "make qemu",
"isBackground": false,
"hide": false,
"dependsOn": [
"Build"
],
"group": {
"kind": "test",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}/../",
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "Build Bootloader",
"type": "shell",
"command": "make -C ../ build_bootloader",
"isBackground": false,
"hide": true,
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "Build Kernel",
"type": "shell",
"command": "make -C ../ build_kernel",
"isBackground": false,
"hide": true,
"dependsOn": [
"Build Bootloader"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "Build Drivers",
"type": "shell",
"command": "make -C ../ build_drivers",
"isBackground": false,
"hide": true,
"dependsOn": [
"Build Kernel"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "Build Userspace",
"type": "shell",
"command": "make -C ../ build_userspace",
"isBackground": false,
"hide": true,
"dependsOn": [
"Build Drivers"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "Build Image",
"type": "shell",
"command": "make -C ../ build_image",
"isBackground": false,
"hide": true,
"dependsOn": [
"Build Userspace"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "QEMU",
"type": "shell",
"command": "make",
"args": [
"-C",
"../",
"vscode_debug_only"
],
"isBackground": true,
// "problemMatcher": "$tsc-watch",
"problemMatcher": [
{
"pattern": [
{
"regexp": ".",
"file": 1,
"location": 2,
"message": 3
}
],
"background": {
"activeOnStart": true,
"beginsPattern": ".",
"endsPattern": "CPU Reset",
}
}
],
"dependsOn": [
"Build Image"
],
"group": {
"kind": "test",
"isDefault": true "isDefault": true
}, },
"presentation": { "presentation": {
@ -23,6 +250,249 @@
] ]
} }
} }
},
{
"label": "CI AMD64 Debug",
"type": "shell",
"command": "make __ci-amd64-debug",
"isBackground": false,
"hide": true,
"dependsOn": [
"Clean"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}/../",
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "CI AMD64 Release",
"type": "shell",
"command": "make __ci-amd64-release",
"isBackground": false,
"hide": true,
"dependsOn": [
"CI AMD64 Debug"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}/../",
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "CI i386 Debug",
"type": "shell",
"command": "make __ci-i386-debug",
"isBackground": false,
"hide": true,
"dependsOn": [
"CI AMD64 Release"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}/../",
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "CI i386 Release",
"type": "shell",
"command": "make __ci-i386-release",
"isBackground": false,
"hide": true,
"dependsOn": [
"CI i386 Debug"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}/../",
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "CI ARM Debug",
"type": "shell",
"command": "make __ci-arm-debug",
"isBackground": false,
"hide": true,
"dependsOn": [
"CI i386 Release"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}/../",
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "CI ARM Release",
"type": "shell",
"command": "make __ci-arm-release",
"isBackground": false,
"hide": true,
"dependsOn": [
"CI ARM Debug"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}/../",
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "CI AARCH64 Debug",
"type": "shell",
"command": "make __ci-aarch64-debug",
"isBackground": false,
"hide": true,
"dependsOn": [
"CI ARM Release"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}/../",
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "CI AARCH64 Release",
"type": "shell",
"command": "make __ci-aarch64-release",
"isBackground": false,
"hide": true,
"dependsOn": [
"CI AARCH64 Debug"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}/../",
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
},
{
"label": "Test CI Build",
"type": "shell",
"command": "make __ci-restore-config",
"isBackground": false,
"dependsOn": [
"CI AARCH64 Release",
"clean"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}/../",
"shell": {
"executable": "bash",
"args": [
"-c"
]
}
}
} }
] ]
} }

1883
CHANGELOG.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -62,6 +62,8 @@ Follow the coding style used in the repository to ensure consistency. Adhere to:
- Start function and global declaration names with an uppercase letter. - Start function and global declaration names with an uppercase letter.
- Start local variable names with a lowercase letter. - Start local variable names with a lowercase letter.
- Maintain consistent formatting and commenting guidelines. - Maintain consistent formatting and commenting guidelines.
- Commit messages must follow [Conventional Commits](https://conventionalcommits.org).
- Release versions must follow [Semantic Versioning](https://semver.org).
Refer to the [style guide document](STYLE_GUIDE.md) if available. Refer to the [style guide document](STYLE_GUIDE.md) if available.

View File

@ -27,6 +27,9 @@ License information can be found in the [LICENSES.md](LICENSES.md) file.
## CPUID 0x7 ## CPUID 0x7
- [CPUID](https://en.wikipedia.org/wiki/CPUID) - [CPUID](https://en.wikipedia.org/wiki/CPUID)
## KVM CPUID
- [kernel.org KVM CPUID](https://www.kernel.org/doc/html/v6.9/virt/kvm/x86/cpuid.html?highlight=cpuid)
## Network ## Network
- [Beej's Guide to Network Programming](https://web.archive.org/web/20051210132103/http://users.pcnet.ro/dmoroian/beej/Beej.html) - [Beej's Guide to Network Programming](https://web.archive.org/web/20051210132103/http://users.pcnet.ro/dmoroian/beej/Beej.html)
- [UDP Socket Programming](https://web.archive.org/web/20060229214053/http://www.cs.rutgers.edu/~pxk/417/notes/sockets/udp.html) - [UDP Socket Programming](https://web.archive.org/web/20060229214053/http://www.cs.rutgers.edu/~pxk/417/notes/sockets/udp.html)
@ -120,6 +123,18 @@ License information can be found in the [LICENSES.md](LICENSES.md) file.
## UART ## UART
- [Interfacing the Serial / RS232 Port V5.0](http://www.senet.com.au/~cpeacock) - [Interfacing the Serial / RS232 Port V5.0](http://www.senet.com.au/~cpeacock)
## UEFI
- [U-Boot EFI Commands](https://docs.u-boot.org/en/latest/usage/cmd/efi.html)
- [UEFI Specification 2.10](https://uefi.org/sites/default/files/resources/UEFI_Spec_2_10_Aug29.pdf)
- [UEFI Boot Process Overview](https://gist.github.com/Velocet/d394281d96191e235ff46a8aa2018d80)
- [Rust OS Development: UEFI](https://blog.malware.re/2023/09/01/rust-os-part2/index.html)
- [GUIDs Database](https://github.com/DSecurity/efiSeek/blob/master/data/guids-db.ini)
## BGRT
- [BGRT on OSDev](https://wiki.osdev.org/BGRT)
- [BMP File Structure @ Gdansk University of Technology](http://www.ue.eti.pg.gda.pl/fpgalab/zadania.spartan3/zad_vga_struktura_pliku_bmp_en.html)
- [BGRT @ Purdue University](https://engineering.purdue.edu/ece264/16au/hw/HW13)
--- ---
Special thanks to all contributors and the creators of the referenced projects and resources! Special thanks to all contributors and the creators of the referenced projects and resources!

View File

@ -43,30 +43,47 @@ endif
export DRIVER_LDFLAGS export DRIVER_LDFLAGS
export DRIVER_CFLAGS export DRIVER_CFLAGS
copy_driver_signatures:
@TMP_FILE="$(OUTPUT_DIR)../../Kernel/drivers/trusted.c.tmp"; \
OUT_FILE="$(OUTPUT_DIR)../../Kernel/drivers/trusted.c"; \
mkdir -p $(OUTPUT_DIR)../../Kernel/drivers/; \
echo "const char *trusted_drivers[] = {" > $$TMP_FILE; \
find $(OUTPUT_DIR) -name "*.drv" -exec sha512sum {} \; | awk '{gsub(/.*\//, "", $$2); gsub(/\./, "_", $$2); sub(/_drv$$/, "_drv", $$2); print "\"" $$1 "\"," }' >> $$TMP_FILE; \
echo "};" >> $$TMP_FILE; \
echo "const __SIZE_TYPE__ trusted_drivers_count = sizeof(trusted_drivers) / sizeof(trusted_drivers[0]);" >> $$TMP_FILE; \
if [ ! -f $$OUT_FILE ] || ! cmp -s $$TMP_FILE $$OUT_FILE; then \
mv $$TMP_FILE $$OUT_FILE; \
printf '\033[0;32m[trusted.c updated]\033[0m\n'; \
else \
rm $$TMP_FILE; \
printf '\033[0;33m[trusted.c unchanged]\033[0m\n'; \
fi
build: build:
cp -rf ../Kernel/include/interface/* include/ cp -rf ../Kernel/include/interface/* include/
mkdir -p out mkdir -p out
make -C library build $(MAKE) -C library build
ifneq ($(filter amd64 i386,$(OSARCH)),) ifneq ($(filter amd64 i386,$(OSARCH)),)
make -C audio build $(MAKE) -C audio build
make -C input build $(MAKE) -C input build
make -C misc build $(MAKE) -C misc build
make -C network build $(MAKE) -C network build
make -C storage build $(MAKE) -C storage build
make -C filesystem build $(MAKE) -C filesystem build
endif endif
$(MAKE) copy_driver_signatures
prepare: prepare:
$(info Nothing to prepare) $(info Nothing to prepare)
clean: clean:
rm -rf out rm -rf out
make -C library clean $(MAKE) -C library clean
ifneq ($(filter amd64 i386,$(OSARCH)),) ifneq ($(filter amd64 i386,$(OSARCH)),)
make -C audio clean $(MAKE) -C audio clean
make -C input clean $(MAKE) -C input clean
make -C misc clean $(MAKE) -C misc clean
make -C network clean $(MAKE) -C network clean
make -C storage clean $(MAKE) -C storage clean
make -C filesystem clean $(MAKE) -C filesystem clean
endif endif

View File

@ -1,35 +0,0 @@
default:
$(error Do not run this Makefile directly!)
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
FILENAME = $(notdir $(shell pwd)).drv
build: $(FILENAME)
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
WARNCFLAG = -Wall -Wextra
%.o: %.c $(HEADERS)
$(info Compiling $<)
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
%.o: %.S
$(info Compiling $<)
$(AS) -o $@ $<
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

View File

@ -1,881 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <audio.h>
#include <regs.h>
#include <base.h>
#include <pci.h>
#include <io.h>
#include <fs.h>
#define DescriptorListLength 0x20
enum AudioVolumeValues
{
AV_Maximum = 0x0,
AV_Minimum = 0x3F,
};
enum AudioEncodingValues
{
AE_PCMs8,
AE_PCMu8,
AE_PCMs16le,
AE_PCMs20le,
AE_PCMs24le,
AE_PCMs32le,
AE_PCMu16le,
AE_PCMu20le,
AE_PCMu24le,
AE_PCMu32le,
AE_PCMs16be,
AE_PCMs20be,
AE_PCMs24be,
AE_PCMs32be,
AE_PCMu16be,
AE_PCMu20be,
AE_PCMu24be,
AE_PCMu32be,
};
enum NativeAudioMixerRegisters
{
/**
* @brief Reset Register
* @note Length: word
*/
NAM_Reset = 0x00,
/**
* @brief Master Volume Register
* @note Length: word
*/
NAM_MasterVolume = 0x02,
/**
* @brief Microphone Volume Register
* @note Length: word
*/
NAM_MicrophoneVolume = 0x0E,
/**
* @brief PCM Out Volume Register
* @note Length: word
*/
NAM_PCMOutVolume = 0x18,
/**
* @brief Select Record Input Register
* @note Length: word
*/
NAM_SelectRecordInput = 0x1A,
/**
* @brief Record Gain Register
* @note Length: word
*/
NAM_RecordGain = 0x1C,
/**
* @brief Record Gain Microphone Register
* @note Length: word
*/
NAM_RecordGainMicrophone = 0x1E,
};
enum NativeAudioBusMasterRegisters
{
/**
* @brief Register box for PCM IN
* @note Length: below
*/
NABM_PCMInBox = 0x00,
/**
* @brief Register box for PCM OUT
* @note Length: below
*/
NABM_PCMOutBox = 0x10,
/**
* @brief Register box for Microphone
* @note Length: below
*/
NABM_MicrophoneBox = 0x20,
/**
* @brief Global Control Register
* @note Length: dword
*/
NABM_GlobalControl = 0x2C, /* 0x30 */
/**
* @brief Global Status Register
* @note Length: dword
*/
NABM_GlobalStatus = 0x30, /* 0x34 */
};
enum NativeAudioBusMasterBoxOffsets
{
/**
* @brief Physical Address of Buffer Descriptor List
* @note Length: dword
*/
NABMBOFF_BufferDescriptorList = 0x00,
/**
* @brief Number of Actual Processed Buffer Descriptor Entry
* @note Length: byte
*/
NABMBOFF_BufferDescriptorEntry = 0x04,
/**
* @brief Number of all Descriptor Entries
* @note Length: byte
*/
NABMBOFF_DescriptorEntries = 0x05,
/**
* @brief Status of transferring Data
* @note Length: word
*/
NABMBOFF_Status = 0x06,
/**
* @brief Number of transferred Samples in Actual Processed Entry
* @note Length: word
*/
NABMBOFF_TransferredSamples = 0x08,
/**
* @brief Number of next processed Buffer Entry
* @note Length: byte
*/
NABMBOFF_NextProcessedBufferEntry = 0x0A,
/**
* @brief Transfer Control
* @note Length: byte
*/
NABMBOFF_TransferControl = 0x0B,
};
enum OutputPulseCodeModulationRegisters
{
/**
* @brief Physical Address of Buffer Descriptor List
* @note Length: dword
*/
PCMOUT_BufferDescriptorList = (int)NABM_PCMOutBox + (int)NABMBOFF_BufferDescriptorList,
/**
* @brief Number of Actual Processed Buffer Descriptor Entry
* @note Length: byte
*/
PCMOUT_BufferDescriptorEntry = (int)NABM_PCMOutBox + (int)NABMBOFF_BufferDescriptorEntry,
/**
* @brief Number of all Descriptor Entries
* @note Length: byte
*/
PCMOUT_DescriptorEntries = (int)NABM_PCMOutBox + (int)NABMBOFF_DescriptorEntries,
/**
* @brief Status of transferring Data
* @note Length: word
*/
PCMOUT_Status = (int)NABM_PCMOutBox + (int)NABMBOFF_Status,
/**
* @brief Number of transferred Samples in Actual Processed Entry
* @note Length: word
*/
PCMOUT_TransferredSamples = (int)NABM_PCMOutBox + (int)NABMBOFF_TransferredSamples,
/**
* @brief Number of next processed Buffer Entry
* @note Length: byte
*/
PCMOUT_NextProcessedBufferEntry = (int)NABM_PCMOutBox + (int)NABMBOFF_NextProcessedBufferEntry,
/**
* @brief Transfer Control
* @note Length: byte
*/
PCMOUT_TransferControl = (int)NABM_PCMOutBox + (int)NABMBOFF_TransferControl,
};
enum TransferControlRegisters
{
/**
* @brief DMA controller control
*
* 0 = Pause transfer
* 1 = Transfer sound data
*/
TC_DMAControllerControl = 0x01,
/**
* @brief Reset
*
* 0 = Remove reset condition
* 1 = Reset this NABM register box, this bit is cleared by card when is reset complete
*/
TC_TransferReset = 0x02,
/**
* @brief Last Buffer Entry Interrupt enable
*
* 0 = Disable interrupt
* 1 = Enable interrupt
*/
TC_LastBufferEntryInterruptEnable = 0x04,
/**
* @brief IOC Interrupt enable
*
* 0 = Disable interrupt
* 1 = Enable interrupt
*/
TC_IOCInterruptEnable = 0x08,
/**
* @brief Fifo ERROR Interrupt enable
*
* 0 = Disable interrupt
* 1 = Enable interrupt
*/
TC_FifoERRORInterruptEnable = 0x10,
};
enum GlobalControlRegisters
{
/**
* @brief Global Interrupt Enable
*
* 0 = Disable Interrupts
* 1 = Enable Interrupts
*/
GC_GlobalInterruptEnable = 0x01,
/**
* @brief Cold reset
*
* 0 = Device is in reset and can not be used
* 1 = Resume to operational state
*/
GC_ColdReset = 0x02,
/**
* @brief Warm reset
*/
GC_WarmReset = 0x04,
/**
* @brief Shut down
*
* 0 = Device is powered
* 1 = Shut down
*/
GC_ShutDown = 0x08,
/**
* @brief Channels for PCM Output
*
* 00 = 2 channels
* 01 = 4 channels
* 10 = 6 channels
* 11 = Reserved
*/
GC_ChannelsForPCMOutput = 0x30,
/**
* @brief PCM Output mode
*
* 00 = 16 bit samples
* 01 = 20 bit samples
*/
GC_PCMOutputMode = 0xC0,
};
struct BufferDescriptorList
{
/**
* @brief Physical Address to sound data in memory
* @note Length: dword
*/
uint32_t Address;
/**
* @brief Number of samples in this buffer
* @note Length: word
*/
uint16_t SampleCount;
/**
* @brief Flags
* @note Length: word
*
* Bit 15 = Interrupt fired when data from this entry is transferred
* Bit 14 = Last entry of buffer, stop playing
* Other bits = Reserved
*/
uint16_t Flags;
} __attribute__((packed));
uint16_t MixerVolume(uint8_t Left, uint8_t Right, bool Mute)
{
return ((uint16_t)((Right & 0x3F) |
((Left & 0x3F) << 0x8) |
(Mute & 1 << 0xF)));
}
class AC97Device
{
private:
PCIHeader0 *Header;
BufferDescriptorList *DescriptorList = nullptr;
uint16_t MixerAddress;
uint16_t BusMasterAddress;
AudioEncodingValues Encoding = AE_PCMs16le;
char Channels = 2;
uint8_t Volume = AV_Maximum;
bool Mute = false;
int SampleRate = 48000;
char SampleSize = 2;
public:
size_t write(uint8_t *Buffer, size_t Size)
{
if (Buffer == nullptr)
{
KernelLog("Invalid buffer.");
return -EINVAL;
}
if ((Size == 0) || (Size % (SampleSize * Channels)))
{
KernelLog("Invalid buffer length.");
return -EINVAL;
}
int TotalBDLToFill = (int)((Size + PAGE_SIZE - 1) >> 12);
while (Size > 0)
{
bool ActiveDMA = !(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl);
if (ActiveDMA)
{
int RemainingBDL = 0;
do
{
int CurrentBDL = inb(BusMasterAddress + PCMOUT_BufferDescriptorEntry);
int LastBDL = inb(BusMasterAddress + PCMOUT_DescriptorEntries);
RemainingBDL = LastBDL - CurrentBDL;
if (RemainingBDL < 0)
RemainingBDL += DescriptorListLength;
RemainingBDL += 1;
if (RemainingBDL >= DescriptorListLength - 1)
{
long SampleCount = DescriptorList[(CurrentBDL + 1) % DescriptorListLength].SampleCount / Channels;
if (SampleCount > 0)
Sleep(SampleCount * 1000 / SampleRate);
}
} while (RemainingBDL >= DescriptorListLength - 1 &&
!(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl));
}
uint8_t CurrentBDL = inb(BusMasterAddress + PCMOUT_BufferDescriptorEntry);
uint8_t LastBDL = inb(BusMasterAddress + PCMOUT_DescriptorEntries);
uint8_t NextBDL = LastBDL % DescriptorListLength;
ActiveDMA = !(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl);
if (ActiveDMA)
{
NextBDL = (uint8_t)((LastBDL + 1) % DescriptorListLength);
if (NextBDL == CurrentBDL)
continue;
}
do
{
size_t Wrote = (PAGE_SIZE > Size) ? size_t(Size)
: size_t(PAGE_SIZE);
if (Wrote == 0)
{
KernelLog("Wrote 0 bytes.");
break;
}
memcpy((void *)((uint64_t)DescriptorList[NextBDL].Address), Buffer, Wrote);
DescriptorList[NextBDL].Flags = 0;
Buffer += Wrote;
Size -= (unsigned int)Wrote;
DescriptorList[NextBDL].SampleCount = uint16_t(Wrote / SampleSize);
TotalBDLToFill--;
NextBDL = (uint8_t)((NextBDL + 1) % DescriptorListLength);
} while (TotalBDLToFill-- && NextBDL != CurrentBDL);
outb(BusMasterAddress + PCMOUT_DescriptorEntries, NextBDL - 1);
ActiveDMA = !(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl);
if (!ActiveDMA)
{
// Start DMA
outb(BusMasterAddress + PCMOUT_TransferControl,
inb(BusMasterAddress + PCMOUT_TransferControl) | TC_DMAControllerControl);
}
}
return Size;
}
int ioctl(AudioIoctl, void *)
{
// if (Data->AudioCallback.Adjust._Volume)
// {
// Volume = (uint8_t)(0x3F - (0x3F * Data->AudioCallback.Adjust.Volume / 100));
// outw(BAR.MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute));
// // outw(BAR.MixerAddress + NAM_PCMOutVolume, MixerVolume(Volume, Volume, Mute));
// }
// else if (Data->AudioCallback.Adjust._Encoding)
// {
// fixme("Encoding changing not supported yet.");
// }
// else if (Data->AudioCallback.Adjust._SampleRate)
// {
// switch (Data->AudioCallback.Adjust.SampleRate)
// {
// case 0:
// {
// SampleRate = 8000;
// break;
// }
// case 1:
// {
// SampleRate = 11025;
// break;
// }
// case 2:
// {
// SampleRate = 16000;
// break;
// }
// case 3:
// {
// SampleRate = 22050;
// break;
// }
// case 4:
// {
// SampleRate = 32000;
// break;
// }
// case 5:
// {
// SampleRate = 44100;
// break;
// }
// case 6:
// {
// SampleRate = 48000;
// break;
// }
// case 7:
// {
// SampleRate = 88200;
// break;
// }
// case 8:
// {
// SampleRate = 96000;
// break;
// }
// default:
// {
// SampleRate = 16000;
// error("Invalid sample rate. Defaulting to 16000.");
// break;
// }
// }
// }
// else if (Data->AudioCallback.Adjust._Channels)
// {
// switch (Data->AudioCallback.Adjust.Channels)
// {
// case 0:
// {
// Channels = 1; // Mono
// break;
// }
// case 1:
// {
// Channels = 2; // Stereo
// break;
// }
// default:
// {
// Channels = 2;
// error("Invalid channel count. Defaulting to 2.");
// break;
// }
// }
// }
return 0;
}
void OnInterruptReceived(TrapFrame *)
{
uint16_t Status = inw(MixerAddress + PCMOUT_Status);
if (Status & TC_IOCInterruptEnable)
{
DebugLog("IOC");
outw(MixerAddress + PCMOUT_Status, TC_IOCInterruptEnable);
uint16_t CurrentBDL = inb(BusMasterAddress + PCMOUT_BufferDescriptorEntry);
uint16_t LastBDL = (CurrentBDL + 2) & (DescriptorListLength - 1);
outb(BusMasterAddress + PCMOUT_DescriptorEntries, LastBDL);
KernelLog("FIXME: CurrentBDL: %d, LastBDL: %d", CurrentBDL, LastBDL);
}
else if (Status & TC_LastBufferEntryInterruptEnable)
{
DebugLog("Last buffer entry");
// Stop DMA
uint8_t TransferControl = inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl));
TransferControl &= ~TC_DMAControllerControl;
outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl), TransferControl);
outw(MixerAddress + PCMOUT_Status, TC_LastBufferEntryInterruptEnable);
}
else if (Status & TC_FifoERRORInterruptEnable)
{
KernelLog("FIFO error");
outw(MixerAddress + PCMOUT_Status, TC_FifoERRORInterruptEnable);
}
else
{
DebugLog("Unknown interrupt status %#x", Status);
outw(MixerAddress + PCMOUT_Status, 0xFFFF);
}
}
void Panic()
{
uint8_t TransferControl = inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl));
TransferControl &= ~(TC_LastBufferEntryInterruptEnable |
TC_IOCInterruptEnable |
TC_FifoERRORInterruptEnable);
outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl), TransferControl);
uint32_t GlobalControl = inl((uint16_t)(BusMasterAddress + NABM_GlobalControl));
GlobalControl &= ~GC_GlobalInterruptEnable;
GlobalControl |= GC_ShutDown;
outl((uint16_t)(BusMasterAddress + NABM_GlobalControl), GlobalControl);
}
AC97Device(PCIHeader0 *_Header)
: Header(_Header)
{
/* Native Audio Mixer Base Address */
uint32_t PCIBAR0 = Header->BAR0;
/* Native Audio Bus Master Base Address */
uint32_t PCIBAR1 = Header->BAR1;
// uint8_t Type = PCIBAR0 & 1;
MixerAddress = (uint16_t)(PCIBAR0 & (~3));
BusMasterAddress = PCIBAR1 & (~15);
uint16_t OutputPCMTransferControl = BusMasterAddress + PCMOUT_TransferControl;
/* DescriptorList address MUST be physical. */
DescriptorList = (BufferDescriptorList *)AllocateMemory(TO_PAGES(sizeof(BufferDescriptorList) * DescriptorListLength));
memset(DescriptorList, 0, sizeof(BufferDescriptorList) * DescriptorListLength);
uint16_t DLSampleCount = (uint16_t)(PAGE_SIZE / SampleSize);
for (int i = 0; i < DescriptorListLength; i++)
{
DescriptorList[i].Address = (uint32_t)(uintptr_t)AllocateMemory(TO_PAGES(sizeof(uint16_t *)));
DescriptorList[i].SampleCount = DLSampleCount;
DescriptorList[i].Flags = 0;
DebugLog("DescriptorList[%d] = { Address: %#lx, SampleCount: %d, Flags: %#lx }",
i,
DescriptorList[i].Address,
DescriptorList[i].SampleCount,
DescriptorList[i].Flags);
}
outw(MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute));
outw(MixerAddress + NAM_PCMOutVolume, MixerVolume(Volume, Volume, Mute));
Volume = 0x3F - (0x3F * /* VOL 50% */ 50 / 100);
outw(MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute));
outb(OutputPCMTransferControl, inb(OutputPCMTransferControl) | TC_TransferReset);
while (inb(OutputPCMTransferControl) & TC_TransferReset)
;
uint32_t GlobalControl = inl(BusMasterAddress + NABM_GlobalControl);
GlobalControl = (GlobalControl & ~((0x3U) << 0x16)); /* PCM 16-bit mode */
GlobalControl = (GlobalControl & ~((0x3U) << 20)); /* 2 channels */
GlobalControl |= GC_GlobalInterruptEnable;
GlobalControl &= ~GC_ShutDown;
outl(BusMasterAddress + PCMOUT_BufferDescriptorList,
(uint32_t)(uint64_t)DescriptorList);
outl(BusMasterAddress + NABM_GlobalControl, GlobalControl);
uint8_t TransferControl = inb(OutputPCMTransferControl);
TransferControl |= TC_IOCInterruptEnable |
TC_FifoERRORInterruptEnable;
outb(OutputPCMTransferControl, TransferControl);
// Stop DMA
outb(OutputPCMTransferControl, inb(OutputPCMTransferControl) & ~TC_DMAControllerControl);
}
~AC97Device()
{
outw(MixerAddress + NAM_MasterVolume, MixerVolume(AV_Maximum, AV_Maximum, true));
outw(MixerAddress + NAM_PCMOutVolume, MixerVolume(AV_Maximum, AV_Maximum, true));
// Stop DMA
outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl),
inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl)) & ~TC_DMAControllerControl);
// Disable interrupts
uint8_t TransferControl = inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl));
TransferControl &= ~(TC_LastBufferEntryInterruptEnable |
TC_IOCInterruptEnable |
TC_FifoERRORInterruptEnable);
outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl), TransferControl);
// Disable global control
uint32_t GlobalControl = inl((uint16_t)(BusMasterAddress + NABM_GlobalControl));
GlobalControl &= ~GC_GlobalInterruptEnable;
GlobalControl |= GC_ShutDown;
outl((uint16_t)(BusMasterAddress + NABM_GlobalControl), GlobalControl);
}
};
AC97Device *Drivers[4] = {nullptr};
dev_t AudioID[4] = {(dev_t)-1};
#define OIR(x) OIR_##x
#define CREATE_OIR(x) \
void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
CREATE_OIR(0);
CREATE_OIR(1);
CREATE_OIR(2);
CREATE_OIR(3);
int __fs_Open(struct Inode *, int, mode_t) { return 0; }
int __fs_Close(struct Inode *) { return 0; }
ssize_t __fs_Read(struct Inode *, void *, size_t, off_t) { return 0; }
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
{
return Drivers[AudioID[Node->GetMinor()]]->write((uint8_t *)Buffer, Size);
}
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
{
return Drivers[AudioID[Node->GetMinor()]]->ioctl((AudioIoctl)Request, Argp);
}
const struct InodeOperations AudioOps = {
.Lookup = nullptr,
.Create = nullptr,
.Remove = nullptr,
.Rename = nullptr,
.Read = __fs_Read,
.Write = __fs_Write,
.Truncate = nullptr,
.Open = __fs_Open,
.Close = __fs_Close,
.Ioctl = __fs_Ioctl,
.ReadDir = nullptr,
.MkDir = nullptr,
.RmDir = nullptr,
.SymLink = nullptr,
.ReadLink = nullptr,
.Seek = nullptr,
.Stat = nullptr,
};
PCIArray *Devices;
EXTERNC int cxx_Panic()
{
PCIArray *ctx = Devices;
short Count = 0;
while (ctx != nullptr)
{
if (Drivers[Count] != nullptr)
Drivers[Count]->Panic();
Count++;
ctx = (PCIArray *)ctx->Next;
}
return 0;
}
EXTERNC int cxx_Probe()
{
uint16_t VendorIDs[] = {0x8086, PCI_END};
uint16_t DeviceIDs[] = {0x2415, PCI_END};
Devices = GetPCIDevices(VendorIDs, DeviceIDs);
if (Devices == nullptr)
{
KernelLog("No AC'97 device found.");
return -ENODEV;
}
PCIArray *ctx = Devices;
bool Found = false;
size_t Count = 0;
while (ctx != nullptr)
{
if (Count++ > sizeof(Drivers) / sizeof(AC97Device *))
break;
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
uint8_t Type = PCIBAR0 & 1;
if (Type != 1)
{
KernelLog("Device %x:%x.%d BAR0 is not I/O.",
PCIBaseAddress->Header.VendorID,
PCIBaseAddress->Header.DeviceID,
PCIBaseAddress->Header.ProgIF);
continue;
}
Found = true;
ctx = (PCIArray *)ctx->Next;
}
if (!Found)
{
KernelLog("No valid AC'97 device found.");
return -EINVAL;
}
return 0;
}
EXTERNC int cxx_Initialize()
{
PCIArray *ctx = Devices;
size_t Count = 0;
while (ctx != nullptr)
{
if (Count > sizeof(Drivers) / sizeof(AC97Device *))
break;
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
uint8_t Type = PCIBAR0 & 1;
if (Type != 1)
{
KernelLog("Device %x:%x.%d BAR0 is not I/O.",
PCIBaseAddress->Header.VendorID,
PCIBaseAddress->Header.DeviceID,
PCIBaseAddress->Header.ProgIF);
continue;
}
InitializePCI(ctx->Device);
Drivers[Count] = new AC97Device((PCIHeader0 *)ctx->Device->Header);
/* FIXME: bad code */
switch (Count)
{
case 0:
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(0));
break;
case 1:
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(1));
break;
case 2:
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(2));
break;
case 3:
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(3));
break;
default:
break;
}
dev_t ret = RegisterDevice(AUDIO_TYPE_PCM, &AudioOps);
AudioID[Count] = ret;
Count++;
ctx = (PCIArray *)ctx->Next;
}
return 0;
}
EXTERNC int cxx_Finalize()
{
PCIArray *ctx = Devices;
size_t Count = 0;
while (ctx != nullptr)
{
if (Count++ > sizeof(Drivers) / sizeof(AC97Device *))
break;
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
uint8_t Type = PCIBAR0 & 1;
if (Type != 1)
{
KernelLog("Device %x:%x.%d BAR0 is not I/O.",
PCIBaseAddress->Header.VendorID,
PCIBaseAddress->Header.DeviceID,
PCIBaseAddress->Header.ProgIF);
continue;
}
delete Drivers[Count++];
ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
ctx = (PCIArray *)ctx->Next;
}
for (size_t i = 0; i < sizeof(AudioID) / sizeof(dev_t); i++)
{
if (AudioID[i] != (dev_t)-1)
UnregisterDevice(AudioID[i]);
}
return 0;
}

View File

@ -1,31 +0,0 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Drivers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include <base.h>
#include "ac97.hpp"
int DriverEntry() { return cxx_Initialize(); }
int DriverFinal() { return cxx_Finalize(); }
int DriverPanic() { return cxx_Panic(); }
int DriverProbe() { return cxx_Probe(); }
DriverInfo("ac97",
"Audio Codec '97 Driver",
"EnderIce2",
0, 0, 1,
"GPLv3");

View File

@ -1,35 +0,0 @@
default:
$(error Do not run this Makefile directly!)
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
FILENAME = $(notdir $(shell pwd)).drv
build: $(FILENAME)
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
WARNCFLAG = -Wall -Wextra
%.o: %.c $(HEADERS)
$(info Compiling $<)
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
%.o: %.S
$(info Compiling $<)
$(AS) -o $@ $<
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

View File

@ -1,263 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <audio.h>
#include <regs.h>
#include <base.h>
#include <pci.h>
#include <io.h>
#include <fs.h>
#include "hda.hpp"
class HDADevice
{
private:
PCIHeader0 *Header;
bool Initialized = false;
ControllerRegisters *CTL;
uint32_t *CORB;
uint64_t *RIRB;
public:
bool IsInitialized() { return Initialized; }
size_t write(uint8_t *, size_t Size)
{
return Size;
}
int ioctl(AudioIoctl, void *)
{
return 0;
}
void OnInterruptReceived(TrapFrame *)
{
}
void Panic()
{
}
HDADevice(PCIHeader0 *_Header)
: Header(_Header),
CORB((uint32_t *)(uintptr_t)AllocateMemory(1)),
RIRB((uint64_t *)AllocateMemory(1))
{
CTL = (ControllerRegisters *)(uintptr_t)Header->BAR0;
KernelLog("Unimplemented HDA driver");
return;
Initialized = true;
}
~HDADevice()
{
if (!Initialized)
return;
}
};
HDADevice *Drivers[4] = {nullptr};
dev_t AudioID[4] = {(dev_t)-1};
#define OIR(x) OIR_##x
#define CREATE_OIR(x) \
void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
CREATE_OIR(0);
CREATE_OIR(1);
CREATE_OIR(2);
CREATE_OIR(3);
int __fs_Open(struct Inode *, int, mode_t) { return 0; }
int __fs_Close(struct Inode *) { return 0; }
ssize_t __fs_Read(struct Inode *, void *, size_t, off_t) { return 0; }
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
{
return Drivers[AudioID[Node->GetMinor()]]->write((uint8_t *)Buffer, Size);
}
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
{
return Drivers[AudioID[Node->GetMinor()]]->ioctl((AudioIoctl)Request, Argp);
}
const struct InodeOperations AudioOps = {
.Lookup = nullptr,
.Create = nullptr,
.Remove = nullptr,
.Rename = nullptr,
.Read = __fs_Read,
.Write = __fs_Write,
.Truncate = nullptr,
.Open = __fs_Open,
.Close = __fs_Close,
.Ioctl = __fs_Ioctl,
.ReadDir = nullptr,
.MkDir = nullptr,
.RmDir = nullptr,
.SymLink = nullptr,
.ReadLink = nullptr,
.Seek = nullptr,
.Stat = nullptr,
};
PCIArray *Devices;
EXTERNC int cxx_Panic()
{
PCIArray *ctx = Devices;
short Count = 0;
while (ctx != nullptr)
{
if (Drivers[Count] != nullptr)
Drivers[Count]->Panic();
Count++;
ctx = (PCIArray *)ctx->Next;
}
return 0;
}
EXTERNC int cxx_Probe()
{
uint16_t VendorIDs[] = {0x8086, /* Intel */
0x15AD, /* VMware */
PCI_END};
uint16_t DeviceIDs[] = {0x9D71 /* Sunrise Point-LP HD Audio */,
0x2668 /* ICH6 */,
0x293E /* ICH9 */,
PCI_END};
Devices = GetPCIDevices(VendorIDs, DeviceIDs);
if (Devices == nullptr)
{
KernelLog("No HDA device found.");
return -ENODEV;
}
PCIArray *ctx = Devices;
bool Found = false;
size_t Count = 0;
while (ctx != nullptr)
{
if (Count++ > sizeof(Drivers) / sizeof(HDADevice *))
break;
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
uint8_t Type = PCIBAR0 & 1;
if (Type == 1)
{
KernelLog("Device %x:%x.%d BAR0 is I/O.",
PCIBaseAddress->Header.VendorID,
PCIBaseAddress->Header.DeviceID,
PCIBaseAddress->Header.ProgIF);
continue;
}
Found = true;
ctx = (PCIArray *)ctx->Next;
}
if (!Found)
{
KernelLog("No valid HDA device found.");
return -EINVAL;
}
return 0;
}
EXTERNC int cxx_Initialize()
{
PCIArray *ctx = Devices;
size_t Count = 0;
while (ctx != nullptr)
{
if (Count > sizeof(Drivers) / sizeof(HDADevice *))
break;
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
uint8_t Type = PCIBAR0 & 1;
if (Type == 1)
{
KernelLog("Device %x:%x.%d BAR0 is I/O.",
PCIBaseAddress->Header.VendorID,
PCIBaseAddress->Header.DeviceID,
PCIBaseAddress->Header.ProgIF);
continue;
}
InitializePCI(ctx->Device);
Drivers[Count] = new HDADevice((PCIHeader0 *)ctx->Device->Header);
if (Drivers[Count]->IsInitialized())
{
dev_t ret = RegisterDevice(AUDIO_TYPE_PCM, &AudioOps);
AudioID[Count] = ret;
Count++;
}
ctx = (PCIArray *)ctx->Next;
}
if (Count == 0)
{
KernelLog("No valid HDA device found.");
return -EINVAL;
}
return 0;
}
EXTERNC int cxx_Finalize()
{
PCIArray *ctx = Devices;
size_t Count = 0;
while (ctx != nullptr)
{
if (Count++ > sizeof(Drivers) / sizeof(HDADevice *))
break;
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
uint8_t Type = PCIBAR0 & 1;
if (Type == 1)
{
KernelLog("Device %x:%x.%d BAR0 is I/O.",
PCIBaseAddress->Header.VendorID,
PCIBaseAddress->Header.DeviceID,
PCIBaseAddress->Header.ProgIF);
continue;
}
delete Drivers[Count++];
ctx = (PCIArray *)ctx->Next;
}
for (size_t i = 0; i < sizeof(AudioID) / sizeof(dev_t); i++)
{
if (AudioID[i] != (dev_t)-1)
UnregisterDevice(AudioID[i]);
}
return 0;
}

View File

@ -1,31 +0,0 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Drivers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include <base.h>
#include "hda.hpp"
int DriverEntry() { return cxx_Initialize(); }
int DriverFinal() { return cxx_Finalize(); }
int DriverPanic() { return cxx_Panic(); }
int DriverProbe() { return cxx_Probe(); }
DriverInfo("hda",
"Intel High Definition Audio Driver",
"EnderIce2",
0, 0, 1,
"GPLv3");

View File

@ -1,35 +0,0 @@
default:
$(error Do not run this Makefile directly!)
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
FILENAME = $(notdir $(shell pwd)).drv
build: $(FILENAME)
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
WARNCFLAG = -Wall -Wextra
%.o: %.c $(HEADERS)
$(info Compiling $<)
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
%.o: %.S
$(info Compiling $<)
$(AS) -o $@ $<
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

View File

@ -1,45 +0,0 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Drivers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include <base.h>
int DriverEntry()
{
return 0;
}
int DriverFinal()
{
return 0;
}
int DriverPanic()
{
return 0;
}
int DriverProbe()
{
/* Nothing to do */
return 0;
}
DriverInfo("fat",
"File Allocation Table Driver",
"EnderIce2",
0, 0, 1,
"GPLv3");

View File

@ -103,6 +103,7 @@ typedef union
uint8_t Raw; uint8_t Raw;
} PS2_OUTPUT_PORT; } PS2_OUTPUT_PORT;
#ifndef __kernel__
void PIC_EOI(uint8_t IRQ); void PIC_EOI(uint8_t IRQ);
void IRQ_MASK(uint8_t IRQ); void IRQ_MASK(uint8_t IRQ);
void IRQ_UNMASK(uint8_t IRQ); void IRQ_UNMASK(uint8_t IRQ);
@ -114,11 +115,11 @@ uint8_t PS2ReadStatus();
uint8_t PS2ReadAfterACK(); uint8_t PS2ReadAfterACK();
void PS2ClearOutputBuffer(); void PS2ClearOutputBuffer();
int PS2ACKTimeout(); int PS2ACKTimeout();
#endif // !__kernel__
#define WaitOutput PS2Wait(DriverID, true) #define WaitOutput PS2Wait(DriverID, true)
#define WaitInput PS2Wait(DriverID, false) #define WaitInput PS2Wait(DriverID, false)
#define PS2_KBD_CMD_SET_LEDS 0xED #define PS2_KBD_CMD_SET_LEDS 0xED
#define PS2_KBD_CMD_ECHO 0xEE #define PS2_KBD_CMD_ECHO 0xEE
#define PS2_KBD_CMD_SCAN_CODE_SET 0xF0 #define PS2_KBD_CMD_SCAN_CODE_SET 0xF0
@ -189,7 +190,6 @@ typedef union
uint8_t Raw; uint8_t Raw;
} PS2_KBD_TYPEMATIC; } PS2_KBD_TYPEMATIC;
#define PS2_MOUSE_CMD_SET_SCALING_1_1 0xE6 #define PS2_MOUSE_CMD_SET_SCALING_1_1 0xE6
#define PS2_MOUSE_CMD_SET_SCALING_2_1 0xE7 #define PS2_MOUSE_CMD_SET_SCALING_2_1 0xE7
#define PS2_MOUSE_CMD_SET_RESOLUTION 0xE8 #define PS2_MOUSE_CMD_SET_RESOLUTION 0xE8

110
Drivers/include/block.h Normal file
View File

@ -0,0 +1,110 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_BLOCK_H__
#define __FENNIX_API_BLOCK_H__
#include <types.h>
#if __has_include(<interface/fs.h>)
#include <interface/fs.h>
#else
#include <fs.h>
#endif
struct BlockDevice
{
/**
* @brief Base name of the device.
*
* This name is used to identify the device in the system. It should be unique
* across all block devices. The kernel may append a number to this name to
* create a unique device name (e.g., "ahci0", "ahci1").
*/
const char *Name;
/**
* @brief Total size of the device in bytes.
*
* This value represents the total addressable storage capacity of the device.
* It is used for bounds checking and partitioning.
*/
size_t Size;
/**
* @brief Size of a single block in bytes.
*
* All read and write operations are performed in multiples of this block size.
* Typical values are 512 or 4096 bytes.
*/
uint32_t BlockSize;
/**
* @brief Number of blocks in the device.
*
* This value is calculated as Size / BlockSize. It represents the total number
* of addressable blocks on the device.
*/
size_t BlockCount;
/**
* @brief Pointer to the block device operations structure.
*
* This structure contains function pointers for various operations that can
* be performed on the block device, such as read, write, and ioctl.
*
* Yea, inode operations are used for block devices too.
*/
const InodeOperations *Ops;
/**
* @brief Opaque pointer to driver-specific or hardware-specific data.
*
* This field allows the driver to associate private context or state with the
* device, such as controller registers or internal buffers.
*/
void *PrivateData;
};
#ifndef __kernel__
/**
* @brief Registers a block device with the kernel block subsystem.
*
* This function should be called by block device drivers after initializing
* a device. The kernel will take ownership of the device structure and assign
* it a unique device ID. The device will then be accessible for filesystem
* mounting and I/O operations.
*
* @param Device Pointer to a fully initialized BlockDevice structure. All required fields must be set and valid for the lifetime of the device.
* @return Device ID (dev_t) assigned by the kernel on success, or an error code on failure.
*/
dev_t RegisterBlockDevice(struct BlockDevice *Device);
/**
* @brief Unregisters a block device from the kernel block subsystem.
*
* This function should be called by drivers when a device is being removed
* or is no longer available. The kernel will release any resources associated
* with the device and invalidate its device ID.
*
* @param DeviceID The device ID (dev_t) previously returned by RegisterBlockDevice().
* @return 0 on success, or an error code.
*/
int UnregisterBlockDevice(dev_t DeviceID);
#endif // __kernel__
#endif // __FENNIX_API_BLOCK_H__

View File

@ -69,7 +69,10 @@ typedef enum
BLOCK_TYPE_FLOPPY = DEVICE_TYPE_BLOCK + 128, BLOCK_TYPE_FLOPPY = DEVICE_TYPE_BLOCK + 128,
} DeviceType; } DeviceType;
#ifndef __kernel__
EXTERNC dev_t CreateDeviceFile(const char *name, mode_t mode, const struct InodeOperations *Operations);
EXTERNC dev_t RegisterDevice(DeviceType Type, const struct InodeOperations *Operations); EXTERNC dev_t RegisterDevice(DeviceType Type, const struct InodeOperations *Operations);
EXTERNC int UnregisterDevice(dev_t Device); EXTERNC int UnregisterDevice(dev_t Device);
#endif // !__kernel__
#endif // !__FENNIX_API_DEVICE_H__ #endif // !__FENNIX_API_DEVICE_H__

File diff suppressed because it is too large Load Diff

109
Drivers/include/fcntl.h Normal file
View File

@ -0,0 +1,109 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_FCNTL_H__
#define __FENNIX_API_FCNTL_H__
#ifdef __kernel__
#include <types.h>
#endif
/* cmd */
#define F_DUPFD 0x1
#define F_DUPFD_CLOEXEC 0x101
#define F_DUPFD_CLOFORK 0x201
#define F_GETFD 0x2
#define F_SETFD 0x3
#define F_GETFL 0x4
#define F_SETFL 0x5
#define F_GETLK 0x6
#define F_SETLK 0x7
#define F_SETLKW 0x8
#define F_OFD_GETLK 0x9
#define F_OFD_SETLK 0xA
#define F_OFD_SETLKW 0xB
#define F_GETOWN 0xC
#define F_GETOWN_EX 0xD
#define F_SETOWN 0xE
#define F_SETOWN_EX 0xF
#define FD_CLOEXEC 0x1
#define FD_CLOFORK 0x2
/* l_type */
#define F_RDLCK 0x1
#define F_UNLCK 0x2
#define F_WRLCK 0x3
/* type */
#define F_OWNER_PID 0
#define F_OWNER_PGRP 1
/* oflag */
#define O_CLOEXEC 02000000
#define O_CLOFORK 04000000
#define O_CREAT 0x8
#define O_DIRECTORY 0200000
#define O_EXCL 0x20
#define O_NOCTTY 0x40
#define O_NOFOLLOW 0400000
#define O_TRUNC 0x400
#define O_TTY_INIT 0x800
#define O_APPEND 0x4
#define O_DSYNC 0x10
#define O_NONBLOCK 0x80
#define O_RSYNC 0x100
#define O_SYNC 0x200
#define O_ACCMODE 0x3
#define O_EXEC 0x4
#define O_RDONLY 0x1
#define O_RDWR 0x3
#define O_SEARCH 0x10
#define O_WRONLY 0x2
#define AT_FDCWD
#define AT_EACCESS
#define AT_SYMLINK_NOFOLLOW
#define AT_SYMLINK_FOLLOW
#define AT_REMOVEDIR
#define POSIX_FADV_DONTNEED
#define POSIX_FADV_NOREUSE
#define POSIX_FADV_NORMAL
#define POSIX_FADV_RANDOM
#define POSIX_FADV_SEQUENTIAL
#define POSIX_FADV_WILLNEED
typedef struct f_owner_ex
{
int type; /* Discriminator for pid. */
pid_t pid; /* Process ID or process group ID. */
} f_owner_ex;
typedef struct flock
{
short l_type; /* Type of lock; F_RDLCK, F_WRLCK, F_UNLCK. */
short l_whence; /* Flag for starting offset. */
off_t l_start; /* Relative offset in bytes. */
off_t l_len; /* Size; if 0 then until EOF. */
pid_t l_pid; /* For a process-owned file lock, ignored on input or the process ID of the owning process on output; for an OFD-owned file lock, zero on input or (pid_t)-1 on output. */
} flock;
#endif // !__FENNIX_API_FCNTL_H__

View File

@ -95,16 +95,6 @@
/** Other: X */ /** Other: X */
#define S_IXOTH 0001 #define S_IXOTH 0001
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
#define O_CREAT 0100
#define O_EXCL 0200
#define O_TRUNC 01000
#define O_APPEND 02000
#define O_NOFOLLOW 0400000
#define O_CLOEXEC 02000000
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
@ -332,11 +322,29 @@ struct InodeOperations
int (*Stat)(struct Inode *Node, struct kstat *Stat); int (*Stat)(struct Inode *Node, struct kstat *Stat);
} __attribute__((packed)); } __attribute__((packed));
#define I_FLAG_ROOT 0x1
#define I_FLAG_MOUNTPOINT 0x2
#define I_FLAG_CACHE_KEEP 0x4
struct FileSystemInfo; struct FileSystemInfo;
struct FileSystemDevice
{
struct
{
/**
* @brief Inode
*
* If the device is a block device, this will be NULL.
*/
struct Inode *node;
struct InodeOperations *ops;
} inode;
/**
* @brief Block Device
*
* If the device is a block device, this will be non-NULL.
*/
struct BlockDevice *Block;
};
struct SuperBlockOperations struct SuperBlockOperations
{ {
int (*AllocateInode)(struct FileSystemInfo *Info, struct Inode **Result); int (*AllocateInode)(struct FileSystemInfo *Info, struct Inode **Result);
@ -347,8 +355,8 @@ struct SuperBlockOperations
* *
* Write all pending changes to the disk. * Write all pending changes to the disk.
* *
* @param Info Inode to synchronize. If NULL, synchronize all inodes. * @param Info Inode to synchronize.
* @param Node Inode to synchronize. * @param Node Inode to synchronize. If NULL, synchronize all inodes.
* *
* @return Zero on success, otherwise an error code. * @return Zero on success, otherwise an error code.
*/ */
@ -364,20 +372,62 @@ struct SuperBlockOperations
* @return Zero on success, otherwise an error code. * @return Zero on success, otherwise an error code.
*/ */
int (*Destroy)(struct FileSystemInfo *Info); int (*Destroy)(struct FileSystemInfo *Info);
/**
* Probe the filesystem.
*
* Check if the filesystem is supported by the driver.
*
* @param Device Device to probe.
*
* @return Zero on success, otherwise an error code.
*/
int (*Probe)(struct FileSystemDevice *Device);
/**
* Mount the filesystem.
*
* Mount the filesystem on the given device.
*
* @param FS Filesystem to mount.
* @param Root Pointer to the root inode.
* @param Device Device to mount. This pointer will be undefined after the function returns!
*
* @return Zero on success, otherwise an error code.
*/
int (*Mount)(struct FileSystemInfo *FS, struct Inode **Root, struct FileSystemDevice *Device);
/**
* Unmount the filesystem.
*
* Unmount the filesystem from the given device.
*
* @param FS Filesystem to unmount.
*
* @return Zero on success, otherwise an error code.
*/
int (*Unmount)(struct FileSystemInfo *FS);
} __attribute__((packed)); } __attribute__((packed));
struct FileSystemInfo struct FileSystemInfo
{ {
const char *Name; const char *Name;
const char *RootName;
int Flags; int Flags;
int Capabilities;
struct SuperBlockOperations SuperOps; struct SuperBlockOperations SuperOps;
struct InodeOperations Ops; struct InodeOperations Ops;
void *PrivateData; void *PrivateData;
} __attribute__((packed)); } __attribute__((packed));
#ifndef __kernel__
dev_t RegisterMountPoint(FileSystemInfo *fsi, Inode *Root);
int UnregisterMountPoint(dev_t Device);
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root); dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
int UnregisterFileSystem(dev_t Device); int UnregisterFileSystem(dev_t Device);
#endif // !__kernel__
#endif // !__FENNIX_API_FILESYSTEM_H__ #endif // !__FENNIX_API_FILESYSTEM_H__

View File

@ -239,6 +239,8 @@ typedef struct
}; };
} InputReport; } InputReport;
#ifndef __kernel__
EXTERNC int ReportInputEvent(InputReport *Report); EXTERNC int ReportInputEvent(InputReport *Report);
#endif // !__kernel__
#endif // !__FENNIX_API_INPUT_H__ #endif // !__FENNIX_API_INPUT_H__

View File

@ -171,11 +171,13 @@ extern "C"
{ {
#endif #endif
#ifndef __kernel__
PCIArray *GetPCIDevices(uint16_t Vendors[], uint16_t Devices[]); PCIArray *GetPCIDevices(uint16_t Vendors[], uint16_t Devices[]);
void InitializePCI(PCIDevice *Device); void InitializePCI(PCIDevice *Device);
uint32_t GetBAR(uint8_t Index, PCIDevice *Device); uint32_t GetBAR(uint8_t Index, PCIDevice *Device);
uint8_t iLine(PCIDevice *Device); uint8_t iLine(PCIDevice *Device);
uint8_t iPin(PCIDevice *Device); uint8_t iPin(PCIDevice *Device);
#endif // !__kernel__
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -15,13 +15,44 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>. along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef __FENNIX_API_SYSCALLS_LIST_H__ #ifndef __FENNIX_API_SYSTEM_CALLS_LIST_H__
#define __FENNIX_API_SYSCALLS_LIST_H__ #define __FENNIX_API_SYSTEM_CALLS_LIST_H__
#if __has_include(<interface/fcntl.h>)
#include <interface/fcntl.h>
#else
#include <fcntl.h>
#endif
#ifndef __fennix__
#error "__fennix__ not defined"
#endif
#pragma region Syscall Wrappers #pragma region Syscall Wrappers
#define scarg __UINTPTR_TYPE__ #define scarg __UINTPTR_TYPE__
#ifdef __arm__
#ifdef __thumb__
#define __thumb_r7
#define __arm_call(...)
#warning "arm thumb code not implemented"
#else /* __thumb__ */
#define __thumb_r7 __asm__("r7")
#define __arm_call(...) \
__asm__ __volatile__("svc 0" \
: "=r"(r0) \
: __VA_ARGS__ \
: "memory")
#endif /* __thumb__ */
#ifdef __thumb2__
#define __r7_operand "rI"(r7)
#else /* __thumb2__ */
#define __r7_operand "r"(r7)
#endif /* __thumb2__ */
#endif /* __arm__ */
/** /**
* @brief Syscall wrapper with 0 arguments * @brief Syscall wrapper with 0 arguments
* *
@ -39,12 +70,17 @@ static inline scarg syscall0(scarg syscall)
: "a"(syscall) : "a"(syscall)
: "rcx", "r11", "memory"); : "rcx", "r11", "memory");
#elif defined(__i386__) #elif defined(__i386__)
#warning "i386 syscall wrapper not implemented" __asm__ __volatile__("int $0x30"
: "=a"(ret)
: "a"(syscall)
: "memory");
#elif defined(__arm__) #elif defined(__arm__)
#warning "arm syscall wrapper not implemented" register scarg r7 __thumb_r7 = syscall;
register scarg r0 __asm__("r0");
__arm_call(__r7_operand);
#elif defined(__aarch64__) #elif defined(__aarch64__)
register long x8 __asm__("x8") = syscall; register scarg x8 __asm__("x8") = syscall;
register long x0 __asm__("x0"); register scarg x0 __asm__("x0");
__asm__ __volatile__("svc 0" __asm__ __volatile__("svc 0"
: "=r"(x0) : "=r"(x0)
: "r"(x8) : "r"(x8)
@ -73,12 +109,17 @@ static inline scarg syscall1(scarg syscall, scarg arg1)
: "a"(syscall), "D"(arg1) : "a"(syscall), "D"(arg1)
: "rcx", "r11", "memory"); : "rcx", "r11", "memory");
#elif defined(__i386__) #elif defined(__i386__)
#warning "i386 syscall wrapper not implemented" __asm__ __volatile__("int $0x30"
: "=a"(ret)
: "a"(syscall), "b"(arg1)
: "memory");
#elif defined(__arm__) #elif defined(__arm__)
#warning "arm syscall wrapper not implemented" register scarg r7 __thumb_r7 = syscall;
register scarg r0 __asm__("r0") = arg1;
__arm_call(__r7_operand, "0"(r0));
#elif defined(__aarch64__) #elif defined(__aarch64__)
register long x8 __asm__("x8") = syscall; register scarg x8 __asm__("x8") = syscall;
register long x0 __asm__("x0") = arg1; register scarg x0 __asm__("x0") = arg1;
__asm__ __volatile__("svc 0" __asm__ __volatile__("svc 0"
: "=r"(ret) : "=r"(ret)
: "r"(x8), "0"(x0) : "r"(x8), "0"(x0)
@ -108,13 +149,19 @@ static inline scarg syscall2(scarg syscall, scarg arg1, scarg arg2)
: "a"(syscall), "D"(arg1), "S"(arg2) : "a"(syscall), "D"(arg1), "S"(arg2)
: "rcx", "r11", "memory"); : "rcx", "r11", "memory");
#elif defined(__i386__) #elif defined(__i386__)
#warning "i386 syscall wrapper not implemented" __asm__ __volatile__("int $0x30"
: "=a"(ret)
: "a"(syscall), "b"(arg1), "c"(arg2)
: "memory");
#elif defined(__arm__) #elif defined(__arm__)
#warning "arm syscall wrapper not implemented" register scarg r7 __thumb_r7 = syscall;
register scarg r0 __asm__("r0") = arg1;
register scarg r1 __asm__("r1") = arg2;
__arm_call(__r7_operand, "0"(r0), "r"(r1));
#elif defined(__aarch64__) #elif defined(__aarch64__)
register long x8 __asm__("x8") = syscall; register scarg x8 __asm__("x8") = syscall;
register long x0 __asm__("x0") = arg1; register scarg x0 __asm__("x0") = arg1;
register long x1 __asm__("x1") = arg2; register scarg x1 __asm__("x1") = arg2;
__asm__ __volatile__("svc 0" __asm__ __volatile__("svc 0"
: "=r"(ret) : "=r"(ret)
: "r"(x8), "0"(x0), "r"(x1) : "r"(x8), "0"(x0), "r"(x1)
@ -145,14 +192,21 @@ static inline scarg syscall3(scarg syscall, scarg arg1, scarg arg2, scarg arg3)
: "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3) : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3)
: "rcx", "r11", "memory"); : "rcx", "r11", "memory");
#elif defined(__i386__) #elif defined(__i386__)
#warning "i386 syscall wrapper not implemented" __asm__ __volatile__("int $0x30"
: "=a"(ret)
: "a"(syscall), "b"(arg1), "c"(arg2), "d"(arg3)
: "memory");
#elif defined(__arm__) #elif defined(__arm__)
#warning "arm syscall wrapper not implemented" register scarg r7 __thumb_r7 = syscall;
register scarg r0 __asm__("r0") = arg1;
register scarg r1 __asm__("r1") = arg2;
register scarg r2 __asm__("r2") = arg3;
__arm_call(__r7_operand, "0"(r0), "r"(r1), "r"(r2));
#elif defined(__aarch64__) #elif defined(__aarch64__)
register long x8 __asm__("x8") = syscall; register scarg x8 __asm__("x8") = syscall;
register long x0 __asm__("x0") = arg1; register scarg x0 __asm__("x0") = arg1;
register long x1 __asm__("x1") = arg2; register scarg x1 __asm__("x1") = arg2;
register long x2 __asm__("x2") = arg3; register scarg x2 __asm__("x2") = arg3;
__asm__ __volatile__("svc 0" __asm__ __volatile__("svc 0"
: "=r"(ret) : "=r"(ret)
: "r"(x8), "0"(x0), "r"(x1), "r"(x2) : "r"(x8), "0"(x0), "r"(x1), "r"(x2)
@ -185,15 +239,23 @@ static inline scarg syscall4(scarg syscall, scarg arg1, scarg arg2, scarg arg3,
: "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10) : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10)
: "rcx", "r11", "memory"); : "rcx", "r11", "memory");
#elif defined(__i386__) #elif defined(__i386__)
#warning "i386 syscall wrapper not implemented" __asm__ __volatile__("int $0x30"
: "=a"(ret)
: "a"(syscall), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4)
: "memory");
#elif defined(__arm__) #elif defined(__arm__)
#warning "arm syscall wrapper not implemented" register scarg r7 __thumb_r7 = syscall;
register scarg r0 __asm__("r0") = arg1;
register scarg r1 __asm__("r1") = arg2;
register scarg r2 __asm__("r2") = arg3;
register scarg r3 __asm__("r3") = arg4;
__arm_call(__r7_operand, "0"(r0), "r"(r1), "r"(r2), "r"(r3));
#elif defined(__aarch64__) #elif defined(__aarch64__)
register long x8 __asm__("x8") = syscall; register scarg x8 __asm__("x8") = syscall;
register long x0 __asm__("x0") = arg1; register scarg x0 __asm__("x0") = arg1;
register long x1 __asm__("x1") = arg2; register scarg x1 __asm__("x1") = arg2;
register long x2 __asm__("x2") = arg3; register scarg x2 __asm__("x2") = arg3;
register long x3 __asm__("x3") = arg4; register scarg x3 __asm__("x3") = arg4;
__asm__ __volatile__("svc 0" __asm__ __volatile__("svc 0"
: "=r"(ret) : "=r"(ret)
: "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3) : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3)
@ -228,16 +290,25 @@ static inline scarg syscall5(scarg syscall, scarg arg1, scarg arg2, scarg arg3,
: "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8) : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8)
: "rcx", "r11", "memory"); : "rcx", "r11", "memory");
#elif defined(__i386__) #elif defined(__i386__)
#warning "i386 syscall wrapper not implemented" __asm__ __volatile__("int $0x30"
: "=a"(ret)
: "a"(syscall), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4), "D"(arg5)
: "memory");
#elif defined(__arm__) #elif defined(__arm__)
#warning "arm syscall wrapper not implemented" register scarg r7 __thumb_r7 = syscall;
register scarg r0 __asm__("r0") = arg1;
register scarg r1 __asm__("r1") = arg2;
register scarg r2 __asm__("r2") = arg3;
register scarg r3 __asm__("r3") = arg4;
register scarg r4 __asm__("r4") = arg5;
__arm_call(__r7_operand, "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4));
#elif defined(__aarch64__) #elif defined(__aarch64__)
register long x8 __asm__("x8") = syscall; register scarg x8 __asm__("x8") = syscall;
register long x0 __asm__("x0") = arg1; register scarg x0 __asm__("x0") = arg1;
register long x1 __asm__("x1") = arg2; register scarg x1 __asm__("x1") = arg2;
register long x2 __asm__("x2") = arg3; register scarg x2 __asm__("x2") = arg3;
register long x3 __asm__("x3") = arg4; register scarg x3 __asm__("x3") = arg4;
register long x4 __asm__("x4") = arg5; register scarg x4 __asm__("x4") = arg5;
__asm__ __volatile__("svc 0" __asm__ __volatile__("svc 0"
: "=r"(ret) : "=r"(ret)
: "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4) : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4)
@ -274,17 +345,27 @@ static inline scarg syscall6(scarg syscall, scarg arg1, scarg arg2, scarg arg3,
: "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8), "r"(r9) : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8), "r"(r9)
: "rcx", "r11", "memory"); : "rcx", "r11", "memory");
#elif defined(__i386__) #elif defined(__i386__)
#warning "i386 syscall wrapper not implemented" __asm__ __volatile__("int $0x30"
: "=a"(ret)
: "a"(syscall), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4), "D"(arg5), "g"(arg6)
: "memory");
#elif defined(__arm__) #elif defined(__arm__)
#warning "arm syscall wrapper not implemented" register scarg r7 __thumb_r7 = syscall;
register scarg r0 __asm__("r0") = arg1;
register scarg r1 __asm__("r1") = arg2;
register scarg r2 __asm__("r2") = arg3;
register scarg r3 __asm__("r3") = arg4;
register scarg r4 __asm__("r4") = arg5;
register scarg r5 __asm__("r5") = arg6;
__arm_call(__r7_operand, "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5));
#elif defined(__aarch64__) #elif defined(__aarch64__)
register long x8 __asm__("x8") = syscall; register scarg x8 __asm__("x8") = syscall;
register long x0 __asm__("x0") = arg1; register scarg x0 __asm__("x0") = arg1;
register long x1 __asm__("x1") = arg2; register scarg x1 __asm__("x1") = arg2;
register long x2 __asm__("x2") = arg3; register scarg x2 __asm__("x2") = arg3;
register long x3 __asm__("x3") = arg4; register scarg x3 __asm__("x3") = arg4;
register long x4 __asm__("x4") = arg5; register scarg x4 __asm__("x4") = arg5;
register long x5 __asm__("x5") = arg6; register scarg x5 __asm__("x5") = arg6;
__asm__ __volatile__("svc 0" __asm__ __volatile__("svc 0"
: "=r"(ret) : "=r"(ret)
: "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5) : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5)
@ -322,18 +403,18 @@ typedef enum
typedef enum typedef enum
{ {
__SYS_O_RDONLY = 0x1, __SYS_O_RDONLY = O_RDONLY,
__SYS_O_WRONLY = 0x2, __SYS_O_WRONLY = O_WRONLY,
__SYS_O_RDWR = 0x3, __SYS_O_RDWR = O_RDWR,
__SYS_O_APPEND = 0x4, __SYS_O_APPEND = O_APPEND,
__SYS_O_CREAT = 0x8, __SYS_O_CREAT = O_CREAT,
__SYS_O_DSYNC = 0x10, __SYS_O_DSYNC = O_DSYNC,
__SYS_O_EXCL = 0x20, __SYS_O_EXCL = O_EXCL,
__SYS_O_NOCTTY = 0x40, __SYS_O_NOCTTY = O_NOCTTY,
__SYS_O_NONBLOCK = 0x80, __SYS_O_NONBLOCK = O_NONBLOCK,
__SYS_O_RSYNC = 0x100, __SYS_O_RSYNC = O_RSYNC,
__SYS_O_SYNC = 0x200, __SYS_O_SYNC = O_SYNC,
__SYS_O_TRUNC = 0x400 __SYS_O_TRUNC = O_TRUNC
} syscall_open_flags_t; } syscall_open_flags_t;
typedef enum typedef enum
@ -531,6 +612,36 @@ static_assert((int)__SYS_SIG_IGN == (int)___SYS_SIG_IGN, "SIG_IGN values do not
typedef int __SYS_clockid_t; typedef int __SYS_clockid_t;
typedef unsigned int __SYS_socklen_t; typedef unsigned int __SYS_socklen_t;
typedef struct FramebufferScreenInfo
{
__UINT32_TYPE__ Width;
__UINT32_TYPE__ Height;
__UINT32_TYPE__ Pitch;
__UINT32_TYPE__ Bpp;
__UINT32_TYPE__ Size;
} FramebufferScreenInfo;
/**
* @brief Get framebuffer screen info
*
* @code
* struct FramebufferScreenInfo info;
* int ioctl(fd, FBIOGET_SCREEN_INFO, &info);
* @endcode
*
* @param fd File descriptor of the framebuffer device
* @param info Pointer to the framebuffer screen info structure
*/
#define FBIOGET_SCREEN_INFO 0xf0
struct kutsname
{
char sysname[65];
char release[65];
char version[65];
char machine[65];
};
/** /**
* @brief List of syscalls * @brief List of syscalls
* *
@ -563,6 +674,8 @@ typedef enum
*/ */
SYS_API_VERSION = 0, SYS_API_VERSION = 0,
SYS_DEBUG_REPORT = 1,
/* I/O */ /* I/O */
/** /**
@ -719,6 +832,25 @@ typedef enum
* - #EINVAL if the request is invalid * - #EINVAL if the request is invalid
*/ */
SYS_IOCTL, SYS_IOCTL,
/**
* @brief Function control
*
* @code
* int fcntl(int fd, int cmd, void *arg);
* @endcode
*
* @details Manipulates the underlying parameters of a device.
*
* @param fd File descriptor referring to the device
* @param cmd Device-specific request code
* @param arg Argument for the request
*
* @return
* - #EOK on success
* - #EBADF if `fd` is not valid
* - #EINVAL if the request is invalid
*/
SYS_FCNTL,
/* File Status */ /* File Status */
@ -1508,6 +1640,22 @@ typedef enum
* - #EACCES if permission is denied * - #EACCES if permission is denied
*/ */
SYS_RENAME, SYS_RENAME,
/**
* @brief Get unix name information
*
* @code
* int uname(struct kutsname *buf);
* @endcode
*
* @details Retrieves information about the operating system.
*
* @param buf Pointer to `kutsname` structure to store information
*
* @return
* - #EOK on success
* - #EFAULT if `buf` is outside accessible address space
*/
SYS_UNAME,
/** /**
* @brief Max number of syscalls * @brief Max number of syscalls
@ -1551,6 +1699,9 @@ typedef enum
/** @copydoc SYS_IOCTL */ /** @copydoc SYS_IOCTL */
#define call_ioctl(fd, request, argp) syscall3(SYS_IOCTL, (scarg)fd, (scarg)request, (scarg)argp) #define call_ioctl(fd, request, argp) syscall3(SYS_IOCTL, (scarg)fd, (scarg)request, (scarg)argp)
/** @copydoc SYS_FCNTL */
#define call_fcntl(fd, cmd, arg) syscall3(SYS_FCNTL, (scarg)fd, (scarg)cmd, (scarg)arg)
/* File Status */ /* File Status */
/** @copydoc SYS_STAT */ /** @copydoc SYS_STAT */
@ -1658,7 +1809,7 @@ typedef enum
/* Time */ /* Time */
/** @copydoc SYS_TIME */ /** @copydoc SYS_TIME */
#define call_time(t) syscall1(SYS_TIME, t) #define call_time(t) syscall1(SYS_TIME, (scarg)t)
/** @copydoc SYS_CLOCK_GETTIME */ /** @copydoc SYS_CLOCK_GETTIME */
#define call_clock_gettime(clockid, tp) syscall2(SYS_CLOCK_GETTIME, (scarg)clockid, (scarg)tp) #define call_clock_gettime(clockid, tp) syscall2(SYS_CLOCK_GETTIME, (scarg)clockid, (scarg)tp)
@ -1689,4 +1840,7 @@ typedef enum
/** @copydoc SYS_RENAME */ /** @copydoc SYS_RENAME */
#define call_rename(oldpath, newpath) syscall2(SYS_RENAME, (scarg)oldpath, (scarg)newpath) #define call_rename(oldpath, newpath) syscall2(SYS_RENAME, (scarg)oldpath, (scarg)newpath)
#endif // !__FENNIX_API_SYSCALLS_LIST_H__ /** @copydoc SYS_UNAME */
#define call_uname(buf) syscall1(SYS_UNAME, (scarg)buf)
#endif // !__FENNIX_API_SYSTEM_CALLS_LIST_H__

View File

@ -1,35 +0,0 @@
default:
$(error Do not run this Makefile directly!)
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
FILENAME = $(notdir $(shell pwd)).drv
build: $(FILENAME)
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
WARNCFLAG = -Wall -Wextra
%.o: %.c $(HEADERS)
$(info Compiling $<)
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
%.o: %.S
$(info Compiling $<)
$(AS) -o $@ $<
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

View File

@ -1,39 +0,0 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Drivers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_DRIVER_AIP_H__
#define __FENNIX_DRIVER_AIP_H__
#include <types.h>
#include <aip.h>
#include <regs.h>
extern uint8_t Device1ID[];
extern uint8_t Device2ID[];
void PS2KbdInterruptHandler(TrapFrame *);
int InitializeKeyboard();
int FinalizeKeyboard();
int DetectPS2Keyboard();
void PS2MouseInterruptHandler(TrapFrame *);
int InitializeMouse();
int FinalizeMouse();
int DetectPS2Mouse();
int DetectUART();
#endif // !__FENNIX_DRIVER_AIP_H__

View File

@ -1,235 +0,0 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Drivers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include "aip.h"
#include <errno.h>
#include <base.h>
bool IsKeyboard(uint8_t ID)
{
/* Common keyboard IDs */
return ID == 0xAB || ID == 0xAC || ID == 0x5D ||
ID == 0x2B || ID == 0x47 || ID == 0x60;
}
bool IsMouse(uint8_t ID)
{
/* Common mouse IDs */
return ID == 0x00 || ID == 0x03 || ID == 0x04;
}
const char *GetPS2DeviceName(uint8_t ID, uint8_t SubID)
{
switch (ID)
{
case 0x00:
return "Standard PS/2 Mouse";
case 0x03:
return "Mouse with scroll wheel";
case 0x04:
return "Mouse 5 buttons";
case 0xAB:
{
switch (SubID)
{
case 0x83: /* Normal */
case 0x41: /* Translated */
case 0xC1: /* Normal + Translated */
return "Standard PS/2 Keyboard";
case 0x84:
case 0x54:
return "IBM Thinkpad/Spacesaver Keyboard";
case 0x85:
return "NCD N-97/122-Key Host Connect(ed) Keyboard";
case 0x86:
return "122-Key Keyboard";
case 0x90:
return "Japanese \"G\" Keyboard";
case 0x91:
return "Japanese \"P\" Keyboard";
case 0x92:
return "Japanese \"A\" Keyboard";
default:
return "Unknown PS/2 Keyboard";
}
}
case 0xAC:
{
switch (SubID)
{
case 0xA1:
return "NCD Sun Keyboard";
default:
return "Unknown NCD Sun Keyboard";
}
}
case 0x5D:
case 0x2B:
return "Trust Keyboard";
case 0x47:
case 0x60:
return "NMB SGI Keyboard";
default:
return "Unknown PS/2 Device";
}
}
uint8_t Device1ID[2] = {0x00, 0x00};
uint8_t Device2ID[2] = {0x00, 0x00};
bool DualChannel = false;
int DriverEntry()
{
PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
PS2ClearOutputBuffer();
PS2WriteCommand(PS2_CMD_READ_CONFIG);
PS2_CONFIGURATION cfg = {.Raw = PS2ReadData()};
DualChannel = cfg.Port2Clock;
if (DualChannel)
KernelLog("Dual channel PS/2 controller detected");
cfg.Port1Interrupt = 1;
cfg.Port2Interrupt = 1;
cfg.Port1Translation = 1;
PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
PS2WriteData(cfg.Raw);
PS2WriteCommand(PS2_CMD_TEST_CONTROLLER);
uint8_t test = PS2ReadData();
if (test != PS2_TEST_PASSED)
{
KernelLog("PS/2 controller self test failed (%#x)", test);
return -EFAULT;
}
PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
PS2WriteData(cfg.Raw);
// bool port2avail = false;
// if (DualChannel)
// {
// PS2WriteCommand(PS2_CMD_ENABLE_PORT_1);
// PS2WriteCommand(PS2_CMD_READ_CONFIG);
// cfg.Raw = PS2ReadData();
// port2avail = cfg.Port2Clock;
// PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
// }
PS2WriteCommand(PS2_CMD_TEST_PORT_1);
test = PS2ReadData();
if (test != 0x00)
{
KernelLog("PS/2 Port 1 self test failed (%#x)", test);
return -EFAULT;
}
if (DualChannel)
{
PS2WriteCommand(PS2_CMD_TEST_PORT_2);
test = PS2ReadData();
if (test != 0x00)
{
KernelLog("PS/2 Port 2 self test failed (%#x)", test);
return -EFAULT;
}
}
PS2WriteCommand(PS2_CMD_ENABLE_PORT_1);
if (DualChannel)
PS2WriteCommand(PS2_CMD_ENABLE_PORT_2);
int errK = InitializeKeyboard();
int errM = 0;
if (DualChannel)
errM = InitializeMouse();
/** A device may fail, but if the other one works,
* we can still use it.
*/
if (errK != 0 && errM != 0)
return -ENODEV;
return 0;
}
int DriverFinal()
{
FinalizeKeyboard();
FinalizeMouse();
PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
return 0;
}
int DriverPanic()
{
PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
return 0;
}
void __intStub() {}
int DriverProbe()
{
RegisterInterruptHandler(1, __intStub);
RegisterInterruptHandler(12, __intStub);
int kbd = DetectPS2Keyboard();
int mouse = DetectPS2Mouse();
int uart = DetectUART();
UnregisterAllInterruptHandlers(__intStub);
if (kbd != 0 && mouse != 0 && uart != 0)
return -ENODEV;
if (kbd == 0)
{
if (!IsKeyboard(Device1ID[0]))
{
KernelLog("PS/2 Port 1 is not a keyboard");
// return -EINVAL;
}
}
if (mouse == 0)
{
if (!IsMouse(Device2ID[0]))
{
KernelLog("PS/2 Port 2 is not a mouse");
// return -EINVAL;
}
}
KernelPrint("PS/2 Port 1: %s (0x%X 0x%X)",
GetPS2DeviceName(Device1ID[0], Device1ID[1]),
Device1ID[0], Device1ID[1]);
KernelPrint("PS/2 Port 2: %s (0x%X 0x%X)",
GetPS2DeviceName(Device2ID[0], Device2ID[1]),
Device2ID[0], Device2ID[1]);
return 0;
}
DriverInfo("aip",
"Advanced Integrated Peripheral Driver",
"EnderIce2",
0, 0, 1,
"GPLv3");

View File

@ -1,244 +0,0 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Drivers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include "aip.h"
#include <errno.h>
#include <base.h>
#include <fs.h>
#include <input.h>
dev_t MouseDevID = -1;
bool PacketReady = false;
bool FourPackets = false;
bool MouseButton45 = false;
uint8_t Cycle = 0;
PS2_MOUSE_PACKET Packet = {0};
InputReport mir = {0};
void PS2MouseInterruptHandler(TrapFrame *)
{
uint8_t data = PS2ReadData();
if (data == PS2_MOUSE_RESP_ACK ||
data == PS2_MOUSE_RESP_RESEND)
return;
if (!PacketReady)
{
switch (Cycle)
{
case 0:
{
if ((data & 0b00001000 /* Always 1 */) == 0)
return;
Packet.Base.Raw = data;
Cycle++;
break;
}
case 1:
{
Packet.XMovement = data;
Cycle++;
break;
}
case 2:
{
Packet.YMovement = data;
if (FourPackets)
Cycle++;
else
{
Cycle = 0;
PacketReady = true;
}
break;
}
case 3:
{
Packet.ZMovement.Raw = data;
Cycle = 0;
PacketReady = true;
break;
}
default:
break;
}
return;
}
/* https://stackoverflow.com/a/3208376/9352057 */
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte) \
((byte) & 0x80 ? '1' : '0'), \
((byte) & 0x40 ? '1' : '0'), \
((byte) & 0x20 ? '1' : '0'), \
((byte) & 0x10 ? '1' : '0'), \
((byte) & 0x08 ? '1' : '0'), \
((byte) & 0x04 ? '1' : '0'), \
((byte) & 0x02 ? '1' : '0'), \
((byte) & 0x01 ? '1' : '0')
DebugLog("PS/2 Mouse Packet: [" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN "] LB:%d RB:%d MB:%d A1:%d XS:%d YS:%d XO:%d YO:%d | X:%03d Y:%03d | Z:%d B4:%d B5:%d A0:%d A0:%d",
BYTE_TO_BINARY(Packet.Base.Raw),
BYTE_TO_BINARY(Packet.XMovement),
BYTE_TO_BINARY(Packet.YMovement),
BYTE_TO_BINARY(Packet.ZMovement.Raw),
Packet.Base.LeftButton, Packet.Base.RightButton, Packet.Base.MiddleButton,
Packet.Base.Always1,
Packet.Base.XSign, Packet.Base.YSign,
Packet.Base.XOverflow, Packet.Base.YOverflow,
Packet.XMovement, Packet.YMovement,
Packet.ZMovement.Z, Packet.ZMovement.Button4, Packet.ZMovement.Button5,
Packet.ZMovement.Always0, Packet.ZMovement.Always0_2);
int X, Y;
X = Packet.XMovement - (Packet.Base.XSign ? 256 : 0);
Y = Packet.YMovement - (Packet.Base.YSign ? 256 : 0);
if (Packet.Base.XOverflow)
X = 0;
if (Packet.Base.YOverflow)
Y = 0;
mir.Type = INPUT_TYPE_MOUSE;
mir.Device = MouseDevID;
mir.Mouse.LeftButton = Packet.Base.LeftButton;
mir.Mouse.RightButton = Packet.Base.RightButton;
mir.Mouse.MiddleButton = Packet.Base.MiddleButton;
mir.Mouse.Button4 = Packet.ZMovement.Button4;
mir.Mouse.Button5 = Packet.ZMovement.Button5;
mir.Mouse.X = X;
mir.Mouse.Y = -Y;
mir.Mouse.Z = Packet.ZMovement.Z;
ReportInputEvent(&mir);
PacketReady = false;
}
void MouseSampleRate(uint8_t SampleRate)
{
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_SET_SAMPLE_RATE);
PS2ReadData();
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(SampleRate);
PS2ReadData();
}
int __fs_ms_Ioctl(struct Inode *, unsigned long, void *)
{
return 0;
}
const struct InodeOperations MouseOps = {
.Ioctl = __fs_ms_Ioctl,
};
int InitializeMouse()
{
PS2WriteData(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_RESET);
uint8_t test = PS2ReadData();
if (test != PS2_MOUSE_RESP_TEST_PASSED &&
test != PS2_MOUSE_RESP_ACK)
{
KernelLog("PS/2 mouse reset failed! (%#x)", test);
return -EFAULT;
}
RegisterInterruptHandler(12, PS2MouseInterruptHandler);
MouseDevID = RegisterDevice(INPUT_TYPE_MOUSE, &MouseOps);
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_SET_DEFAULTS);
PS2ReadData();
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_ENABLE_DATA_REPORTING);
MouseSampleRate(200);
MouseSampleRate(100);
MouseSampleRate(80);
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_READ_ID);
uint8_t Device2ID = PS2ReadData();
KernelLog("PS/2 Mouse ID: %#x", Device2ID);
MouseSampleRate(200);
MouseSampleRate(200);
MouseSampleRate(80);
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_READ_ID);
Device2ID = PS2ReadData();
KernelLog("PS/2 Mouse ID: %#x", Device2ID);
if (Device2ID >= 3 && Device2ID <= 4)
FourPackets = true;
if (Device2ID == 4)
MouseButton45 = true;
return 0;
}
int FinalizeMouse()
{
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
UnregisterDevice(MouseDevID);
return 0;
}
int DetectPS2Mouse()
{
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
if (PS2ACKTimeout() != 0)
KernelLog("PS/2 mouse failed to disable data reporting!");
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_READ_ID);
if (PS2ACKTimeout() != 0)
KernelLog("PS/2 mouse failed to read ID!");
uint8_t recByte;
int timeout = 1000000;
while (timeout--)
{
recByte = PS2ReadData();
if (recByte != PS2_ACK)
break;
}
Device2ID[0] = recByte;
timeout = 1000000;
while (timeout--)
{
recByte = PS2ReadData();
if (recByte != PS2_ACK)
break;
}
Device2ID[1] = recByte;
KernelLog("PS2 Mouse Device: 0x%X 0x%X", Device2ID[0], Device2ID[1]);
return 0;
}

View File

@ -1,646 +0,0 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Drivers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include "aip.h"
#include <errno.h>
#include <base.h>
#include <fs.h>
#include <input.h>
#include <io.h>
#define SERIAL_ENABLE_DLAB 0x80
#define SERIAL_BUFFER_EMPTY 0x20
enum Ports
{
COM1 = 0x3F8,
COM2 = 0x2F8,
COM3 = 0x3E8,
COM4 = 0x2E8,
COM5 = 0x5F8,
COM6 = 0x4F8,
COM7 = 0x5E8,
COM8 = 0x4E8,
LPT1 = 0x378,
LPT2 = 0x278,
LPT3 = 0x3BC
};
enum SerialSpeed
{
RATE_50_HI = 0x09,
RATE_50_LO = 0x00,
RATE_300_HI = 0x01,
RATE_300_LO = 0x80,
RATE_600_HI = 0x00,
RATE_600_LO = 0xC0,
RATE_2400_HI = 0x00,
RATE_2400_LO = 0x30,
RATE_4800_HI = 0x00,
RATE_4800_LO = 0x18,
RATE_9600_HI = 0x00,
RATE_9600_LO = 0x0C,
RATE_19200_HI = 0x00,
RATE_19200_LO = 0x06,
RATE_38400_HI = 0x00,
RATE_38400_LO = 0x03,
RATE_57600_HI = 0x00,
RATE_57600_LO = 0x02,
RATE_115200_HI = 0x00,
RATE_115200_LO = 0x01
};
/*
. Table of Registers .
/---------------------------------------------------------------------\
| Base Address | DLAB | R/W | Abr | Register Name |
|---------------------------------------------------------------------|
| +0 | =0 | W | - | Transmitter Holding Buffer |
| | =0 | R | - | Receiver Buffer |
| | =1 | R/W | - | Divisor Latch Low Byte |
| +1 | =0 | R/W | IER | Interrupt Enable Register |
| | =1 | R/W | - | Divisor Latch High Byte |
| +2 | - | R | IIR | Interrupt Identification Register |
| | - | W | FCR | FIFO Control Register |
| +3 | - | R/W | LCR | Line Control Register |
| +4 | - | R/W | MCR | Modem Control Register |
| +5 | - | R | LSR | Line Status Register |
| +6 | - | R | MSR | Modem Status Register |
| +7 | - | R/W | - | Scratch Register |
\---------------------------------------------------------------------/
Source:
Interfacing the Serial / RS232 Port V5.0
Table 5 : Table of Registers
*/
/** Interrupt Enable Register */
typedef union
{
struct
{
/* Enable Received Data Available Interrupt */
uint8_t InterruptOnReceive : 1;
/* Enable Transmitter Holding Register Empty Interrupt */
uint8_t InterruptOnTransmitter : 1;
/* Enable Receiver Line Status Interrupt */
uint8_t LineStatusInterrupt : 1;
/* Enable Modem Status Interrupt */
uint8_t ModemStatusInterrupt : 1;
/* Enables Sleep Mode (16750) */
uint8_t SleepMode : 1;
/* Enables Low Power Mode (16750) */
uint8_t LowPowerMode : 1;
/* Reserved */
uint8_t __reserved : 2;
};
uint8_t raw;
} IER;
/** Interrupt Identification Register */
typedef union
{
struct
{
/* Interrupt pending */
uint8_t InterruptPending : 1;
/**
* Interrupt Status
*
* 00b = Modem Status Interrupt
* 01b = Transmitter Holding Register Empty Interrupt
* 10b = Received Data Available Interrupt
* 11b = Receiver Line Status Interrupt
*/
uint8_t InterruptStatus : 2;
/**
* 16550 Time-out Interrupt Pending
*
* @note Reserved on 8250, 16450
*/
uint8_t TimeOutIP : 1;
/** Reserved */
uint8_t __reserved : 1;
/** 64 Byte Fifo Enabled (16750 only) */
uint8_t FIFO64 : 1;
/**
* Enable FIFO
*
* 00b = No FIFO
* 01b = FIFO Enabled but Unusable
* 11b = FIFO Enabled
*/
uint8_t FIFO : 2;
};
uint8_t raw;
} IIR;
/** First In / First Out Control Register */
typedef union
{
struct
{
/** Enable FIFO's */
uint8_t FIFO : 1;
/** Clear Receive FIFO */
uint8_t ClearRX : 1;
/** Clear Transmit FIFO */
uint8_t ClearTX : 1;
/** DMA Mode Select.
*
* Change status of RXRDY & TXRDY pins from mode 1 to mode 2.
*/
uint8_t DMAMode : 1;
/** Reserved */
uint8_t __reserved : 1;
/** Enable 64 Byte FIFO (16750 only) */
uint8_t FIFO64 : 1;
/** Interrupt Trigger Level
*
* 00b = 1 Byte
* 01b = 4 Bytes
* 10b = 8 Bytes
* 11b = 14 Bytes
*/
uint8_t TriggerLevel : 2;
};
uint8_t raw;
} FCR;
/** Line Control Register */
typedef union
{
struct
{
/** Word Length
*
* 00b = 5 bits
* 01b = 6 bits
* 10b = 7 bits
* 11b = 8 bits
*/
uint8_t WordLength : 2;
/** Length of Stop Bit
*
* 0b = One Stop Bit
* 1b = 2 Stop bits for words of length 6,7 or 8 bits or 1.5 Stop Bits for Word lengths of 5 bits.
*/
uint8_t StopBit : 1;
/** Parity Select
*
* 0b = No Parity
* 001b = Odd Parity
* 011b = Even Parity
* 101b = High Parity (Sticky)
* 111b = Low Parity (Sticky)
*/
uint8_t Parity : 3;
/** Set Break Enable */
uint8_t SetBreak : 1;
/**
* Divisor Latch Access
*
* 0b = Access to Receiver buffer, Transmitter buffer & Interrupt Enable Register
* 1b = Divisor Latch Access Bit
*/
uint8_t DLAB : 1;
};
uint8_t raw;
} LCR;
/** Modem Control Register */
typedef union
{
struct
{
/** Force Data Terminal Ready */
uint8_t DataTerminalReady : 1;
/** Force Request to Send */
uint8_t RequestToSend : 1;
/** Auxiliary Output 1 */
uint8_t Out1 : 1;
/** Auxiliary Output 2 */
uint8_t Out2 : 1;
/** Loopback Mode */
uint8_t Loopback : 1;
/** Autoflow Control Enabled (16750 only) */
uint8_t Autoflow : 1;
/** Reserved */
uint8_t __reserved : 2;
};
uint8_t raw;
} MCR;
/** Line Status Register */
typedef union
{
struct
{
/** Data Ready */
uint8_t DataReady : 1;
/** Overrun Error */
uint8_t OverrunError : 1;
/** Parity Error */
uint8_t ParityError : 1;
/** Framing Error */
uint8_t FramingError : 1;
/** Break Interrupt */
uint8_t BreakInterrupt : 1;
/** Empty Transmitter Holding Register */
uint8_t EmptyTransmitterHolding : 1;
/** Empty Data Holding Registers */
uint8_t EmptyDataHolding : 1;
/** Error in Received FIFO */
uint8_t ErrorReceivedFIFO : 1;
};
uint8_t raw;
} LSR;
/** Modem Status Register */
typedef union
{
struct
{
/** Delta Clear to Send */
uint8_t DeltaClearToSend : 1;
/** Delta Data Set Ready */
uint8_t DeltaDataSetReady : 1;
/** Trailing Edge Ring Indicator */
uint8_t TrailingEdgeRingIndicator : 1;
/** Delta Data Carrier Detect */
uint8_t DeltaDataCarrierDetect : 1;
/** Clear To Send */
uint8_t ClearToSend : 1;
/** Data Set Ready */
uint8_t DataSetReady : 1;
/** Ring Indicator */
uint8_t RingIndicator : 1;
/** Carrier Detect */
uint8_t CarrierDetect : 1;
};
uint8_t raw;
} MSR;
union UARTs
{
struct
{
uint8_t com1 : 1;
uint8_t com2 : 1;
uint8_t com3 : 1;
uint8_t com4 : 1;
uint8_t com5 : 1;
uint8_t com6 : 1;
uint8_t com7 : 1;
uint8_t com8 : 1;
uint8_t lpt1 : 1;
uint8_t lpt2 : 1;
uint8_t lpt3 : 1;
uint8_t __reserved : 5;
};
uint16_t raw;
} uart;
bool IsDataReady(uint16_t Port)
{
LSR lsr;
lsr.raw = inb(Port + 5);
return lsr.DataReady;
}
bool IsTransmitEmpty(uint16_t Port)
{
LSR lsr;
lsr.raw = inb(Port + 5);
return lsr.EmptyTransmitterHolding;
}
char ReadSerial(uint16_t Port)
{
while (!IsDataReady(Port))
Yield();
return inb(Port);
}
void WriteSerial(uint16_t Port, char Character)
{
while (!IsTransmitEmpty(Port))
Yield();
outb(Port, Character);
}
void ReportSerialReceived(uint8_t Data)
{
DebugLog("%c", Data);
}
void UartCOM24(TrapFrame *)
{
LSR lsr2, lsr4;
do
{
lsr2.raw = inb(COM2 + 5);
if (lsr2.DataReady)
ReportSerialReceived(inb(COM2));
lsr4.raw = inb(COM4 + 5);
if (lsr4.DataReady)
ReportSerialReceived(inb(COM4));
} while (lsr2.DataReady || lsr4.DataReady);
}
void UartCOM13(TrapFrame *)
{
LSR lsr1, lsr3;
do
{
lsr1.raw = inb(COM1 + 5);
if (lsr1.DataReady)
ReportSerialReceived(inb(COM1));
lsr3.raw = inb(COM3 + 5);
if (lsr3.DataReady)
ReportSerialReceived(inb(COM3));
} while (lsr1.DataReady || lsr3.DataReady);
}
bool InitializePort(uint16_t Port)
{
ECS;
LCR lcr = {0};
IER ier = {0};
FCR fcr = {0};
MCR mcr = {0};
outb(Port + 3, lcr.raw);
outb(Port + 1, ier.raw);
lcr.DLAB = 1;
outb(Port + 3, lcr.raw);
outb(Port + 0, RATE_115200_LO);
outb(Port + 1, RATE_115200_HI);
lcr.DLAB = 0;
lcr.WordLength = 0b11;
outb(Port + 3, lcr.raw);
fcr.FIFO = 1;
fcr.ClearRX = 1;
fcr.ClearTX = 1;
fcr.TriggerLevel = 0b11;
outb(Port + 2, fcr.raw);
mcr.DataTerminalReady = 1;
mcr.RequestToSend = 1;
mcr.Out2 = 1;
mcr.Loopback = 1;
outb(Port + 4, mcr.raw);
/* Test the serial port */
outb(Port + 0, 0x48);
uint8_t result = inb(Port + 0);
if (result != 0x48)
{
/* FIXME: DETECT BAUD RATE
Do multiple test to check if the output is garbage.
If so, reduce the baud rate until it works. */
LCS;
KernelPrint("Port %#X test failed!", Port);
return false;
}
/* Set normal operation mode */
mcr.DataTerminalReady = 1;
mcr.RequestToSend = 1;
mcr.Out1 = 1;
mcr.Out2 = 1;
mcr.Loopback = 0;
outb(Port + 4, mcr.raw);
/* Enable interrupts on receive */
ier.InterruptOnReceive = 1;
outb(Port + 1, ier.raw);
RegisterInterruptHandler(3, UartCOM24);
RegisterInterruptHandler(4, UartCOM13);
LCS;
KernelPrint("Port %#X initialized", Port);
return true;
}
int DetectUART()
{
uart.com1 = inb(COM1) != 0xFF ? true : false;
uart.com2 = inb(COM2) != 0xFF ? true : false;
uart.com3 = inb(COM3) != 0xFF ? true : false;
uart.com4 = inb(COM4) != 0xFF ? true : false;
uart.com5 = inb(COM5) != 0xFF ? true : false;
uart.com6 = inb(COM6) != 0xFF ? true : false;
uart.com7 = inb(COM7) != 0xFF ? true : false;
uart.com8 = inb(COM8) != 0xFF ? true : false;
uart.lpt1 = inb(LPT1) != 0xFF ? true : false;
uart.lpt2 = inb(LPT2) != 0xFF ? true : false;
uart.lpt3 = inb(LPT3) != 0xFF ? true : false;
if (uart.com1 == true)
if (InitializePort(COM1) == false)
uart.com1 = false;
if (uart.com2 == true)
if (InitializePort(COM2) == false)
uart.com1 = false;
if (uart.com3 == true)
if (InitializePort(COM3) == false)
uart.com1 = false;
if (uart.com4 == true)
if (InitializePort(COM4) == false)
uart.com1 = false;
if (uart.com5 == true)
if (InitializePort(COM5) == false)
uart.com1 = false;
if (uart.com6 == true)
if (InitializePort(COM6) == false)
uart.com1 = false;
if (uart.com7 == true)
if (InitializePort(COM7) == false)
uart.com1 = false;
if (uart.com8 == true)
if (InitializePort(COM8) == false)
uart.com1 = false;
if (uart.lpt1 == true)
KernelPrint("LPT1 is present");
if (uart.lpt2 == true)
KernelPrint("LPT2 is present");
if (uart.lpt3 == true)
KernelPrint("LPT3 is present");
return 0;
}
// static int once = 0;
// static uint8_t com4 = 0xFF;
// if (!once++)
// com4 = inb(0x2E8);
// if (com4 == 0xFF)
// CPU::Halt(true);
// char UserInputBuffer[256]{'\0'};
// int BackSpaceLimit = 0;
// while (true)
// {
// while ((inb(0x2E8 + 5) & 1) == 0)
// CPU::Pause();
// char key = inb(0x2E8);
// // debug("key: %d", key);
// if (key == '\x7f') /* Backspace (DEL) */
// {
// if (BackSpaceLimit <= 0)
// continue;
// char keyBuf[5] = {'\b', '\x1b', '[', 'K', '\0'};
// ExPrint(keyBuf);
// backspace(UserInputBuffer);
// BackSpaceLimit--;
// continue;
// }
// else if (key == '\x0d') /* Enter (CR) */
// {
// UserInput(UserInputBuffer);
// BackSpaceLimit = 0;
// UserInputBuffer[0] = '\0';
// continue;
// }
// else if (key == '\x1b') /* Escape */
// {
// char tmp[16]{'\0'};
// append(tmp, key);
// while ((inb(0x2E8 + 5) & 1) == 0)
// CPU::Pause();
// char key = inb(0x2E8);
// append(tmp, key);
// if (key == '[')
// {
// // 27 91
// // < 68
// // > 67
// // down 66
// // up 65
// while ((inb(0x2E8 + 5) & 1) == 0)
// CPU::Pause();
// key = inb(0x2E8);
// append(tmp, key);
// switch (key)
// {
// case 'A':
// key = KEY_D_UP;
// break;
// case 'B':
// key = KEY_D_DOWN;
// break;
// case 'C':
// key = KEY_D_RIGHT;
// break;
// case 'D':
// key = KEY_D_LEFT;
// break;
// default:
// {
// for (size_t i = 0; i < strlen(tmp); i++)
// {
// if ((int)sizeof(UserInputBuffer) <= BackSpaceLimit)
// continue;
// append(UserInputBuffer, tmp[i]);
// BackSpaceLimit++;
// char keyBuf[2] = {(char)tmp[i], '\0'};
// ExPrint(keyBuf);
// }
// continue;
// }
// }
// ArrowInput(key);
// continue;
// }
// }
// if ((int)sizeof(UserInputBuffer) <= BackSpaceLimit)
// continue;
// append(UserInputBuffer, key);
// BackSpaceLimit++;
// char keyBuf[2] = {(char)key, '\0'};
// ExPrint(keyBuf);
// }

View File

@ -1,35 +0,0 @@
default:
$(error Do not run this Makefile directly!)
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
FILENAME = $(notdir $(shell pwd)).drv
build: $(FILENAME)
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
WARNCFLAG = -Wall -Wextra
%.o: %.c $(HEADERS)
$(info Compiling $<)
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
%.o: %.S
$(info Compiling $<)
$(AS) -o $@ $<
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

View File

@ -1,897 +0,0 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Drivers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include <driver.h>
#include <errno.h>
#include <fs.h>
#include <input.h>
#include <regs.h>
#include <base.h>
#include <aip.h>
#include <io.h>
enum RPCMessages
{
MSG_OPEN,
MSG_SENDSIZE,
MSG_SENDPAYLOAD,
MSG_RECVSIZE,
MSG_RECVPAYLOAD,
MSG_RECVSTATUS,
MSG_CLOSE,
};
enum RPCStatus
{
STATUS_SUCCESS = 0x1,
STATUS_DORECV = 0x2,
STATUS_CPT = 0x10,
STATUS_HB = 0x80,
};
typedef struct
{
union
{
uint32_t ax;
uint32_t magic;
};
union
{
uint32_t bx;
size_t size;
};
union
{
uint32_t cx;
uint16_t command;
};
union
{
uint32_t dx;
uint16_t port;
};
uint32_t si;
uint32_t di;
} VMwareCommand;
#define VMWARE_MAGIC 0x564D5868
#define VMWARE_PORT 0x5658
#define VMWARE_PORTHB 0x5659
#define VMWARE_HYPERVISOR_HB 0x00000000
#define VMWARE_HYPERVISOR_OUT 0x00000001
#define CMD_GETVERSION 0xA
#define CMD_MESSAGE 0x1E
#define CMD_ABSPOINTER_DATA 0x27
#define CMD_ABSPOINTER_STATUS 0x28
#define CMD_ABSPOINTER_COMMAND 0x29
#define ABSPOINTER_ENABLE 0x45414552
#define ABSPOINTER_RELATIVE 0xF5
#define ABSPOINTER_ABSOLUTE 0x53424152
#define MESSAGE_RPCI 0x49435052
#define MESSAGE_TCLO 0x4f4c4354
#define FLAG_COOKIE 0x80000000
#define ToMsg(x) ((x) << 16 | CMD_MESSAGE)
#define HighWord(x) ((x & 0xFFFF0000) >> 16)
#define MESSAGE_HB_MSG 0
#define MESSAGE_OPEN_CHANNEL ToMsg(MSG_OPEN)
#define MESSAGE_CLOSE_CHANNEL ToMsg(MSG_CLOSE)
#define MESSAGE_SEND_SIZE ToMsg(MSG_SENDSIZE)
#define MESSAGE_SEND_PAYLOAD ToMsg(MSG_SENDPAYLOAD)
#define MESSAGE_RECV_SIZE ToMsg(MSG_RECVSIZE)
#define MESSAGE_RECV_PAYLOAD ToMsg(MSG_RECVPAYLOAD)
#define MESSAGE_RECV_STATUS ToMsg(MSG_RECVSTATUS)
#if defined(__amd64__)
#define VM_PORT(cmd, in_ebx, isi, idi, \
flags, magic, \
ax, bx, cx, dx, si, di) \
__asm__ __volatile__("movw $0x5658, %%dx\n" \
"inl %%dx, %%eax\n" \
: "=a"(ax), \
"=b"(bx), \
"=c"(cx), \
"=d"(dx), \
"=S"(si), \
"=D"(di) \
: "a"(magic), \
"b"(in_ebx), \
"c"(cmd), \
"d"(flags), \
"S"(isi), \
"D"(idi) : "memory")
#define VM_PORT_HB_OUT(cmd, in_ecx, isi, idi, \
flags, magic, bp, \
ax, bx, cx, dx, si, di) \
__asm__ __volatile__("push %%rbp\n" \
"mov %12, %%rbp\n" \
"movw $0x5659, %%dx\n" \
"rep outsb\n" \
"pop %%rbp\n" \
: "=a"(ax), \
"=b"(bx), \
"=c"(cx), \
"=d"(dx), \
"=S"(si), \
"=D"(di) \
: "a"(magic), \
"b"(cmd), \
"c"(in_ecx), \
"d"(flags), \
"S"(isi), \
"D"(idi), \
"r"(bp) : "memory", "cc")
#define VM_PORT_HB_IN(cmd, in_ecx, isi, idi, \
flags, magic, bp, \
ax, bx, cx, dx, si, di) \
__asm__ __volatile__("push %%rbp\n" \
"mov %12, %%rbp\n" \
"movw $0x5659, %%dx\n" \
"rep insb\n" \
"pop %%rbp\n" \
: "=a"(ax), \
"=b"(bx), \
"=c"(cx), \
"=d"(dx), \
"=S"(si), \
"=D"(di) \
: "a"(magic), \
"b"(cmd), \
"c"(in_ecx), \
"d"(flags), \
"S"(isi), \
"D"(idi), \
"r"(bp) : "memory", "cc")
#elif defined(__i386__)
#define VM_PORT(cmd, in_ebx, isi, idi, \
flags, magic, \
ax, bx, cx, dx, si, di)
#define VM_PORT_HB_OUT(cmd, in_ecx, isi, idi, \
flags, \
magic, bp, ax, \
bx, cx, dx, si, di)
#define VM_PORT_HB_IN(cmd, in_ecx, isi, idi, \
flags, magic, bp, \
ax, bx, cx, dx, si, di)
#endif
/* TODO:
- use vmcall or vmmcall instead of "out" and "in" if available
*/
typedef struct
{
int TCLOChannel;
uint16_t ChannelID;
uint32_t CookieHigh;
uint32_t CookieLow;
} ToolboxContext;
dev_t MouseDevID = -1;
int __strcmp(const char *l, const char *r)
{
for (; *l == *r && *l; l++, r++)
;
return *(unsigned char *)l - *(unsigned char *)r;
}
void __cpuid(uint32_t Function,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx)
{
asmv("cpuid"
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
: "a"(Function));
}
bool __CheckHypervisorBit()
{
uint32_t eax, ebx, ecx, edx;
__cpuid(0x1, &eax, &ebx, &ecx, &edx);
if (!(ecx & (1 << 31)))
return false; /* Hypervisor not detected */
return true;
}
bool __VMwareBackdoorHypervisors()
{
const char hv[13] = {0};
uint32_t eax, ebx, ecx, edx;
__cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
*(uint32_t *)hv = ebx;
*(uint32_t *)(hv + 4) = ecx;
*(uint32_t *)(hv + 8) = edx;
if (__strcmp(hv, "VMwareVMware") != 0 &&
__strcmp(hv, "KVMKVMKVM") != 0 &&
__strcmp(hv, "TCGTCGTCGTCG") != 0)
{
return false;
}
return true;
}
bool IsVMwareBackdoorAvailable()
{
if (!__CheckHypervisorBit())
return false;
if (!__VMwareBackdoorHypervisors())
return false;
struct
{
union
{
uint32_t ax;
uint32_t magic;
};
union
{
uint32_t bx;
size_t size;
};
union
{
uint32_t cx;
uint16_t command;
};
union
{
uint32_t dx;
uint16_t port;
};
uint32_t si;
uint32_t di;
} cmd;
cmd.si = cmd.di = 0;
cmd.bx = ~0x564D5868;
cmd.command = 0xA;
cmd.magic = 0x564D5868;
cmd.port = 0x5658;
asmv("in %%dx, %0"
: "+a"(cmd.ax), "+b"(cmd.bx),
"+c"(cmd.cx), "+d"(cmd.dx),
"+S"(cmd.si), "+D"(cmd.di));
if (cmd.bx != 0x564D5868 ||
cmd.ax == 0xFFFFFFFF)
return false;
return true;
}
static int OpenMessageChannel(ToolboxContext *ctx, uint32_t Protocol)
{
uintptr_t ax, bx, cx, dx, si = 0, di = 0;
VM_PORT(MESSAGE_OPEN_CHANNEL,
(Protocol | FLAG_COOKIE), si, di,
0, VMWARE_MAGIC,
ax, bx, cx, dx, si, di);
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
{
KernelLog("Failed to open message channel %#lx", Protocol);
return -EINVAL;
}
DebugLog("Opened message channel %d (Protocol: %#lx)",
HighWord(dx), Protocol);
ctx->ChannelID = (uint16_t)HighWord(dx);
ctx->CookieHigh = si;
ctx->CookieLow = di;
return 0;
}
static void MessageClose(ToolboxContext *ctx)
{
uintptr_t ax, bx, cx, dx,
si = ctx->CookieHigh,
di = ctx->CookieLow;
VM_PORT(MESSAGE_CLOSE_CHANNEL,
0, si, di,
ctx->ChannelID << 16,
VMWARE_MAGIC,
ax, bx, cx, dx, si, di);
DebugLog("Closed message channel %d", ctx->ChannelID);
}
static uintptr_t MessageSendHB(ToolboxContext *ctx,
const char *Message)
{
uintptr_t ax, bx, cx, dx,
si = (uintptr_t)Message,
di = ctx->CookieLow,
bp = ctx->CookieHigh;
uint32_t ChannelID = ctx->ChannelID << 16;
size_t Size = StringLength(Message);
VM_PORT_HB_OUT((STATUS_SUCCESS << 16) | MESSAGE_HB_MSG,
Size, si, di,
VMWARE_HYPERVISOR_HB | ChannelID | VMWARE_HYPERVISOR_OUT,
VMWARE_MAGIC, bp,
ax, bx, cx, dx, si, di);
return bx;
}
static uintptr_t MessageSendLB(ToolboxContext *ctx,
const char *Message)
{
uintptr_t ax, bx,
cx = STATUS_SUCCESS << 16,
dx, si, di;
size_t Size = StringLength(Message);
while (Size &&
(HighWord(cx) & STATUS_SUCCESS))
{
uint32_t TotalBytes = MIN((uint32_t)Size, (uint32_t)4);
uint32_t Word = 0;
MemoryCopy(&Word, Message, TotalBytes);
Message += TotalBytes;
si = ctx->CookieHigh;
di = ctx->CookieLow;
VM_PORT(MESSAGE_SEND_PAYLOAD,
Word, si, di,
ctx->ChannelID << 16,
VMWARE_MAGIC,
ax, bx, cx, dx, si, di);
}
return cx;
}
static uintptr_t MessageReceiveHB(ToolboxContext *ctx,
char *Buffer,
size_t BufferSize)
{
uintptr_t ax, bx, cx, dx,
si = ctx->CookieHigh,
di = (uintptr_t)Buffer,
bp = ctx->CookieLow;
uint32_t ChannelID = ctx->ChannelID << 16;
VM_PORT_HB_IN((STATUS_SUCCESS << 16) | MESSAGE_HB_MSG,
BufferSize, si, di,
VMWARE_HYPERVISOR_HB | ChannelID | VMWARE_HYPERVISOR_OUT,
VMWARE_MAGIC, bp,
ax, bx, cx, dx, si, di);
return bx;
}
static uintptr_t MessageReceiveLB(ToolboxContext *ctx,
char *Buffer,
size_t BufferSize)
{
uintptr_t ax, bx,
cx = STATUS_SUCCESS << 16,
dx, si, di;
while (BufferSize)
{
uint32_t TotalBytes = MIN((uint32_t)BufferSize, (uint32_t)4);
si = ctx->CookieHigh;
di = ctx->CookieLow;
VM_PORT(MESSAGE_RECV_PAYLOAD,
STATUS_SUCCESS, si, di,
ctx->ChannelID << 16,
VMWARE_MAGIC,
ax, bx, cx, dx, si, di);
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
break;
MemoryCopy(Buffer, &bx, TotalBytes);
Buffer += TotalBytes;
BufferSize -= TotalBytes;
}
return cx;
}
static int MessageSend(ToolboxContext *ctx,
const char *Message)
{
uintptr_t ax, bx, cx, dx, si, di;
size_t Size = StringLength(Message);
int Retries = 0;
while (Retries < 2)
{
Retries++;
si = ctx->CookieHigh;
di = ctx->CookieLow;
VM_PORT(MESSAGE_SEND_SIZE,
Size, si, di,
ctx->ChannelID << 16,
VMWARE_MAGIC,
ax, bx, cx, dx, si, di);
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
{
KernelLog("Failed to send message size for \"%s\": %d",
Message, cx);
return -EINVAL;
}
bool HighBand = (HighWord(cx) & STATUS_HB) != 0;
if (HighBand)
bx = MessageSendHB(ctx, Message);
else
bx = MessageSendLB(ctx, Message);
int status = HighWord(bx);
if ((status & STATUS_SUCCESS) != 0)
{
DebugLog("Message \"%s\" sent", Message);
return 0;
}
else if ((status & STATUS_CPT) == 0)
{
KernelLog("Checkpoint occurred for message \"%s\"", Message);
continue;
}
else
break;
}
KernelLog("Failed to send message \"%s\": %#lx", Message, bx);
return -EINVAL;
}
static int MessageReceive(ToolboxContext *ctx,
char **Buffer,
size_t *BufferSize)
{
uintptr_t ax, bx, cx, dx, si, di;
int Retries = 0;
*Buffer = NULL;
*BufferSize = 0;
char *ReplyBuf = NULL;
size_t ReplyBufPages = 0;
size_t ReplySize = 0;
while (Retries < 2)
{
Retries++;
si = ctx->CookieHigh;
di = ctx->CookieLow;
VM_PORT(MESSAGE_RECV_SIZE,
0, si, di,
ctx->ChannelID << 16,
VMWARE_MAGIC,
ax, bx, cx, dx, si, di);
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
{
KernelLog("Failed to receive message size: %d", cx);
return -EINVAL;
}
else if ((HighWord(cx) & STATUS_DORECV) == 0)
{
DebugLog("No message to receive");
return -EAGAIN;
}
ReplySize = bx;
if (ReplyBuf != NULL)
FreeMemory(ReplyBuf, ReplyBufPages);
ReplyBufPages = ReplySize / 0x1000 + 1;
ReplyBuf = AllocateMemory(ReplyBufPages);
bool HighBand = (HighWord(cx) & STATUS_HB) != 0;
if (HighBand)
bx = MessageReceiveHB(ctx, ReplyBuf, ReplySize);
else
bx = MessageReceiveLB(ctx, ReplyBuf, ReplySize);
if ((HighWord(bx) & STATUS_SUCCESS) == 0)
{
if ((HighWord(bx) & STATUS_CPT) == 0)
{
KernelLog("Checkpoint occurred for message payload");
continue;
}
KernelLog("Failed to receive message payload: %d", HighWord(bx));
FreeMemory(ReplyBuf, ReplyBufPages);
return -EINVAL;
}
ReplyBuf[ReplySize] = '\0';
si = ctx->CookieHigh;
di = ctx->CookieLow;
VM_PORT(MESSAGE_RECV_STATUS,
STATUS_SUCCESS, si, di,
ctx->ChannelID << 16,
VMWARE_MAGIC,
ax, bx, cx, dx, si, di);
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
{
if ((HighWord(cx) & STATUS_CPT) == 0)
{
KernelLog("Retrying message receive");
continue;
}
KernelLog("Failed to receive message status: %d", HighWord(cx));
FreeMemory(ReplyBuf, ReplyBufPages);
return -EINVAL;
}
break;
}
if (ReplyBuf == NULL)
{
KernelLog("Failed to receive message");
return -EINVAL;
}
*Buffer = ReplyBuf;
*BufferSize = ReplySize;
DebugLog("Received message \"%s\"", ReplyBuf);
return 0;
}
static int SendRPCI(ToolboxContext *, const char *Request)
{
ToolboxContext rpci_ctx = {0};
int status = OpenMessageChannel(&rpci_ctx, MESSAGE_RPCI);
if (status < 0)
{
KernelLog("Failed to open RPCI channel: %d", status);
return status;
}
status = MessageSend(&rpci_ctx, Request);
if (status < 0)
{
KernelLog("Failed to send RPCI request: %d", status);
return status;
}
MessageClose(&rpci_ctx);
return 0;
}
int MsgEqual(const char *haystack, const char *needle)
{
return strstr(haystack, needle) == haystack;
}
static int DisplayGetSize(ToolboxContext *ctx)
{
if (ctx->TCLOChannel != -1)
MessageClose(ctx);
OpenMessageChannel(ctx, MESSAGE_TCLO);
char EmptyBuffer[256] = {'\0'};
MessageSend(ctx, EmptyBuffer);
while (true)
{
/* FIXME: buf memory leak */
char *buf;
size_t len;
int status = MessageReceive(ctx, &buf, &len);
if (status == -EAGAIN)
{
Sleep(1000);
continue;
}
else if (status < 0)
{
KernelLog("Failed to receive message");
return 1;
}
buf[StringLength(buf)] = '\0';
if (MsgEqual(buf, "reset"))
{
if (MessageSend(ctx, "OK ATR toolbox") < 0)
return 1;
}
else if (MsgEqual(buf, "ping"))
{
if (MessageSend(ctx, "OK ") < 0)
return 1;
}
else if (MsgEqual(buf, "Capabilities_Register"))
{
SendRPCI(ctx, "tools.capability.resolution_set 1");
SendRPCI(ctx, "tools.capability.resolution_server toolbox 1");
SendRPCI(ctx, "tools.capability.display_topology_set 1");
SendRPCI(ctx, "tools.capability.color_depth_set 1");
SendRPCI(ctx, "tools.capability.resolution_min 0 0");
SendRPCI(ctx, "tools.capability.unity 1");
if (MessageSend(ctx, "OK ") < 0)
return 1;
}
else if (MsgEqual(buf, "Resolution_Set"))
{
DebugLog("%s", buf);
if (MessageSend(ctx, "OK ") < 0)
return 1;
MessageClose(ctx);
return 0;
}
else
{
if (MessageSend(ctx, "ERROR Unknown command") < 0)
return 1;
}
}
}
pid_t dst_id = -1;
pid_t dst_pid = -1;
ToolboxContext *tb_ctx = NULL;
void DisplayScaleThread()
{
/* sizeof ToolboxContext */
tb_ctx = AllocateMemory(1);
Sleep(2000);
while (true)
{
if (DisplayGetSize(tb_ctx) != 0)
KernelLog("Failed to scale display");
Sleep(1000);
}
}
void CommandSend(VMwareCommand *cmd)
{
cmd->magic = VMWARE_MAGIC;
cmd->port = VMWARE_PORT;
asm volatile("in %%dx, %0"
: "+a"(cmd->ax), "+b"(cmd->bx),
"+c"(cmd->cx), "+d"(cmd->dx),
"+S"(cmd->si), "+D"(cmd->di));
}
void Absolute()
{
VMwareCommand cmd = {0};
/* Enable */
cmd.bx = ABSPOINTER_ENABLE;
cmd.command = CMD_ABSPOINTER_COMMAND;
CommandSend(&cmd);
/* Status */
cmd.bx = 0;
cmd.command = CMD_ABSPOINTER_STATUS;
CommandSend(&cmd);
/* Read data (1) */
cmd.bx = 1;
cmd.command = CMD_ABSPOINTER_DATA;
CommandSend(&cmd);
/* Enable absolute */
cmd.bx = ABSPOINTER_ABSOLUTE;
cmd.command = CMD_ABSPOINTER_COMMAND;
CommandSend(&cmd);
}
void Relative()
{
VMwareCommand cmd = {0};
cmd.bx = ABSPOINTER_RELATIVE;
cmd.command = CMD_ABSPOINTER_COMMAND;
CommandSend(&cmd);
}
InputReport ir = {0};
void InterruptHandler(TrapFrame *)
{
uint8_t Data = inb(0x60);
(void)Data;
VMwareCommand cmd = {0};
cmd.bx = 0;
cmd.command = CMD_ABSPOINTER_STATUS;
CommandSend(&cmd);
if (cmd.ax == 0xFFFF0000)
{
KernelLog("VMware mouse is not connected?");
Relative();
Absolute();
return;
}
if ((cmd.ax & 0xFFFF) < 4)
return;
cmd.bx = 4;
cmd.command = CMD_ABSPOINTER_DATA;
CommandSend(&cmd);
int Buttons = (cmd.ax & 0xFFFF);
/**
* How should I handle this?
* (cmd.[bx,cx] * Width) / 0xFFFF
* Maybe TODO: Width and Height API?
*/
uintptr_t AbsoluteX = cmd.bx;
uintptr_t AbsoluteY = cmd.cx;
ir.Type = INPUT_TYPE_MOUSE;
ir.Device = MouseDevID;
ir.Mouse.X = AbsoluteX;
ir.Mouse.Y = AbsoluteY;
ir.Mouse.Z = (int8_t)cmd.dx;
ir.Mouse.Absolute = 1;
ir.Mouse.LeftButton = Buttons & 0x20;
ir.Mouse.RightButton = Buttons & 0x10;
ir.Mouse.MiddleButton = Buttons & 0x08;
// ir.Mouse.Button4 = 0x0;
// ir.Mouse.Button5 = 0x0;
// ir.Mouse.Button6 = 0x0;
// ir.Mouse.Button7 = 0x0;
// ir.Mouse.Button8 = 0x0;
ReportInputEvent(&ir);
}
int __fs_Ioctl(struct Inode *, unsigned long Request, void *)
{
switch (Request)
{
case 0x1:
Relative();
break;
case 0x2:
Absolute();
break;
default:
return -EINVAL;
}
return 0;
}
const struct InodeOperations MouseOps = {
.Ioctl = __fs_Ioctl,
};
bool ToolboxSupported = false;
int DriverEntry()
{
ToolboxContext tb_ctx = {0};
/* Test if it's supported */
int status = OpenMessageChannel(&tb_ctx, MESSAGE_TCLO);
if (status == 0)
{
ToolboxSupported = true;
MessageClose(&tb_ctx);
dst_id = CreateKernelThread(0, "VMware Display Scale",
(void *)DisplayScaleThread, NULL);
dst_pid = GetCurrentProcess();
}
PS2WriteCommand(PS2_CMD_ENABLE_PORT_2);
PS2WriteCommand(PS2_CMD_READ_CONFIG);
PS2_CONFIGURATION config = {.Raw = PS2ReadData()};
config.Port2Interrupt = 1;
PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
PS2WriteData(config.Raw);
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_SET_DEFAULTS);
PS2ReadData();
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_ENABLE_DATA_REPORTING);
PS2ReadData();
Absolute();
/**
* If we have another driver using the PS/2 mouse, we need to
* override its interrupt handler.
*/
OverrideInterruptHandler(12, InterruptHandler);
MouseDevID = RegisterDevice(INPUT_TYPE_MOUSE, &MouseOps);
return 0;
}
int DriverFinal()
{
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
Relative();
UnregisterDevice(MouseDevID);
if (ToolboxSupported)
{
KillThread(dst_id, dst_pid, 0);
if (tb_ctx->TCLOChannel != -1)
MessageClose(tb_ctx);
FreeMemory(tb_ctx, 1);
}
return 0;
}
int DriverPanic()
{
Relative();
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
return 0;
}
int DriverProbe()
{
if (!IsVMwareBackdoorAvailable())
return -ENODEV;
return 0;
}
DriverInfo("vmware",
"VMware Tools Driver",
"EnderIce2",
0, 0, 1,
"GPLv3");

View File

@ -1,35 +0,0 @@
default:
$(error Do not run this Makefile directly!)
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
FILENAME = $(notdir $(shell pwd)).drv
build: $(FILENAME)
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
WARNCFLAG = -Wall -Wextra
%.o: %.c $(HEADERS)
$(info Compiling $<)
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
%.o: %.S
$(info Compiling $<)
$(AS) -o $@ $<
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

View File

@ -1,512 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <netools.h>
#include <errno.h>
#include <regs.h>
#include <base.h>
#include <pci.h>
#include <network.h>
#include <io.h>
#include "e1000.hpp"
class E1000Device
{
private:
PCIHeader0 *Header;
uint16_t DeviceID;
bool Initialized = false;
bool EEPROMAvailable;
struct BARData
{
uint8_t Type;
uint16_t IOBase;
uint64_t MemoryBase;
} BAR;
#define E1000_NUM_RX_DESC 32
#define E1000_NUM_TX_DESC 8
RXDescriptor *RX[E1000_NUM_RX_DESC];
TXDescriptor *TX[E1000_NUM_TX_DESC];
uint16_t RXCurrent;
uint16_t TXCurrent;
const int BaseBufferSize = 8192;
const int AdditionalBytes = 16;
uint32_t CurrentPacket;
void WriteCMD(uint16_t Address, uint32_t Value)
{
if (BAR.Type == 0)
mmoutl((void *)(BAR.MemoryBase + Address), Value);
else
{
outl(BAR.IOBase, Address);
outl(BAR.IOBase + 4, Value);
}
}
uint32_t ReadCMD(uint16_t Address)
{
if (BAR.Type == 0)
return mminl((void *)(BAR.MemoryBase + Address));
else
{
outl(BAR.IOBase, Address);
return inl(BAR.IOBase + 0x4);
}
}
uint32_t ReadEEPROM(uint8_t Address)
{
uint16_t Data = 0;
uint32_t temp = 0;
if (EEPROMAvailable)
{
WriteCMD(REG::EEPROM, (1) | ((uint32_t)(Address) << 8));
while (!((temp = ReadCMD(REG::EEPROM)) & (1 << 4)))
;
}
else
{
WriteCMD(REG::EEPROM, (1) | ((uint32_t)(Address) << 2));
while (!((temp = ReadCMD(REG::EEPROM)) & (1 << 1)))
;
}
Data = (uint16_t)((temp >> 16) & 0xFFFF);
return Data;
}
void InitializeRX()
{
DebugLog("Initializing RX...");
uintptr_t Ptr = (uintptr_t)AllocateMemory(TO_PAGES(sizeof(RXDescriptor) *
E1000_NUM_RX_DESC +
AdditionalBytes));
for (int i = 0; i < E1000_NUM_RX_DESC; i++)
{
RX[i] = (RXDescriptor *)(Ptr + i * 16);
RX[i]->Address = (uint64_t)AllocateMemory(TO_PAGES(BaseBufferSize + AdditionalBytes));
RX[i]->Status = 0;
}
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
WriteCMD(REG::TXDESCLO, (uint32_t)(Ptr >> 32));
WriteCMD(REG::TXDESCHI, (uint32_t)(Ptr & 0xFFFFFFFF));
WriteCMD(REG::RXDESCLO, (uint32_t)Ptr);
WriteCMD(REG::RXDESCHI, 0);
WriteCMD(REG::RXDESCLEN, E1000_NUM_RX_DESC * 16);
WriteCMD(REG::RXDESCHEAD, 0);
WriteCMD(REG::RXDESCTAIL, E1000_NUM_RX_DESC - 1);
RXCurrent = 0;
WriteCMD(REG::RCTRL, RCTL::EN | RCTL::SBP | RCTL::UPE |
RCTL::MPE | RCTL::LBM_NONE |
RTCL::RDMTS_HALF | RCTL::BAM |
RCTL::SECRC | RCTL::BSIZE_8192);
}
void InitializeTX()
{
DebugLog("Initializing TX...");
uintptr_t Ptr = (uintptr_t)AllocateMemory(TO_PAGES(sizeof(TXDescriptor) *
E1000_NUM_RX_DESC +
AdditionalBytes));
for (short i = 0; i < E1000_NUM_TX_DESC; i++)
{
TX[i] = (TXDescriptor *)((uintptr_t)Ptr + i * 16);
TX[i]->Address = 0;
TX[i]->Command = 0;
TX[i]->Status = TSTA::DD;
}
WriteCMD(REG::TXDESCHI, (uint32_t)((uint64_t)Ptr >> 32));
WriteCMD(REG::TXDESCLO, (uint32_t)((uint64_t)Ptr & 0xFFFFFFFF));
WriteCMD(REG::TXDESCLEN, E1000_NUM_TX_DESC * 16);
WriteCMD(REG::TXDESCHEAD, 0);
WriteCMD(REG::TXDESCTAIL, 0);
TXCurrent = 0;
WriteCMD(REG::TCTRL, TCTL::EN_ | TCTL::PSP |
(15 << TCTL::CT_SHIFT) |
(64 << TCTL::COLD_SHIFT) |
TCTL::RTLC);
WriteCMD(REG::TCTRL, 0b0110000000000111111000011111010);
WriteCMD(REG::TIPG, 0x0060200A);
}
public:
dev_t ID;
bool IsInitialized() { return Initialized; }
size_t write(uint8_t *Buffer, size_t Size)
{
TX[TXCurrent]->Address = (uint64_t)Buffer;
TX[TXCurrent]->Length = (uint16_t)Size;
TX[TXCurrent]->Command = CMD::EOP | CMD::IFCS | CMD::RS;
TX[TXCurrent]->Status = 0;
uint16_t OldTXCurrent = TXCurrent;
TXCurrent = (uint16_t)((TXCurrent + 1) % E1000_NUM_TX_DESC);
WriteCMD(REG::TXDESCTAIL, TXCurrent);
while (!(TX[OldTXCurrent]->Status & 0xFF))
Yield();
return Size;
}
MediaAccessControl GetMAC()
{
MediaAccessControl mac;
if (EEPROMAvailable)
{
uint32_t temp;
temp = ReadEEPROM(0);
mac.Address[0] = temp & 0xff;
mac.Address[1] = (uint8_t)(temp >> 8);
temp = ReadEEPROM(1);
mac.Address[2] = temp & 0xff;
mac.Address[3] = (uint8_t)(temp >> 8);
temp = ReadEEPROM(2);
mac.Address[4] = temp & 0xff;
mac.Address[5] = (uint8_t)(temp >> 8);
}
else
{
uint8_t *BaseMac8 = (uint8_t *)(BAR.MemoryBase + 0x5400);
uint32_t *BaseMac32 = (uint32_t *)(BAR.MemoryBase + 0x5400);
if (BaseMac32[0] != 0)
for (int i = 0; i < 6; i++)
mac.Address[i] = BaseMac8[i];
else
{
KernelLog("No MAC address found.");
return MediaAccessControl();
}
}
return mac;
}
int ioctl(NetIoctl req, void *arg)
{
switch (req)
{
case IOCTL_NET_GET_MAC:
{
MediaAccessControl mac = GetMAC();
*((uint48_t *)arg) = mac.ToHex(); /* UNTESTED */
return 0;
}
default:
return -EINVAL;
}
return 0;
}
void OnInterruptReceived(TrapFrame *)
{
WriteCMD(REG::IMASK, 0x1);
uint32_t status = ReadCMD(0xC0);
UNUSED(status);
while ((RX[RXCurrent]->Status & 0x1))
{
uint8_t *data = (uint8_t *)RX[RXCurrent]->Address;
uint16_t dataSz = RX[RXCurrent]->Length;
// ReportNetworkPacket(ID, data, dataSz);
/* FIXME: Implement */
KernelLog("FIXME: Received packet");
(void)data;
(void)dataSz;
RX[RXCurrent]->Status = 0;
uint16_t OldRXCurrent = RXCurrent;
RXCurrent = (uint16_t)((RXCurrent + 1) % E1000_NUM_RX_DESC);
WriteCMD(REG::RXDESCTAIL, OldRXCurrent);
}
}
void Panic()
{
WriteCMD(REG::IMASK, 0x00000000);
WriteCMD(REG::ITR, 0x00000000);
WriteCMD(REG::IAM, 0x00000000);
}
E1000Device(PCIHeader0 *_Header, uint16_t _DeviceID)
: Header(_Header),
DeviceID(_DeviceID)
{
uint32_t PCIBAR0 = Header->BAR0;
uint32_t PCIBAR1 = Header->BAR1;
BAR.Type = PCIBAR0 & 1;
BAR.IOBase = (uint16_t)(PCIBAR0 & (~3));
BAR.MemoryBase = PCIBAR1 & (~15);
switch (DeviceID)
{
case 0x100E:
{
KernelLog("Found Intel 82540EM Gigabit Ethernet Controller.");
/* Detect EEPROM */
WriteCMD(REG::EEPROM, 0x1);
for (int i = 0; i < 1000 && !EEPROMAvailable; i++)
if (ReadCMD(REG::EEPROM) & 0x10)
EEPROMAvailable = true;
else
EEPROMAvailable = false;
if (!GetMAC().Valid())
{
KernelLog("Failed to get MAC");
return;
}
/* Start link */
uint32_t cmdret = ReadCMD(REG::CTRL);
WriteCMD(REG::CTRL, cmdret | ECTRL::SLU);
for (int i = 0; i < 0x80; i++)
WriteCMD((uint16_t)(0x5200 + i * 4), 0);
WriteCMD(REG::IMASK, 0x1F6DC);
WriteCMD(REG::IMASK, 0xFF & ~4);
ReadCMD(0xC0);
InitializeRX();
InitializeTX();
break;
}
default:
{
KernelLog("Unimplemented E1000 device.");
return;
}
}
Initialized = true;
}
~E1000Device()
{
if (!Initialized)
return;
switch (DeviceID)
{
case 0x100E:
{
// Clearing Enable bit in Receive Control Register
uint32_t cmdret = ReadCMD(REG::RCTRL);
WriteCMD(REG::RCTRL, cmdret & ~RCTL::EN);
// Masking Interrupt Mask, Interrupt Throttling Rate & Interrupt Auto-Mask
WriteCMD(REG::IMASK, 0x00000000);
WriteCMD(REG::ITR, 0x00000000);
WriteCMD(REG::IAM, 0x00000000);
// Clearing SLU bit in Device Control Register
cmdret = ReadCMD(REG::CTRL);
WriteCMD(REG::CTRL, cmdret & ~ECTRL::SLU);
// Clear the Interrupt Cause Read register by reading it
ReadCMD(REG::ICR);
// Powering down the device (?)
WriteCMD(REG::CTRL, PCTRL::POWER_DOWN);
/* TODO: Stop link; further testing required */
break;
}
default:
{
KernelLog("Unimplemented E1000 device.");
return;
}
}
}
};
E1000Device *Drivers[4] = {nullptr};
dev_t NetID[4] = {(dev_t)-1};
#define OIR(x) OIR_##x
#define CREATE_OIR(x) \
void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
CREATE_OIR(0);
CREATE_OIR(1);
CREATE_OIR(2);
CREATE_OIR(3);
int __fs_Open(struct Inode *, int, mode_t) { return 0; }
int __fs_Close(struct Inode *) { return 0; }
ssize_t __fs_Read(struct Inode *, void *, size_t, off_t) { return 0; }
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
{
return Drivers[NetID[Node->GetMinor()]]->write((uint8_t *)Buffer, Size);
}
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
{
return Drivers[NetID[Node->GetMinor()]]->ioctl((NetIoctl)Request, Argp);
}
const struct InodeOperations NetOps = {
.Lookup = nullptr,
.Create = nullptr,
.Remove = nullptr,
.Rename = nullptr,
.Read = __fs_Read,
.Write = __fs_Write,
.Truncate = nullptr,
.Open = __fs_Open,
.Close = __fs_Close,
.Ioctl = __fs_Ioctl,
.ReadDir = nullptr,
.MkDir = nullptr,
.RmDir = nullptr,
.SymLink = nullptr,
.ReadLink = nullptr,
.Seek = nullptr,
.Stat = nullptr,
};
PCIArray *Devices;
EXTERNC int cxx_Panic()
{
PCIArray *ctx = Devices;
short Count = 0;
while (ctx != nullptr)
{
if (Drivers[Count] != nullptr)
Drivers[Count]->Panic();
Count++;
ctx = (PCIArray *)ctx->Next;
}
return 0;
}
EXTERNC int cxx_Probe()
{
uint16_t VendorIDs[] = {0x8086, /* Intel */
PCI_END};
uint16_t DeviceIDs[] = {0x100E, /* 82540EM */
0x100F, /* 82545EM */
0x10D3, /* 82574L */
0x10EA, /* I217-LM */
0x153A, /* 82577LM */
PCI_END};
Devices = GetPCIDevices(VendorIDs, DeviceIDs);
if (Devices == nullptr)
{
KernelLog("No E1000 device found.");
return -ENODEV;
}
return 0;
}
EXTERNC int cxx_Initialize()
{
PCIArray *ctx = Devices;
size_t Count = 0;
while (ctx != nullptr)
{
if (Count > sizeof(Drivers) / sizeof(E1000Device *))
break;
InitializePCI(ctx->Device);
Drivers[Count] = new E1000Device((PCIHeader0 *)ctx->Device->Header,
ctx->Device->Header->DeviceID);
if (Drivers[Count]->IsInitialized())
{
dev_t ret = RegisterDevice(NETWORK_TYPE_ETHERNET, &NetOps);
NetID[Count] = ret;
Drivers[Count]->ID = ret;
/* FIXME: bad code */
switch (Count)
{
case 0:
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(0));
break;
case 1:
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(1));
break;
case 2:
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(2));
break;
case 3:
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(3));
break;
default:
break;
}
Count++;
}
ctx = (PCIArray *)ctx->Next;
}
if (Count == 0)
{
KernelLog("No valid E1000 device found.");
return -EINVAL;
}
return 0;
}
EXTERNC int cxx_Finalize()
{
PCIArray *ctx = Devices;
size_t Count = 0;
while (ctx != nullptr)
{
if (Count++ > sizeof(Drivers) / sizeof(E1000Device *))
break;
delete Drivers[Count++];
ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
ctx = (PCIArray *)ctx->Next;
}
for (size_t i = 0; i < sizeof(NetID) / sizeof(dev_t); i++)
{
if (NetID[i] != (dev_t)-1)
UnregisterDevice(NetID[i]);
}
return 0;
}

View File

@ -1,31 +0,0 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Drivers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include <base.h>
#include "e1000.hpp"
int DriverEntry() { return cxx_Initialize(); }
int DriverFinal() { return cxx_Finalize(); }
int DriverPanic() { return cxx_Panic(); }
int DriverProbe() { return cxx_Probe(); }
DriverInfo("e1000",
"Intel(R) PRO/1000 Network Driver",
"EnderIce2",
0, 0, 1,
"GPLv3");

View File

@ -1,35 +0,0 @@
default:
$(error Do not run this Makefile directly!)
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
FILENAME = $(notdir $(shell pwd)).drv
build: $(FILENAME)
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
WARNCFLAG = -Wall -Wextra
%.o: %.c $(HEADERS)
$(info Compiling $<)
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
%.o: %.S
$(info Compiling $<)
$(AS) -o $@ $<
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

View File

@ -1,31 +0,0 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Drivers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include <base.h>
#include "rtl8139.hpp"
int DriverEntry() { return cxx_Initialize(); }
int DriverFinal() { return cxx_Finalize(); }
int DriverPanic() { return cxx_Panic(); }
int DriverProbe() { return cxx_Probe(); }
DriverInfo("rtl8139",
"Realtek RTL8139 Network Driver",
"EnderIce2",
0, 0, 1,
"GPLv3");

View File

@ -1,325 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <netools.h>
#include <errno.h>
#include <regs.h>
#include <base.h>
#include <pci.h>
#include <network.h>
#include <io.h>
#include "rtl8139.hpp"
class RTL8139Device
{
private:
PCIHeader0 *Header;
bool Initialized = false;
struct BARData
{
uint8_t Type;
uint16_t IOBase;
uint64_t MemoryBase;
} BAR;
const int BaseBufferSize = 8192;
const int WRAPBytes = 1500;
const int AdditionalBytes = 16;
const int BufferSize = BaseBufferSize +
WRAPBytes +
AdditionalBytes;
uint8_t *RXBuffer = nullptr;
int TXCurrent = 0;
uint16_t CurrentPacket = 0;
uint8_t TSAD[4] = {0x20, 0x24, 0x28, 0x2C};
uint8_t TSD[4] = {0x10, 0x14, 0x18, 0x1C};
public:
dev_t ID;
bool IsInitialized() { return Initialized; }
size_t write(uint8_t *Buffer, size_t Size)
{
outl(TSAD[TXCurrent], (uint32_t)(reinterpret_cast<uint64_t>(Buffer)));
outl(TSD[TXCurrent++], (uint32_t)Size);
if (TXCurrent > 3)
TXCurrent = 0;
return Size;
}
MediaAccessControl GetMAC()
{
return MediaAccessControl();
}
int ioctl(NetIoctl req, void *)
{
switch (req)
{
case IOCTL_NET_GET_MAC:
{
return -ENOSYS;
}
default:
return -EINVAL;
}
return 0;
}
void OnInterruptReceived(TrapFrame *)
{
/* Acknowledge interrupt */
uint16_t status = inw(RegISR);
DebugLog("%#lx", status);
/* Read status */
if (status & RecOK)
{
/* Get the current packet */
uint16_t *data = (uint16_t *)(RXBuffer + CurrentPacket);
uint16_t dataSz = *(data + 1);
data += 2;
// ReportNetworkPacket(ID, data, dataSz);
/* FIXME: Implement */
KernelLog("FIXME: Received packet");
(void)data;
(void)dataSz;
/* Update CAPR */
#define RX_READ_PTR_MASK (~0x3)
CurrentPacket = (uint16_t)((CurrentPacket + dataSz + 4 + 3) & RX_READ_PTR_MASK);
if (CurrentPacket > BufferSize)
CurrentPacket -= uint16_t(BufferSize);
outw(RegCAPR, CurrentPacket - 0x10);
}
/* Clear interrupt */
outw(RegISR, (RecOK | RecBad | SendOK | SendBad));
}
void Panic()
{
}
RTL8139Device(PCIHeader0 *_Header)
: Header(_Header)
{
uint32_t PCIBAR0 = Header->BAR0;
uint32_t PCIBAR1 = Header->BAR1;
BAR.Type = PCIBAR0 & 1;
BAR.IOBase = (uint16_t)(PCIBAR0 & (~3));
BAR.MemoryBase = PCIBAR1 & (~15);
RXBuffer = (uint8_t *)AllocateMemory(TO_PAGES(BufferSize));
/* Power on */
outb(RegCONFIG1, 0x0);
/* Software Reset */
outb(RegCMD, 0x10);
while (inb(RegCMD) & 0x10)
Yield();
/* Initialize receive buffer */
outl(RegRBSTART, (uint32_t)(reinterpret_cast<uintptr_t>(RXBuffer)));
/* Configure interrupt mask register */
outw(RegIMR, (RecOK | RecBad | SendOK | SendBad));
outl(regRCR, (RcAB | RcAM | RcAPM | RcAAP) | RcWRAP);
/* Enable receive and transmit */
outb(RegCMD, 0xC); /* 0xC = RE and TE bit */
uint32_t MAC1 = inl(RegMAC);
uint16_t MAC2 = inw(RegMAR);
MediaAccessControl mac = {
mac.Address[0] = (uint8_t)MAC1,
mac.Address[1] = (uint8_t)(MAC1 >> 8),
mac.Address[2] = (uint8_t)(MAC1 >> 16),
mac.Address[3] = (uint8_t)(MAC1 >> 24),
mac.Address[4] = (uint8_t)MAC2,
mac.Address[5] = (uint8_t)(MAC2 >> 8)};
Initialized = true;
}
~RTL8139Device()
{
if (!Initialized)
return;
/* FIXME: Shutdown code */
}
};
RTL8139Device *Drivers[4] = {nullptr};
dev_t NetID[4] = {(dev_t)-1};
#define OIR(x) OIR_##x
#define CREATE_OIR(x) \
void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
CREATE_OIR(0);
CREATE_OIR(1);
CREATE_OIR(2);
CREATE_OIR(3);
int __fs_Open(struct Inode *, int, mode_t) { return 0; }
int __fs_Close(struct Inode *) { return 0; }
ssize_t __fs_Read(struct Inode *, void *, size_t, off_t) { return 0; }
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
{
return Drivers[NetID[Node->GetMinor()]]->write((uint8_t *)Buffer, Size);
}
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
{
return Drivers[NetID[Node->GetMinor()]]->ioctl((NetIoctl)Request, Argp);
}
const struct InodeOperations NetOps = {
.Lookup = nullptr,
.Create = nullptr,
.Remove = nullptr,
.Rename = nullptr,
.Read = __fs_Read,
.Write = __fs_Write,
.Truncate = nullptr,
.Open = __fs_Open,
.Close = __fs_Close,
.Ioctl = __fs_Ioctl,
.ReadDir = nullptr,
.MkDir = nullptr,
.RmDir = nullptr,
.SymLink = nullptr,
.ReadLink = nullptr,
.Seek = nullptr,
.Stat = nullptr,
};
PCIArray *Devices;
EXTERNC int cxx_Panic()
{
PCIArray *ctx = Devices;
short Count = 0;
while (ctx != nullptr)
{
if (Drivers[Count] != nullptr)
Drivers[Count]->Panic();
Count++;
ctx = (PCIArray *)ctx->Next;
}
return 0;
}
EXTERNC int cxx_Probe()
{
uint16_t VendorIDs[] = {0x10EC, /* Realtek */
PCI_END};
uint16_t DeviceIDs[] = {0x8139, /* RTL8139 */
PCI_END};
Devices = GetPCIDevices(VendorIDs, DeviceIDs);
if (Devices == nullptr)
{
KernelLog("No RTL8139 device found.");
return -ENODEV;
}
return 0;
}
EXTERNC int cxx_Initialize()
{
PCIArray *ctx = Devices;
size_t Count = 0;
while (ctx != nullptr)
{
if (Count > sizeof(Drivers) / sizeof(RTL8139Device *))
break;
InitializePCI(ctx->Device);
Drivers[Count] = new RTL8139Device((PCIHeader0 *)ctx->Device->Header);
if (Drivers[Count]->IsInitialized())
{
dev_t ret = RegisterDevice(NETWORK_TYPE_ETHERNET, &NetOps);
NetID[Count] = ret;
Drivers[Count]->ID = ret;
/* FIXME: bad code */
switch (Count)
{
case 0:
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(0));
break;
case 1:
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(1));
break;
case 2:
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(2));
break;
case 3:
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(3));
break;
default:
break;
}
Count++;
}
ctx = (PCIArray *)ctx->Next;
}
if (Count == 0)
{
KernelLog("No valid RTL8139 device found.");
return -EINVAL;
}
return 0;
}
EXTERNC int cxx_Finalize()
{
PCIArray *ctx = Devices;
size_t Count = 0;
while (ctx != nullptr)
{
if (Count++ > sizeof(Drivers) / sizeof(RTL8139Device *))
break;
delete Drivers[Count++];
ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
ctx = (PCIArray *)ctx->Next;
}
for (size_t i = 0; i < sizeof(NetID) / sizeof(dev_t); i++)
{
if (NetID[i] != (dev_t)-1)
UnregisterDevice(NetID[i]);
}
return 0;
}

View File

@ -1,7 +1,9 @@
build: MAKE_TARGETS := build clean
make -C ahci build DIRECTORIES := $(sort $(dir $(wildcard ./*/)))
make -C ata build
clean: .PHONY: $(MAKE_TARGETS) $(DIRECTORIES)
make -C ahci clean
make -C ata clean $(MAKE_TARGETS): $(DIRECTORIES)
$(DIRECTORIES):
$(MAKE) -C $@ $(MAKECMDGOALS)

View File

@ -1,35 +0,0 @@
default:
$(error Do not run this Makefile directly!)
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
FILENAME = $(notdir $(shell pwd)).drv
build: $(FILENAME)
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
WARNCFLAG = -Wall -Wextra
%.o: %.c $(HEADERS)
$(info Compiling $<)
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
%.o: %.S
$(info Compiling $<)
$(AS) -o $@ $<
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +0,0 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Drivers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include <base.h>
#include "ahci.hpp"
int DriverEntry() { return cxx_Initialize(); }
int DriverFinal() { return cxx_Finalize(); }
int DriverPanic() { return cxx_Panic(); }
int DriverProbe() { return cxx_Probe(); }
DriverInfo("ahci",
"Advanced Host Controller Interface Driver",
"EnderIce2",
0, 0, 1,
"GPLv3");

View File

@ -1,35 +0,0 @@
default:
$(error Do not run this Makefile directly!)
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
FILENAME = $(notdir $(shell pwd)).drv
build: $(FILENAME)
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
WARNCFLAG = -Wall -Wextra
%.o: %.c $(HEADERS)
$(info Compiling $<)
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
%.o: %.S
$(info Compiling $<)
$(AS) -o $@ $<
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

View File

@ -1,76 +0,0 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Drivers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <regs.h>
#include <base.h>
#include <io.h>
bool IsATAPresent()
{
outb(0x1F0 + 2, 0);
outb(0x1F0 + 3, 0);
outb(0x1F0 + 4, 0);
outb(0x1F0 + 5, 0);
outb(0x1F0 + 7, 0xEC);
if (inb(0x1F0 + 7) == 0 || inb(0x1F0 + 1) != 0)
return false;
return true;
}
void MasterInterruptHandler(TrapFrame *)
{
}
void SlaveInterruptHandler(TrapFrame *)
{
}
int DriverEntry()
{
RegisterInterruptHandler(14, MasterInterruptHandler);
RegisterInterruptHandler(15, SlaveInterruptHandler);
return 0;
}
int DriverFinal()
{
UnregisterInterruptHandler(14, MasterInterruptHandler);
UnregisterInterruptHandler(15, SlaveInterruptHandler);
return 0;
}
int DriverPanic()
{
return 0;
}
int DriverProbe()
{
if (!IsATAPresent())
return -ENODEV;
return 0;
}
DriverInfo("ata",
"Advanced Technology Attachment Driver",
"EnderIce2",
0, 0, 1,
"GPLv3");

View File

@ -7,9 +7,8 @@
"settings": { "settings": {
"terminal.integrated.cwd": "../", "terminal.integrated.cwd": "../",
"debug.allowBreakpointsEverywhere": true, "debug.allowBreakpointsEverywhere": true,
"git.alwaysSignOff": true,
"git.defaultBranchName": "master", "git.defaultBranchName": "master",
"git.openRepositoryInParentFolders": "always", "git.openRepositoryInParentFolders": "always",
"C_Cpp.autoAddFileAssociations": false "C_Cpp.autoAddFileAssociations": false,
} }
} }

View File

@ -7,9 +7,8 @@
"settings": { "settings": {
"terminal.integrated.cwd": "../", "terminal.integrated.cwd": "../",
"debug.allowBreakpointsEverywhere": true, "debug.allowBreakpointsEverywhere": true,
"git.alwaysSignOff": true,
"git.defaultBranchName": "master", "git.defaultBranchName": "master",
"git.openRepositoryInParentFolders": "always", "git.openRepositoryInParentFolders": "always",
"C_Cpp.autoAddFileAssociations": false "C_Cpp.autoAddFileAssociations": false,
} }
} }

View File

@ -7,25 +7,25 @@
"settings": { "settings": {
"terminal.integrated.cwd": "../", "terminal.integrated.cwd": "../",
"debug.allowBreakpointsEverywhere": true, "debug.allowBreakpointsEverywhere": true,
"editor.tabCompletion": "on",
"diffEditor.codeLens": true,
"editor.quickSuggestionsDelay": 100,
"zenMode.hideLineNumbers": false,
"zenMode.hideActivityBar": false,
"zenMode.hideStatusBar": true,
"zenMode.centerLayout": true,
"zenMode.fullScreen": true,
"zenMode.restore": true,
"zenMode.silentNotifications": true,
"window.commandCenter": false,
"window.density.editorTabHeight": "default",
"editor.cursorBlinking": "blink",
"editor.cursorSmoothCaretAnimation": "on",
"editor.cursorStyle": "line",
"editor.cursorWidth": 2,
"git.alwaysSignOff": true,
"git.defaultBranchName": "master", "git.defaultBranchName": "master",
"git.openRepositoryInParentFolders": "always", "git.openRepositoryInParentFolders": "always",
"C_Cpp.autoAddFileAssociations": false "C_Cpp.autoAddFileAssociations": false,
"conventionalCommits.scopes": [
"kernel/api",
"kernel/syscalls",
"vscode",
"kernel",
"kernel/pci",
"kernel/driver",
"kernel/drivers",
"kernel/elf",
"kernel/scheduler",
"kernel/tty",
"kernel/std",
"kernel/vfs",
"kernel/memory",
"kernel/efi",
"kernel/bootstrap"
]
} }
} }

View File

@ -7,9 +7,20 @@
"settings": { "settings": {
"terminal.integrated.cwd": "../", "terminal.integrated.cwd": "../",
"debug.allowBreakpointsEverywhere": true, "debug.allowBreakpointsEverywhere": true,
"git.alwaysSignOff": true,
"git.defaultBranchName": "master", "git.defaultBranchName": "master",
"git.openRepositoryInParentFolders": "always", "git.openRepositoryInParentFolders": "always",
"C_Cpp.autoAddFileAssociations": false "C_Cpp.autoAddFileAssociations": false,
"conventionalCommits.scopes": [
"userspace",
"userspace/libc",
"userspace/coreutils",
"userspace/apps",
"userspace/libs",
"userspace/apps/sys",
"userspace/apps/test",
"userspace/apps/usr",
"devcontainer",
"vscode"
]
} }
} }

View File

@ -6,7 +6,6 @@
], ],
"settings": { "settings": {
"debug.allowBreakpointsEverywhere": true, "debug.allowBreakpointsEverywhere": true,
"git.alwaysSignOff": true,
"git.defaultBranchName": "master", "git.defaultBranchName": "master",
"git.openRepositoryInParentFolders": "always", "git.openRepositoryInParentFolders": "always",
"C_Cpp.autoAddFileAssociations": false "C_Cpp.autoAddFileAssociations": false

View File

@ -6,9 +6,14 @@
], ],
"settings": { "settings": {
"debug.allowBreakpointsEverywhere": true, "debug.allowBreakpointsEverywhere": true,
"git.alwaysSignOff": true,
"git.defaultBranchName": "master", "git.defaultBranchName": "master",
"git.openRepositoryInParentFolders": "always", "git.openRepositoryInParentFolders": "always",
"C_Cpp.autoAddFileAssociations": false "C_Cpp.autoAddFileAssociations": false,
"conventionalCommits.scopes": [
"rootfs",
"tools",
"devcontainer",
"workspace"
]
} }
} }

72
INSTALL.md Normal file
View File

@ -0,0 +1,72 @@
# 🚀 Installation Guide
This guide will help you install Fennix on your system.
## 🛠️ Preparing the Environment
There are two ways to build the project:
1. **🐳 Use Dev Container (Recommended)**
* This is the easiest way to prepare the environment for building the project. But firstly, you need to install [Docker](https://docs.docker.com/get-docker/) and [Visual Studio Code](https://code.visualstudio.com/).
* After installing Docker and Visual Studio Code, you can open the project in Visual Studio Code and click on the "Reopen in Container" button.
* This will open the project in a Dev Container with all the required tools installed.
* If you encounter errors while the Dev Container is building, ensure the following are correctly configured:
* `/tmp/.X11-unix`
* Environment variable `XAUTHORITY`
* `/run/user/1000/pulse/native`
* **Note:** These configurations are only necessary if you plan to use QEMU inside the container.
2. **💻 Build the Project Locally**
* The instructions below will guide you through the process of building the project locally.
**NOTE:** You MUST have `autoconf 2.69` and `automake 1.15.1` versions installed on your system. A complete list of dependencies can be found in the [.devcontainer/Dockerfile](.devcontainer/Dockerfile) file.
Before building the project, you need to build the cross-compiler toolchain and QEMU.
You can do this by running the following command:
```sh
make setup
```
This will clone, patch, and build the required tools for you.
Alternatively, if you wish to skip building QEMU, you can run `make setup-no-qemu`.
However, in this case, you will need to manually specify the path to the QEMU binary in the `config.mk` file.
## 🏗️ Building the Project
To build the project, run:
```sh
make build
```
This will build the kernel, userspace, and drivers. The resulting ISO image will be `Fennix.iso`.
## 🚀 Running the OS
To run the OS, execute:
```sh
make run
```
The `run` target will automatically build the project if it hasn't been built yet.
## ⚙️ Additional Configuration
You can customize the project by editing the `config.mk` file.
## 🧪 Debugging
If you use Visual Studio Code, you can press `F5` to start debugging the OS.
The configuration is already set up for you.
Alternatively, you can run the following command to start debugging:
```sh
make debug
```
This will start QEMU in debug mode, allowing you to connect to it using GDB.
The GDB FIFO file is located at `/tmp/gdb-fennix`.

View File

@ -9,5 +9,9 @@ insert_final_newline = true
indent_style = tab indent_style = tab
indent_size = 4 indent_size = 4
[*.py]
indent_size = 4
indent_style = space
[Makefile] [Makefile]
indent_style = tab indent_style = tab

View File

@ -1,91 +0,0 @@
# Usage: add-symbol-file-all <filename> [<offset>]
# remove-symbol-file-all <filename> [<offset>]
#
# Credit: https://stackoverflow.com/a/33087762/9352057
# CC BY-SA 4.0
python
import subprocess
import re
def relocatesections(filename, addr):
p = subprocess.Popen(["readelf", "-S", filename], stdout = subprocess.PIPE)
sections = []
textaddr = '0'
for line in p.stdout.readlines():
line = line.decode("utf-8").strip()
if not line.startswith('[') or line.startswith('[Nr]'):
continue
line = re.sub(r' +', ' ', line)
line = re.sub(r'\[ *(\d+)\]', '\g<1>', line)
fieldsvalue = line.split(' ')
fieldsname = ['number', 'name', 'type', 'addr', 'offset', 'size', 'entsize', 'flags', 'link', 'info', 'addralign']
sec = dict(zip(fieldsname, fieldsvalue))
if sec['number'] == '0':
continue
sections.append(sec)
if sec['name'] == '.text':
textaddr = sec['addr']
return (textaddr, sections)
class AddSymbolFileAll(gdb.Command):
"""The right version for add-symbol-file"""
def __init__(self):
super(AddSymbolFileAll, self).__init__("add-symbol-file-all", gdb.COMMAND_USER)
self.dont_repeat()
def invoke(self, arg, from_tty):
argv = gdb.string_to_argv(arg)
filename = argv[0]
if len(argv) > 1:
offset = int(str(gdb.parse_and_eval(argv[1])), 0)
else:
offset = 0
(textaddr, sections) = relocatesections(filename, offset)
cmd = "add-symbol-file %s 0x%08x" % (filename, int(textaddr, 16) + offset)
for s in sections:
addr = int(s['addr'], 16)
if s['name'] == '.text' or addr == 0:
continue
cmd += " -s %s 0x%08x" % (s['name'], addr + offset)
gdb.execute(cmd)
class RemoveSymbolFileAll(gdb.Command):
"""The right version for remove-symbol-file"""
def __init__(self):
super(RemoveSymbolFileAll, self).__init__("remove-symbol-file-all", gdb.COMMAND_USER)
self.dont_repeat()
def invoke(self, arg, from_tty):
argv = gdb.string_to_argv(arg)
filename = argv[0]
if len(argv) > 1:
offset = int(str(gdb.parse_and_eval(argv[1])), 0)
else:
offset = 0
(textaddr, _) = relocatesections(filename, offset)
cmd = "remove-symbol-file -a 0x%08x" % (int(textaddr, 16) + offset)
gdb.execute(cmd)
AddSymbolFileAll()
RemoveSymbolFileAll()
end

16
Kernel/.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,16 @@
{
"recommendations": [
"ms-vscode.cpptools",
"maziac.asm-code-lens",
"editorconfig.editorconfig",
"vivaxy.vscode-conventional-commits",
"ms-vscode.hexeditor",
"webfreak.debug",
"ibm.output-colorizer",
"gruntfuggly.todo-tree",
"naumovs.color-highlight",
"seven1bit.vscode-ext-ansi-color-highlight",
"jeff-hykin.better-cpp-syntax",
"aaron-bond.better-comments"
]
}

View File

@ -9,6 +9,6 @@
#define __kernel__ 1 #define __kernel__ 1
#define KERNEL_NAME "Fennix" #define KERNEL_NAME "Fennix"
#define KERNEL_ARCH "amd64" #define KERNEL_ARCH "amd64"
#define KERNEL_VERSION "1.0" #define KERNEL_VERSION "1.0.0"
#define GIT_COMMIT "0000000000000000000000000000000000000000" #define GIT_COMMIT "0000000000000000000000000000000000000000"
#define GIT_COMMIT_SHORT "0000000" #define GIT_COMMIT_SHORT "0000000"

View File

@ -10,14 +10,14 @@ define find-sources
$(shell find ./ -type f -name '$1' $(shell echo $(foreach arch,$(filter-out $(OSARCH),$(AVAILABLE_ARCHS)), -not -path \"./arch/$(arch)/*\")) -print0 | xargs -0) $(shell find ./ -type f -name '$1' $(shell echo $(foreach arch,$(filter-out $(OSARCH),$(AVAILABLE_ARCHS)), -not -path \"./arch/$(arch)/*\")) -print0 | xargs -0)
endef endef
BMP_SOURCES := $(call find-sources,*.bmp) PNG_SOURCES := $(call find-sources,*.png)
PSF_SOURCES := $(call find-sources,*.psf) PSF_SOURCES := $(call find-sources,*.psf)
S_SOURCES := $(call find-sources,*.S) S_SOURCES := $(call find-sources,*.S)
s_SOURCES := $(call find-sources,*.s) s_SOURCES := $(call find-sources,*.s)
C_SOURCES := $(call find-sources,*.c) C_SOURCES := $(call find-sources,*.c)
CXX_SOURCES := $(call find-sources,*.cpp) CXX_SOURCES := $(call find-sources,*.cpp)
OBJ = $(BMP_SOURCES:.bmp=.o) $(PSF_SOURCES:.psf=.o) $(s_SOURCES:.s=.o) $(S_SOURCES:.S=.o) $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) OBJ = $(PNG_SOURCES:.png=.o) $(PSF_SOURCES:.psf=.o) $(s_SOURCES:.s=.o) $(S_SOURCES:.S=.o) $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su) STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
GCNO_OBJ = $(C_SOURCES:.c=.gcno) $(CXX_SOURCES:.cpp=.gcno) GCNO_OBJ = $(C_SOURCES:.c=.gcno) $(CXX_SOURCES:.cpp=.gcno)
@ -68,6 +68,7 @@ ifeq ($(DEBUG), 1)
# CFLAGS += -pg # CFLAGS += -pg
# CFLAGS += -finstrument-functions # CFLAGS += -finstrument-functions
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage -fsanitize=undefined CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage -fsanitize=undefined
CXXFLAGS += -fdiagnostics-all-candidates
ifeq ($(OSARCH), amd64) ifeq ($(OSARCH), amd64)
CFLAGS += -fverbose-asm CFLAGS += -fverbose-asm
endif # amd64 endif # amd64
@ -111,7 +112,7 @@ $(KERNEL_FILENAME): $(OBJ)
# https://gcc.gnu.org/projects/cxx-status.html # https://gcc.gnu.org/projects/cxx-status.html
%.o: %.cpp $(HEADERS) %.o: %.cpp $(HEADERS)
$(info Compiling $<) $(info Compiling $<)
$(__CONF_CXX) $(CFLAGS) -fcoroutines $(CFLAG_STACK_PROTECTOR) $(WARNCFLAG) -std=c++20 -c $< -o $@ -fno-rtti $(__CONF_CXX) $(CFLAGS) $(CXXFLAGS) -fcoroutines $(CFLAG_STACK_PROTECTOR) $(WARNCFLAG) -std=c++20 -c $< -o $@ -fno-rtti
%.o: %.S %.o: %.S
$(info Compiling $<) $(info Compiling $<)
@ -133,7 +134,7 @@ else ifeq ($(OSARCH), aarch64)
endif endif
$(__CONF_NM) $@ $(__CONF_NM) $@
%.o: %.bmp %.o: %.png
ifeq ($(OSARCH), amd64) ifeq ($(OSARCH), amd64)
$(__CONF_OBJCOPY) -O elf64-x86-64 -I binary $< $@ $(__CONF_OBJCOPY) -O elf64-x86-64 -I binary $< $@
else ifeq ($(OSARCH), i386) else ifeq ($(OSARCH), i386)

View File

@ -9,7 +9,7 @@
- [ ] ~~Do not map the entire memory. Map only the needed memory address at allocation time.~~ (we just copy the pages for userland, see `Fork()` inside [core/memory/page_table.cpp](core/memory/page_table.cpp)) - [ ] ~~Do not map the entire memory. Map only the needed memory address at allocation time.~~ (we just copy the pages for userland, see `Fork()` inside [core/memory/page_table.cpp](core/memory/page_table.cpp))
- [ ] Implementation of logging (beside serial) with log rotation. - [ ] Implementation of logging (beside serial) with log rotation.
- [x] Implement a better task manager. (replace struct P/TCB with classes) - [x] Implement a better task manager. (replace struct P/TCB with classes)
- [ ] Rewrite virtual file system. - [x] Rewrite virtual file system.
- [ ] Colors in crash screen are not following the kernel color scheme. - [ ] Colors in crash screen are not following the kernel color scheme.
- [x] ~~Find a way to add intrinsics.~~ (not feasible, use inline assembly) - [x] ~~Find a way to add intrinsics.~~ (not feasible, use inline assembly)
- [ ] Rework PSF1 font loader. - [ ] Rework PSF1 font loader.

View File

@ -77,6 +77,14 @@ SECTIONS
*(.rodata .rodata.*) *(.rodata .rodata.*)
} :rodata } :rodata
.builtin_drivers ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.builtin_drivers) - KERNEL_VMA)
{
__kernel_builtin_drivers_start = .;
KEEP(*(SORT(.builtin_drivers.*)))
KEEP(*(.builtin_drivers))
__kernel_builtin_drivers_end = .;
} :rodata
.init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA) .init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA)
{ {
PROVIDE_HIDDEN(__init_array_start = .); PROVIDE_HIDDEN(__init_array_start = .);

View File

@ -25,33 +25,41 @@
void InitLimine(); void InitLimine();
static volatile struct limine_entry_point_request EntryPointRequest = { #define LIMREQ __attribute__((used, section(".limine_requests"))) static volatile
#define LIMREQ_S __attribute__((used, section(".limine_requests_start"))) static volatile
#define LIMREQ_E __attribute__((used, section(".limine_requests_end"))) static volatile
LIMREQ LIMINE_BASE_REVISION(3);
LIMREQ_S LIMINE_REQUESTS_START_MARKER;
LIMREQ_E LIMINE_REQUESTS_END_MARKER;
LIMREQ struct limine_entry_point_request EntryPointRequest = {
.id = LIMINE_ENTRY_POINT_REQUEST, .id = LIMINE_ENTRY_POINT_REQUEST,
.revision = 0, .revision = 0,
.response = NULL, .response = NULL,
.entry = InitLimine}; .entry = InitLimine};
static volatile struct limine_bootloader_info_request BootloaderInfoRequest = { LIMREQ struct limine_bootloader_info_request BootloaderInfoRequest = {
.id = LIMINE_BOOTLOADER_INFO_REQUEST, .id = LIMINE_BOOTLOADER_INFO_REQUEST,
.revision = 0}; .revision = 0};
static volatile struct limine_framebuffer_request FramebufferRequest = { LIMREQ struct limine_framebuffer_request FramebufferRequest = {
.id = LIMINE_FRAMEBUFFER_REQUEST, .id = LIMINE_FRAMEBUFFER_REQUEST,
.revision = 0}; .revision = 0};
static volatile struct limine_memmap_request MemmapRequest = { LIMREQ struct limine_memmap_request MemmapRequest = {
.id = LIMINE_MEMMAP_REQUEST, .id = LIMINE_MEMMAP_REQUEST,
.revision = 0}; .revision = 0};
static volatile struct limine_kernel_address_request KernelAddressRequest = { LIMREQ struct limine_kernel_address_request KernelAddressRequest = {
.id = LIMINE_KERNEL_ADDRESS_REQUEST, .id = LIMINE_KERNEL_ADDRESS_REQUEST,
.revision = 0}; .revision = 0};
static volatile struct limine_rsdp_request RsdpRequest = { LIMREQ struct limine_rsdp_request RsdpRequest = {
.id = LIMINE_RSDP_REQUEST, .id = LIMINE_RSDP_REQUEST,
.revision = 0}; .revision = 0};
static volatile struct limine_kernel_file_request KernelFileRequest = { LIMREQ struct limine_kernel_file_request KernelFileRequest = {
.id = LIMINE_KERNEL_FILE_REQUEST, .id = LIMINE_KERNEL_FILE_REQUEST,
.revision = 0}; .revision = 0};
static volatile struct limine_module_request ModuleRequest = { LIMREQ struct limine_module_request ModuleRequest = {
.id = LIMINE_MODULE_REQUEST, .id = LIMINE_MODULE_REQUEST,
.revision = 0}; .revision = 0};
static volatile struct limine_smbios_request SmbiosRequest = { LIMREQ struct limine_smbios_request SmbiosRequest = {
.id = LIMINE_SMBIOS_REQUEST, .id = LIMINE_SMBIOS_REQUEST,
.revision = 0}; .revision = 0};
@ -84,7 +92,7 @@ __naked __used __no_stack_protector void InitLimine()
asmv("jmp InitLimineAfterStack"); asmv("jmp InitLimineAfterStack");
} }
nsa NIF void InitLimineAfterStack() nsa nif void InitLimineAfterStack()
{ {
struct BootInfo binfo = {}; struct BootInfo binfo = {};
struct limine_bootloader_info_response *BootloaderInfoResponse = BootloaderInfoRequest.response; struct limine_bootloader_info_response *BootloaderInfoResponse = BootloaderInfoRequest.response;

View File

@ -38,14 +38,14 @@ union __attribute__((packed)) PageTableEntry
}; };
uint64_t raw; uint64_t raw;
__always_inline inline nsa NIF void SetAddress(uintptr_t _Address) __always_inline inline nsa nif void SetAddress(uintptr_t _Address)
{ {
_Address &= 0x000000FFFFFFFFFF; _Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF; this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12); this->raw |= (_Address << 12);
} }
__always_inline inline nsa NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; } __always_inline inline nsa nif uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
}; };
struct __attribute__((packed)) PageTableEntryPtr struct __attribute__((packed)) PageTableEntryPtr
@ -72,14 +72,14 @@ union __attribute__((packed)) PageDirectoryEntry
}; };
uint64_t raw; uint64_t raw;
__always_inline inline nsa NIF void SetAddress(uintptr_t _Address) __always_inline inline nsa nif void SetAddress(uintptr_t _Address)
{ {
_Address &= 0x000000FFFFFFFFFF; _Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF; this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12); this->raw |= (_Address << 12);
} }
__always_inline inline nsa NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; } __always_inline inline nsa nif uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
}; };
struct __attribute__((packed)) PageDirectoryEntryPtr struct __attribute__((packed)) PageDirectoryEntryPtr
@ -106,14 +106,14 @@ union __attribute__((packed)) PageDirectoryPointerTableEntry
}; };
uint64_t raw; uint64_t raw;
__always_inline inline nsa NIF void SetAddress(uintptr_t _Address) __always_inline inline nsa nif void SetAddress(uintptr_t _Address)
{ {
_Address &= 0x000000FFFFFFFFFF; _Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF; this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12); this->raw |= (_Address << 12);
} }
__always_inline inline nsa NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; } __always_inline inline nsa nif uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
}; };
struct __attribute__((packed)) PageDirectoryPointerTableEntryPtr struct __attribute__((packed)) PageDirectoryPointerTableEntryPtr
@ -140,14 +140,14 @@ union __attribute__((packed)) PageMapLevel4
}; };
uint64_t raw; uint64_t raw;
__always_inline inline nsa NIF void SetAddress(uintptr_t _Address) __always_inline inline nsa nif void SetAddress(uintptr_t _Address)
{ {
_Address &= 0x000000FFFFFFFFFF; _Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF; this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12); this->raw |= (_Address << 12);
} }
__always_inline inline nsa NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; } __always_inline inline nsa nif uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
}; };
struct PageTable4 struct PageTable4
@ -161,7 +161,7 @@ extern uintptr_t _kernel_start, _kernel_end;
__attribute__((section(".bootstrap.data"))) static PageTable4 *BPTable = (PageTable4 *)BootPageTable; __attribute__((section(".bootstrap.data"))) static PageTable4 *BPTable = (PageTable4 *)BootPageTable;
__attribute__((section(".bootstrap.data"))) static size_t BPT_Allocated = 0x4000; __attribute__((section(".bootstrap.data"))) static size_t BPT_Allocated = 0x4000;
__always_inline inline nsa NIF void *RequestPage() __always_inline inline nsa nif void *RequestPage()
{ {
void *Page = (void *)(BootPageTable + BPT_Allocated); void *Page = (void *)(BootPageTable + BPT_Allocated);
BPT_Allocated += 0x1000; BPT_Allocated += 0x1000;
@ -180,7 +180,7 @@ public:
uintptr_t PDPTEIndex = 0; uintptr_t PDPTEIndex = 0;
uintptr_t PDEIndex = 0; uintptr_t PDEIndex = 0;
uintptr_t PTEIndex = 0; uintptr_t PTEIndex = 0;
__always_inline inline nsa NIF PageMapIndexer(uintptr_t VirtualAddress) __always_inline inline nsa nif PageMapIndexer(uintptr_t VirtualAddress)
{ {
uintptr_t Address = VirtualAddress; uintptr_t Address = VirtualAddress;
Address >>= 12; Address >>= 12;
@ -194,7 +194,7 @@ public:
} }
}; };
__attribute__((section(".bootstrap.text"))) nsa NIF void MB2_64_Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags) __attribute__((section(".bootstrap.text"))) nsa nif void MB2_64_Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags)
{ {
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
// Clear any flags that are not 1 << 0 (Present) - 1 << 5 (Accessed) because rest are for page table entries only // Clear any flags that are not 1 << 0 (Present) - 1 << 5 (Accessed) because rest are for page table entries only
@ -280,7 +280,7 @@ __attribute__((section(".bootstrap.text"))) nsa NIF void MB2_64_Map(void *Virtua
: "memory"); : "memory");
} }
EXTERNC __attribute__((section(".bootstrap.text"))) nsa NIF __attribute__((section(".bootstrap.text"))) void UpdatePageTable64() EXTERNC __attribute__((section(".bootstrap.text"))) nsa nif __attribute__((section(".bootstrap.text"))) void UpdatePageTable64()
{ {
BPTable = (PageTable4 *)BootPageTable; BPTable = (PageTable4 *)BootPageTable;

View File

@ -24,10 +24,8 @@
void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info) void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
{ {
auto InfoAddress = Info; auto infoAddr = Info;
for (auto Tag = (struct multiboot_tag *)((uint8_t *)InfoAddress + 8); for (auto Tag = (struct multiboot_tag *)((uint8_t *)infoAddr + 8);; Tag = (struct multiboot_tag *)((multiboot_uint8_t *)Tag + ((Tag->size + 7) & ~7)))
;
Tag = (struct multiboot_tag *)((multiboot_uint8_t *)Tag + ((Tag->size + 7) & ~7)))
{ {
if (Tag->type == MULTIBOOT_TAG_TYPE_END) if (Tag->type == MULTIBOOT_TAG_TYPE_END)
{ {
@ -39,17 +37,17 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
{ {
case MULTIBOOT_TAG_TYPE_CMDLINE: case MULTIBOOT_TAG_TYPE_CMDLINE:
{ {
strncpy(mb2binfo.Kernel.CommandLine, multiboot_tag_string *cmdline = (multiboot_tag_string *)Tag;
((multiboot_tag_string *)Tag)->string, strncpy(mb2binfo.Kernel.CommandLine, cmdline->string, strlen(cmdline->string));
strlen(((multiboot_tag_string *)Tag)->string));
debug("Kernel command line: %s", mb2binfo.Kernel.CommandLine); debug("Kernel command line: %s", mb2binfo.Kernel.CommandLine);
break; break;
} }
case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
{ {
strncpy(mb2binfo.Bootloader.Name, multiboot_tag_string *blName = (multiboot_tag_string *)Tag;
((multiboot_tag_string *)Tag)->string, strncpy(mb2binfo.Bootloader.Name, blName->string, strlen(blName->string));
strlen(((multiboot_tag_string *)Tag)->string));
debug("Bootloader name: %s", mb2binfo.Bootloader.Name); debug("Bootloader name: %s", mb2binfo.Bootloader.Name);
break; break;
} }
@ -60,24 +58,29 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
mb2binfo.Modules[module_count].Address = (void *)(uint64_t)module->mod_start; mb2binfo.Modules[module_count].Address = (void *)(uint64_t)module->mod_start;
mb2binfo.Modules[module_count].Size = module->mod_end - module->mod_start; mb2binfo.Modules[module_count].Size = module->mod_end - module->mod_start;
strncpy(mb2binfo.Modules[module_count].Path, "(null)", 6); strncpy(mb2binfo.Modules[module_count].Path, "(null)", 6);
strncpy(mb2binfo.Modules[module_count].CommandLine, module->cmdline, strncpy(mb2binfo.Modules[module_count].CommandLine, module->cmdline, strlen(module->cmdline));
strlen(module->cmdline));
debug("Module: %s", mb2binfo.Modules[module_count].Path); debug("Module: %s", mb2binfo.Modules[module_count].CommandLine);
module_count++; module_count++;
break; break;
} }
case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
{ {
multiboot_tag_basic_meminfo *meminfo = (multiboot_tag_basic_meminfo *)Tag; multiboot_tag_basic_meminfo *meminfo = (multiboot_tag_basic_meminfo *)Tag;
fixme("basic_meminfo->[mem_lower: %#x, mem_upper: %#x]", fixme("basic_meminfo->[mem_lower: %#x, mem_upper: %#x]",
meminfo->mem_lower, meminfo->mem_upper); meminfo->mem_lower,
meminfo->mem_upper);
break; break;
} }
case MULTIBOOT_TAG_TYPE_BOOTDEV: case MULTIBOOT_TAG_TYPE_BOOTDEV:
{ {
multiboot_tag_bootdev *bootdev = (multiboot_tag_bootdev *)Tag; multiboot_tag_bootdev *bootdev = (multiboot_tag_bootdev *)Tag;
fixme("bootdev->[biosdev: %#x, slice: %#x, part: %#x]", fixme("bootdev->[biosdev: %#x, slice: %#x, part: %#x]",
bootdev->biosdev, bootdev->slice, bootdev->part); bootdev->biosdev,
bootdev->slice,
bootdev->part);
break; break;
} }
case MULTIBOOT_TAG_TYPE_MMAP: case MULTIBOOT_TAG_TYPE_MMAP:
@ -92,6 +95,7 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
warn("Too many memory entries, skipping the rest..."); warn("Too many memory entries, skipping the rest...");
break; break;
} }
multiboot_mmap_entry entry = mmap->entries[i]; multiboot_mmap_entry entry = mmap->entries[i];
mb2binfo.Memory.Size += entry.len; mb2binfo.Memory.Size += entry.len;
switch (entry.type) switch (entry.type)
@ -127,6 +131,7 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
mb2binfo.Memory.Entry[i].Type = Unknown; mb2binfo.Memory.Entry[i].Type = Unknown;
break; break;
} }
debug("Memory entry: [BaseAddress: %#x, Length: %#x, Type: %d]", debug("Memory entry: [BaseAddress: %#x, Length: %#x, Type: %d]",
mb2binfo.Memory.Entry[i].BaseAddress, mb2binfo.Memory.Entry[i].BaseAddress,
mb2binfo.Memory.Entry[i].Length, mb2binfo.Memory.Entry[i].Length,
@ -137,54 +142,52 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
case MULTIBOOT_TAG_TYPE_VBE: case MULTIBOOT_TAG_TYPE_VBE:
{ {
multiboot_tag_vbe *vbe = (multiboot_tag_vbe *)Tag; multiboot_tag_vbe *vbe = (multiboot_tag_vbe *)Tag;
fixme("vbe->[vbe_mode: %#x, vbe_interface_seg: %#x, vbe_interface_off: %#x, vbe_interface_len: %#x]", fixme("vbe->[vbe_mode: %#x, vbe_interface_seg: %#x, vbe_interface_off: %#x, vbe_interface_len: %#x]",
vbe->vbe_mode, vbe->vbe_interface_seg, vbe->vbe_interface_off, vbe->vbe_interface_len); vbe->vbe_mode,
vbe->vbe_interface_seg,
vbe->vbe_interface_off,
vbe->vbe_interface_len);
break; break;
} }
case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
{ {
multiboot_tag_framebuffer *fb = (multiboot_tag_framebuffer *)Tag; multiboot_tag_framebuffer *fb = (multiboot_tag_framebuffer *)Tag;
static int fb_count = 0; static int fbCount = 0;
mb2binfo.Framebuffer[fb_count].BaseAddress = (void *)fb->common.framebuffer_addr; mb2binfo.Framebuffer[fbCount].BaseAddress = (void *)fb->common.framebuffer_addr;
mb2binfo.Framebuffer[fb_count].Width = fb->common.framebuffer_width; mb2binfo.Framebuffer[fbCount].Width = fb->common.framebuffer_width;
mb2binfo.Framebuffer[fb_count].Height = fb->common.framebuffer_height; mb2binfo.Framebuffer[fbCount].Height = fb->common.framebuffer_height;
mb2binfo.Framebuffer[fb_count].Pitch = fb->common.framebuffer_pitch; mb2binfo.Framebuffer[fbCount].Pitch = fb->common.framebuffer_pitch;
mb2binfo.Framebuffer[fb_count].BitsPerPixel = fb->common.framebuffer_bpp; mb2binfo.Framebuffer[fbCount].BitsPerPixel = fb->common.framebuffer_bpp;
switch (fb->common.framebuffer_type) switch (fb->common.framebuffer_type)
{ {
case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED: case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
{ mb2binfo.Framebuffer[fbCount].Type = Indexed;
mb2binfo.Framebuffer[fb_count].Type = Indexed;
break; break;
}
case MULTIBOOT_FRAMEBUFFER_TYPE_RGB: case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
{ mb2binfo.Framebuffer[fbCount].Type = RGB;
mb2binfo.Framebuffer[fb_count].Type = RGB; mb2binfo.Framebuffer[fbCount].RedMaskSize = fb->framebuffer_red_mask_size;
mb2binfo.Framebuffer[fb_count].RedMaskSize = fb->framebuffer_red_mask_size; mb2binfo.Framebuffer[fbCount].RedMaskShift = fb->framebuffer_red_field_position;
mb2binfo.Framebuffer[fb_count].RedMaskShift = fb->framebuffer_red_field_position; mb2binfo.Framebuffer[fbCount].GreenMaskSize = fb->framebuffer_green_mask_size;
mb2binfo.Framebuffer[fb_count].GreenMaskSize = fb->framebuffer_green_mask_size; mb2binfo.Framebuffer[fbCount].GreenMaskShift = fb->framebuffer_green_field_position;
mb2binfo.Framebuffer[fb_count].GreenMaskShift = fb->framebuffer_green_field_position; mb2binfo.Framebuffer[fbCount].BlueMaskSize = fb->framebuffer_blue_mask_size;
mb2binfo.Framebuffer[fb_count].BlueMaskSize = fb->framebuffer_blue_mask_size; mb2binfo.Framebuffer[fbCount].BlueMaskShift = fb->framebuffer_blue_field_position;
mb2binfo.Framebuffer[fb_count].BlueMaskShift = fb->framebuffer_blue_field_position;
break; break;
}
case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT: case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
{ mb2binfo.Framebuffer[fbCount].Type = EGA;
mb2binfo.Framebuffer[fb_count].Type = EGA;
break; break;
}
default: default:
{ mb2binfo.Framebuffer[fbCount].Type = Unknown_Framebuffer_Type;
mb2binfo.Framebuffer[fb_count].Type = Unknown_Framebuffer_Type;
break; break;
} }
}
debug("Framebuffer %d: %dx%d %d bpp", fb_count, fb->common.framebuffer_width, fb->common.framebuffer_height, fb->common.framebuffer_bpp); debug("fb %d: %dx%d %d bpp", fbCount, fb->common.framebuffer_width, fb->common.framebuffer_height, fb->common.framebuffer_bpp);
debug("More info:\nAddress: %p\nPitch: %d\nMemoryModel: %d\nRedMaskSize: %d\nRedMaskShift: %d\nGreenMaskSize: %d\nGreenMaskShift: %d\nBlueMaskSize: %d\nBlueMaskShift: %d", debug("More info: addr:%#lx pitch:%d mm:%d RMSize:%d RMShift:%d GMSize:%d GMShift:%d BMSize:%d BMShift:%d",
fb->common.framebuffer_addr, fb->common.framebuffer_pitch, fb->common.framebuffer_type, fb->common.framebuffer_addr, fb->common.framebuffer_pitch, fb->common.framebuffer_type,
fb->framebuffer_red_mask_size, fb->framebuffer_red_field_position, fb->framebuffer_green_mask_size, fb->framebuffer_red_mask_size, fb->framebuffer_red_field_position,
fb->framebuffer_green_field_position, fb->framebuffer_blue_mask_size, fb->framebuffer_blue_field_position); fb->framebuffer_green_mask_size, fb->framebuffer_green_field_position,
fb_count++; fb->framebuffer_blue_mask_size, fb->framebuffer_blue_field_position);
fbCount++;
break; break;
} }
case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
@ -194,73 +197,115 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
mb2binfo.Kernel.Symbols.EntSize = elf->entsize; mb2binfo.Kernel.Symbols.EntSize = elf->entsize;
mb2binfo.Kernel.Symbols.Shndx = elf->shndx; mb2binfo.Kernel.Symbols.Shndx = elf->shndx;
mb2binfo.Kernel.Symbols.Sections = r_cst(uintptr_t, elf->sections); mb2binfo.Kernel.Symbols.Sections = r_cst(uintptr_t, elf->sections);
debug("elf_sections->[num: %d, entsize: %d, shndx: %d, sections: %#lx]",
elf->num, elf->entsize, elf->shndx, elf->sections);
break; break;
} }
case MULTIBOOT_TAG_TYPE_APM: case MULTIBOOT_TAG_TYPE_APM:
{ {
multiboot_tag_apm *apm = (multiboot_tag_apm *)Tag; multiboot_tag_apm *apm = (multiboot_tag_apm *)Tag;
fixme("apm->[version: %d, cseg: %d, offset: %d, cseg_16: %d, dseg: %d, flags: %d, cseg_len: %d, cseg_16_len: %d, dseg_len: %d]",
apm->version, apm->cseg, apm->offset, apm->cseg_16, apm->dseg, apm->flags, apm->cseg_len, apm->cseg_16_len, apm->dseg_len); fixme("apm->[version:%d, cseg:%d, offset:%d, cseg_16:%d, dseg:%d, flags:%d, cseg_len:%d, cseg_16_len:%d, dseg_len:%d]",
apm->version, apm->cseg, apm->offset, apm->cseg_16, apm->dseg,
apm->flags, apm->cseg_len, apm->cseg_16_len, apm->dseg_len);
break; break;
} }
case MULTIBOOT_TAG_TYPE_EFI32: case MULTIBOOT_TAG_TYPE_EFI32:
{ {
mb2binfo.EFI.Info.Enabled = 1;
mb2binfo.EFI.Info.ST = 1;
multiboot_tag_efi32 *efi32 = (multiboot_tag_efi32 *)Tag; multiboot_tag_efi32 *efi32 = (multiboot_tag_efi32 *)Tag;
fixme("efi32->[pointer: %p, size: %d]", efi32->pointer, efi32->size); mb2binfo.EFI.SystemTable = (void *)(uintptr_t)efi32->pointer;
debug("efi32->[pointer: %#lx, size: %d]", efi32->pointer, efi32->size);
break; break;
} }
case MULTIBOOT_TAG_TYPE_EFI64: case MULTIBOOT_TAG_TYPE_EFI64:
{ {
mb2binfo.EFI.Info.Enabled = 1;
mb2binfo.EFI.Info.ST = 1;
multiboot_tag_efi64 *efi64 = (multiboot_tag_efi64 *)Tag; multiboot_tag_efi64 *efi64 = (multiboot_tag_efi64 *)Tag;
fixme("efi64->[pointer: %p, size: %d]", efi64->pointer, efi64->size); mb2binfo.EFI.SystemTable = (void *)(uintptr_t)efi64->pointer;
debug("efi64->[pointer: %#lx, size: %d]", efi64->pointer, efi64->size);
break; break;
} }
case MULTIBOOT_TAG_TYPE_SMBIOS: case MULTIBOOT_TAG_TYPE_SMBIOS:
{ {
multiboot_tag_smbios *smbios = (multiboot_tag_smbios *)Tag; multiboot_tag_smbios *smbios = (multiboot_tag_smbios *)Tag;
fixme("smbios->[major: %d, minor: %d]", smbios->major, smbios->minor); mb2binfo.SMBIOSPtr = (void *)smbios->tables;
debug("smbios->[major: %d, minor: %d]", smbios->major, smbios->minor);
break; break;
} }
case MULTIBOOT_TAG_TYPE_ACPI_OLD: case MULTIBOOT_TAG_TYPE_ACPI_OLD:
{ {
mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_old_acpi *)Tag)->rsdp; mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_old_acpi *)Tag)->rsdp;
debug("OLD ACPI RSDP: %p", mb2binfo.RSDP);
debug("OLD ACPI RSDP: %#lx", mb2binfo.RSDP);
break; break;
} }
case MULTIBOOT_TAG_TYPE_ACPI_NEW: case MULTIBOOT_TAG_TYPE_ACPI_NEW:
{ {
mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_new_acpi *)Tag)->rsdp; mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_new_acpi *)Tag)->rsdp;
debug("NEW ACPI RSDP: %p", mb2binfo.RSDP);
debug("NEW ACPI RSDP: %#lx", mb2binfo.RSDP);
break; break;
} }
case MULTIBOOT_TAG_TYPE_NETWORK: case MULTIBOOT_TAG_TYPE_NETWORK:
{ {
multiboot_tag_network *net = (multiboot_tag_network *)Tag; multiboot_tag_network *net = (multiboot_tag_network *)Tag;
fixme("network->[dhcpack: %p]", net->dhcpack);
fixme("network->[dhcpack: %#lx]", net->dhcpack);
break; break;
} }
case MULTIBOOT_TAG_TYPE_EFI_MMAP: case MULTIBOOT_TAG_TYPE_EFI_MMAP:
{ {
mb2binfo.EFI.Info.Enabled = 1;
mb2binfo.EFI.Info.MemoryMap = 1;
multiboot_tag_efi_mmap *efi_mmap = (multiboot_tag_efi_mmap *)Tag; multiboot_tag_efi_mmap *efi_mmap = (multiboot_tag_efi_mmap *)Tag;
fixme("efi_mmap->[descr_size: %d, descr_vers: %d, efi_mmap: %p]", mb2binfo.EFI.MemoryMap.BaseAddress = (void *)efi_mmap->efi_mmap;
mb2binfo.EFI.MemoryMap.DescriptorSize = efi_mmap->descr_size;
mb2binfo.EFI.MemoryMap.DescriptorVersion = efi_mmap->descr_vers;
mb2binfo.EFI.MemoryMap.NumberOfEntries = (efi_mmap->size - sizeof(multiboot_tag_efi_mmap)) / efi_mmap->descr_size;
// mb2binfo.EFI.MemoryMap.NumberOfEntries = efi_mmap->size / efi_mmap->descr_size;
debug("efi_mmap->[descr_size: %d, descr_vers: %d, efi_mmap: %#lx]",
efi_mmap->descr_size, efi_mmap->descr_vers, efi_mmap->efi_mmap); efi_mmap->descr_size, efi_mmap->descr_vers, efi_mmap->efi_mmap);
break; break;
} }
case MULTIBOOT_TAG_TYPE_EFI_BS: case MULTIBOOT_TAG_TYPE_EFI_BS:
{ {
fixme("efi_bs->[%p] (unknown structure)", Tag); mb2binfo.EFI.Info.Enabled = 1;
mb2binfo.EFI.Info.BS = 1;
debug("efi_bs");
break; break;
} }
case MULTIBOOT_TAG_TYPE_EFI32_IH: case MULTIBOOT_TAG_TYPE_EFI32_IH:
{ {
mb2binfo.EFI.Info.Enabled = 1;
mb2binfo.EFI.Info.IH = 1;
multiboot_tag_efi32_ih *efi32_ih = (multiboot_tag_efi32_ih *)Tag; multiboot_tag_efi32_ih *efi32_ih = (multiboot_tag_efi32_ih *)Tag;
fixme("efi32_ih->[pointer: %p]", efi32_ih->pointer); mb2binfo.EFI.ImageHandle = (void *)(uintptr_t)efi32_ih->pointer;
debug("efi32_ih->[pointer: %#lx]", efi32_ih->pointer);
break; break;
} }
case MULTIBOOT_TAG_TYPE_EFI64_IH: case MULTIBOOT_TAG_TYPE_EFI64_IH:
{ {
mb2binfo.EFI.Info.Enabled = 1;
mb2binfo.EFI.Info.IH = 1;
multiboot_tag_efi64_ih *efi64_ih = (multiboot_tag_efi64_ih *)Tag; multiboot_tag_efi64_ih *efi64_ih = (multiboot_tag_efi64_ih *)Tag;
fixme("efi64_ih->[pointer: %p]", efi64_ih->pointer); mb2binfo.EFI.ImageHandle = (void *)(uintptr_t)efi64_ih->pointer;
debug("efi64_ih->[pointer: %#lx]", efi64_ih->pointer);
break; break;
} }
case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR: case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
@ -269,7 +314,8 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
mb2binfo.Kernel.PhysicalBase = (void *)(uint64_t)load_base_addr->load_base_addr; mb2binfo.Kernel.PhysicalBase = (void *)(uint64_t)load_base_addr->load_base_addr;
mb2binfo.Kernel.VirtualBase = (void *)(uint64_t)(load_base_addr->load_base_addr + 0xFFFFFFFF80000000); mb2binfo.Kernel.VirtualBase = (void *)(uint64_t)(load_base_addr->load_base_addr + 0xFFFFFFFF80000000);
mb2binfo.Kernel.Size = ((uint64_t)&_kernel_end - (uint64_t)&_kernel_start) + ((uint64_t)&_bootstrap_end - (uint64_t)&_bootstrap_start); mb2binfo.Kernel.Size = ((uint64_t)&_kernel_end - (uint64_t)&_kernel_start) + ((uint64_t)&_bootstrap_end - (uint64_t)&_bootstrap_start);
debug("Kernel base: %p (physical) %p (virtual)", mb2binfo.Kernel.PhysicalBase, mb2binfo.Kernel.VirtualBase);
debug("Kernel base: %#lx (physical) %#lx (virtual)", mb2binfo.Kernel.PhysicalBase, mb2binfo.Kernel.VirtualBase);
break; break;
} }
default: default:

View File

@ -68,8 +68,10 @@ Multiboot_start:
je x32Hang je x32Hang
mov %cr4, %ecx mov %cr4, %ecx
or $0x00000010, %ecx /* PSE */ or $0x10, %ecx /* PSE */
or $0x00000020, %ecx /* PAE */ or $0x20, %ecx /* PAE */
or $0x200, %ecx /* OSFXSR */
or $0x400, %ecx /* OSXMMEXCPT */
mov %ecx, %cr4 mov %ecx, %cr4
call LoadGDT32 call LoadGDT32
@ -82,12 +84,14 @@ Multiboot_start:
rdmsr rdmsr
or $0x800, %eax /* LME */ or $0x800, %eax /* LME */
or $0x100, %eax /* LMA */ or $0x100, %eax /* LMA */
or $0x1, %eax /* SCE */ or $0x1, %eax /* SCE */
wrmsr wrmsr
mov %cr0, %ecx mov %cr0, %ecx
and $~0x4, %ecx /* EM */
or $0x2, %ecx /* MP */
or $0x80000000, %ecx /* PG */ or $0x80000000, %ecx /* PG */
or $0x1, %ecx /* PE */ or $0x1, %ecx /* PE */
mov %ecx, %cr0 mov %ecx, %cr0
lgdt [GDT64.Ptr] lgdt [GDT64.Ptr]

View File

@ -442,7 +442,7 @@ namespace APIC
this->lapic->Write(APIC_TICR, 0xFFFFFFFF); this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
} }
TimeManager->Sleep(1, Time::Units::Milliseconds); TimeManager->Sleep(Time::FromMilliseconds(1));
// Mask the timer // Mask the timer
if (this->lapic->x2APIC) if (this->lapic->x2APIC)

View File

@ -650,7 +650,7 @@ namespace InterruptDescriptorTable
#ifdef DEBUG #ifdef DEBUG
EnableISRs = !DebuggerIsAttached; EnableISRs = !DebuggerIsAttached;
if (!EnableISRs) if (!EnableISRs)
KPrint("\x1b[34mThe debugger is attached, disabling all ISRs."); KPrint("\x1b[32mThe debugger is attached, disabling all ISRs.");
#endif #endif
/* ISR */ /* ISR */

View File

@ -167,14 +167,14 @@ namespace SMP
} }
apic->SendInitIPI(lapic->APICId); apic->SendInitIPI(lapic->APICId);
TimeManager->Sleep(20, Time::Units::Milliseconds); TimeManager->Sleep(Time::FromMilliseconds(20));
apic->SendStartupIPI(lapic->APICId, TRAMPOLINE_START); apic->SendStartupIPI(lapic->APICId, TRAMPOLINE_START);
debug("Waiting for CPU %d to load...", lapic->APICId); debug("Waiting for CPU %d to load...", lapic->APICId);
uint64_t Timeout = TimeManager->CalculateTarget(2, Time::Units::Seconds); uint64_t Timeout = TimeManager->GetTimeNs() + Time::FromSeconds(2);
while (CPUEnabled.load(std::memory_order_acquire) == false) while (CPUEnabled.load(std::memory_order_acquire) == false)
{ {
if (TimeManager->GetCounter() > Timeout) if (TimeManager->GetTimeNs() > Timeout)
{ {
error("CPU %d failed to load!", lapic->APICId); error("CPU %d failed to load!", lapic->APICId);
KPrint("\x1b[1;37;41mCPU %d failed to load!", KPrint("\x1b[1;37;41mCPU %d failed to load!",

View File

@ -46,9 +46,17 @@ SECTIONS
*(.bootstrap .bootstrap.*) *(.bootstrap .bootstrap.*)
} :bootstrap } :bootstrap
_bootstrap_end = ALIGN(CONSTANT(MAXPAGESIZE)); _bootstrap_end = ALIGN(CONSTANT(MAXPAGESIZE));
. += KERNEL_VMA; . += KERNEL_VMA;
/* . += KERNEL_VMA;
_bootstrap_start = .;
.limine_requests : {
KEEP(*(.limine_requests_start))
KEEP(*(.limine_requests))
KEEP(*(.limine_requests_end))
} :bootstrap
_bootstrap_end = ALIGN(CONSTANT(MAXPAGESIZE)); */
_kernel_start = ALIGN(CONSTANT(MAXPAGESIZE)); _kernel_start = ALIGN(CONSTANT(MAXPAGESIZE));
_kernel_text_start = ALIGN(CONSTANT(MAXPAGESIZE)); _kernel_text_start = ALIGN(CONSTANT(MAXPAGESIZE));
.text ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.text) - KERNEL_VMA) .text ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.text) - KERNEL_VMA)
@ -80,6 +88,14 @@ SECTIONS
*(.rodata .rodata.*) *(.rodata .rodata.*)
} :rodata } :rodata
.builtin_drivers ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.builtin_drivers) - KERNEL_VMA)
{
__kernel_builtin_drivers_start = .;
KEEP(*(SORT(.builtin_drivers.*)))
KEEP(*(.builtin_drivers))
__kernel_builtin_drivers_end = .;
} :rodata
.init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA) .init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA)
{ {
PROVIDE_HIDDEN(__init_array_start = .); PROVIDE_HIDDEN(__init_array_start = .);

View File

@ -58,6 +58,14 @@ SECTIONS
} }
. = ALIGN(4096); . = ALIGN(4096);
.builtin_drivers :
{
__kernel_builtin_drivers_start = .;
KEEP(*(SORT(.builtin_drivers.*)))
KEEP(*(.builtin_drivers))
__kernel_builtin_drivers_end = .;
}
.init_array : .init_array :
{ {
PROVIDE_HIDDEN(__init_array_start = .); PROVIDE_HIDDEN(__init_array_start = .);

View File

@ -368,7 +368,7 @@ namespace APIC
this->lapic->Write(APIC_TDCR, DivideBy128); this->lapic->Write(APIC_TDCR, DivideBy128);
else else
this->lapic->Write(APIC_TDCR, DivideBy16); this->lapic->Write(APIC_TDCR, DivideBy16);
this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks * Miliseconds)); this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks *Miliseconds));
this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw)); this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw));
} }
@ -383,7 +383,7 @@ namespace APIC
this->lapic->Write(APIC_TDCR, Divider); this->lapic->Write(APIC_TDCR, Divider);
this->lapic->Write(APIC_TICR, 0xFFFFFFFF); this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
TimeManager->Sleep(1, Time::Units::Milliseconds); TimeManager->Sleep(Time::FromMilliseconds(1));
// Mask the timer // Mask the timer
this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */); this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */);

View File

@ -464,7 +464,7 @@ namespace InterruptDescriptorTable
// #ifdef DEBUG // #ifdef DEBUG
EnableISRs = !DebuggerIsAttached; EnableISRs = !DebuggerIsAttached;
if (!EnableISRs) if (!EnableISRs)
KPrint("\x1b[34mThe debugger is attached, disabling all ISRs."); KPrint("\x1b[32mThe debugger is attached, disabling all ISRs.");
// #endif // #endif
SetEntry(0x0, InterruptHandler_0x0, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE); SetEntry(0x0, InterruptHandler_0x0, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);

View File

@ -80,6 +80,14 @@ SECTIONS
*(.rodata .rodata.*) *(.rodata .rodata.*)
} :rodata } :rodata
.builtin_drivers ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.builtin_drivers) - KERNEL_VMA)
{
__kernel_builtin_drivers_start = .;
KEEP(*(SORT(.builtin_drivers.*)))
KEEP(*(.builtin_drivers))
__kernel_builtin_drivers_end = .;
} :rodata
.init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA) .init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA)
{ {
PROVIDE_HIDDEN(__init_array_start = .); PROVIDE_HIDDEN(__init_array_start = .);

View File

@ -20,13 +20,16 @@
#include <memory.hpp> #include <memory.hpp>
#include <stropts.h> #include <stropts.h>
#include <string.h> #include <string.h>
#include <thread>
#include <ini.h> #include <ini.h>
#include "../kernel.h" #include "../kernel.h"
using namespace std::chrono_literals;
namespace KernelConsole namespace KernelConsole
{ {
int TermColors[] = { static int TermColors[] = {
[TerminalColor::BLACK] = 0x000000, [TerminalColor::BLACK] = 0x000000,
[TerminalColor::RED] = 0xAA0000, [TerminalColor::RED] = 0xAA0000,
[TerminalColor::GREEN] = 0x00AA00, [TerminalColor::GREEN] = 0x00AA00,
@ -37,7 +40,7 @@ namespace KernelConsole
[TerminalColor::GREY] = 0xAAAAAA, [TerminalColor::GREY] = 0xAAAAAA,
}; };
int TermBrightColors[] = { static int TermBrightColors[] = {
[TerminalColor::BLACK] = 0x858585, [TerminalColor::BLACK] = 0x858585,
[TerminalColor::RED] = 0xFF5555, [TerminalColor::RED] = 0xFF5555,
[TerminalColor::GREEN] = 0x55FF55, [TerminalColor::GREEN] = 0x55FF55,
@ -112,6 +115,33 @@ namespace KernelConsole
FontRenderer Renderer; FontRenderer Renderer;
ConsoleTerminal *Terminals[16] = {nullptr};
std::atomic<ConsoleTerminal *> CurrentTerminal = nullptr;
void paint_blinker(bool Enable)
{
if (CurrentTerminal == nullptr)
return;
ConsoleTerminal *term = CurrentTerminal.load();
ConsoleTerminal::Blinker &blinker = term->Blink;
size_t cellIndex = Renderer.Cursor.Y * term->Term->GetWinsize()->ws_col + Renderer.Cursor.X;
TerminalCell *cell = term->Term->GetCell(cellIndex);
uint32_t bgColor = cell->attr.Bright ? TermBrightColors[cell->attr.Background] : TermColors[cell->attr.Background];
Renderer.Paint(Renderer.Cursor.X, Renderer.Cursor.Y, blinker.Character, Enable ? blinker.Color : bgColor, bgColor);
}
void paint_blinker_thread()
{
bool blink = false;
while (true)
{
paint_blinker(blink);
blink = !blink;
std::this_thread::sleep_for(std::chrono::milliseconds(CurrentTerminal.load()->Blink.Delay));
}
}
void paint_callback(TerminalCell *cell, long x, long y) void paint_callback(TerminalCell *cell, long x, long y)
{ {
if (cell->attr.Bright) if (cell->attr.Bright)
@ -123,22 +153,20 @@ namespace KernelConsole
void cursor_callback(TerminalCursor *cur) void cursor_callback(TerminalCursor *cur)
{ {
Renderer.Cursor = {cur->X, cur->Y}; Renderer.Cursor = {cur->X, cur->Y};
paint_blinker(false);
} }
VirtualTerminal *Terminals[16] = {nullptr};
std::atomic<VirtualTerminal *> CurrentTerminal = nullptr;
bool SetTheme(std::string Theme) bool SetTheme(std::string Theme)
{ {
FileNode *rn = fs->GetByPath("/etc/term", thisProcess->Info.RootNode); Node rn = fs->Lookup(thisProcess->Info.RootNode, "/sys/cfg/term");
if (rn == nullptr) if (rn == nullptr)
return false; return false;
kstat st{}; kstat st;
rn->Stat(&st); fs->Stat(rn, &st);
char *sh = new char[st.Size]; char *sh = new char[st.Size];
rn->Read(sh, st.Size, 0); fs->Read(rn, sh, st.Size, 0);
ini_t *ini = ini_load(sh, NULL); ini_t *ini = ini_load(sh, NULL);
int themeSection, c0, c1, c2, c3, c4, c5, c6, c7, colorsIdx; int themeSection, c0, c1, c2, c3, c4, c5, c6, c7, colorsIdx;
@ -267,24 +295,15 @@ namespace KernelConsole
size_t Rows = Display->GetWidth / Renderer.CurrentFont->GetInfo().Width; size_t Rows = Display->GetWidth / Renderer.CurrentFont->GetInfo().Width;
size_t Cols = Display->GetHeight / Renderer.CurrentFont->GetInfo().Height; size_t Cols = Display->GetHeight / Renderer.CurrentFont->GetInfo().Height;
debug("Terminal size: %ux%u", Rows, Cols); debug("Terminal size: %ux%u", Rows, Cols);
Terminals[0] = new VirtualTerminal(Rows, Cols, Display->GetWidth, Display->GetHeight, paint_callback, cursor_callback); Terminals[0] = new ConsoleTerminal;
Terminals[0]->Clear(0, 0, Rows, Cols - 1); Terminals[0]->Term = new VirtualTerminal(Rows, Cols, Display->GetWidth, Display->GetHeight, paint_callback, cursor_callback);
Terminals[0]->Term->Clear(0, 0, Rows, Cols - 1);
CurrentTerminal.store(Terminals[0], std::memory_order_release); CurrentTerminal.store(Terminals[0], std::memory_order_release);
} }
void LateInit() void LoadConsoleConfig(std::string &Config)
{ {
FileNode *rn = fs->GetByPath("/etc/term", thisProcess->Info.RootNode); ini_t *ini = ini_load(Config.c_str(), NULL);
if (rn == nullptr)
return;
kstat st{};
rn->Stat(&st);
char *sh = new char[st.Size];
rn->Read(sh, st.Size, 0);
ini_t *ini = ini_load(sh, NULL);
int general = ini_find_section(ini, "general", NULL); int general = ini_find_section(ini, "general", NULL);
int cursor = ini_find_section(ini, "cursor", NULL); int cursor = ini_find_section(ini, "cursor", NULL);
assert(general != INI_NOT_FOUND && cursor != INI_NOT_FOUND); assert(general != INI_NOT_FOUND && cursor != INI_NOT_FOUND);
@ -292,16 +311,22 @@ namespace KernelConsole
int themeIndex = ini_find_property(ini, general, "theme", NULL); int themeIndex = ini_find_property(ini, general, "theme", NULL);
assert(themeIndex != INI_NOT_FOUND); assert(themeIndex != INI_NOT_FOUND);
int cursorColor = ini_find_property(ini, cursor, "color", NULL);
int cursorBlink = ini_find_property(ini, cursor, "blink", NULL); int cursorBlink = ini_find_property(ini, cursor, "blink", NULL);
assert(cursorColor != INI_NOT_FOUND && cursorBlink != INI_NOT_FOUND); int cursorColor = ini_find_property(ini, cursor, "color", NULL);
int cursorChar = ini_find_property(ini, cursor, "char", NULL);
int cursorDelay = ini_find_property(ini, cursor, "delay", NULL);
assert(cursorBlink != INI_NOT_FOUND && cursorColor != INI_NOT_FOUND && cursorChar != INI_NOT_FOUND && cursorDelay != INI_NOT_FOUND);
const char *colorThemeStr = ini_property_value(ini, general, themeIndex); const char *colorThemeStr = ini_property_value(ini, general, themeIndex);
const char *cursorColorStr = ini_property_value(ini, cursor, cursorColor); const char *cursorColorStr = ini_property_value(ini, cursor, cursorColor);
const char *cursorBlinkStr = ini_property_value(ini, cursor, cursorBlink); const char *cursorBlinkStr = ini_property_value(ini, cursor, cursorBlink);
const char *cursorCharStr = ini_property_value(ini, cursor, cursorChar);
const char *cursorDelayStr = ini_property_value(ini, cursor, cursorDelay);
debug("colorThemeStr=%s", colorThemeStr); debug("colorThemeStr=%s", colorThemeStr);
debug("cursorColorStr=%s", cursorColorStr);
debug("cursorBlinkStr=%s", cursorBlinkStr); debug("cursorBlinkStr=%s", cursorBlinkStr);
debug("cursorColorStr=%s", cursorColorStr);
debug("cursorCharStr=%s", cursorCharStr);
debug("cursorDelayStr=%s", cursorDelayStr);
auto getColorComponent = [](const char *str, int &index) -> int auto getColorComponent = [](const char *str, int &index) -> int
{ {
@ -335,11 +360,36 @@ namespace KernelConsole
uint32_t blinkColor = 0xFFFFFF; uint32_t blinkColor = 0xFFFFFF;
if (cursorColorStr != 0) if (cursorColorStr != 0)
blinkColor = parseColor(cursorColorStr); blinkColor = parseColor(cursorColorStr);
fixme("cursor blink with colors %X", blinkColor); debug("cursor blink with colors %X and char '%s' and delay %s", blinkColor, cursorCharStr, cursorDelayStr);
Terminals[0]->Blink.Enabled = true;
Terminals[0]->Blink.Color = blinkColor;
Terminals[0]->Blink.Character = *cursorCharStr;
Terminals[0]->Blink.Delay = atoi(cursorDelayStr);
} }
ini_destroy(ini); ini_destroy(ini);
delete[] sh; }
void LateInit()
{
Node rn = fs->Lookup(thisProcess->Info.RootNode, "/sys/cfg/term");
if (rn == nullptr)
return;
{
kstat st;
fs->Stat(rn, &st);
std::string cfg;
cfg.resize(st.Size);
fs->Read(rn, cfg.data(), st.Size, 0);
LoadConsoleConfig(cfg);
}
if (Terminals[0]->Blink.Enabled)
{
std::thread t = std::thread(paint_blinker_thread);
t.detach();
}
#ifdef DEBUG #ifdef DEBUG
// __test_themes(); // __test_themes();

View File

@ -27,12 +27,12 @@ NewLock(DebuggerLock);
extern bool serialports[8]; extern bool serialports[8];
EXTERNC NIF void uart_wrapper(char c, void *) EXTERNC nif void uart_wrapper(char c, void *)
{ {
uart.DebugWrite(c); uart.DebugWrite(c);
} }
static inline NIF bool WritePrefix(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, va_list args) static inline nif bool WritePrefix(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, va_list args)
{ {
const char *DbgLvlString; const char *DbgLvlString;
switch (Level) switch (Level)
@ -79,7 +79,7 @@ static inline NIF bool WritePrefix(DebugLevel Level, const char *File, int Line,
namespace SysDbg namespace SysDbg
{ {
NIF void Write(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) nif void Write(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
va_list args; va_list args;
va_start(args, Format); va_start(args, Format);
@ -92,7 +92,7 @@ namespace SysDbg
va_end(args); va_end(args);
} }
NIF void WriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) nif void WriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
va_list args; va_list args;
va_start(args, Format); va_start(args, Format);
@ -106,7 +106,7 @@ namespace SysDbg
uart_wrapper('\n', nullptr); uart_wrapper('\n', nullptr);
} }
NIF void LockedWrite(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) nif void LockedWrite(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
SmartTimeoutLock(DebuggerLock, 1000); SmartTimeoutLock(DebuggerLock, 1000);
va_list args; va_list args;
@ -120,7 +120,7 @@ namespace SysDbg
va_end(args); va_end(args);
} }
NIF void LockedWriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) nif void LockedWriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
SmartTimeoutLock(DebuggerLock, 1000); SmartTimeoutLock(DebuggerLock, 1000);
va_list args; va_list args;
@ -137,7 +137,7 @@ namespace SysDbg
} }
// C compatibility // C compatibility
extern "C" NIF void SysDbgWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) extern "C" nif void SysDbgWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
va_list args; va_list args;
va_start(args, Format); va_start(args, Format);
@ -151,7 +151,7 @@ extern "C" NIF void SysDbgWrite(enum DebugLevel Level, const char *File, int Lin
} }
// C compatibility // C compatibility
extern "C" NIF void SysDbgWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) extern "C" nif void SysDbgWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
va_list args; va_list args;
va_start(args, Format); va_start(args, Format);
@ -166,7 +166,7 @@ extern "C" NIF void SysDbgWriteLine(enum DebugLevel Level, const char *File, int
} }
// C compatibility // C compatibility
extern "C" NIF void SysDbgLockedWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) extern "C" nif void SysDbgLockedWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
SmartTimeoutLock(DebuggerLock, 1000); SmartTimeoutLock(DebuggerLock, 1000);
va_list args; va_list args;
@ -181,7 +181,7 @@ extern "C" NIF void SysDbgLockedWrite(enum DebugLevel Level, const char *File, i
} }
// C compatibility // C compatibility
extern "C" NIF void SysDbgLockedWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) extern "C" nif void SysDbgLockedWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
SmartTimeoutLock(DebuggerLock, 1000); SmartTimeoutLock(DebuggerLock, 1000);
va_list args; va_list args;

View File

@ -15,6 +15,7 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>. along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/ */
#define NO_API_IN_HEADER 1
#include <driver.hpp> #include <driver.hpp>
#include <interface/driver.h> #include <interface/driver.h>
#include <interface/fs.h> #include <interface/fs.h>
@ -66,12 +67,10 @@ namespace v0
uintptr_t Flags; uintptr_t Flags;
#if defined(__x86_64__) #if defined(__x86_64__)
asmv("pushfq"); asmv("pushfq");
asmv("popq %0" asmv("popq %0" : "=r"(Flags));
: "=r"(Flags));
#else #else
asmv("pushfl"); asmv("pushfl");
asmv("popl %0" asmv("popl %0" : "=r"(Flags));
: "=r"(Flags));
#endif #endif
cs = Flags & (1 << 9); cs = Flags & (1 << 9);
asmv("cli"); asmv("cli");
@ -192,11 +191,11 @@ namespace v0
/* --------- */ /* --------- */
dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info, struct Inode *Root) dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info)
{ {
dbg_api("%d, %#lx, %#lx", DriverID, Info, Root); dbg_api("%d, %#lx", DriverID, Info);
return fs->RegisterFileSystem(Info, Root); return fs->RegisterFileSystem(Info);
} }
int UnregisterFileSystem(dev_t DriverID, dev_t Device) int UnregisterFileSystem(dev_t DriverID, dev_t Device)
@ -274,7 +273,7 @@ namespace v0
{ {
dbg_api("%d, %d", DriverID, Milliseconds); dbg_api("%d, %d", DriverID, Milliseconds);
TaskManager->Sleep(Milliseconds); TaskManager->Sleep(Time::FromMilliseconds(Milliseconds));
} }
/* --------- */ /* --------- */
@ -334,7 +333,7 @@ namespace v0
void PS2Wait(dev_t DriverID, const bool Output) void PS2Wait(dev_t DriverID, const bool Output)
{ {
dbg_api("%d, %d", DriverID, Output); // dbg_api("%d, %d", DriverID, Output);
#if defined(__amd64__) || defined(__i386__) #if defined(__amd64__) || defined(__i386__)
int Timeout = 100000; int Timeout = 100000;
@ -380,7 +379,7 @@ namespace v0
uint8_t PS2ReadData(dev_t DriverID) uint8_t PS2ReadData(dev_t DriverID)
{ {
dbg_api("%d", DriverID); // dbg_api("%d", DriverID);
#if defined(__amd64__) || defined(__i386__) #if defined(__amd64__) || defined(__i386__)
WaitOutput; WaitOutput;
@ -453,29 +452,13 @@ namespace v0
void *AllocateMemory(dev_t DriverID, size_t Pages) void *AllocateMemory(dev_t DriverID, size_t Pages)
{ {
dbg_api("%d, %d", DriverID, Pages); dbg_api("%d, %d", DriverID, Pages);
return DriverManager->AllocateMemory(DriverID, Pages);
std::unordered_map<dev_t, Driver::DriverObject> &Drivers =
DriverManager->GetDrivers();
auto itr = Drivers.find(DriverID);
assert(itr != Drivers.end());
void *ptr = itr->second.vma->RequestPages(Pages);
memset(ptr, 0, FROM_PAGES(Pages));
return ptr;
} }
void FreeMemory(dev_t DriverID, void *Pointer, size_t Pages) void FreeMemory(dev_t DriverID, void *Pointer, size_t Pages)
{ {
dbg_api("%d, %#lx, %d", DriverID, Pointer, Pages); dbg_api("%d, %#lx, %d", DriverID, Pointer, Pages);
DriverManager->FreeMemory(DriverID, Pointer, Pages);
std::unordered_map<dev_t, Driver::DriverObject> &Drivers =
DriverManager->GetDrivers();
auto itr = Drivers.find(DriverID);
assert(itr != Drivers.end());
itr->second.vma->FreePages(Pointer, Pages);
} }
void *MemoryCopy(dev_t DriverID, void *Destination, const void *Source, size_t Length) void *MemoryCopy(dev_t DriverID, void *Destination, const void *Source, size_t Length)
@ -588,7 +571,7 @@ namespace v0
__PCIArray *head = nullptr; __PCIArray *head = nullptr;
__PCIArray *array = nullptr; __PCIArray *array = nullptr;
foreach (auto &dev in Devices) for (auto &dev : Devices)
{ {
/* TODO: optimize memory allocation */ /* TODO: optimize memory allocation */
PCI::PCIDevice *dptr = (PCI::PCIDevice *)vma->RequestPages(TO_PAGES(sizeof(PCI::PCIDevice))); PCI::PCIDevice *dptr = (PCI::PCIDevice *)vma->RequestPages(TO_PAGES(sizeof(PCI::PCIDevice)));
@ -621,131 +604,7 @@ namespace v0
void InitializePCI(dev_t DriverID, void *_Header) void InitializePCI(dev_t DriverID, void *_Header)
{ {
dbg_api("%d, %#lx", DriverID, _Header); dbg_api("%d, %#lx", DriverID, _Header);
PCIManager->InitializeDevice(*(PCI::PCIDevice *)_Header, KernelPageTable);
PCI::PCIDevice *__device = (PCI::PCIDevice *)_Header;
PCI::PCIDeviceHeader *Header = (PCI::PCIDeviceHeader *)__device->Header;
debug("Header Type: %d", Header->HeaderType);
switch (Header->HeaderType)
{
case 128:
warn("Unknown header type %d! Guessing PCI Header 0",
Header->HeaderType);
[[fallthrough]];
case 0: /* PCI Header 0 */
{
PCI::PCIHeader0 *hdr0 = (PCI::PCIHeader0 *)Header;
uint32_t BAR[6];
size_t BARsSize[6];
BAR[0] = hdr0->BAR0;
BAR[1] = hdr0->BAR1;
BAR[2] = hdr0->BAR2;
BAR[3] = hdr0->BAR3;
BAR[4] = hdr0->BAR4;
BAR[5] = hdr0->BAR5;
debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx",
BAR[0] & 1, BAR[1] & (~3), BAR[0] & (~15));
/* BARs Size */
for (short i = 0; i < 6; i++)
{
if (BAR[i] == 0)
continue;
size_t size;
if ((BAR[i] & 1) == 0) /* Memory Base */
{
hdr0->BAR0 = 0xFFFFFFFF;
size = hdr0->BAR0;
hdr0->BAR0 = BAR[i];
BARsSize[i] = size & (~15);
BARsSize[i] = ~BARsSize[i] + 1;
BARsSize[i] = BARsSize[i] & 0xFFFFFFFF;
debug("BAR%d %#lx size: %d",
i, BAR[i], BARsSize[i]);
}
else if ((BAR[i] & 1) == 1) /* I/O Base */
{
hdr0->BAR1 = 0xFFFFFFFF;
size = hdr0->BAR1;
hdr0->BAR1 = BAR[i];
BARsSize[i] = size & (~3);
BARsSize[i] = ~BARsSize[i] + 1;
BARsSize[i] = BARsSize[i] & 0xFFFF;
debug("BAR%d %#lx size: %d",
i, BAR[i], BARsSize[i]);
}
}
Memory::Virtual vmm(KernelPageTable);
/* Mapping the BARs */
for (short i = 0; i < 6; i++)
{
if (BAR[i] == 0)
continue;
if ((BAR[i] & 1) == 0) /* Memory Base */
{
uintptr_t BARBase = BAR[i] & (~15);
size_t BARSize = BARsSize[i];
debug("Mapping BAR%d %#lx-%#lx",
i, BARBase, BARBase + BARSize);
if (BARSize == 0)
{
warn("BAR%d size is zero!", i);
BARSize++;
}
vmm.Map((void *)BARBase, (void *)BARBase,
BARSize, Memory::RW | Memory::PWT | Memory::PCD);
}
else if ((BAR[i] & 1) == 1) /* I/O Base */
{
uintptr_t BARBase = BAR[i] & (~3);
size_t BARSize = BARsSize[i];
debug("Mapping BAR%d %#x-%#x",
i, BARBase, BARBase + BARSize);
if (BARSize == 0)
{
warn("BAR%d size is zero!", i);
BARSize++;
}
vmm.Map((void *)BARBase, (void *)BARBase,
BARSize, Memory::RW | Memory::PWT | Memory::PCD);
}
}
break;
}
case 1: /* PCI Header 1 (PCI-to-PCI Bridge) */
{
fixme("PCI Header 1 (PCI-to-PCI Bridge) not implemented yet");
break;
}
case 2: /* PCI Header 2 (PCI-to-CardBus Bridge) */
{
fixme("PCI Header 2 (PCI-to-CardBus Bridge) not implemented yet");
break;
}
default:
{
error("Unknown header type %d", Header->HeaderType);
break;
}
}
Header->Command |= PCI_COMMAND_MASTER |
PCI_COMMAND_IO |
PCI_COMMAND_MEMORY;
Header->Command &= ~PCI_COMMAND_INTX_DISABLE;
} }
uint32_t GetBAR(dev_t DriverID, uint8_t i, void *_Header) uint32_t GetBAR(dev_t DriverID, uint8_t i, void *_Header)
@ -824,6 +683,13 @@ namespace v0
/* --------- */ /* --------- */
dev_t CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, const InodeOperations *Operations)
{
dbg_api("%d, %s, %#o, %#lx", DriverID, name, mode, Operations);
return DriverManager->CreateDeviceFile(DriverID, name, mode, Operations);
}
dev_t RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations) dev_t RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
{ {
dbg_api("%d, %d, %#lx", DriverID, Type, Operations); dbg_api("%d, %d, %#lx", DriverID, Type, Operations);
@ -844,6 +710,20 @@ namespace v0
return DriverManager->ReportInputEvent(DriverID, Report); return DriverManager->ReportInputEvent(DriverID, Report);
} }
dev_t RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device)
{
dbg_api("%d, %#lx", DriverID, Device);
return DriverManager->RegisterBlockDevice(DriverID, Device);
}
int UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID)
{
dbg_api("%d, %d", DriverID, DeviceID);
return DriverManager->UnregisterBlockDevice(DriverID, DeviceID);
}
} }
struct APISymbols struct APISymbols
@ -907,9 +787,12 @@ static struct APISymbols APISymbols_v0[] = {
{"__iLine", (void *)v0::iLine}, {"__iLine", (void *)v0::iLine},
{"__iPin", (void *)v0::iPin}, {"__iPin", (void *)v0::iPin},
{"__CreateDeviceFile", (void *)v0::CreateDeviceFile},
{"__RegisterDevice", (void *)v0::RegisterDevice}, {"__RegisterDevice", (void *)v0::RegisterDevice},
{"__UnregisterDevice", (void *)v0::UnregisterDevice}, {"__UnregisterDevice", (void *)v0::UnregisterDevice},
{"__ReportInputEvent", (void *)v0::ReportInputEvent}, {"__ReportInputEvent", (void *)v0::ReportInputEvent},
{"__RegisterBlockDevice", (void *)v0::RegisterBlockDevice},
{"__UnregisterBlockDevice", (void *)v0::UnregisterBlockDevice},
}; };
long __KernelUndefinedFunction(long arg0, long arg1, long arg2, long arg3, long __KernelUndefinedFunction(long arg0, long arg1, long arg2, long arg3,

View File

@ -1,890 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <driver.hpp>
#include <interface/driver.h>
#include <interface/input.h>
#include <memory.hpp>
#include <stropts.h>
#include <ints.hpp>
#include <task.hpp>
#include <printf.h>
#include <exec.hpp>
#include <rand.hpp>
#include <cwalk.h>
#include <md5.h>
#include "../../kernel.h"
using namespace vfs;
namespace Driver
{
/**
* maj = 0
* min:
* 0 - <ROOT>
* 1 - /proc/self
* 2 - /dev/null
* 3 - /dev/zero
* 4 - /dev/random
* 5 - /dev/mem
* 6 - /dev/kcon
* 7 - /dev/tty
* 8 - /dev/ptmx
*
* maj = 1
* min:
* 0 - /dev/input/keyboard
* 1 - /dev/input/mouse
* ..- /dev/input/eventX
*/
TTY::PTMXDevice *ptmx = nullptr;
int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
{
func("%#lx %s %#lx", _Parent, Name, Result);
assert(_Parent != nullptr);
const char *basename;
size_t length;
cwk_path_get_basename(Name, &basename, &length);
if (basename == NULL)
{
error("Invalid name %s", Name);
return -EINVAL;
}
auto Parent = (Manager::DeviceInode *)_Parent;
for (const auto &child : Parent->Children)
{
debug("Comparing %s with %s", basename, child->Name.c_str());
if (strcmp(child->Name.c_str(), basename) != 0)
continue;
*Result = &child->Node;
return 0;
}
debug("Not found %s", Name);
return -ENOENT;
}
int __fs_Create(struct Inode *_Parent, const char *Name, mode_t Mode, struct Inode **Result)
{
func("%#lx %s %d", _Parent, Name, Mode);
assert(_Parent != nullptr);
/* We expect to be /dev or children of it */
auto Parent = (Manager::DeviceInode *)_Parent;
auto _dev = new Manager::DeviceInode;
_dev->Parent = nullptr;
_dev->ParentInode = _Parent;
_dev->Name = Name;
_dev->Node.Mode = Mode;
_dev->Node.Index = Parent->Node.Index + Parent->Children.size();
Parent->Children.push_back(_dev);
*Result = &_dev->Node;
return 0;
}
ssize_t __fs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
{
func("%#lx %d %d", Node, Size, Offset);
switch (Node->GetMajor())
{
case 0:
{
switch (Node->GetMinor())
{
case 2: /* /dev/null */
{
return 0;
}
case 3: /* /dev/zero */
{
if (Size <= 0)
return 0;
memset(Buffer, 0, Size);
return Size;
}
case 4: /* /dev/random */
{
if (Size <= 0)
return 0;
if (Size < sizeof(uint64_t))
{
uint8_t *buf = (uint8_t *)Buffer;
for (size_t i = 0; i < Size; i++)
buf[i] = (uint8_t)(Random::rand16() & 0xFF);
return Size;
}
uint64_t *buf = (uint64_t *)Buffer;
for (size_t i = 0; i < Size / sizeof(uint64_t); i++)
buf[i] = Random::rand64();
return Size;
}
case 5: /* /dev/mem */
{
stub;
return 0;
}
case 6: /* /dev/kcon */
return KernelConsole::CurrentTerminal.load()->Read(Buffer, Size, Offset);
case 7: /* /dev/tty */
{
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
if (tty == nullptr)
return -ENOTTY;
return tty->Read(Buffer, Size, Offset);
}
case 8: /* /dev/ptmx */
return -ENOSYS;
default:
return -ENOENT;
};
break;
}
case 1:
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
{
if (Size < sizeof(KeyboardReport))
return -EINVAL;
size_t nReads = Size / sizeof(KeyboardReport);
KeyboardReport *report = (KeyboardReport *)Buffer;
while (DriverManager->GlobalKeyboardInputReports.Count() == 0)
TaskManager->Yield();
DriverManager->GlobalKeyboardInputReports.Read(report, nReads);
return sizeof(KeyboardReport) * nReads;
}
case 1: /* /dev/input/mouse */
{
if (Size < sizeof(MouseReport))
return -EINVAL;
size_t nReads = Size / sizeof(MouseReport);
MouseReport *report = (MouseReport *)Buffer;
while (DriverManager->GlobalMouseInputReports.Count() == 0)
TaskManager->Yield();
DriverManager->GlobalMouseInputReports.Read(report, nReads);
return sizeof(MouseReport) * nReads;
}
default:
return -ENOENT;
};
}
default:
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Read, -ENOTSUP);
return dOps->second.Ops->Read(Node, Buffer, Size, Offset);
}
}
}
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
{
func("%#lx %p %d %d", Node, Buffer, Size, Offset);
switch (Node->GetMajor())
{
case 0:
{
switch (Node->GetMinor())
{
case 2: /* /dev/null */
{
return Size;
}
case 3: /* /dev/zero */
{
return Size;
}
case 4: /* /dev/random */
{
return Size;
}
case 5: /* /dev/mem */
{
stub;
return 0;
}
case 6: /* /dev/kcon */
return KernelConsole::CurrentTerminal.load()->Write(Buffer, Size, Offset);
case 7: /* /dev/tty */
{
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
if (tty == nullptr)
return -ENOTTY;
return tty->Write(Buffer, Size, Offset);
}
case 8: /* /dev/ptmx */
return -ENOSYS;
default:
return -ENOENT;
};
}
case 1:
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
{
return -ENOTSUP;
}
case 1: /* /dev/input/mouse */
{
return -ENOTSUP;
}
default:
return -ENOENT;
};
}
default:
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Write, -ENOTSUP);
return dOps->second.Ops->Write(Node, Buffer, Size, Offset);
}
}
}
int __fs_Open(struct Inode *Node, int Flags, mode_t Mode)
{
func("%#lx %d %d", Node, Flags, Mode);
switch (Node->GetMajor())
{
case 0:
{
switch (Node->GetMinor())
{
case 2: /* /dev/null */
case 3: /* /dev/zero */
case 4: /* /dev/random */
case 5: /* /dev/mem */
return -ENOSYS;
case 6: /* /dev/kcon */
return KernelConsole::CurrentTerminal.load()->Open(Flags, Mode);
case 7: /* /dev/tty */
{
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
if (tty == nullptr)
return -ENOTTY;
return tty->Open(Flags, Mode);
}
case 8: /* /dev/ptmx */
return ptmx->Open();
default:
return -ENOENT;
};
}
case 1:
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
case 1: /* /dev/input/mouse */
return -ENOTSUP;
default:
return -ENOENT;
};
}
default:
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Open, -ENOTSUP);
return dOps->second.Ops->Open(Node, Flags, Mode);
}
}
}
int __fs_Close(struct Inode *Node)
{
func("%#lx", Node);
switch (Node->GetMajor())
{
case 0:
{
switch (Node->GetMinor())
{
case 2: /* /dev/null */
case 3: /* /dev/zero */
case 4: /* /dev/random */
case 5: /* /dev/mem */
return -ENOSYS;
case 6: /* /dev/kcon */
return KernelConsole::CurrentTerminal.load()->Close();
case 7: /* /dev/tty */
{
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
if (tty == nullptr)
return -ENOTTY;
return tty->Close();
}
case 8: /* /dev/ptmx */
return ptmx->Close();
default:
return -ENOENT;
};
}
case 1:
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
case 1: /* /dev/input/mouse */
return -ENOTSUP;
default:
return -ENOENT;
};
}
default:
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Close, -ENOTSUP);
return dOps->second.Ops->Close(Node);
}
}
}
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
{
func("%#lx %lu %#lx", Node, Request, Argp);
switch (Node->GetMajor())
{
case 0:
{
switch (Node->GetMinor())
{
case 2: /* /dev/null */
case 3: /* /dev/zero */
case 4: /* /dev/random */
case 5: /* /dev/mem */
return -ENOSYS;
case 6: /* /dev/kcon */
return KernelConsole::CurrentTerminal.load()->Ioctl(Request, Argp);
case 7: /* /dev/tty */
{
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
if (tty == nullptr)
return -ENOTTY;
return tty->Ioctl(Request, Argp);
}
case 8: /* /dev/ptmx */
return -ENOSYS;
default:
return -ENOENT;
};
break;
}
case 1:
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
case 1: /* /dev/input/mouse */
return -ENOSYS;
default:
return -ENOENT;
};
}
default:
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Ioctl, -ENOTSUP);
return dOps->second.Ops->Ioctl(Node, Request, Argp);
}
}
}
__no_sanitize("alignment")
ssize_t __fs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
{
func("%#lx %#lx %d %d %d", _Node, Buffer, Size, Offset, Entries);
auto Node = (Manager::DeviceInode *)_Node;
off_t realOffset = Offset;
size_t totalSize = 0;
uint16_t reclen = 0;
struct kdirent *ent = nullptr;
if (Offset == 0)
{
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1);
if (totalSize + reclen >= Size)
return -EINVAL;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = Node->Node.Index;
ent->d_off = Offset++;
ent->d_reclen = reclen;
ent->d_type = DT_DIR;
strcpy(ent->d_name, ".");
totalSize += reclen;
}
if (Offset <= 1)
{
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1);
if (totalSize + reclen >= Size)
{
if (realOffset == 1)
return -EINVAL;
return totalSize;
}
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
if (Node->Parent)
ent->d_ino = Node->Parent->Node->Index;
else if (Node->ParentInode)
ent->d_ino = Node->ParentInode->Index;
else
{
warn("Parent is null for %s", Node->Name.c_str());
ent->d_ino = Node->Node.Index;
}
ent->d_off = Offset++;
ent->d_reclen = reclen;
ent->d_type = DT_DIR;
strcpy(ent->d_name, "..");
totalSize += reclen;
}
if (!S_ISDIR(Node->Node.Mode))
return -ENOTDIR;
if ((Offset >= 2 ? (Offset - 2) : Offset) > (off_t)Node->Children.size())
return -EINVAL;
off_t entries = 0;
for (const auto &var : Node->Children)
{
debug("iterating \"%s\" inside \"%s\"", var->Name.c_str(), Node->Name.c_str());
if (var->Node.Offset < realOffset)
{
debug("skipping \"%s\" (%d < %d)", var->Name.c_str(), var->Node.Offset, Offset);
continue;
}
if (entries >= Entries)
break;
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
if (totalSize + reclen >= Size)
break;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = var->Node.Index;
ent->d_off = var->Node.Offset;
ent->d_reclen = reclen;
ent->d_type = IFTODT(var->Node.Mode);
strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str()));
totalSize += reclen;
entries++;
}
if (totalSize + sizeof(struct kdirent) >= Size)
return totalSize;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = 0;
ent->d_off = 0;
ent->d_reclen = 0;
ent->d_type = DT_UNKNOWN;
ent->d_name[0] = '\0';
return totalSize;
}
void ManagerDaemonWrapper() { DriverManager->Daemon(); }
void Manager::Daemon()
{
while (true)
{
TaskManager->Sleep(1000);
}
}
dev_t Manager::RegisterInputDevice(std::unordered_map<dev_t, DriverHandlers> *dop,
dev_t DriverID, size_t i, const InodeOperations *Operations)
{
std::string prefix = "event";
for (size_t j = 0; j < 128; j++)
{
std::string deviceName = prefix + std::to_string(j);
FileNode *node = fs->GetByPath(deviceName.c_str(), devInputNode);
if (node)
continue;
/* c rwx r-- r-- */
mode_t mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFCHR;
node = fs->ForceCreate(devInputNode, deviceName.c_str(), mode);
node->Node->SetDevice(DriverID, i);
DriverHandlers dh{};
dh.Ops = Operations;
dh.Node = node->Node;
dh.InputReports = new RingBuffer<InputReport>(16);
dop->insert({i, std::move(dh)});
return i;
}
ReturnLogError(-1, "No available slots for device %d", DriverID);
return -1; /* -Werror=return-type */
}
dev_t Manager::RegisterBlockDevice(std::unordered_map<dev_t, DriverHandlers> *dop,
dev_t DriverID, size_t i, const InodeOperations *Operations)
{
std::string prefix = "event";
for (size_t j = 0; j < 128; j++)
{
std::string deviceName = prefix + std::to_string(j);
FileNode *node = fs->GetByPath(deviceName.c_str(), devInputNode);
if (node)
continue;
/* c rwx r-- r-- */
mode_t mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFBLK;
node = fs->ForceCreate(devInputNode, deviceName.c_str(), mode);
node->Node->SetDevice(DriverID, i);
DriverHandlers dh{};
dh.Ops = Operations;
dh.Node = node->Node;
dh.InputReports = new RingBuffer<InputReport>(16);
dop->insert({i, std::move(dh)});
return i;
}
ReturnLogError(-1, "No available slots for device %d", DriverID);
return -1; /* -Werror=return-type */
}
dev_t Manager::RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
for (size_t i = 0; i < 128; i++)
{
const auto dOps = dop->find(i);
const auto dOpsEnd = dop->end();
if (dOps != dOpsEnd)
continue;
DeviceType devType = (DeviceType)(Type & DEVICE_TYPE_MASK);
switch (devType)
{
case DEVICE_TYPE_INPUT:
return RegisterInputDevice(dop, DriverID, i, Operations);
case DEVICE_TYPE_BLOCK:
return RegisterBlockDevice(dop, DriverID, i, Operations);
default:
ReturnLogError(-1, "Invalid device type %d", Type);
}
}
ReturnLogError(-1, "No available slots for device %d", DriverID);
}
int Manager::UnregisterDevice(dev_t DriverID, dev_t Device)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
const auto dOps = dop->find(Device);
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Device);
dop->erase(dOps);
fixme("remove eventX from /dev/input");
fixme("delete InputReports");
return 0;
}
int Manager::ReportInputEvent(dev_t DriverID, InputReport *Report)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Report->Device);
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Report->Device);
dOps->second.InputReports->Write(Report, 1);
switch (Report->Type)
{
case INPUT_TYPE_KEYBOARD:
{
KeyboardReport *kReport = &Report->Keyboard;
GlobalKeyboardInputReports.Write(kReport, 1);
break;
}
case INPUT_TYPE_MOUSE:
{
MouseReport *mReport = &Report->Mouse;
GlobalMouseInputReports.Write(mReport, 1);
break;
}
default:
assert(!"Invalid input type");
}
return 0;
}
void Manager::InitializeDaemonFS()
{
ptmx = new TTY::PTMXDevice;
dev_t MinorID = 0;
DeviceInode *_dev = new DeviceInode;
_dev->Name = "dev";
/* d rwx r-- r-- */
mode_t mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFDIR;
Inode *dev = (Inode *)_dev;
dev->Mode = mode;
dev->Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
FileSystemInfo *fsi = new FileSystemInfo;
fsi->Name = "Device Virtual File System";
fsi->RootName = "dev";
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
fsi->SuperOps = {};
fsi->Ops.Lookup = __fs_Lookup;
fsi->Ops.Create = __fs_Create;
fsi->Ops.Read = __fs_Read;
fsi->Ops.Write = __fs_Write;
fsi->Ops.Open = __fs_Open;
fsi->Ops.Close = __fs_Close;
fsi->Ops.Ioctl = __fs_Ioctl;
fsi->Ops.ReadDir = __fs_Readdir;
dev->Device = fs->RegisterFileSystem(fsi, dev);
dev->SetDevice(0, MinorID++);
MinorID++; /* 1 = /proc/self */
devNode = fs->Mount(fs->GetRoot(0), dev, "/dev");
_dev->Parent = devNode->Parent;
_dev->ParentInode = devNode->Parent->Node;
/* d rwx r-- r-- */
mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFDIR;
DeviceInode *input = new DeviceInode;
input->Parent = devNode;
input->ParentInode = devNode->Node;
input->Name = "input";
input->Node.Device = dev->Device;
input->Node.Mode = mode;
input->Node.Flags = I_FLAG_CACHE_KEEP;
input->Node.Offset = _dev->Children.size();
_dev->Children.push_back(input);
devInputNode = fs->GetByPath("input", devNode);
auto createDevice = [](DeviceInode *p1, FileNode *p2, const std::string &name, dev_t maj, dev_t min, mode_t mode)
{
DeviceInode *device = new DeviceInode;
device->Parent = p2;
device->ParentInode = p2->Node;
device->Name = name;
device->Node.Device = p2->Node->Device;
device->Node.Mode = mode;
device->Node.SetDevice(maj, min);
device->Node.Flags = I_FLAG_CACHE_KEEP;
device->Node.Offset = p1->Children.size();
p1->Children.push_back(device);
};
/* c rw- rw- rw- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH |
S_IFCHR;
createDevice(_dev, devNode, "null", 0, MinorID++, mode);
/* c rw- rw- rw- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH |
S_IFCHR;
createDevice(_dev, devNode, "zero", 0, MinorID++, mode);
/* c rw- rw- rw- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH |
S_IFCHR;
createDevice(_dev, devNode, "random", 0, MinorID++, mode);
/* c rw- r-- --- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP |
S_IFCHR;
createDevice(_dev, devNode, "mem", 0, MinorID++, mode);
/* c rw- r-- --- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP |
S_IFCHR;
createDevice(_dev, devNode, "kcon", 0, MinorID++, mode);
/* c rw- rw- rw- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IRUSR | S_IWUSR |
S_IFCHR;
createDevice(_dev, devNode, "tty", 0, MinorID++, mode);
/* c rw- rw- rw- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IRUSR | S_IWUSR |
S_IFCHR;
createDevice(_dev, devNode, "ptmx", 0, MinorID++, mode);
/* ------------------------------------------------------ */
MinorID = 0;
/* c rw- r-- --- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP |
S_IFCHR;
createDevice(input, devInputNode, "keyboard", 1, MinorID++, mode);
/* c rw- r-- --- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP |
S_IFCHR;
createDevice(input, devInputNode, "mouse", 1, MinorID++, mode);
}
}

483
Kernel/core/driver/dev.cpp Normal file
View File

@ -0,0 +1,483 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <driver.hpp>
#include "../../kernel.h"
namespace Driver
{
dev_t DeviceDirID;
int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
{
func("%#lx %s %#lx", _Parent, Name, Result);
assert(_Parent != nullptr);
const char *basename;
size_t length;
cwk_path_get_basename(Name, &basename, &length);
if (basename == NULL)
{
error("Invalid name %s", Name);
return -EINVAL;
}
auto Parent = (Manager::DeviceInode *)_Parent;
for (const auto &child : Parent->Children)
{
debug("Comparing %s with %s", basename, child->Name.c_str());
if (strcmp(child->Name.c_str(), basename) != 0)
continue;
*Result = &child->inode;
return 0;
}
debug("Not found %s", Name);
return -ENOENT;
}
int __fs_Create(struct Inode *_Parent, const char *Name, mode_t Mode, struct Inode **Result)
{
func("%#lx %s %d", _Parent, Name, Mode);
assert(_Parent != nullptr);
/* We expect to be /dev or children of it */
auto Parent = (Manager::DeviceInode *)_Parent;
auto _dev = new Manager::DeviceInode;
_dev->Parent = nullptr;
_dev->ParentInode = _Parent;
_dev->Name = Name;
_dev->inode.Device = Parent->inode.Device;
_dev->inode.Mode = Mode;
_dev->inode.Index = Parent->inode.Index + Parent->Children.size();
_dev->inode.Offset = Parent->Children.size();
Parent->Children.push_back(_dev);
*Result = &_dev->inode;
return 0;
}
ssize_t __fs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
{
func("%#lx %d %d", Node, Size, Offset);
if ((dev_t)Node->GetMajor() == DeviceDirID)
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
{
if (Size < sizeof(KeyboardReport))
return -EINVAL;
size_t nReads = Size / sizeof(KeyboardReport);
KeyboardReport *report = (KeyboardReport *)Buffer;
while (DriverManager->GlobalKeyboardInputReports.Count() == 0)
TaskManager->Yield();
DriverManager->GlobalKeyboardInputReports.Read(report, nReads);
return sizeof(KeyboardReport) * nReads;
}
case 1: /* /dev/input/mouse */
{
if (Size < sizeof(MouseReport))
return -EINVAL;
size_t nReads = Size / sizeof(MouseReport);
MouseReport *report = (MouseReport *)Buffer;
while (DriverManager->GlobalMouseInputReports.Count() == 0)
TaskManager->Yield();
DriverManager->GlobalMouseInputReports.Read(report, nReads);
return sizeof(MouseReport) * nReads;
}
default:
return -ENOENT;
};
}
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Read, -ENOTSUP);
return dOps->second.Ops->Read(Node, Buffer, Size, Offset);
}
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
{
func("%#lx %p %d %d", Node, Buffer, Size, Offset);
if ((dev_t)Node->GetMajor() == DeviceDirID)
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
{
return -ENOTSUP;
}
case 1: /* /dev/input/mouse */
{
return -ENOTSUP;
}
default:
return -ENOENT;
};
}
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Write, -ENOTSUP);
return dOps->second.Ops->Write(Node, Buffer, Size, Offset);
}
int __fs_Open(struct Inode *Node, int Flags, mode_t Mode)
{
func("%#lx %d %d", Node, Flags, Mode);
if ((dev_t)Node->GetMajor() == DeviceDirID)
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
case 1: /* /dev/input/mouse */
return -ENOTSUP;
default:
return -ENOENT;
};
}
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Open, -ENOTSUP);
return dOps->second.Ops->Open(Node, Flags, Mode);
}
int __fs_Close(struct Inode *Node)
{
func("%#lx", Node);
if ((dev_t)Node->GetMajor() == DeviceDirID)
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
case 1: /* /dev/input/mouse */
return -ENOTSUP;
default:
return -ENOENT;
};
}
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Close, -ENOTSUP);
return dOps->second.Ops->Close(Node);
}
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
{
func("%#lx %lu %#lx", Node, Request, Argp);
if ((dev_t)Node->GetMajor() == DeviceDirID)
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
case 1: /* /dev/input/mouse */
return -ENOSYS;
default:
return -ENOENT;
};
}
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Ioctl, -ENOTSUP);
return dOps->second.Ops->Ioctl(Node, Request, Argp);
}
__no_sanitize("alignment") ssize_t __fs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
{
func("%#lx %#lx %d %d %d", _Node, Buffer, Size, Offset, Entries);
auto node = (Manager::DeviceInode *)_Node;
off_t realOffset = Offset;
size_t totalSize = 0;
uint16_t reclen = 0;
struct kdirent *ent = nullptr;
if (!S_ISDIR(node->inode.Mode))
return -ENOTDIR;
if (Offset == 0)
{
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1);
if (totalSize + reclen > Size)
return -EINVAL;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = node->inode.Index;
ent->d_off = 0;
ent->d_reclen = reclen;
ent->d_type = DT_DIR;
strcpy(ent->d_name, ".");
totalSize += reclen;
Offset++;
}
if (Offset == 1)
{
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1);
if (totalSize + reclen > Size)
return totalSize;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
if (node->Parent)
ent->d_ino = node->Parent->inode->Index;
else if (node->ParentInode)
ent->d_ino = node->ParentInode->Index;
else
ent->d_ino = node->inode.Index;
ent->d_off = 1;
ent->d_reclen = reclen;
ent->d_type = DT_DIR;
strcpy(ent->d_name, "..");
totalSize += reclen;
Offset++;
}
off_t entryIndex = 0;
for (const auto &var : node->Children)
{
if (entryIndex + 2 < realOffset)
{
entryIndex++;
continue;
}
if (Entries && entryIndex >= Entries)
break;
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
if (totalSize + reclen > Size)
break;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = var->inode.Index;
ent->d_off = entryIndex + 2;
ent->d_reclen = reclen;
ent->d_type = IFTODT(var->inode.Mode);
strcpy(ent->d_name, var->Name.c_str());
totalSize += reclen;
entryIndex++;
}
if (totalSize + offsetof(struct kdirent, d_name) + 1 > Size)
return totalSize;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = 0;
ent->d_off = 0;
ent->d_reclen = 0;
ent->d_type = DT_UNKNOWN;
ent->d_name[0] = '\0';
return totalSize;
}
int __fs_Stat(struct Inode *_Node, struct kstat *Stat)
{
func("%#lx %#lx", _Node, Stat);
auto node = (Manager::DeviceInode *)_Node;
assert(node != nullptr);
assert(Stat != nullptr);
Stat->Device = node->inode.Device;
Stat->Index = node->inode.Index;
Stat->HardLinks = 1;
Stat->UserID = 0;
Stat->GroupID = 0;
Stat->RawDevice = node->inode.RawDevice;
Stat->Size = node->Size;
Stat->AccessTime = node->AccessTime;
Stat->ModifyTime = node->ModifyTime;
Stat->ChangeTime = node->ChangeTime;
Stat->BlockSize = node->BlockSize;
Stat->Blocks = node->Blocks;
Stat->Attribute = 0;
return 0;
}
void Manager::InitializeDeviceDirectory()
{
dev_t MinorID = 0;
DeviceInode *_dev = new DeviceInode;
_dev->Name = "dev";
/* d rwx r-- r-- */
mode_t mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFDIR;
Inode *dev = (Inode *)_dev;
dev->Mode = mode;
FileSystemInfo *fsi = new FileSystemInfo;
fsi->Name = "devfs";
fsi->SuperOps = {};
fsi->Ops.Lookup = __fs_Lookup;
fsi->Ops.Create = __fs_Create;
fsi->Ops.Remove = nullptr;
fsi->Ops.Rename = nullptr;
fsi->Ops.Read = __fs_Read;
fsi->Ops.Write = __fs_Write;
fsi->Ops.Truncate = nullptr;
fsi->Ops.Open = __fs_Open;
fsi->Ops.Close = __fs_Close;
fsi->Ops.Ioctl = __fs_Ioctl;
fsi->Ops.ReadDir = __fs_Readdir;
fsi->Ops.MkDir = nullptr;
fsi->Ops.RmDir = nullptr;
fsi->Ops.SymLink = nullptr;
fsi->Ops.ReadLink = nullptr;
fsi->Ops.Seek = nullptr;
fsi->Ops.Stat = __fs_Stat;
DeviceDirID = dev->Device = fs->RegisterFileSystem(fsi);
dev->SetDevice(0, MinorID++);
Node root = fs->GetRoot(0);
devNode = fs->Mount(root, dev, "dev", fsi);
assert(devNode->Parent != nullptr);
_dev->Parent = devNode->Parent;
_dev->ParentInode = devNode->Parent->inode;
/* d rwx r-- r-- */
mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFDIR;
DeviceInode *blk = new DeviceInode;
blk->Parent = devNode;
blk->ParentInode = devNode->inode;
blk->Name = "block";
blk->inode.Device = dev->Device;
blk->inode.Mode = mode;
blk->inode.Offset = _dev->Children.size();
_dev->Children.push_back(blk);
devBlockNode = fs->Lookup(devNode, "block");
/* d rwx r-- r-- */
mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFDIR;
DeviceInode *input = new DeviceInode;
input->Parent = devNode;
input->ParentInode = devNode->inode;
input->Name = "input";
input->inode.Device = dev->Device;
input->inode.Mode = mode;
input->inode.Offset = _dev->Children.size();
_dev->Children.push_back(input);
devInputNode = fs->Lookup(devNode, "input");
auto createDevice = [](DeviceInode *p1, Node p2, const std::string &name, dev_t maj, dev_t min, mode_t mode)
{
DeviceInode *device = new DeviceInode;
device->Parent = p2;
device->ParentInode = p2->inode;
device->Name = name;
device->inode.Device = p2->inode->Device;
device->inode.Mode = mode;
device->inode.SetDevice(maj, min);
device->inode.Offset = p1->Children.size();
p1->Children.push_back(device);
};
MinorID = 0;
/* c rw- r-- --- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP |
S_IFCHR;
createDevice(input, devInputNode, "keyboard", DeviceDirID, MinorID++, mode);
/* c rw- r-- --- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP |
S_IFCHR;
createDevice(input, devInputNode, "mouse", DeviceDirID, MinorID++, mode);
}
}

View File

@ -26,19 +26,84 @@
#include <exec.hpp> #include <exec.hpp>
#include <rand.hpp> #include <rand.hpp>
#include <cwalk.h> #include <cwalk.h>
#include <sha512.h>
#include <md5.h> #include <md5.h>
#include "../../kernel.h" #include "../../kernel.h"
using namespace vfs; using namespace vfs;
extern const char *trusted_drivers[];
extern const __SIZE_TYPE__ trusted_drivers_count;
namespace Driver namespace Driver
{ {
bool Manager::IsDriverTrusted(Node File)
{
kstat st;
fs->Stat(File, &st);
std::unique_ptr<uint8_t[]> ptr(new uint8_t[st.Size]);
fs->Read(File, ptr.get(), st.Size, 0);
uint8_t *sha = sha512_sum(ptr.get(), st.Size);
char hash_str[129];
for (int j = 0; j < 64; j++)
sprintf(hash_str + j * 2, "%02x", sha[j]);
hash_str[128] = '\0';
for (__SIZE_TYPE__ i = 0; i < trusted_drivers_count; i++)
{
if (strcmp(hash_str, trusted_drivers[i]) == 0)
{
kfree(sha);
return true;
}
else
{
trace("Expected \"%s\" but got \"%s\" for driver %s",
trusted_drivers[i], hash_str, File->GetName().c_str());
}
}
kfree(sha);
return false;
}
void Manager::PreloadDrivers() void Manager::PreloadDrivers()
{ {
debug("Initializing driver manager"); debug("Initializing driver manager");
auto &bs = __kernel_builtin_drivers_start;
auto &be = __kernel_builtin_drivers_end;
for (const BuiltInDriver *drv = bs; drv < be; ++drv)
{
debug("Loading built-in driver %s", drv->Name);
DriverObject drvObj = {};
strncpy(drvObj.Name, drv->Name, sizeof(drvObj.Name));
strncpy(drvObj.Description, drv->Description, sizeof(drvObj.Description));
strncpy(drvObj.Author, drv->Author, sizeof(drvObj.Author));
drvObj.Version.Major = drv->Version.Major;
drvObj.Version.Minor = drv->Version.Minor;
drvObj.Version.Patch = drv->Version.Patch;
drvObj.Entry = drv->Entry;
drvObj.Final = drv->Final;
drvObj.Panic = drv->Panic;
drvObj.Probe = drv->Probe;
drvObj.IsBuiltIn = true;
drvObj.BaseAddress = 0;
drvObj.EntryPoint = drv->EntryPoint;
drvObj.vma = new Memory::VirtualMemoryArea(thisProcess->PageTable);
drvObj.Path = "<builtin>";
drvObj.InterruptHandlers = new std::unordered_map<uint8_t, void *>();
drvObj.DeviceOperations = new std::unordered_map<dev_t, DriverHandlers>();
drvObj.ID = DriverIDCounter;
Drivers.insert({DriverIDCounter++, drvObj});
}
const char *DriverDirectory = Config.DriverDirectory; const char *DriverDirectory = Config.DriverDirectory;
FileNode *drvDirNode = fs->GetByPath(DriverDirectory, nullptr); Node root = fs->GetRoot(0);
Node drvDirNode = fs->Lookup(root, DriverDirectory);
if (!drvDirNode) if (!drvDirNode)
{ {
error("Failed to open driver directory %s", DriverDirectory); error("Failed to open driver directory %s", DriverDirectory);
@ -46,25 +111,37 @@ namespace Driver
return; return;
} }
foreach (const auto &drvNode in drvDirNode->Children) for (const auto &drvNode : fs->ReadDirectory(drvDirNode))
{ {
debug("Checking driver %s", drvNode->Path.c_str()); debug("Checking driver %s", drvNode->Path.c_str());
if (!drvNode->IsRegularFile()) if (!drvNode->IsRegularFile())
continue; continue;
if (std::string(drvNode->Path).find(".drv") == std::string::npos)
continue;
if (Execute::GetBinaryType(drvNode->Path) != Execute::BinTypeELF) if (Execute::GetBinaryType(drvNode->Path) != Execute::BinTypeELF)
{ {
error("Driver %s is not an ELF binary", drvNode->Path.c_str()); error("Driver %s is not an ELF binary", drvNode->GetPath().c_str());
continue; continue;
} }
DriverObject drvObj = {.BaseAddress = 0, if (!IsDriverTrusted(drvNode))
.EntryPoint = 0, {
.vma = new Memory::VirtualMemoryArea(thisProcess->PageTable), error("Driver %s is not trusted", drvNode->GetName().c_str());
.Path = drvNode->Path, KPrint("%s is not in the list of trusted drivers", drvNode->GetName().c_str());
.InterruptHandlers = new std::unordered_map<uint8_t, void *>(), continue;
.DeviceOperations = new std::unordered_map<dev_t, DriverHandlers>(), }
.ID = DriverIDCounter};
DriverObject drvObj = {};
drvObj.IsBuiltIn = false;
drvObj.BaseAddress = 0;
drvObj.EntryPoint = 0;
drvObj.vma = new Memory::VirtualMemoryArea(thisProcess->PageTable);
drvObj.Path = drvNode->Path;
drvObj.InterruptHandlers = new std::unordered_map<uint8_t, void *>();
drvObj.DeviceOperations = new std::unordered_map<dev_t, DriverHandlers>();
drvObj.ID = DriverIDCounter;
int err = this->LoadDriverFile(drvObj, drvNode); int err = this->LoadDriverFile(drvObj, drvNode);
debug("err = %d (%s)", err, strerror(err)); debug("err = %d (%s)", err, strerror(err));
@ -93,7 +170,7 @@ namespace Driver
return; return;
} }
foreach (auto &var in Drivers) for (auto &var : Drivers)
{ {
DriverObject &Drv = var.second; DriverObject &Drv = var.second;
@ -111,7 +188,7 @@ namespace Driver
continue; continue;
} }
KPrint("Loading driver %s", Drv.Name); KPrint("Loading driver %s (%d)", Drv.Name, Drv.ID);
debug("Calling Probe()=%#lx on driver %s", debug("Calling Probe()=%#lx on driver %s",
Drv.Probe, Drv.Path.c_str()); Drv.Probe, Drv.Path.c_str());
@ -148,7 +225,7 @@ namespace Driver
void Manager::UnloadAllDrivers() void Manager::UnloadAllDrivers()
{ {
foreach (auto &var in Drivers) for (auto &var : Drivers)
{ {
DriverObject *Drv = &var.second; DriverObject *Drv = &var.second;
if (!Drv->Initialized) if (!Drv->Initialized)
@ -164,7 +241,7 @@ namespace Driver
if (!Drv->InterruptHandlers->empty()) if (!Drv->InterruptHandlers->empty())
{ {
foreach (auto &rInt in * Drv->InterruptHandlers) for (auto &rInt : *Drv->InterruptHandlers)
{ {
Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))rInt.second); Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))rInt.second);
} }
@ -180,7 +257,7 @@ namespace Driver
if (Drivers.size() == 0) if (Drivers.size() == 0)
return; return;
foreach (auto Driver in Drivers) for (auto Driver : Drivers)
{ {
if (!Driver.second.Initialized) if (!Driver.second.Initialized)
continue; continue;
@ -197,12 +274,12 @@ namespace Driver
} }
} }
int Manager::LoadDriverFile(DriverObject &Drv, FileNode *File) int Manager::LoadDriverFile(DriverObject &Drv, Node File)
{ {
trace("Loading driver %s in memory", File->Name.c_str()); trace("Loading driver %s in memory", File->Name.c_str());
Elf_Ehdr ELFHeader{}; Elf_Ehdr ELFHeader{};
File->Read(&ELFHeader, sizeof(Elf_Ehdr), 0); fs->Read(File, &ELFHeader, sizeof(Elf_Ehdr), 0);
AssertReturnError(ELFHeader.e_ident[EI_CLASS] == ELFCLASS64, -ENOEXEC); AssertReturnError(ELFHeader.e_ident[EI_CLASS] == ELFCLASS64, -ENOEXEC);
AssertReturnError(ELFHeader.e_ident[EI_DATA] == ELFDATA2LSB, -ENOEXEC); AssertReturnError(ELFHeader.e_ident[EI_DATA] == ELFDATA2LSB, -ENOEXEC);
@ -219,7 +296,7 @@ namespace Driver
Elf_Phdr phdr{}; Elf_Phdr phdr{};
for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++) for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++)
{ {
File->Read(&phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); fs->Read(File, &phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
if (phdr.p_type == PT_LOAD || phdr.p_type == PT_DYNAMIC) if (phdr.p_type == PT_LOAD || phdr.p_type == PT_DYNAMIC)
{ {
if (segSize < phdr.p_vaddr + phdr.p_memsz) if (segSize < phdr.p_vaddr + phdr.p_memsz)
@ -230,7 +307,7 @@ namespace Driver
if (phdr.p_type == PT_INTERP) if (phdr.p_type == PT_INTERP)
{ {
char interp[17]; char interp[17];
File->Read(interp, sizeof(interp), phdr.p_offset); fs->Read(File, interp, sizeof(interp), phdr.p_offset);
if (strncmp(interp, "/boot/fennix.elf", sizeof(interp)) != 0) if (strncmp(interp, "/boot/fennix.elf", sizeof(interp)) != 0)
{ {
error("Interpreter is not /boot/fennix.elf"); error("Interpreter is not /boot/fennix.elf");
@ -250,13 +327,13 @@ namespace Driver
Elf_Shdr shstrtab{}; Elf_Shdr shstrtab{};
Elf_Shdr shdr{}; Elf_Shdr shdr{};
__DriverInfo driverInfo{}; __DriverInfo driverInfo{};
File->Read(&shstrtab, sizeof(Elf_Shdr), ELFHeader.e_shoff + (ELFHeader.e_shstrndx * ELFHeader.e_shentsize)); fs->Read(File, &shstrtab, sizeof(Elf_Shdr), ELFHeader.e_shoff + (ELFHeader.e_shstrndx * ELFHeader.e_shentsize));
for (Elf_Half i = 0; i < ELFHeader.e_shnum; i++) for (Elf_Half i = 0; i < ELFHeader.e_shnum; i++)
{ {
if (i == ELFHeader.e_shstrndx) if (i == ELFHeader.e_shstrndx)
continue; continue;
File->Read(&shdr, ELFHeader.e_shentsize, ELFHeader.e_shoff + (i * ELFHeader.e_shentsize)); fs->Read(File, &shdr, ELFHeader.e_shentsize, ELFHeader.e_shoff + (i * ELFHeader.e_shentsize));
switch (shdr.sh_type) switch (shdr.sh_type)
{ {
@ -274,11 +351,11 @@ namespace Driver
} }
char symName[16]; char symName[16];
File->Read(symName, sizeof(symName), shstrtab.sh_offset + shdr.sh_name); fs->Read(File, symName, sizeof(symName), shstrtab.sh_offset + shdr.sh_name);
if (strcmp(symName, ".driver.info") != 0) if (strcmp(symName, ".driver.info") != 0)
continue; continue;
File->Read(&driverInfo, sizeof(__DriverInfo), shdr.sh_offset); fs->Read(File, &driverInfo, sizeof(__DriverInfo), shdr.sh_offset);
/* Perform relocations */ /* Perform relocations */
driverInfo.Name = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.Name); driverInfo.Name = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.Name);
@ -287,17 +364,17 @@ namespace Driver
driverInfo.License = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.License); driverInfo.License = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.License);
} }
for (size_t h = 0; h < (sht_symtab.sh_size / sizeof(Elf64_Sym)); h++) for (size_t h = 0; h < (sht_symtab.sh_size / sizeof(Elf_Sym)); h++)
{ {
Elf64_Sym symEntry{}; Elf_Sym symEntry{};
uintptr_t symOffset = sht_symtab.sh_offset + (h * sizeof(Elf64_Sym)); uintptr_t symOffset = sht_symtab.sh_offset + (h * sizeof(Elf_Sym));
File->Read(&symEntry, sizeof(Elf64_Sym), symOffset); fs->Read(File, &symEntry, sizeof(Elf_Sym), symOffset);
if (symEntry.st_name == 0) if (symEntry.st_name == 0)
continue; continue;
char symName[16]; char symName[16];
File->Read(symName, sizeof(symName), sht_strtab.sh_offset + symEntry.st_name); fs->Read(File, symName, sizeof(symName), sht_strtab.sh_offset + symEntry.st_name);
switch (symEntry.st_shndx) switch (symEntry.st_shndx)
{ {
@ -329,7 +406,7 @@ namespace Driver
for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++) for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++)
{ {
File->Read(&phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr))); fs->Read(File, &phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
switch (phdr.p_type) switch (phdr.p_type)
{ {
@ -345,7 +422,7 @@ namespace Driver
phdr.p_filesz, phdr.p_memsz); phdr.p_filesz, phdr.p_memsz);
if (phdr.p_filesz > 0) if (phdr.p_filesz > 0)
File->Read(dest, phdr.p_filesz, phdr.p_offset); fs->Read(File, (void *)dest, phdr.p_filesz, phdr.p_offset);
if (phdr.p_memsz - phdr.p_filesz > 0) if (phdr.p_memsz - phdr.p_filesz > 0)
{ {
@ -401,10 +478,10 @@ namespace Driver
{ {
AssertReturnError(relaSize != nullptr, -ENOEXEC); AssertReturnError(relaSize != nullptr, -ENOEXEC);
Elf64_Rela *rela = (Elf64_Rela *)(Drv.BaseAddress + dyn->d_un.d_ptr); Elf_Rela *rela = (Elf_Rela *)(Drv.BaseAddress + dyn->d_un.d_ptr);
for (size_t i = 0; i < (relaSize->d_un.d_val / sizeof(Elf64_Rela)); i++) for (size_t i = 0; i < (relaSize->d_un.d_val / sizeof(Elf_Rela)); i++)
{ {
Elf64_Rela *r = &rela[i]; Elf_Rela *r = &rela[i];
uintptr_t *reloc = (uintptr_t *)(Drv.BaseAddress + r->r_offset); uintptr_t *reloc = (uintptr_t *)(Drv.BaseAddress + r->r_offset);
uintptr_t relocTarget = 0; uintptr_t relocTarget = 0;
@ -424,8 +501,7 @@ namespace Driver
} }
default: default:
{ {
fixme("Unhandled relocation type: %#lx", fixme("Unhandled relocation type: %#lx", ELF_R_TYPE(r->r_info));
ELF64_R_TYPE(r->r_info));
break; break;
} }
} }
@ -441,26 +517,26 @@ namespace Driver
{ {
AssertReturnError(pltrelSize != nullptr, -ENOEXEC); AssertReturnError(pltrelSize != nullptr, -ENOEXEC);
std::vector<Elf64_Dyn> symtab = Execute::ELFGetDynamicTag_x86_64(File, DT_SYMTAB); std::vector<Elf_Dyn> symtab = Execute::ELFGetDynamicTag(File, DT_SYMTAB);
Elf64_Sym *symbols = (Elf64_Sym *)((uintptr_t)Drv.BaseAddress + symtab[0].d_un.d_ptr); Elf_Sym *symbols = (Elf_Sym *)((uintptr_t)Drv.BaseAddress + symtab[0].d_un.d_ptr);
std::vector<Elf64_Dyn> StrTab = Execute::ELFGetDynamicTag_x86_64(File, DT_STRTAB); std::vector<Elf_Dyn> StrTab = Execute::ELFGetDynamicTag(File, DT_STRTAB);
char *DynStr = (char *)((uintptr_t)Drv.BaseAddress + StrTab[0].d_un.d_ptr); char *dynStr = (char *)((uintptr_t)Drv.BaseAddress + StrTab[0].d_un.d_ptr);
Elf64_Rela *rela = (Elf64_Rela *)(Drv.BaseAddress + dyn->d_un.d_ptr); Elf_Rela *rela = (Elf_Rela *)(Drv.BaseAddress + dyn->d_un.d_ptr);
for (size_t i = 0; i < (pltrelSize->d_un.d_val / sizeof(Elf64_Rela)); i++) for (size_t i = 0; i < (pltrelSize->d_un.d_val / sizeof(Elf_Rela)); i++)
{ {
Elf64_Rela *r = &rela[i]; Elf_Rela *r = &rela[i];
uintptr_t *reloc = (uintptr_t *)(Drv.BaseAddress + r->r_offset); uintptr_t *reloc = (uintptr_t *)(Drv.BaseAddress + r->r_offset);
switch (ELF64_R_TYPE(r->r_info)) switch (ELF_R_TYPE(r->r_info))
{ {
case R_X86_64_JUMP_SLOT: case R_X86_64_JUMP_SLOT:
{ {
Elf64_Xword symIndex = ELF64_R_SYM(r->r_info); Elf_Xword symIndex = ELF_R_SYM(r->r_info);
Elf64_Sym *sym = symbols + symIndex; Elf_Sym *sym = symbols + symIndex;
const char *symName = DynStr + sym->st_name; const char *symName = dynStr + sym->st_name;
debug("Resolving symbol %s", symName); debug("Resolving symbol %s", symName);
*reloc = (uintptr_t)GetSymbolByName(symName, driverInfo.Version.APIVersion); *reloc = (uintptr_t)GetSymbolByName(symName, driverInfo.Version.APIVersion);
@ -468,8 +544,7 @@ namespace Driver
} }
default: default:
{ {
fixme("Unhandled relocation type: %#lx", fixme("Unhandled relocation type: %#lx", ELF_R_TYPE(r->r_info));
ELF64_R_TYPE(r->r_info));
break; break;
} }
} }
@ -514,7 +589,104 @@ namespace Driver
return 0; return 0;
} }
Manager::Manager() { this->InitializeDaemonFS(); } void Manager::ReloadDriver(dev_t driverID)
{
auto it = Drivers.find(driverID);
if (it == Drivers.end())
{
error("Driver with ID %d not found", driverID);
return;
}
DriverObject &Drv = it->second;
if (!Drv.Initialized)
{
error("Driver %s is not initialized", Drv.Name);
return;
}
debug("Reloading driver %s", Drv.Name);
/* Unload the driver */
int err = Drv.Final();
if (err < 0)
{
warn("Failed to unload driver %s: %s", Drv.Name, strerror(err));
}
/* Free resources */
Drv.vma->FreeAllPages();
delete Drv.vma;
delete Drv.InterruptHandlers;
delete Drv.DeviceOperations;
/* Reload the driver */
Node root = fs->GetRoot(0);
Node drvNode = fs->Lookup(root, Drv.Path);
if (!drvNode)
{
error("Failed to open driver file %s", Drv.Path.c_str());
return;
}
DriverObject newDrvObj = {};
newDrvObj.IsBuiltIn = false;
newDrvObj.BaseAddress = 0;
newDrvObj.EntryPoint = 0;
newDrvObj.vma = new Memory::VirtualMemoryArea(thisProcess->PageTable);
newDrvObj.Path = drvNode->Path;
newDrvObj.InterruptHandlers = new std::unordered_map<uint8_t, void *>();
newDrvObj.DeviceOperations = new std::unordered_map<dev_t, DriverHandlers>();
newDrvObj.ID = driverID;
err = this->LoadDriverFile(newDrvObj, drvNode);
if (err != 0)
{
error("Failed to load driver %s: %s", drvNode->Path.c_str(), strerror(err));
delete newDrvObj.vma;
delete newDrvObj.InterruptHandlers;
delete newDrvObj.DeviceOperations;
return;
}
Drivers[driverID] = newDrvObj;
/* Initialize the driver */
int (*DrvInit)(dev_t) = (int (*)(dev_t))newDrvObj.EntryPoint;
newDrvObj.ErrorCode = DrvInit(newDrvObj.ID);
if (newDrvObj.ErrorCode < 0)
{
KPrint("FATAL: _start() failed for %s: %s", newDrvObj.Name, strerror(newDrvObj.ErrorCode));
error("Failed to load driver %s: %s", newDrvObj.Path.c_str(), strerror(newDrvObj.ErrorCode));
newDrvObj.vma->FreeAllPages();
return;
}
KPrint("Loading driver %s", newDrvObj.Name);
newDrvObj.ErrorCode = newDrvObj.Probe();
if (newDrvObj.ErrorCode < 0)
{
KPrint("Probe() failed for %s: %s", newDrvObj.Name, strerror(newDrvObj.ErrorCode));
error("Failed to probe driver %s: %s", newDrvObj.Path.c_str(), strerror(newDrvObj.ErrorCode));
newDrvObj.vma->FreeAllPages();
return;
}
newDrvObj.ErrorCode = newDrvObj.Entry();
if (newDrvObj.ErrorCode < 0)
{
KPrint("Entry() failed for %s: %s", newDrvObj.Name, strerror(newDrvObj.ErrorCode));
error("Failed to initialize driver %s: %s", newDrvObj.Path.c_str(), strerror(newDrvObj.ErrorCode));
newDrvObj.vma->FreeAllPages();
return;
}
debug("Reloaded driver %s", newDrvObj.Path.c_str());
newDrvObj.Initialized = true;
}
Manager::Manager() { this->InitializeDeviceDirectory(); }
Manager::~Manager() Manager::~Manager()
{ {

View File

@ -0,0 +1,256 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <driver.hpp>
#include <interface/driver.h>
#include <interface/input.h>
#include <memory.hpp>
#include <stropts.h>
#include <ints.hpp>
#include <task.hpp>
#include <printf.h>
#include <exec.hpp>
#include <rand.hpp>
#include <cwalk.h>
#include <md5.h>
#include "../../kernel.h"
using namespace vfs;
namespace Driver
{
dev_t Manager::RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
for (size_t i = 0; i < 128; i++)
{
const auto dOps = dop->find(i);
const auto dOpsEnd = dop->end();
if (dOps != dOpsEnd)
continue;
DeviceType devType = (DeviceType)(Type & DEVICE_TYPE_MASK);
switch (devType)
{
case DEVICE_TYPE_INPUT:
{
std::string prefix = "event";
for (size_t j = 0; j < 128; j++)
{
std::string deviceName = prefix + std::to_string(j);
Node node = fs->Lookup(devInputNode, deviceName);
if (node)
continue;
/* c rwx r-- r-- */
mode_t mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFCHR;
node = fs->Create(devInputNode, deviceName, mode);
node->inode->SetDevice(DriverID, i);
DriverHandlers dh{};
dh.Ops = Operations;
dh.Node = node->inode;
dh.InputReports = new RingBuffer<InputReport>(16);
dop->insert({i, std::move(dh)});
return i;
}
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
}
default:
ReturnLogError(-EINVAL, "Invalid device type %d", Type);
}
}
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
}
dev_t Manager::CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, const InodeOperations *Operations)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
for (size_t i = 0; i < 128; i++)
{
const auto dOps = dop->find(i);
if (dOps != dop->end())
continue;
eNode node = fs->Lookup(devNode, name);
if (node == true)
ReturnLogError(-EEXIST, "Device file %s already exists", name);
node = fs->Create(devNode, name, mode);
if (node == false)
ReturnLogError(-node.Error, "Failed to create device file %s; %s", name, node.what());
node.Value->inode->SetDevice(DriverID, i);
DriverHandlers dh{};
dh.Ops = Operations;
dh.Node = node.Value->inode;
dh.InputReports = new RingBuffer<InputReport>(16);
dop->insert({i, std::move(dh)});
return i;
}
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
}
int Manager::UnregisterDevice(dev_t DriverID, dev_t Device)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
const auto dOps = dop->find(Device);
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Device);
dop->erase(dOps);
fixme("remove eventX from /dev/input");
fixme("delete InputReports");
return 0;
}
dev_t Manager::RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
std::string prefix = Device->Name;
for (size_t j = 0; j < 128; j++)
{
std::string deviceName = prefix + std::to_string(j);
Node node = fs->Lookup(devBlockNode, deviceName);
if (node)
continue;
debug("Creating \"%s\"", deviceName.c_str());
/* b rwx --- --- */
mode_t mode = S_IRWXU |
S_IFBLK;
node = fs->Create(devBlockNode, deviceName, mode);
node->inode->SetDevice(DriverID, j);
auto devNode = (Manager::DeviceInode *)node->inode;
devNode->Size = Device->Size;
devNode->BlockSize = Device->BlockSize;
devNode->Blocks = Device->BlockCount;
devNode->inode.PrivateData = Device->PrivateData;
DriverHandlers dh{};
dh.Ops = Device->Ops;
dh.Node = node->inode;
dop->insert({j, std::move(dh)});
debug("dh ops:%#lx node:%#lx %d", dh.Ops, dh.Node, j);
return j;
}
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
}
int Manager::UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
const auto dOps = dop->find(DeviceID);
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", DeviceID);
dop->erase(dOps);
return 0;
}
void *Manager::AllocateMemory(dev_t DriverID, size_t Pages)
{
auto itr = Drivers.find(DriverID);
assert(itr != Drivers.end());
void *ptr = itr->second.vma->RequestPages(Pages);
memset(ptr, 0, FROM_PAGES(Pages));
return ptr;
}
void Manager::FreeMemory(dev_t DriverID, void *Pointer, size_t Pages)
{
auto itr = Drivers.find(DriverID);
assert(itr != Drivers.end());
itr->second.vma->FreePages(Pointer, Pages);
}
int Manager::ReportInputEvent(dev_t DriverID, InputReport *Report)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Report->Device);
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Report->Device);
dOps->second.InputReports->Write(Report, 1);
switch (Report->Type)
{
case INPUT_TYPE_KEYBOARD:
{
KeyboardReport *kReport = &Report->Keyboard;
GlobalKeyboardInputReports.Write(kReport, 1);
break;
}
case INPUT_TYPE_MOUSE:
{
MouseReport *mReport = &Report->Mouse;
GlobalMouseInputReports.Write(mReport, 1);
break;
}
default:
assert(!"Invalid input type");
}
return 0;
}
}

View File

@ -331,6 +331,80 @@ namespace Driver
: ScanCodeConversionTableLower[ScanCode]; : ScanCodeConversionTableLower[ScanCode];
} }
char GetControlCharacter(KeyScanCodes ScanCode)
{
ScanCode = static_cast<KeyScanCodes>(static_cast<int>(ScanCode) & 0x7F); /* Remove KEY_PRESSED bit */
switch (ScanCode)
{
case KEY_2:
return 0x00; /* Ctrl-@ (NUL) */
case KEY_A:
return 0x01; /* Ctrl-A (SOH) */
case KEY_B:
return 0x02; /* Ctrl-B (STX) */
case KEY_C:
return 0x03; /* Ctrl-C (ETX) */
case KEY_D:
return 0x04; /* Ctrl-D (EOT) */
case KEY_E:
return 0x05; /* Ctrl-E (ENQ) */
case KEY_F:
return 0x06; /* Ctrl-F (ACK) */
case KEY_G:
return 0x07; /* Ctrl-G (BEL) */
case KEY_H:
return 0x08; /* Ctrl-H (BS) */
case KEY_I:
return 0x09; /* Ctrl-I (HT) */
case KEY_J:
return 0x0A; /* Ctrl-J (LF) */
case KEY_K:
return 0x0B; /* Ctrl-K (VT) */
case KEY_L:
return 0x0C; /* Ctrl-L (FF) */
case KEY_M:
return 0x0D; /* Ctrl-M (CR) */
case KEY_N:
return 0x0E; /* Ctrl-N (SO) */
case KEY_O:
return 0x0F; /* Ctrl-O (SI) */
case KEY_P:
return 0x10; /* Ctrl-P (DLE) */
case KEY_Q:
return 0x11; /* Ctrl-Q (DC1) */
case KEY_R:
return 0x12; /* Ctrl-R (DC2) */
case KEY_S:
return 0x13; /* Ctrl-S (DC3) */
case KEY_T:
return 0x14; /* Ctrl-T (DC4) */
case KEY_U:
return 0x15; /* Ctrl-U (NAK) */
case KEY_V:
return 0x16; /* Ctrl-V (SYN) */
case KEY_W:
return 0x17; /* Ctrl-W (ETB) */
case KEY_X:
return 0x18; /* Ctrl-X (CAN) */
case KEY_Y:
return 0x19; /* Ctrl-Y (EM) */
case KEY_Z:
return 0x1A; /* Ctrl-Z (SUB) */
case KEY_LEFT_BRACKET:
return 0x1B; /* Ctrl-[ (ESC) */
case KEY_BACKSLASH:
return 0x1C; /* Ctrl-\ (FS) */
case KEY_RIGHT_BRACKET:
return 0x1D; /* Ctrl-] (GS) */
case KEY_6:
return 0x1E; /* Ctrl-^ (RS) */
case KEY_MINUS:
return 0x1F; /* Ctrl-_ (US) */
default:
return 0x00; /* Not a control character */
}
}
bool IsValidChar(uint8_t ScanCode) bool IsValidChar(uint8_t ScanCode)
{ {
ScanCode &= 0x7F; /* Remove KEY_PRESSED bit */ ScanCode &= 0x7F; /* Remove KEY_PRESSED bit */

View File

@ -191,7 +191,7 @@ namespace Interrupts
void *ctx, bool Critical) void *ctx, bool Critical)
{ {
/* Just log a warning if the interrupt is already registered. */ /* Just log a warning if the interrupt is already registered. */
foreach (auto ev in RegisteredEvents) for (auto ev : RegisteredEvents)
{ {
if (ev.IRQ == InterruptNumber && if (ev.IRQ == InterruptNumber &&
ev.Callback == Callback) ev.Callback == Callback)
@ -264,7 +264,7 @@ namespace Interrupts
warn("IRQ%d not found.", InterruptNumber); warn("IRQ%d not found.", InterruptNumber);
} }
nsa inline void ReturnFromInterrupt() nsa hot inline void ReturnFromInterrupt()
{ {
#if defined(__amd64__) || defined(__i386__) #if defined(__amd64__) || defined(__i386__)
CPUData *CoreData = GetCurrentCPU(); CPUData *CoreData = GetCurrentCPU();
@ -279,7 +279,7 @@ namespace Interrupts
{ return a.Priority < b.Priority; }); { return a.Priority < b.Priority; });
#ifdef DEBUG #ifdef DEBUG
foreach (auto ev in RegisteredEvents) for (auto ev : RegisteredEvents)
{ {
void *fct = ev.IsHandler void *fct = ev.IsHandler
? ev.Data ? ev.Data
@ -302,14 +302,14 @@ namespace Interrupts
} }
else else
fixme("APIC not found for core %d", Core); fixme("APIC not found for core %d", Core);
// TODO: Handle PIC too // TODO: Handle PIC too
#endif #endif
assert(!"EOI not handled."); assert(!"EOI not handled.");
CPU::Stop(); CPU::Stop();
} }
extern "C" nsa void MainInterruptHandler(void *Data) extern "C" nsa hot void MainInterruptHandler(void *Data)
{ {
class AutoSwitchPageTable class AutoSwitchPageTable
{ {
@ -384,7 +384,7 @@ namespace Interrupts
#endif #endif
} }
extern "C" nsa void SchedulerInterruptHandler(void *Data) extern "C" nsa hot void SchedulerInterruptHandler(void *Data)
{ {
#if defined(__amd64__) || defined(__i386__) #if defined(__amd64__) || defined(__i386__)
KernelPageTable->Update(); KernelPageTable->Update();
@ -421,13 +421,12 @@ namespace Interrupts
Handler::Handler(int InterruptNumber, bool Critical) Handler::Handler(int InterruptNumber, bool Critical)
{ {
foreach (auto ev in RegisteredEvents) for (auto ev : RegisteredEvents)
{ {
if (ev.IRQ == InterruptNumber) if (ev.IRQ != InterruptNumber)
{ continue;
warn("IRQ%d is already registered.",
InterruptNumber); warn("IRQ%d is already registered.", InterruptNumber);
}
} }
this->InterruptNumber = InterruptNumber; this->InterruptNumber = InterruptNumber;
@ -441,15 +440,12 @@ namespace Interrupts
0, /* Priority */ 0, /* Priority */
Critical}; /* Critical */ Critical}; /* Critical */
RegisteredEvents.push_back(newEvent); RegisteredEvents.push_back(newEvent);
debug("Registered interrupt handler for IRQ%d.", debug("Registered interrupt handler for IRQ%d.", InterruptNumber);
InterruptNumber);
} }
Handler::Handler(PCI::PCIDevice Device, bool Critical) Handler::Handler(PCI::PCIDevice Device, bool Critical)
: Handler(((PCI::PCIHeader0 *)Device.Header)->InterruptLine, Critical)
{ {
PCI::PCIHeader0 *hdr0 =
(PCI::PCIHeader0 *)Device.Header;
Handler(hdr0->InterruptLine, Critical);
} }
Handler::Handler() Handler::Handler()
@ -459,16 +455,14 @@ namespace Interrupts
Handler::~Handler() Handler::~Handler()
{ {
debug("Unregistering interrupt handler for IRQ%d.", debug("Unregistering interrupt handler for IRQ%d.", this->InterruptNumber);
this->InterruptNumber);
forItr(itr, RegisteredEvents) forItr(itr, RegisteredEvents)
{ {
if (itr->IRQ == this->InterruptNumber) if (itr->IRQ != this->InterruptNumber)
{ continue;
RegisteredEvents.erase(itr);
return; RegisteredEvents.erase(itr);
} return;
} }
warn("Event %d not found.", this->InterruptNumber); warn("Event %d not found.", this->InterruptNumber);
} }

View File

@ -195,7 +195,7 @@ void LockClass::TimeoutDeadLock(SpinLockData &Lock, uint64_t Timeout)
if (CoreData != nullptr) if (CoreData != nullptr)
CCore = CoreData->ID; CCore = CoreData->ID;
uint64_t Counter = TimeManager->GetCounter(); uint64_t Counter = TimeManager->GetTimeNs();
warn("Potential deadlock in lock '%s' held by '%s'! %ld %s in queue. Interrupts are %s. Core %ld held by %ld. Timeout in %ld (%ld ticks remaining).", warn("Potential deadlock in lock '%s' held by '%s'! %ld %s in queue. Interrupts are %s. Core %ld held by %ld. Timeout in %ld (%ld ticks remaining).",
Lock.AttemptingToGet, Lock.CurrentHolder, Lock.Count, Lock.Count > 1 ? "locks" : "lock", Lock.AttemptingToGet, Lock.CurrentHolder, Lock.Count, Lock.Count > 1 ? "locks" : "lock",
@ -235,8 +235,7 @@ Retry:
if (i >= DEADLOCK_TIMEOUT) if (i >= DEADLOCK_TIMEOUT)
{ {
if (Target.load() == 0) if (Target.load() == 0)
Target.store(TimeManager->CalculateTarget(Timeout, Target.store(TimeManager->GetTimeNs() + Timeout);
Time::Units::Milliseconds));
TimeoutDeadLock(LockData, Target.load()); TimeoutDeadLock(LockData, Target.load());
goto Retry; goto Retry;
} }

View File

@ -28,8 +28,7 @@
namespace Memory namespace Memory
{ {
__no_sanitize("alignment") void Physical::FindBitmapRegion(uintptr_t &BitmapAddress, __no_sanitize("alignment") void Physical::FindBitmapRegion(uintptr_t &BitmapAddress, size_t &BitmapAddressSize)
size_t &BitmapAddressSize)
{ {
size_t BitmapSize = (size_t)(bInfo.Memory.Size / PAGE_SIZE) / 8 + 1; size_t BitmapSize = (size_t)(bInfo.Memory.Size / PAGE_SIZE) / 8 + 1;
@ -47,24 +46,19 @@ namespace Memory
uintptr_t RSDPStart = 0x0; uintptr_t RSDPStart = 0x0;
uintptr_t RSDPEnd = 0x0; uintptr_t RSDPEnd = 0x0;
if (bInfo.Kernel.Symbols.Num && if (bInfo.Kernel.Symbols.Num && bInfo.Kernel.Symbols.EntSize && bInfo.Kernel.Symbols.Shndx)
bInfo.Kernel.Symbols.EntSize &&
bInfo.Kernel.Symbols.Shndx)
{ {
char *sections = r_cst(char *, bInfo.Kernel.Symbols.Sections); char *sections = r_cst(char *, bInfo.Kernel.Symbols.Sections);
SectionsStart = (uintptr_t)sections; SectionsStart = (uintptr_t)sections;
SectionsEnd = (uintptr_t)sections + bInfo.Kernel.Symbols.EntSize * SectionsEnd = (uintptr_t)sections + bInfo.Kernel.Symbols.EntSize * bInfo.Kernel.Symbols.Num;
bInfo.Kernel.Symbols.Num;
for (size_t i = 0; i < bInfo.Kernel.Symbols.Num; ++i) for (size_t i = 0; i < bInfo.Kernel.Symbols.Num; ++i)
{ {
Elf_Shdr *sym = (Elf_Shdr *)&sections[bInfo.Kernel.Symbols.EntSize * i]; Elf_Shdr *sym = (Elf_Shdr *)&sections[bInfo.Kernel.Symbols.EntSize * i];
Elf_Shdr *str = (Elf_Shdr *)&sections[bInfo.Kernel.Symbols.EntSize * Elf_Shdr *str = (Elf_Shdr *)&sections[bInfo.Kernel.Symbols.EntSize * sym->sh_link];
sym->sh_link];
if (sym->sh_type == SHT_SYMTAB && if (sym->sh_type == SHT_SYMTAB && str->sh_type == SHT_STRTAB)
str->sh_type == SHT_STRTAB)
{ {
Symbols = (uintptr_t)sym->sh_addr; Symbols = (uintptr_t)sym->sh_addr;
StringAddress = (uintptr_t)str->sh_addr; StringAddress = (uintptr_t)str->sh_addr;
@ -95,8 +89,7 @@ namespace Memory
if (Memory::Virtual().Check(ACPIPtr)) if (Memory::Virtual().Check(ACPIPtr))
{ {
size_t TableSize = ((ACPIPtr->Length - sizeof(ACPI::ACPI::ACPIHeader)) / size_t TableSize = ((ACPIPtr->Length - sizeof(ACPI::ACPI::ACPIHeader)) / (XSDT ? 8 : 4));
(XSDT ? 8 : 4));
debug("There are %d ACPI tables", TableSize); debug("There are %d ACPI tables", TableSize);
} }
#endif #endif
@ -131,6 +124,7 @@ namespace Memory
{ {
uintptr_t Start; uintptr_t Start;
uintptr_t End; uintptr_t End;
char Description[16];
}; };
auto SortAddresses = [](AddrRange *Array, size_t n) auto SortAddresses = [](AddrRange *Array, size_t n)
@ -151,61 +145,57 @@ namespace Memory
AddrRange PtrArray[] = AddrRange PtrArray[] =
{ {
{KernelStart, {KernelStart, KernelEnd, "kernel"},
KernelEnd}, {SectionsStart, SectionsEnd, "sections"},
{SectionsStart, {Symbols, Symbols + SymbolSize, "symbols"},
SectionsEnd}, {StringAddress, StringAddress + StringSize, "string"},
{Symbols, {RSDPStart, RSDPEnd, "rsdp"},
Symbols + SymbolSize}, {(uintptr_t)bInfo.Kernel.FileBase, (uintptr_t)bInfo.Kernel.FileBase + bInfo.Kernel.Size, "file"},
{StringAddress, {(uintptr_t)bInfo.Modules[0].Address, (uintptr_t)bInfo.Modules[0].Address + bInfo.Modules[0].Size, "module 0"},
StringAddress + StringSize}, {(uintptr_t)bInfo.Modules[1].Address, (uintptr_t)bInfo.Modules[1].Address + bInfo.Modules[1].Size, "module 1"},
{RSDPStart, {(uintptr_t)bInfo.Modules[2].Address, (uintptr_t)bInfo.Modules[2].Address + bInfo.Modules[2].Size, "module 2"},
RSDPEnd}, {(uintptr_t)bInfo.Modules[3].Address, (uintptr_t)bInfo.Modules[3].Address + bInfo.Modules[3].Size, "module 3"},
{(uintptr_t)bInfo.Kernel.FileBase,
(uintptr_t)bInfo.Kernel.FileBase + bInfo.Kernel.Size},
{(uintptr_t)bInfo.Modules[0].Address,
(uintptr_t)bInfo.Modules[0].Address + bInfo.Modules[0].Size},
{(uintptr_t)bInfo.Modules[1].Address,
(uintptr_t)bInfo.Modules[1].Address + bInfo.Modules[1].Size},
{(uintptr_t)bInfo.Modules[2].Address,
(uintptr_t)bInfo.Modules[2].Address + bInfo.Modules[2].Size},
{(uintptr_t)bInfo.Modules[3].Address,
(uintptr_t)bInfo.Modules[3].Address + bInfo.Modules[3].Size},
/* MAX_MODULES == 4 */ /* MAX_MODULES == 4 */
}; };
SortAddresses(PtrArray, sizeof(PtrArray) / sizeof(PtrArray[0])); SortAddresses(PtrArray, sizeof(PtrArray) / sizeof(PtrArray[0]));
uintptr_t MaxEnd = RegionAddress;
for (size_t i = 0; i < sizeof(PtrArray) / sizeof(PtrArray[0]); i++) for (size_t i = 0; i < sizeof(PtrArray) / sizeof(PtrArray[0]); i++)
{ {
if (PtrArray[i].Start == 0x0) if (PtrArray[i].Start == 0x0)
{
debug("skipping %#lx %zu %s", PtrArray[i].Start, i, PtrArray[i].Description);
continue; continue;
}
uintptr_t Start = PtrArray[i].Start; uintptr_t Start = PtrArray[i].Start;
uintptr_t End = PtrArray[i].End; uintptr_t End = PtrArray[i].End;
debug("%#lx - %#lx", Start, End); debug("[%s] %#lx - %#lx", PtrArray[i].Description, Start, End);
if (RegionAddress >= Start && if ((Start < (RegionAddress + RegionSize)) && (End > RegionAddress))
End <= (RegionAddress + RegionSize))
{ {
BitmapAddress = End; if (End > MaxEnd)
BitmapAddressSize = RegionSize - (End - RegionAddress); MaxEnd = End;
} }
} }
if ((BitmapSize + 0x100) > BitmapAddressSize) if (MaxEnd >= RegionAddress && MaxEnd < (RegionAddress + RegionSize))
{ {
debug("Region %p-%p (%d MiB) is too small for bitmap.", BitmapAddress = MaxEnd;
(void *)BitmapAddress, BitmapAddressSize = RegionAddress + RegionSize - MaxEnd;
(void *)(BitmapAddress + BitmapAddressSize),
TO_MiB(BitmapAddressSize));
continue;
}
debug("Found free memory for bitmap: %p (%d MiB)", debug("BitmapAddress = %#lx; Size = %zu", BitmapAddress, BitmapAddressSize);
(void *)BitmapAddress,
TO_MiB(BitmapAddressSize)); if ((BitmapSize + 0x100) > BitmapAddressSize)
break; {
debug("Region %#lx-%#lx (%d MiB) is too small for bitmap.", BitmapAddress, BitmapAddress + BitmapAddressSize, TO_MiB(BitmapAddressSize));
continue;
}
debug("Found free memory for bitmap: %#lx (%d MiB)", BitmapAddress, TO_MiB(BitmapAddressSize));
break;
}
} }
} }
} }

View File

@ -52,7 +52,7 @@ Xalloc::V1 *XallocV1Allocator = nullptr;
Xalloc::V2 *XallocV2Allocator = nullptr; Xalloc::V2 *XallocV2Allocator = nullptr;
#ifdef DEBUG #ifdef DEBUG
NIF void tracepagetable(PageTable *pt) nif void tracepagetable(PageTable *pt)
{ {
for (int i = 0; i < 512; i++) for (int i = 0; i < 512; i++)
{ {
@ -71,7 +71,7 @@ NIF void tracepagetable(PageTable *pt)
} }
#endif #endif
NIF void MapEntries(PageTable *PT) nif void MapEntries(PageTable *PT)
{ {
debug("mapping %d memory entries", bInfo.Memory.Entries); debug("mapping %d memory entries", bInfo.Memory.Entries);
Virtual vmm = Virtual(PT); Virtual vmm = Virtual(PT);
@ -89,7 +89,7 @@ NIF void MapEntries(PageTable *PT)
vmm.Unmap((void *)0); vmm.Unmap((void *)0);
} }
NIF void MapFramebuffer(PageTable *PT) nif void MapFramebuffer(PageTable *PT)
{ {
debug("Mapping Framebuffer"); debug("Mapping Framebuffer");
Virtual vmm = Virtual(PT); Virtual vmm = Virtual(PT);
@ -123,7 +123,7 @@ NIF void MapFramebuffer(PageTable *PT)
} }
} }
NIF void MapKernel(PageTable *PT) nif void MapKernel(PageTable *PT)
{ {
debug("Mapping Kernel"); debug("Mapping Kernel");
@ -237,7 +237,7 @@ NIF void MapKernel(PageTable *PT)
info("Cannot determine kernel file address. Ignoring."); info("Cannot determine kernel file address. Ignoring.");
} }
NIF void CreatePageTable(PageTable *pt) nif void CreatePageTable(PageTable *pt)
{ {
static int check_cpuid = 0; static int check_cpuid = 0;
@ -286,7 +286,7 @@ NIF void CreatePageTable(PageTable *pt)
#endif #endif
} }
NIF void InitializeMemoryManagement() nif void InitializeMemoryManagement()
{ {
#ifdef DEBUG #ifdef DEBUG
#ifndef __i386__ #ifndef __i386__
@ -340,7 +340,7 @@ NIF void InitializeMemoryManagement()
KernelAllocator.Init(); KernelAllocator.Init();
debug("Memory Info:\n\n%lld MiB / %lld MiB (%lld MiB reserved)\n", debug("Memory Info:\n\n%lld MiB / %lld MiB (%lld MiB reserved)\n",
TO_MiB(KernelAllocator.GetUsedMemory()), TO_MiB(KernelAllocator.GetUsedMemory()),
TO_MiB(KernelAllocator.GetTotalMemory()), TO_MiB(KernelAllocator.GetTotalMemory() - KernelAllocator.GetReservedMemory()),
TO_MiB(KernelAllocator.GetReservedMemory())); TO_MiB(KernelAllocator.GetReservedMemory()));
/* -- Debugging -- /* -- Debugging --
@ -361,8 +361,7 @@ NIF void InitializeMemoryManagement()
CreatePageTable(KernelPageTable); CreatePageTable(KernelPageTable);
trace("Applying new page table from address %#lx", trace("Applying new page table from address %#lx", KernelPageTable);
KernelPageTable);
CPU::PageTable(KernelPageTable); CPU::PageTable(KernelPageTable);
debug("Page table updated."); debug("Page table updated.");

View File

@ -1,6 +1,6 @@
#include <memory.hpp> #include <memory.hpp>
#include <filesystem.hpp> #include <fs/vfs.hpp>
#include <signal.hpp> #include <signal.hpp>
#include <utsname.h> #include <utsname.h>
#include <time.h> #include <time.h>

View File

@ -264,7 +264,7 @@ namespace Memory
uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE; uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == true)) if (unlikely(PageBitmap[Index] == true))
return; continue;
if (PageBitmap.Set(Index, true)) if (PageBitmap.Set(Index, true))
{ {
@ -322,8 +322,7 @@ namespace Memory
SmartLock(this->MemoryLock); SmartLock(this->MemoryLock);
uint64_t MemorySize = bInfo.Memory.Size; uint64_t MemorySize = bInfo.Memory.Size;
debug("Memory size: %lld bytes (%ld pages)", debug("Memory size: %lld bytes (%ld pages)", MemorySize, TO_PAGES(MemorySize));
MemorySize, TO_PAGES(MemorySize));
TotalMemory.store(MemorySize); TotalMemory.store(MemorySize);
FreeMemory.store(MemorySize); FreeMemory.store(MemorySize);
@ -338,16 +337,10 @@ namespace Memory
CPU::Stop(); CPU::Stop();
} }
debug("Initializing Bitmap at %p-%p (%d Bytes)", debug("Initializing Bitmap at %#lx-%#lx (%zu Bytes)", BitmapAddress, BitmapAddress + BitmapSize, BitmapSize);
BitmapAddress,
(void *)(BitmapAddress + BitmapSize),
BitmapSize);
PageBitmap.Size = BitmapSize; PageBitmap.Size = BitmapSize;
PageBitmap.Buffer = (uint8_t *)BitmapAddress; PageBitmap.Buffer = (uint8_t *)BitmapAddress;
for (size_t i = 0; i < BitmapSize; i++) memset((void *)BitmapAddress, 0, BitmapSize);
*(uint8_t *)(PageBitmap.Buffer + i) = 0;
ReserveEssentials(); ReserveEssentials();
} }

View File

@ -80,12 +80,9 @@ namespace Memory
{ {
char *sections = r_cst(char *, bInfo.Kernel.Symbols.Sections); char *sections = r_cst(char *, bInfo.Kernel.Symbols.Sections);
debug("Reserving sections region %#lx-%#lx...", debug("Reserving sections region %#lx-%#lx...",
sections, sections, (uintptr_t)sections + bInfo.Kernel.Symbols.EntSize * bInfo.Kernel.Symbols.Num);
(void *)((uintptr_t)sections + bInfo.Kernel.Symbols.EntSize *
bInfo.Kernel.Symbols.Num));
this->ReservePages(sections, TO_PAGES(bInfo.Kernel.Symbols.EntSize * this->ReservePages(sections, TO_PAGES(bInfo.Kernel.Symbols.EntSize * bInfo.Kernel.Symbols.Num));
bInfo.Kernel.Symbols.Num));
Elf_Sym *Symbols = nullptr; Elf_Sym *Symbols = nullptr;
uint8_t *StringAddress = nullptr; uint8_t *StringAddress = nullptr;
@ -101,11 +98,9 @@ namespace Memory
for (size_t i = 0; i < bInfo.Kernel.Symbols.Num; ++i) for (size_t i = 0; i < bInfo.Kernel.Symbols.Num; ++i)
{ {
Elf_Shdr *sym = (Elf_Shdr *)&sections[bInfo.Kernel.Symbols.EntSize * i]; Elf_Shdr *sym = (Elf_Shdr *)&sections[bInfo.Kernel.Symbols.EntSize * i];
Elf_Shdr *str = (Elf_Shdr *)&sections[bInfo.Kernel.Symbols.EntSize * Elf_Shdr *str = (Elf_Shdr *)&sections[bInfo.Kernel.Symbols.EntSize * sym->sh_link];
sym->sh_link];
if (sym->sh_type == SHT_SYMTAB && if (sym->sh_type == SHT_SYMTAB && str->sh_type == SHT_STRTAB)
str->sh_type == SHT_STRTAB)
{ {
Symbols = (Elf_Sym *)sym->sh_addr; Symbols = (Elf_Sym *)sym->sh_addr;
StringAddress = (uint8_t *)str->sh_addr; StringAddress = (uint8_t *)str->sh_addr;
@ -145,8 +140,7 @@ namespace Memory
bInfo.Modules[i].Address, bInfo.Modules[i].Address,
(void *)((uintptr_t)bInfo.Modules[i].Address + bInfo.Modules[i].Size)); (void *)((uintptr_t)bInfo.Modules[i].Address + bInfo.Modules[i].Size));
this->ReservePages((void *)bInfo.Modules[i].Address, this->ReservePages((void *)bInfo.Modules[i].Address, TO_PAGES(bInfo.Modules[i].Size));
TO_PAGES(bInfo.Modules[i].Size));
} }
#if defined(__amd64__) || defined(__i386__) #if defined(__amd64__) || defined(__i386__)
@ -200,6 +194,15 @@ namespace Memory
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
this->ReservePages(SDTHdr, TO_PAGES(SDTHdr->Length)); this->ReservePages(SDTHdr, TO_PAGES(SDTHdr->Length));
} }
if (bInfo.EFI.Info.Enabled)
{
debug("Reserving EFI related...");
if (bInfo.EFI.Info.IH)
this->ReservePage(bInfo.EFI.ImageHandle);
if (bInfo.EFI.Info.ST)
this->ReservePage(bInfo.EFI.SystemTable);
}
} }
#elif defined(__aarch64__) #elif defined(__aarch64__)
#endif #endif

View File

@ -79,7 +79,7 @@ namespace Memory
this->Expanded = Parent->Expanded; this->Expanded = Parent->Expanded;
std::list<AllocatedPages> ParentAllocatedPages = Parent->GetAllocatedPages(); std::list<AllocatedPages> ParentAllocatedPages = Parent->GetAllocatedPages();
foreach (auto Page in ParentAllocatedPages) for (auto Page : ParentAllocatedPages)
{ {
void *NewPhysical = vma->RequestPages(1); void *NewPhysical = vma->RequestPages(1);
debug("Forking address %#lx to %#lx", Page.PhysicalAddress, NewPhysical); debug("Forking address %#lx to %#lx", Page.PhysicalAddress, NewPhysical);

View File

@ -82,7 +82,7 @@ namespace Memory
func("%#lx, %lld", Address, Count); func("%#lx, %lld", Address, Count);
SmartLock(MgrLock); SmartLock(MgrLock);
foreach (auto &apl in AllocatedPagesList) for (auto &apl : AllocatedPagesList)
{ {
if (apl.VirtualAddress != Address) if (apl.VirtualAddress != Address)
continue; continue;
@ -128,7 +128,7 @@ namespace Memory
/* No need to remap pages, the page table will be destroyed */ /* No need to remap pages, the page table will be destroyed */
Virtual vmm(this->Table); Virtual vmm(this->Table);
foreach (auto ap in AllocatedPagesList) for (auto ap : AllocatedPagesList)
{ {
KernelAllocator.FreePages(ap.PhysicalAddress, ap.PageCount); KernelAllocator.FreePages(ap.PhysicalAddress, ap.PageCount);

View File

@ -29,7 +29,7 @@ namespace Memory
{ {
SmartLock(MgrLock); SmartLock(MgrLock);
uint64_t Size = 0; uint64_t Size = 0;
foreach (auto ap in AllocatedPagesList) for (auto ap : AllocatedPagesList)
Size += ap.PageCount; Size += ap.PageCount;
return FROM_PAGES(Size); return FROM_PAGES(Size);
} }
@ -214,7 +214,7 @@ namespace Memory
return false; return false;
} }
foreach (auto sr in SharedRegions) for (auto sr : SharedRegions)
{ {
uintptr_t Start = (uintptr_t)sr.Address; uintptr_t Start = (uintptr_t)sr.Address;
uintptr_t End = (uintptr_t)sr.Address + sr.Length; uintptr_t End = (uintptr_t)sr.Address + sr.Length;
@ -263,7 +263,7 @@ namespace Memory
void VirtualMemoryArea::FreeAllPages() void VirtualMemoryArea::FreeAllPages()
{ {
SmartLock(MgrLock); SmartLock(MgrLock);
foreach (auto ap in AllocatedPagesList) for (auto ap : AllocatedPagesList)
{ {
KernelAllocator.FreePages(ap.Address, ap.PageCount); KernelAllocator.FreePages(ap.Address, ap.PageCount);
Virtual vmm(this->Table); Virtual vmm(this->Table);
@ -287,7 +287,7 @@ namespace Memory
Virtual vmm(this->Table); Virtual vmm(this->Table);
SmartLock(MgrLock); SmartLock(MgrLock);
foreach (auto &ap in Parent->AllocatedPagesList) for (auto &ap : Parent->AllocatedPagesList)
{ {
if (ap.Protected) if (ap.Protected)
{ {
@ -339,7 +339,7 @@ namespace Memory
(uintptr_t)ap.Address + (ap.PageCount * PAGE_SIZE)); (uintptr_t)ap.Address + (ap.PageCount * PAGE_SIZE));
} }
foreach (auto &sr in Parent->SharedRegions) for (auto &sr : Parent->SharedRegions)
{ {
MgrLock.Unlock(); MgrLock.Unlock();
void *Address = this->CreateCoWRegion(sr.Address, sr.Length, void *Address = this->CreateCoWRegion(sr.Address, sr.Length,
@ -496,7 +496,7 @@ namespace Memory
/* No need to remap pages, the page table will be destroyed */ /* No need to remap pages, the page table will be destroyed */
SmartLock(MgrLock); SmartLock(MgrLock);
foreach (auto ap in AllocatedPagesList) for (auto ap : AllocatedPagesList)
KernelAllocator.FreePages(ap.Address, ap.PageCount); KernelAllocator.FreePages(ap.Address, ap.PageCount);
} }
} }

View File

@ -64,7 +64,7 @@ struct DiagnosticFile
} Data; } Data;
}; };
nsa bool WriteDiagDataToNode(FileNode *node) nsa bool WriteDiagDataToNode(Node node)
{ {
uintptr_t KStart = (uintptr_t)&_kernel_start; uintptr_t KStart = (uintptr_t)&_kernel_start;
uintptr_t kEnd = (uintptr_t)&_kernel_end; uintptr_t kEnd = (uintptr_t)&_kernel_end;
@ -89,7 +89,7 @@ nsa bool WriteDiagDataToNode(FileNode *node)
memcpy(file->Data.KernelMemory, (void *)KStart, kSize); memcpy(file->Data.KernelMemory, (void *)KStart, kSize);
ExPrint("Writing to %s\n", node->Path.c_str()); ExPrint("Writing to %s\n", node->Path.c_str());
size_t w = node->Write(buf, fileSize, 0); size_t w = fs->Write(node, buf, fileSize, 0);
if (w != fileSize) if (w != fileSize)
{ {
debug("%d out of %d bytes written", w, fileSize); debug("%d out of %d bytes written", w, fileSize);
@ -115,22 +115,23 @@ nsa void DiagnosticDataCollection()
S_IROTH | S_IROTH |
S_IFDIR; S_IFDIR;
FileNode *panicDir = fs->ForceCreate(nullptr, "/var/panic", mode); Node root = fs->GetRoot(0);
Node panicDir = fs->Create(root, "/sys/log/panic", mode);
if (!panicDir) if (!panicDir)
{ {
ExPrint("\x1b[0;30;41mFailed to create /var/panic\x1b[0m\n"); ExPrint("\x1b[0;30;41mFailed to create /sys/log/panic\x1b[0m\n");
Display->UpdateBuffer(); Display->UpdateBuffer();
return; return;
} }
FileNode *dumpFile; Node dumpFile;
Time::Clock clock = Time::ReadClock(); Time::Clock clock = Time::ReadClock();
char filename[64]; char filename[64];
for (int i = 0; i < INT32_MAX; i++) for (int i = 0; i < INT32_MAX; i++)
{ {
sprintf(filename, "dump-%d-%d-%d-%d.dmp", sprintf(filename, "dump-%d-%d-%d-%d.dmp",
clock.Year, clock.Month, clock.Day, i); clock.Year, clock.Month, clock.Day, i);
if (fs->PathExists(filename, panicDir)) if (fs->Lookup(panicDir, filename))
continue; continue;
mode = S_IRWXU | mode = S_IRWXU |
@ -145,6 +146,6 @@ nsa void DiagnosticDataCollection()
if (!WriteDiagDataToNode(dumpFile)) if (!WriteDiagDataToNode(dumpFile))
return; return;
ExPrint("You can find the diagnostic file in /var/panic/%s\n", filename); ExPrint("You can find the diagnostic file in /sys/log/panic/%s\n", filename);
Display->UpdateBuffer(); Display->UpdateBuffer();
} }

View File

@ -52,7 +52,7 @@ void *FbBeforePanic = nullptr;
size_t FbPagesBeforePanic = 0; size_t FbPagesBeforePanic = 0;
FontRenderer CrashFontRenderer; FontRenderer CrashFontRenderer;
int ExTermColors[] = { static int ExTermColors[] = {
[TerminalColor::BLACK] = 0x000000, [TerminalColor::BLACK] = 0x000000,
[TerminalColor::RED] = 0xAA0000, [TerminalColor::RED] = 0xAA0000,
[TerminalColor::GREEN] = 0x00AA00, [TerminalColor::GREEN] = 0x00AA00,
@ -63,7 +63,7 @@ int ExTermColors[] = {
[TerminalColor::GREY] = 0xAAAAAA, [TerminalColor::GREY] = 0xAAAAAA,
}; };
int ExTermBrightColors[] = { static int ExTermBrightColors[] = {
[TerminalColor::BLACK] = 0x858585, [TerminalColor::BLACK] = 0x858585,
[TerminalColor::RED] = 0xFF5555, [TerminalColor::RED] = 0xFF5555,
[TerminalColor::GREEN] = 0x55FF55, [TerminalColor::GREEN] = 0x55FF55,
@ -84,7 +84,7 @@ void paint_callback(TerminalCell *cell, long x, long y)
nsa void __printfWrapper(char c, void *) nsa void __printfWrapper(char c, void *)
{ {
KernelConsole::Terminals[15]->Process(c); KernelConsole::Terminals[15]->Term->Process(c);
} }
nsa void ExPrint(const char *Format, ...) nsa void ExPrint(const char *Format, ...)
@ -162,7 +162,8 @@ nsa void InitFont()
{ {
size_t Cols = Display->GetWidth / CrashFontRenderer.CurrentFont->GetInfo().Width; size_t Cols = Display->GetWidth / CrashFontRenderer.CurrentFont->GetInfo().Width;
size_t Rows = Display->GetHeight / CrashFontRenderer.CurrentFont->GetInfo().Height; size_t Rows = Display->GetHeight / CrashFontRenderer.CurrentFont->GetInfo().Height;
Terminals[15] = new VirtualTerminal(Cols, Rows, Display->GetWidth, Display->GetHeight, paint_callback, nullptr); Terminals[15] = new ConsoleTerminal;
Terminals[15]->Term = new VirtualTerminal(Cols, Rows, Display->GetWidth, Display->GetHeight, paint_callback, nullptr);
} }
} }
@ -372,7 +373,8 @@ nsa void BaseBufferStackError(bool Stack)
{ {
size_t Cols = Display->GetWidth / CrashFontRenderer.CurrentFont->GetInfo().Width; size_t Cols = Display->GetWidth / CrashFontRenderer.CurrentFont->GetInfo().Width;
size_t Rows = Display->GetHeight / CrashFontRenderer.CurrentFont->GetInfo().Height; size_t Rows = Display->GetHeight / CrashFontRenderer.CurrentFont->GetInfo().Height;
Terminals[15] = new VirtualTerminal(Cols, Rows, Display->GetWidth, Display->GetHeight, paint_callback, nullptr); Terminals[15] = new ConsoleTerminal;
Terminals[15]->Term = new VirtualTerminal(Cols, Rows, Display->GetWidth, Display->GetHeight, paint_callback, nullptr);
} }
ExceptionLock.store(true, std::memory_order_release); ExceptionLock.store(true, std::memory_order_release);
@ -406,8 +408,7 @@ nsa __noreturn void HandleBufferOverflow()
CPU::Stop(); CPU::Stop();
} }
EXTERNC nsa __noreturn void HandleAssertionFailed(const char *File, int Line, EXTERNC nsa __noreturn void HandleAssertionFailed(const char *File, int Line, const char *Expression)
const char *Expression)
{ {
DisplayAssertionFailed(File, Line, Expression); DisplayAssertionFailed(File, Line, Expression);
CPU::Stop(); CPU::Stop();

View File

@ -58,7 +58,7 @@ nsa bool CrashXHCIKeyboardDriver::TakeOwnership()
return true; return true;
exCap->USBLEGSUP.OSOwnsHC = 1; exCap->USBLEGSUP.OSOwnsHC = 1;
TimeManager->Sleep(200, Time::Milliseconds); TimeManager->Sleep(Time::FromMilliseconds(200));
if (exCap->USBLEGSUP.BIOSOwnsHC == 0) if (exCap->USBLEGSUP.BIOSOwnsHC == 0)
return true; return true;

View File

@ -489,12 +489,12 @@ nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame, bool IgnoreReady = tru
bool pRdy = false; bool pRdy = false;
bool showNote = false; bool showNote = false;
/* FIXME: This is slow */ /* FIXME: This is slow */
foreach (auto Process in Plist) for (auto Process : Plist)
{ {
bool ignore = true; bool ignore = true;
if (Process->State == Tasking::Ready && IgnoreReady) if (Process->State == Tasking::Ready && IgnoreReady)
{ {
foreach (auto Thread in Process->Threads) for (auto Thread : Process->Threads)
{ {
if (Thread->State == Tasking::Ready) if (Thread->State == Tasking::Ready)
continue; continue;
@ -522,7 +522,7 @@ nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame, bool IgnoreReady = tru
: "none"); : "none");
bool tRdy = false; bool tRdy = false;
foreach (auto Thread in Process->Threads) for (auto Thread : Process->Threads)
{ {
if (Thread->State == Tasking::Ready && IgnoreReady) if (Thread->State == Tasking::Ready && IgnoreReady)
{ {
@ -571,6 +571,7 @@ nsa void DisplayCrashScreen(CPU::ExceptionFrame *Frame)
DisplayTopOverlay(); DisplayTopOverlay();
DisplayMainScreen(Frame); DisplayMainScreen(Frame);
DisplayStackScreen(Frame);
InitializeKeyboards(); InitializeKeyboards();
DisplayBottomOverlay(); DisplayBottomOverlay();

View File

@ -887,8 +887,8 @@ namespace PCI
{ {
PCIHeader0 *hdr0 = (PCIHeader0 *)Device.Header; PCIHeader0 *hdr0 = (PCIHeader0 *)Device.Header;
uint32_t BAR[6]; uint32_t BAR[6] = {};
size_t BARsSize[6]; size_t BARsSize[6] = {};
BAR[0] = hdr0->BAR0; BAR[0] = hdr0->BAR0;
BAR[1] = hdr0->BAR1; BAR[1] = hdr0->BAR1;
@ -897,8 +897,7 @@ namespace PCI
BAR[4] = hdr0->BAR4; BAR[4] = hdr0->BAR4;
BAR[5] = hdr0->BAR5; BAR[5] = hdr0->BAR5;
debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx", debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx", BAR[0] & 1, BAR[1] & (~3), BAR[0] & (~15));
BAR[0] & 1, BAR[1] & (~3), BAR[0] & (~15));
/* BARs Size */ /* BARs Size */
for (short i = 0; i < 6; i++) for (short i = 0; i < 6; i++)
@ -909,26 +908,46 @@ namespace PCI
size_t size; size_t size;
if ((BAR[i] & 1) == 0) /* Memory Base */ if ((BAR[i] & 1) == 0) /* Memory Base */
{ {
hdr0->BAR0 = 0xFFFFFFFF; hdr0->BAR0 = UINT32_MAX;
size = hdr0->BAR0; size = hdr0->BAR0;
hdr0->BAR0 = BAR[i]; hdr0->BAR0 = BAR[i];
BARsSize[i] = size & (~15);
BARsSize[i] = ~BARsSize[i] + 1; /* FIXME: further testing required */
BARsSize[i] = BARsSize[i] & 0xFFFFFFFF; // if ((BAR[i] & 0x6) == 0x4) /* 64-bit address */
debug("BAR%d %#lx size: %d", // {
i, BAR[i], BARsSize[i]); // hdr0->BAR1 = UINT32_MAX;
// size |= ((size_t)hdr0->BAR1 << 32);
// hdr0->BAR1 = BAR[i + 1];
// i++; /* Skip the next BAR since it's part of the 64-bit address */
// }
size = size & (~15);
size = ~size + 1;
size = size & UINT32_MAX;
if (size == 0)
{
warn("MEM BAR%d size is zero! Device: %#x:%#x", i, Device.Header->VendorID, Device.Header->DeviceID);
size++;
}
BARsSize[i] = size;
} }
else if ((BAR[i] & 1) == 1) /* I/O Base */ else if ((BAR[i] & 1) == 1) /* I/O Base */
{ {
hdr0->BAR1 = 0xFFFFFFFF; hdr0->BAR1 = UINT32_MAX;
size = hdr0->BAR1; size = hdr0->BAR1;
hdr0->BAR1 = BAR[i]; hdr0->BAR1 = BAR[i];
BARsSize[i] = size & (~3);
BARsSize[i] = ~BARsSize[i] + 1; size = size & (~3);
BARsSize[i] = BARsSize[i] & 0xFFFF; size = ~size + 1;
debug("BAR%d %#lx size: %d", size = size & UINT16_MAX;
i, BAR[i], BARsSize[i]); if (size == 0)
{
warn("I/O BAR%d size is zero! Device: %#x:%#x", i, Device.Header->VendorID, Device.Header->DeviceID);
size++;
}
BARsSize[i] = size;
} }
debug("BAR%d %#lx size: %zu", i, BAR[i], BARsSize[i]);
} }
/* Mapping the BARs */ /* Mapping the BARs */
@ -942,24 +961,17 @@ namespace PCI
uintptr_t BARBase = BAR[i] & (~15); uintptr_t BARBase = BAR[i] & (~15);
size_t BARSize = BARsSize[i]; size_t BARSize = BARsSize[i];
debug("Mapping BAR%d %#lx-%#lx", debug("Mapping BAR%d %#lx-%#lx", i, BARBase, BARBase + BARSize);
i, BARBase, BARBase + BARSize);
if (BARSize > 0) Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase,
Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase, BARSize, Memory::RW | Memory::PWT | Memory::PCD);
BARSize, Memory::RW | Memory::PWT);
} }
else if ((BAR[i] & 1) == 1) /* I/O Base */ else if ((BAR[i] & 1) == 1) /* I/O Base */
{ {
uintptr_t BARBase = BAR[i] & (~3); uintptr_t BARBase = BAR[i] & (~3);
size_t BARSize = BARsSize[i]; size_t BARSize = BARsSize[i];
debug("Mapping BAR%d %#x-%#x", debug("no need to map BAR%d %#x-%#x as it's an I/O space", i, BARBase, BARBase + BARSize);
i, BARBase, BARBase + BARSize);
if (BARSize > 0)
Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase,
BARSize, Memory::RW | Memory::PWT);
} }
} }
break; break;
@ -982,6 +994,18 @@ namespace PCI
} }
} }
void Manager::InitializeDevice(PCIDevice Device, Memory::PageTable *Table)
{
this->MapPCIAddresses(Device, Table);
PCI::PCIDeviceHeader *Header = Device.Header;
Header->Command |= PCI_COMMAND_MASTER |
PCI_COMMAND_IO |
PCI_COMMAND_MEMORY;
Header->Command &= ~PCI_COMMAND_INTX_DISABLE;
}
void Manager::EnumerateFunction(uint64_t DeviceAddress, uint32_t Function, PCIDevice dev) void Manager::EnumerateFunction(uint64_t DeviceAddress, uint32_t Function, PCIDevice dev)
{ {
dev.Function = Function; dev.Function = Function;
@ -1051,7 +1075,7 @@ namespace PCI
std::list<PCIDevice> Manager::FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF) std::list<PCIDevice> Manager::FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF)
{ {
std::list<PCIDevice> DeviceFound; std::list<PCIDevice> DeviceFound;
foreach (auto dev in Devices) for (auto dev : Devices)
{ {
if (dev.Header->Class == Class && if (dev.Header->Class == Class &&
dev.Header->Subclass == Subclass && dev.Header->Subclass == Subclass &&
@ -1066,7 +1090,7 @@ namespace PCI
std::list<PCIDevice> Manager::FindPCIDevice(uint16_t VendorID, uint16_t DeviceID) std::list<PCIDevice> Manager::FindPCIDevice(uint16_t VendorID, uint16_t DeviceID)
{ {
std::list<PCIDevice> DeviceFound; std::list<PCIDevice> DeviceFound;
foreach (auto dev in Devices) for (auto dev : Devices)
{ {
if (dev.Header->VendorID == VendorID && if (dev.Header->VendorID == VendorID &&
dev.Header->DeviceID == DeviceID) dev.Header->DeviceID == DeviceID)
@ -1081,11 +1105,11 @@ namespace PCI
std::list<uint16_t> DeviceIDs) std::list<uint16_t> DeviceIDs)
{ {
std::list<PCIDevice> DeviceFound; std::list<PCIDevice> DeviceFound;
foreach (auto dev in Devices) for (auto dev : Devices)
{ {
foreach (auto VendorID in VendorIDs) for (auto VendorID : VendorIDs)
{ {
foreach (auto DeviceID in DeviceIDs) for (auto DeviceID : DeviceIDs)
{ {
if (dev.Header->VendorID == VendorID && if (dev.Header->VendorID == VendorID &&
dev.Header->DeviceID == DeviceID) dev.Header->DeviceID == DeviceID)

View File

@ -67,8 +67,7 @@ namespace Random
if (RDRANDFlag) if (RDRANDFlag)
{ {
uint16_t RDRANDValue = 0; uint16_t RDRANDValue = 0;
asmv("1: rdrand %0; jnc 1b" asmv("1: rdrand %0; jnc 1b" : "=r"(RDRANDValue));
: "=r"(RDRANDValue));
return RDRANDValue; return RDRANDValue;
} }
@ -84,8 +83,7 @@ namespace Random
if (RDRANDFlag) if (RDRANDFlag)
{ {
uint32_t RDRANDValue = 0; uint32_t RDRANDValue = 0;
asmv("1: rdrand %0; jnc 1b" asmv("1: rdrand %0; jnc 1b" : "=r"(RDRANDValue));
: "=r"(RDRANDValue));
return RDRANDValue; return RDRANDValue;
} }
@ -101,8 +99,7 @@ namespace Random
if (RDRANDFlag) if (RDRANDFlag)
{ {
uintptr_t RDRANDValue = 0; uintptr_t RDRANDValue = 0;
asmv("1: rdrand %0; jnc 1b" asmv("1: rdrand %0; jnc 1b" : "=r"(RDRANDValue));
: "=r"(RDRANDValue));
return RDRANDValue; return RDRANDValue;
} }

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